[go: nahoru, domu]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!: update to use dynamic imports for web components #210

Closed
wants to merge 37 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
a327c2f
Use dynamic imports for web components
web-padawan Dec 26, 2023
e2c9422
Import from theme folder
web-padawan Jan 8, 2024
6047f1d
Fix import for chart-series and iconset
web-padawan Jan 8, 2024
b98d577
Add ts-ignore comment to dynamic imports
web-padawan Jan 8, 2024
394b639
Fix Select to not throw before defined
web-padawan Jan 8, 2024
6fbc419
Re-export types, revert some changes
web-padawan Jan 8, 2024
bc60bfa
Make column re-export from Grid type-only
web-padawan Jan 8, 2024
d68079f
Update ComboBox tests to use await
web-padawan Jan 8, 2024
51bfb3e
Use type-only imports in typings tests
web-padawan Jan 8, 2024
ba1f784
Make Dialog and VirtualList tests async
web-padawan Jan 8, 2024
d2da13a
Make MenuBar and Notification tests async
web-padawan Jan 8, 2024
539eff7
Make ContextMenu and Select tests async
web-padawan Jan 8, 2024
7e55b1f
Fix MultiSelectComboBox event spy in test
web-padawan Jan 8, 2024
77e1d43
Add TODO comment clarifying need for ts-ignore
web-padawan Jan 15, 2024
6948a00
Suppress post-finalize style warning
web-padawan Jan 15, 2024
9652fb1
Revert GridDefaultItem import change
web-padawan Jan 15, 2024
d90f5d8
Make Notification.show import the WC if needed
web-padawan Jan 15, 2024
d4b6ad1
Mark CrudEditColumn as element without theme
web-padawan Jan 15, 2024
3fbf642
Add vaadin-crud-edit to elements without theme
web-padawan Jan 15, 2024
e4533c2
Apply code review suggestion regarding render
web-padawan Jan 15, 2024
8649529
Add define option to call importFunc explicitly
web-padawan Jan 16, 2024
af6f700
Update Dialog to expose define helper
web-padawan Jan 16, 2024
c77b8ca
Fix MenuBar test suite to use type-only import
web-padawan Jan 16, 2024
acfa5ba
Update ContextMenu to expose define helper
web-padawan Jan 16, 2024
16e76c0
Update Select to expose define helper
web-padawan Jan 16, 2024
bf4b085
Update VirtualList to expose define helper
web-padawan Jan 16, 2024
2d36906
Update ComboBox to expose define helper
web-padawan Jan 16, 2024
286ec7f
Update ComboBoxLight to expose define helper
web-padawan Jan 17, 2024
b862067
Update MenuBar to expose define helper
web-padawan Jan 17, 2024
5089f60
Update MultiSelectComboBox to expose define helper
web-padawan Jan 17, 2024
edfca5b
Update Notification to expose define helper
web-padawan Jan 17, 2024
8a17135
Add define helper to components return types
web-padawan Jan 17, 2024
f801fa9
Update DateTimePicker to expose define helper
web-padawan Jan 17, 2024
fd5bc44
Update TimePicker to expose define helper
web-padawan Jan 17, 2024
ca6fbcc
Update TabSheet to expose define helper
web-padawan Jan 17, 2024
2a59862
Add define to Grid, GridPro and columns
web-padawan Jan 17, 2024
84e7dc2
Revert no longer needed generator tweaks
web-padawan Jan 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Use dynamic imports for web components
  • Loading branch information
web-padawan committed Jan 17, 2024
commit a327c2f192eb02e9657444f1b8a1d5a3e9f6ba3f
2 changes: 1 addition & 1 deletion dev/pages/Grid.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Grid, type GridDataProvider } from '../../src/Grid.js';
import { GridSelectionColumn } from '../../src/GridSelectionColumn.js';
import { GridTreeColumn } from '../../src/GridTreeColumn.js';
import { GridColumn, GridColumnElement } from '../../src/GridColumn.js';
import { GridColumn, type GridColumnElement } from '../../src/GridColumn.js';
import { Tooltip } from '../../src/Tooltip.js';

