[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
This commit is contained in:
Raphaël Bosi
2026-02-12 12:48:16 +01:00
committed by GitHub
parent c48ccbca99
commit cb7d0b83a8
133 changed files with 10556 additions and 984 deletions
@@ -5,7 +5,7 @@ const StyledSoonPill = styled(Pill)`
margin-left: auto;
`;
type ButtonSoonProps = {
export type ButtonSoonProps = {
label?: string;
};
@@ -6,7 +6,7 @@ import {
type LightIconButtonProps,
} from '@ui/input/button/components/LightIconButton';
type ColorPickerButtonProps = Pick<ColorSampleProps, 'colorName'> &
export type ColorPickerButtonProps = Pick<ColorSampleProps, 'colorName'> &
Pick<LightIconButtonProps, 'onClick'> & {
isSelected?: boolean;
};
@@ -5,7 +5,7 @@ import React, { type FunctionComponent } from 'react';
export type MainButtonVariant = 'primary' | 'secondary';
type Props = {
export type Props = {
title: string;
fullWidth?: boolean;
width?: number;
@@ -102,7 +102,7 @@ const StyledButton = styled.button<
}};
`;
type MainButtonProps = Props & {
export type MainButtonProps = Props & {
Icon?: IconComponent | FunctionComponent<{ size: number }>;
};
@@ -28,7 +28,7 @@ const StyledIconButton = styled.button<{ size: RoundedIconButtonSize }>`
width: ${({ size }) => (size === 'small' ? '20px' : '24px')};
`;
type RoundedIconButtonProps = {
export type RoundedIconButtonProps = {
Icon: IconComponent;
size?: RoundedIconButtonSize;
} & React.ButtonHTMLAttributes<HTMLButtonElement>;
@@ -4,7 +4,7 @@ import { TabContent } from '@ui/input/button/components/TabButton/internals/comp
import { type ReactElement } from 'react';
import { Link } from 'react-router-dom';
type TabButtonProps = {
export type TabButtonProps = {
id: string;
active?: boolean;
disabled?: boolean;