cb7d0b83a8
## 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
58 lines
1.2 KiB
TypeScript
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);
|
|
});
|
|
};
|