Files
twenty/packages/twenty-sdk/scripts/remote-dom/twenty-ui-extractor/utils/log-discovered-components.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

64 lines
1.4 KiB
TypeScript

import chalk from 'chalk';
import {
formatEvents,
formatProps,
formatSlots,
logCountInline,
logDimText,
logLine,
} from '../../utils/logger';
type ComponentSummary = {
tag: string;
componentImport: string;
properties: Record<string, unknown>;
events: string[];
slots: string[];
};
export const logDiscoveredComponents = (
discoveredComponents: ComponentSummary[],
): void => {
if (discoveredComponents.length === 0) {
logDimText(' No components found');
return;
}
logLine(
' ' +
logCountInline(
discoveredComponents.length,
'component found',
'components found',
),
);
for (const discoveredComponent of discoveredComponents) {
const propertyCount = Object.keys(discoveredComponent.properties).length;
const eventCount = discoveredComponent.events.length;
const slotCount = discoveredComponent.slots.length;
const parts: string[] = [formatProps(propertyCount)];
if (eventCount > 0) {
parts.push(formatEvents(eventCount, discoveredComponent.events));
}
if (slotCount > 0) {
parts.push(formatSlots(slotCount, discoveredComponent.slots));
}
logLine(
chalk.green(' · ') +
chalk.green(discoveredComponent.componentImport) +
chalk.gray(' -> ') +
chalk.white(discoveredComponent.tag) +
chalk.gray(' (') +
parts.join(chalk.green(', ')) +
chalk.gray(')'),
);
}
};