type Item = {
Expand Down
46 changes: 39 additions & 7 deletions scripts/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const CREATE_COMPONENT_PATH = '$CREATE_COMPONENT_PATH$';
const EVENT_MAP = '$EVENT_MAP$';
const EVENT_MAP_REF_IN_EVENTS = '$EVENT_MAP_REF_IN_EVENTS$';
const EVENTS_DECLARATION = '$EVENTS_DECLARATION$';
const PROPERTIES_DECLARATION = '$PROPERTIES_DECLARATION$';
const LIT_REACT_PATH = '@lit/react';
const MODULE_PATH = '$MODULE_PATH$';

Expand Down Expand Up @@ -89,6 +90,10 @@ function isEventListDeclaration(node: Node): node is Identifier {
return ts.isIdentifier(node) && node.text === EVENTS_DECLARATION;
}

function isPropertiesListDeclaration(node: Node): node is Identifier {
return ts.isIdentifier(node) && node.text === PROPERTIES_DECLARATION;
}

function isEventMapReferenceInEventsDeclaration(node: Node): node is Identifier {
return ts.isIdentifier(node) && node.text === EVENT_MAP_REF_IN_EVENTS;
}
Expand Down Expand Up @@ -161,6 +166,29 @@ function createEventList(elementName: string, events: readonly NamedGenericJsCon
);
}

function createPropertiesList(
elementName: string,
properties: readonly NamedGenericJsContribution[] | undefined,
): Node {
return ts.factory.createObjectLiteralExpression([
ts.factory.createPropertyAssignment(
ts.factory.createIdentifier('name'),
ts.factory.createStringLiteral(elementName),
),
ts.factory.createPropertyAssignment(
ts.factory.createIdentifier('_properties'),
ts.factory.createObjectLiteralExpression(
properties?.map((property) => {
return ts.factory.createPropertyAssignment(
ts.factory.createIdentifier(property.name),
ts.factory.createStringLiteral(''),
);
}),
),
),
]);
}

