Files
twenty/packages/twenty-sdk/scripts/remote-dom/twenty-ui-extractor/utils/is-dom-event-handler.ts
T
Raphaël Bosi cb7d0b83a8 [FRONT COMPONENTS] Twenty UI elements generation (#17866)
## PR description

This PR:
- Creates a TypeScript-based extractor that discovers all exported
twenty-ui components by scanning barrel files, extracting
props/slots/events via ts-morph type analysis, and generating the remote
DOM bindings automatically.

- Adds a new ESLint rule which enforces all *Props types in twenty-ui
components to be exported, which is required for the extractor to
discover component prop types. Existing twenty-ui components are updated
to comply with this rule.

- Extends the remote DOM generation to support slots, per-component
events, forwardRef wrappers, and richer property types (array, object,
function)

## Edge cases to fix in another PR

- Icons cannot be rendered inside buttons
- IconButtons throw an error when mounted
- MenuItems are not displayed correctly
- MenuItemNavigate throws on click

## Video Demo


https://github.com/user-attachments/assets/c2ed67cf-6a15-4896-9fec-e83fac0e862b
2026-02-12 12:48:16 +01:00

58 lines
1.2 KiB
TypeScript

import { type Type } from 'ts-morph';
import { isDefined, isNonEmptyArray } from 'twenty-shared/utils';
const DOM_EVENT_TYPE_NAMES = new Set([
'Event',
'UIEvent',
'MouseEvent',
'KeyboardEvent',
'FocusEvent',
'ChangeEvent',
'FormEvent',
'DragEvent',
'WheelEvent',
'ClipboardEvent',
'TouchEvent',
'PointerEvent',
'AnimationEvent',
'TransitionEvent',
'SyntheticEvent',
'BaseSyntheticEvent',
]);
const isEventType = (type: Type): boolean => {
const symbol = type.getSymbol() ?? type.getAliasSymbol();
if (isDefined(symbol) && DOM_EVENT_TYPE_NAMES.has(symbol.getName())) {
return true;
}
return type.getBaseTypes().some(isEventType);
};
export const isDomEventHandler = (propertyType: Type): boolean => {
const nonNullableType = propertyType.getNonNullableType();
const callSignatures = nonNullableType.getCallSignatures();
if (!isNonEmptyArray(callSignatures)) {
return false;
}
return callSignatures.some((signature) => {
const firstParam = signature.getParameters()[0];
if (!isDefined(firstParam)) {
return false;
}
const paramType = firstParam.getValueDeclaration()?.getType();
if (!isDefined(paramType)) {
return false;
}
return isEventType(paramType);
});
};