eb651180aa
Front components are third-party UI that runs in a sandboxed worker, so every DOM event reaching them has to be on an explicit allow-list. That list was small: mostly click, focus and pointer events. This adds touch, drag and drop, focusin/focusout, animationend/transitionend and scrollend, plus load/error on `<img>` and toggle on `<details>`/`<dialog>`. Two of them need the host to do more than forward the event: - react-dom has no `onFocusIn`/`onFocusOut` props, so the host attaches those two with `addEventListener` instead. - a browser only fires `drop` on an element whose `dragover` default was prevented, and the component's own `preventDefault` arrives too late across the async worker boundary. The host prevents it synchronously as soon as the component declares either handler. Touch events carry their coordinates on `changedTouches`, so the first touch fills the existing coordinate fields. Still not crossing, since each would need a new serialized field: touch lists, `animationName`/`propertyName`/`elapsedTime`, toggle `newState` and `dataTransfer`. The diff also renames a few things it touches (`filterProps` and `EventToReact` in particular) so the host-side event path reads in order. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22616?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
59 lines
1.6 KiB
TypeScript
59 lines
1.6 KiB
TypeScript
import type { Project, SourceFile } from 'ts-morph';
|
|
|
|
import { DOM_EVENT_TYPE_TO_REACT_PROP } from '../../../src/constants/DomEventTypeToReactProp';
|
|
import { type ComponentSchema } from './schemas';
|
|
import { addExportedConst } from './utils';
|
|
|
|
const generateComponentDefinition = (
|
|
sourceFile: SourceFile,
|
|
component: ComponentSchema,
|
|
): void => {
|
|
const hasEvents = component.events.length > 0;
|
|
|
|
let initializer: string;
|
|
|
|
if (hasEvents) {
|
|
const eventProps = component.events
|
|
.map((event) => {
|
|
const propName = DOM_EVENT_TYPE_TO_REACT_PROP[event];
|
|
return ` ${propName}: { event: '${event}' },`;
|
|
})
|
|
.join('\n');
|
|
|
|
initializer = `createRemoteComponent('${component.customElementName}', ${component.name}Element, {
|
|
eventProps: {
|
|
${eventProps}
|
|
},
|
|
})`;
|
|
} else {
|
|
initializer = `createRemoteComponent('${component.customElementName}', ${component.name}Element)`;
|
|
}
|
|
|
|
addExportedConst(sourceFile, component.name, initializer);
|
|
};
|
|
|
|
export const generateRemoteComponents = (
|
|
project: Project,
|
|
components: ComponentSchema[],
|
|
): SourceFile => {
|
|
const sourceFile = project.createSourceFile('remote-components.ts', '', {
|
|
overwrite: true,
|
|
});
|
|
|
|
sourceFile.addImportDeclaration({
|
|
moduleSpecifier: '@remote-dom/react',
|
|
namedImports: ['createRemoteComponent'],
|
|
});
|
|
|
|
sourceFile.addImportDeclaration({
|
|
moduleSpecifier: './remote-elements',
|
|
namedImports: components.map((component) => `${component.name}Element`),
|
|
});
|
|
|
|
for (const component of components) {
|
|
generateComponentDefinition(sourceFile, component);
|
|
}
|
|
|
|
return sourceFile;
|
|
};
|