function removeAllEventRelated(node: Node, hasEvents: boolean, hasKnownEvents: boolean): Node | undefined {
if (hasEvents && hasKnownEvents) {
return node;
Expand Down Expand Up @@ -302,6 +330,7 @@ function generateReactComponent({ name, js }: SchemaHTMLElement, { packageName,

const hasEvents = !!js?.events && js.events.length > 0;
const events = js?.events;
const properties = js?.properties as readonly NamedGenericJsContribution[] | undefined;
const eventNameMissingLogger = () => console.error(`[${packageName}]: event name is missing`);
const namedEvents = pickNamedEvents(events, eventNameMissingLogger);
const { remove: eventsToRemove, makeUnknown: eventsToBeUnknown } = eventSettings.get(elementName) ?? {};
Expand All @@ -311,27 +340,29 @@ function generateReactComponent({ name, js }: SchemaHTMLElement, { packageName,
const ast = template(
`
import type { EventName } from "${LIT_REACT_PATH}";
import {
import type {
${COMPONENT_NAME} as ${COMPONENT_NAME}Element
type ${COMPONENT_NAME}EventMap as _${COMPONENT_NAME}EventMap,
${COMPONENT_NAME}EventMap as _${COMPONENT_NAME}EventMap,
} from "${MODULE_PATH}";
import * as React from "react";
import { createComponent, type WebComponentProps } from "${CREATE_COMPONENT_PATH}";
import { createComponent, type PolymerConstructor, type WebComponentProps } from "${CREATE_COMPONENT_PATH}";

export * from "${MODULE_PATH}";
const importFunc = () => import("${MODULE_PATH}");

export {
export type {
${COMPONENT_NAME}Element,
};

export type ${EVENT_MAP};
const elementClass = ${PROPERTIES_DECLARATION} as unknown as PolymerConstructor<${COMPONENT_NAME}Element>;
const events = ${EVENTS_DECLARATION} as ${EVENT_MAP_REF_IN_EVENTS};
export type ${COMPONENT_NAME}Props = WebComponentProps<${COMPONENT_NAME}Element, ${EVENT_MAP}>;
export const ${COMPONENT_NAME} = createComponent({
elementClass: ${COMPONENT_NAME}Element,
elementClass,
events,
react: React,
tagName: ${COMPONENT_TAG}
tagName: ${COMPONENT_TAG},
importFunc
});
`,
(statements) => statements,
Expand All @@ -341,6 +372,7 @@ export const ${COMPONENT_NAME} = createComponent({
isEventMapDeclaration(node) ? createEventMapDeclaration(node, elementName, namedEvents) : node,
),
transform((node) => (isEventListDeclaration(node) ? createEventList(elementName, namedEvents) : node)),
transform((node) => (isPropertiesListDeclaration(node) ? createPropertiesList(elementName, properties) : node)),
transform((node) => addGenerics(node, elementName)),
transform((node) => {
if (!ts.isStringLiteral(node)) {
Expand Down
2 changes: 1 addition & 1 deletion src/ChartSeries.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { HTMLAttributes, ReactElement, RefAttributes } from 'react';
import {
ChartSeriesElement,
type ChartSeriesElement,
ChartSeries as _ChartSeries,
type ChartSeriesProps as _ChartSeriesProps,
} from './generated/ChartSeries.js';
Expand Down
2 changes: 1 addition & 1 deletion src/ConfirmDialog.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { HTMLAttributes, ReactElement, RefAttributes } from 'react';
import {
ConfirmDialogElement,
type ConfirmDialogElement,
ConfirmDialog as _ConfirmDialog,
type ConfirmDialogProps as _ConfirmDialogProps,
} from './generated/ConfirmDialog.js';
Expand Down
3 changes: 1 addition & 2 deletions src/ContextMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { type ComponentType, type ForwardedRef, forwardRef, type ReactElement } from 'react';
import type { ContextMenuItem as _ContextMenuItem, ContextMenuRendererContext } from '@vaadin/context-menu';
import {
ContextMenu as _ContextMenu,
type ContextMenuRendererContext,
type ContextMenuElement,
type ContextMenuProps as _ContextMenuProps,
type ContextMenuItem as _ContextMenuItem,
} from './generated/ContextMenu.js';
import { type ReactContextRendererProps, useContextRenderer } from './renderers/useContextRenderer.js';
import { getOriginalItem, mapItemsWithComponents } from './utils/mapItemsWithComponents.js';
Expand Down
2 changes: 1 addition & 1 deletion src/CookieConsent.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { HTMLAttributes, ReactElement, RefAttributes } from 'react';
import {
CookieConsentElement,
type CookieConsentElement,
CookieConsent as _CookieConsent,
type CookieConsentProps as _CookieConsentProps,
} from './generated/CookieConsent.js';
Expand Down
10 changes: 3 additions & 7 deletions src/Grid.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import { type ComponentType, type ForwardedRef, forwardRef, type ReactElement, type RefAttributes } from 'react';
import {
Grid as _Grid,
type GridDefaultItem,
type GridElement,
type GridProps as _GridProps,
} from './generated/Grid.js';
import type { GridDefaultItem } from '@vaadin/grid';
import { Grid as _Grid, type GridElement, type GridProps as _GridProps } from './generated/Grid.js';
import type { GridRowDetailsReactRendererProps } from './renderers/grid.js';
import { useModelRenderer } from './renderers/useModelRenderer.js';

Expand All @@ -14,7 +10,7 @@ import { useModelRenderer } from './renderers/useModelRenderer.js';
// Fix: use re-exports from raw "src/vaadin-grid.js" as a workaround, until
// the re-export is removed.
export * from '@vaadin/grid/src/vaadin-grid.js';
export { GridElement, type GridEventMap } from './generated/Grid.js';
export type { GridElement, GridEventMap } from './generated/Grid.js';

export type GridProps<TItem> = Partial<Omit<_GridProps<TItem>, 'rowDetailsRenderer'>> &
Readonly<{
Expand Down
2 changes: 1 addition & 1 deletion src/GridColumn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
type ReactNode,
type RefAttributes,
} from 'react';
import type { GridDefaultItem } from './generated/Grid.js';
import type { GridDefaultItem } from '@vaadin/grid';
import {
GridColumn as _GridColumn,
type GridColumnElement,
Expand Down
2 changes: 1 addition & 1 deletion src/GridFilterColumn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
type ReactNode,
type RefAttributes,
} from 'react';
import type { GridDefaultItem } from './generated/Grid.js';
import type { GridDefaultItem } from '@vaadin/grid';
import {
GridFilterColumn as _GridFilterColumn,
type GridFilterColumnElement,
Expand Down
2 changes: 1 addition & 1 deletion src/GridPro.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type ComponentType, type ForwardedRef, forwardRef, type ReactElement, type RefAttributes } from 'react';
import type { GridDefaultItem } from './generated/Grid.js';
import type { GridDefaultItem } from '@vaadin/grid';
import { GridPro as _GridPro, type GridProElement, type GridProProps as _GridProProps } from './generated/GridPro.js';
import type { GridRowDetailsReactRendererProps } from './renderers/grid.js';
import { useModelRenderer } from './renderers/useModelRenderer.js';
Expand Down
2 changes: 1 addition & 1 deletion src/GridSelectionColumn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
type ReactNode,
type RefAttributes,
} from 'react';
import type { GridDefaultItem } from './generated/Grid.js';
import type { GridDefaultItem } from '@vaadin/grid';
import {
GridSelectionColumn as _GridSelectionColumn,
type GridSelectionColumnElement,
Expand Down
2 changes: 1 addition & 1 deletion src/GridSortColumn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
type ReactNode,
type RefAttributes,
} from 'react';
import type { GridDefaultItem } from './generated/Grid.js';
import type { GridDefaultItem } from '@vaadin/grid';
import {
GridSortColumn as _GridSortColumn,
type GridSortColumnElement,
Expand Down
4 changes: 2 additions & 2 deletions src/GridTreeColumn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import {
type ReactNode,
type RefAttributes,
} from 'react';
import type { GridDefaultItem } from './generated/Grid.js';
import type { GridDefaultItem } from '@vaadin/grid';
import {
GridTreeColumnElement,
type GridTreeColumnElement,
GridTreeColumn as _GridTreeColumn,
type GridTreeColumnProps as _GridTreeColumnProps,
} from './generated/GridTreeColumn.js';
Expand Down
2 changes: 1 addition & 1 deletion src/LoginOverlay.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { HTMLAttributes, ReactElement, RefAttributes } from 'react';
import {
LoginOverlayElement,
type LoginOverlayElement,
LoginOverlay as _LoginOverlay,
type LoginOverlayProps as _LoginOverlayProps,
} from './generated/LoginOverlay.js';
Expand Down
9 changes: 2 additions & 7 deletions src/MenuBar.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import { type ForwardedRef, forwardRef, type ReactElement } from 'react';
import {
MenuBar as _MenuBar,
type MenuBarElement,
type MenuBarProps as _MenuBarProps,
type MenuBarItem as _MenuBarItem,
type SubMenuItem as _SubMenuItem,
} from './generated/MenuBar.js';
import { MenuBar as _MenuBar, type MenuBarElement, type MenuBarProps as _MenuBarProps } from './generated/MenuBar.js';
import { getOriginalItem, mapItemsWithComponents } from './utils/mapItemsWithComponents.js';
import type { MenuBarItem as _MenuBarItem, SubMenuItem as _SubMenuItem } from '@vaadin/menu-bar';

export * from './generated/MenuBar.js';

Expand Down
21 changes: 16 additions & 5 deletions src/Notification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import {
} from 'react';
import {
Notification as _Notification,
NotificationElement,
type NotificationElement,
type NotificationProps as _NotificationProps,
type ShowOptions,
} from './generated/Notification.js';
import { useSimpleOrChildrenRenderer } from './renderers/useSimpleOrChildrenRenderer.js';
import type { ReactSimpleRendererProps } from './renderers/useSimpleRenderer.js';
import type { ShowOptions } from '@vaadin/notification';

export * from './generated/Notification.js';

Expand Down Expand Up @@ -47,11 +47,22 @@ function Notification(
);
}

export type NotificationFunction = ForwardRefExoticComponent<NotificationProps & RefAttributes<NotificationElement>> & {
show(contents: string, options?: ShowOptions): NotificationElement;
type NotificationShow = {
show(contents: string, options?: ShowOptions): Promise<NotificationElement>;
};

export type NotificationFunction = ForwardRefExoticComponent<NotificationProps & RefAttributes<NotificationElement>> &
NotificationShow;

const ForwardedNotification = forwardRef(Notification) as NotificationFunction;
ForwardedNotification.show = NotificationElement.show;

ForwardedNotification.show = function (contents: string, options?: ShowOptions) {
return new Promise((resolve) => {
customElements.whenDefined('vaadin-notification').then(() => {
const Notification = customElements.get('vaadin-notification') as unknown as NotificationShow;
resolve(Notification.show(contents, options));
});
});
};

export { ForwardedNotification as Notification };
3 changes: 1 addition & 2 deletions src/VirtualList.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { type ComponentType, type ForwardedRef, forwardRef, type ReactElement, type RefAttributes } from 'react';
import {
VirtualList as _VirtualList,
type VirtualListDefaultItem,
type VirtualListElement,
type VirtualListItemModel,
type VirtualListProps as _VirtualListProps,
} from './generated/VirtualList.js';
import { type ReactModelRendererProps, useModelRenderer } from './renderers/useModelRenderer.js';
import type { VirtualListDefaultItem, VirtualListItemModel } from '@vaadin/virtual-list';

export * from './generated/VirtualList.js';

Expand Down
25 changes: 21 additions & 4 deletions src/utils/createComponent.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createComponent as _createComponent, type EventName } from '@lit/react';
import type { ThemePropertyMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-theme-property-mixin.js';
import type React from 'react';
import React from 'react';
import type { RefAttributes } from 'react';

declare const __VERSION__: string;
Expand Down Expand Up @@ -31,13 +31,14 @@ window.Vaadin.registrations.push({
// TODO: Remove when types from @lit-labs/react are exported
export type EventNames = Record<string, EventName | string>;
type Constructor<T> = { new (): T; name: string };
type PolymerConstructor<T> = Constructor<T> & { _properties: Record<string, unknown> };
export type PolymerConstructor<T> = Constructor<T> & { _properties: Record<string, unknown> };
type Options<I extends HTMLElement, E extends EventNames = {}> = Readonly<{
displayName?: string;
elementClass: Constructor<I> | PolymerConstructor<I>;
events?: E;
react: typeof window.React;
tagName: string;
importFunc?: Function;
}>;

// A map of expected event listener types based on EventNames.
Expand Down Expand Up @@ -86,9 +87,9 @@ export function createComponent<I extends HTMLElement, E extends EventNames = {}
): (props: WebComponentProps<I, E> & RefAttributes<I>) => React.ReactElement | null;

export function createComponent<I extends HTMLElement, E extends EventNames = {}>(options: Options<I, E>): any {
const { elementClass } = options;
const { elementClass, importFunc } = options;

return _createComponent(
const Component = _createComponent(
'_properties' in elementClass
? {
...options,
Expand All @@ -105,4 +106,20 @@ export function createComponent<I extends HTMLElement, E extends EventNames = {}
}
: options,
);

const originalRenderFunc = (Component as any).render;

(Component as any).render = (props: any, ...rest: any) => {
tomivirkki marked this conversation as resolved.
Show resolved Hide resolved
React.useEffect(() => {
// Run dynamic import for the component
if (importFunc && !('__called' in importFunc)) {
(importFunc as any).__called = true;
importFunc();
}
}, []);

return originalRenderFunc(props, ...rest);
};

return Component;
}
2 changes: 1 addition & 1 deletion test/Grid.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { expect, use as useChaiPlugin } from '@esm-bundle/chai';
import chaiDom from 'chai-dom';
import { cleanup, render } from '@testing-library/react/pure.js';
import { Grid, type GridDataProvider } from '../src/Grid.js';
import { GridColumn, GridColumnElement } from '../src/GridColumn.js';
import { GridColumn, type GridColumnElement } from '../src/GridColumn.js';
import { GridFilterColumn } from '../src/GridFilterColumn.js';
import { GridProEditColumn } from '../src/GridProEditColumn.js';
import { GridSelectionColumn } from '../src/GridSelectionColumn.js';
Expand Down
4 changes: 2 additions & 2 deletions test/Notification.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ describe('Notification', () => {
});

describe('show()', () => {
it('should render correctly', () => {
ref.current = Notification.show('FooBar');
it('should render correctly', async () => {
ref.current = await Notification.show('FooBar');
assert();
});
});
Expand Down
2 changes: 1 addition & 1 deletion test/Select.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import chaiDom from 'chai-dom';
import type { ReactElement } from 'react';
import { ListBox } from '../src/ListBox.js';
import { Item } from '../src/Item.js';
import { Select, SelectElement } from '../src/Select.js';
import { Select, type SelectElement } from '../src/Select.js';
import { findByQuerySelector } from './utils/findByQuerySelector.js';

useChaiPlugin(chaiDom);
Expand Down
2 changes: 1 addition & 1 deletion test/SideNav.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect, use as useChaiPlugin } from '@esm-bundle/chai';
import { render } from '@testing-library/react';
import chaiDom from 'chai-dom';
import { SideNav, SideNavElement } from '../src/SideNav.js';
import { SideNav, type SideNavElement } from '../src/SideNav.js';
import { findByQuerySelector } from './utils/findByQuerySelector.js';

useChaiPlugin(chaiDom);
Expand Down