snapshot of https://github.com/twentyhq/twenty.git (main, 2026-09-17; blobs > 131072B omitted)
Some checks failed
App Prod-Parity E2E Dispatch / dispatch (push) Failing after 10s
CD Storybook UI / build (push) Failing after 3m25s
CD Storybook UI / dispatch (push) Has been skipped
CD deploy main / website-changed-files (push) Successful in 18m8s
CI Agent Skills / changed-files-check (push) Successful in 18m9s
CI Create App E2E minimal / changed-files-check (push) Successful in 24s
CI Create App / changed-files-check (push) Successful in 26s
CI Docs / changed-files-check (push) Successful in 26s
CI Emails / changed-files-check (push) Successful in 28s
CI Example App Hello World / changed-files-check (push) Successful in 23s
CI Front / changed-files-check (push) Has been skipped
CI Example App Postcard / changed-files-check (push) Successful in 27s
CI UI / changed-files-check (push) Has been skipped
CI Utils Test / changed-files-check (push) Successful in 45s
CI Twenty Apps / discover (push) Successful in 1m3s
CD deploy main / deploy-main (push) Failing after 3s
CI Agent Skills / agent-skills-validate (push) Has been skipped
CI Create App / create-app-test (lint) (push) Has been skipped
CI Emails / emails-test (push) Has been skipped
CI Front / front-task (lingui:compile) (push) Has been skipped
CI Front / front-task (lint) (push) Has been skipped
CI Example App Postcard / example-app-postcard (push) Has been skipped
CI UI / ui-task (lint) (push) Has been skipped
CI UI / ui-task (pack-size) (push) Has been skipped
CI UI / ui-task (size) (push) Has been skipped
CI UI / ui-task (test) (push) Has been skipped
CI UI / ui-task (typecheck) (push) Has been skipped
CI Utils Test / utils-test (push) Has been skipped
CI Twenty Apps / ${{ matrix.app.name }} (push) Has been skipped
CI Emails / ci-emails-status-check (push) Successful in 2s
CI Example App Hello World / ci-example-app-hello-world-status-check (push) Successful in 2s
CI Example App Postcard / ci-example-app-postcard-status-check (push) Successful in 3s
CI UI / ui-sb-test (push) Has been skipped
CI Utils Test / ci-utils-test-status-check (push) Successful in 2s
CI Twenty Apps / ci-twenty-apps-status-check (push) Successful in 2s
CI UI / ci-ui-status-check (push) Successful in 2s
CI Desktop / desktop (push) Failing after 1m8s
Push docs to Crowdin / Push documentation to Crowdin (push) Failing after 55s
Push translations to Crowdin / Extract and upload translations (push) Failing after 5s
Push website translations to Crowdin / Extract and upload website translations (push) Failing after 5s
CI Create App / create-app-test (test) (push) Has been skipped
CI Create App / create-app-test (typecheck) (push) Has been skipped
CI Docs / docs-lint (push) Has been skipped
CI Example App Hello World / example-app-hello-world (push) Has been skipped
CI Front / front-task (lingui:extract) (push) Has been skipped
CI Front / front-task (test) (push) Has been skipped
CI Front / front-task (typecheck) (push) Has been skipped
CI UI / ui-sb-build (push) Failing after 1m32s
CI Twenty Apps / ${{ matrix.app.name }} (${{ matrix.server-source }}) (push) Has been skipped
CI Agent Skills / agent-skills-publish (push) Has been skipped
CI Create App / ci-create-app-status-check (push) Successful in 2s
CI Agent Skills / agent-skills-remote-source (push) Has been skipped
CI Create App E2E minimal / create-app-e2e-minimal (push) Has been cancelled
CI E2E Main / e2e-test (push) Has been cancelled
CI Front / front-sb-build (push) Has been cancelled
CI Front / front-build (push) Has been cancelled
CI Create App E2E minimal / ci-create-app-e2e-minimal-status-check (push) Has been cancelled
CI E2E Main / ci-e2e-main-status-check (push) Has been cancelled
CI E2E Main / notify-main-ci-failure (push) Has been cancelled
CI E2E Main / qa-scout-comment (push) Has been cancelled
CI Front / front-sb-test (push) Has been cancelled
CI Front / front-sb-screenshots (push) Has been cancelled
CI Front / ci-front-status-check (push) Has been cancelled
DPA Sub-Processor Sync / sync-subprocessors (push) Failing after 3s
AI Catalog Sync / sync-catalog (push) Failing after 2s

This commit is contained in:
upstream-mirror
2026-09-17 23:28:13 +05:00
commit e7da97194a
32688 changed files with 4208681 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
import { Parser, type ParserOptions } from 'react-docgen-typescript';
import type ts from 'typescript';
type DocComment = ReturnType<Parser['findDocComment']>;
const hasDocComment = (comment: DocComment): boolean =>
comment.fullComment.length > 0 || comment.tags.default !== undefined;
export class DocumentationParser extends Parser {
private readonly typeChecker: ts.TypeChecker;
constructor(program: ts.Program, options: ParserOptions) {
super(program, options);
this.typeChecker = program.getTypeChecker();
}
override findDocComment(symbol: ts.Symbol): DocComment {
const declaringSymbols = this.typeChecker
.getRootSymbols(symbol)
.filter((rootSymbol) => rootSymbol !== symbol);
if (declaringSymbols.length < 2) {
return super.findDocComment(symbol);
}
const mostSpecificComment = [...declaringSymbols]
.reverse()
.map((declaringSymbol) => super.findDocComment(declaringSymbol))
.find(hasDocComment);
return mostSpecificComment ?? super.findDocComment(symbol);
}
}

View File

@@ -0,0 +1,19 @@
import { type AvatarProps } from '../src/primitives/data-display/Avatar/types/AvatarProps';
export const AVATAR_PROP_DESCRIPTIONS = {
src: 'Image URL. A missing or failed image shows the fallback.',
name: 'Name used for the first-letter fallback and the default accessible name when clickable.',
colorSeed: 'Stable value used to choose fallback colors. Defaults to `name`.',
size: 'Avatar size: `xs` (12px), `sm` (14px), `md` (16px), `lg` (24px), or `xl` (40px).',
shape: 'Shape of the avatar and its fallback.',
variant: 'Visual treatment of the fallback.',
icon: 'Icon rendered instead of the image and first-letter fallback.',
color: 'Text color override for a first-letter fallback.',
backgroundColor: 'Background color override for a first-letter fallback.',
borderColor: 'Border color override for the outline fallback.',
pulsing: 'Animates the avatar opacity. Respects reduced-motion preferences.',
disabled:
'Applies disabled styling and disables activation when `onClick` is supplied.',
nativeButton:
'Set to `false` when a clickable avatar uses `render` with an element other than a native button.',
} satisfies Partial<Record<keyof AvatarProps, string>>;

View File

@@ -0,0 +1,9 @@
import { type ButtonGroupProps } from '../src/primitives/input/ButtonGroup/types/ButtonGroupProps';
export const BUTTON_GROUP_PROP_DESCRIPTIONS = {
variant:
'Shared surface treatment that overrides the variant of buttons in the group.',
color:
'Shared semantic color that overrides the color of buttons in the group.',
size: 'Shared button height that overrides the size of buttons in the group.',
} satisfies Partial<Record<keyof ButtonGroupProps, string>>;

View File

@@ -0,0 +1,19 @@
import { type ButtonProps } from '../src/primitives/input/Button/types/ButtonProps';
export const BUTTON_PROP_DESCRIPTIONS = {
variant: 'Visual treatment of the button surface.',
color: 'Semantic color of the button.',
size: 'Button height: `sm` (24px) or `md` (32px).',
fullWidth: 'Expands the button to fill its container width.',
loading:
'Shows a loading indicator and disables activation while preserving the button width.',
elevated: 'Adds a shadow to the button.',
startIcon: 'Decorative content displayed before the label.',
endIcon: 'Decorative content displayed after the label.',
hotkeys: 'Keyboard shortcut hints displayed on non-mobile screens.',
soon: 'Displays a coming-soon label and disables activation.',
soonLabel: 'Text for the coming-soon label.',
href: 'Destination URL. Enables native link semantics instead of button semantics.',
render:
'Caller-supplied root element or renderer. Preserve a native button, or an anchor when `href` is set. Router integration belongs to the caller.',
} satisfies Partial<Record<keyof ButtonProps, string>>;

View File

@@ -0,0 +1,33 @@
import { type ChipProps } from '../src/primitives/data-display/Chip/types/ChipProps';
export const CHIP_PROP_DESCRIPTIONS = {
size: 'Visual size of the chip.',
variant: 'Background treatment of the chip.',
color: 'Primary or secondary text color.',
shape: 'Square or round corners.',
weight: 'Font weight of the label.',
disabled:
'Applies disabled styling and disables activation when `onClick` is supplied.',
clickable:
'Enables hover and pointer styling. Defaults to whether `onClick` is supplied; does not add button semantics by itself.',
nativeButton:
'Set to `false` when a clickable chip uses `render` with an element other than a native button.',
startElement: 'Content before the label, such as an avatar or icon.',
endElement:
'Content after the label. Avoid interactive content when the chip itself is a button.',
endElementDivider:
'Adds a divider before `endElement` when that slot has content.',
maxWidth:
'Maximum chip width in pixels, used to constrain and truncate the label.',
tooltipLabel:
'Tooltip content for a string label. Defaults to the label text.',
tooltipPlace: 'Position of the string-label tooltip.',
alwaysShowTooltip:
'Shows the string-label tooltip even when the label is not truncated.',
isLabelHidden:
'Hides the label while keeping the start and end elements. Supply an accessible name for an interactive chip.',
forceEmptyText:
'Suppresses the empty label when children are missing, empty, or false.',
emptyLabel:
'Placeholder shown when children are missing, empty, or false, unless `forceEmptyText` is enabled.',
} satisfies Partial<Record<keyof ChipProps, string>>;

View File

@@ -0,0 +1,216 @@
import { AVATAR_PROP_DESCRIPTIONS } from './avatarPropDescriptions';
import { BUTTON_GROUP_PROP_DESCRIPTIONS } from './buttonGroupPropDescriptions';
import { BUTTON_PROP_DESCRIPTIONS } from './buttonPropDescriptions';
import { ICON_BUTTON_PROP_DESCRIPTIONS } from './iconButtonPropDescriptions';
import { CHIP_PROP_DESCRIPTIONS } from './chipPropDescriptions';
import { DIALOG_TITLE_PROP_DESCRIPTIONS } from './dialogTitlePropDescriptions';
import { HEADING_PROP_DESCRIPTIONS } from './headingPropDescriptions';
import { LIGHT_BUTTON_PROP_DESCRIPTIONS } from './lightButtonPropDescriptions';
import { SECTION_HEADER_PROP_DESCRIPTIONS } from './sectionHeaderPropDescriptions';
import { SECTION_ROOT_PROP_DESCRIPTIONS } from './sectionRootPropDescriptions';
import { STATUS_PROP_DESCRIPTIONS } from './statusPropDescriptions';
import { TAG_PROP_DESCRIPTIONS } from './tagPropDescriptions';
import { TOOLTIP_PART_PROP_DESCRIPTIONS } from './tooltipPartPropDescriptions';
import { TOOLTIP_PROP_DESCRIPTIONS } from './tooltipPropDescriptions';
export const DOCUMENTED_COMPONENTS = [
{
name: 'IconButton',
source: 'components/IconButton/IconButton.tsx',
entryPoint: 'twenty-ui/components',
slug: 'input/icon-button',
propDescriptions: ICON_BUTTON_PROP_DESCRIPTIONS,
},
{
name: 'MainButton',
source: 'components/MainButton/MainButton.tsx',
entryPoint: 'twenty-ui/components',
slug: 'input/main-button',
propDescriptions: BUTTON_PROP_DESCRIPTIONS,
},
{
name: 'LightButton',
source: 'components/LightButton/LightButton.tsx',
entryPoint: 'twenty-ui/components',
slug: 'input/light-button',
propDescriptions: LIGHT_BUTTON_PROP_DESCRIPTIONS,
},
{
name: 'Button',
source: 'primitives/input/Button/Button.tsx',
entryPoint: 'twenty-ui/primitives/input',
slug: 'input/button',
propDescriptions: BUTTON_PROP_DESCRIPTIONS,
},
{
name: 'ButtonGroup',
source: 'primitives/input/ButtonGroup/ButtonGroup.tsx',
entryPoint: 'twenty-ui/primitives/input',
slug: 'input/button-group',
propDescriptions: BUTTON_GROUP_PROP_DESCRIPTIONS,
},
{
name: 'Field',
source: 'primitives/input/Field/Field.tsx',
entryPoint: 'twenty-ui/primitives/input',
slug: 'input/field',
},
{
name: 'Input',
source: 'primitives/input/Input/Input.tsx',
entryPoint: 'twenty-ui/primitives/input',
slug: 'input/input',
},
{
name: 'InputGroup',
source: 'primitives/input/InputGroup/InputGroup.tsx',
entryPoint: 'twenty-ui/primitives/input',
slug: 'input/input-group',
},
{
name: 'Textarea',
source: 'primitives/input/Textarea/Textarea.tsx',
entryPoint: 'twenty-ui/primitives/input',
slug: 'input/textarea',
},
{
name: 'Checkbox',
source: 'primitives/input/Checkbox/Checkbox.tsx',
entryPoint: 'twenty-ui/primitives/input',
slug: 'input/checkbox',
},
{
name: 'Radio',
source: 'primitives/input/Radio/Radio.tsx',
entryPoint: 'twenty-ui/primitives/input',
slug: 'input/radio',
},
{
name: 'RadioGroup',
source: 'primitives/input/RadioGroup/RadioGroup.tsx',
entryPoint: 'twenty-ui/primitives/input',
slug: 'input/radio-group',
},
{
name: 'Select',
source: 'primitives/input/Select/Select.tsx',
entryPoint: 'twenty-ui/primitives/input',
slug: 'input/select',
},
{
name: 'Slider',
source: 'primitives/input/Slider/Slider.tsx',
entryPoint: 'twenty-ui/primitives/input',
slug: 'input/slider',
},
{
name: 'Switch',
source: 'primitives/input/Switch/Switch.tsx',
entryPoint: 'twenty-ui/primitives/input',
slug: 'input/switch',
},
{
name: 'ListItem',
source: 'primitives/navigation/ListItem/ListItem.tsx',
entryPoint: 'twenty-ui/primitives/navigation',
slug: 'navigation/list-item',
},
{
name: 'Tabs',
source: 'primitives/navigation/Tabs/Tabs.tsx',
entryPoint: 'twenty-ui/primitives/navigation',
slug: 'navigation/tabs',
},
{
name: 'AlertDialog',
source: 'primitives/surfaces/AlertDialog/AlertDialog.tsx',
entryPoint: 'twenty-ui/primitives/surfaces',
slug: 'surfaces/alert-dialog',
},
{
name: 'Menu',
source: 'primitives/surfaces/Menu/Menu.tsx',
entryPoint: 'twenty-ui/primitives/surfaces',
slug: 'surfaces/menu',
},
{
name: 'Popover',
source: 'primitives/surfaces/Popover/Popover.tsx',
entryPoint: 'twenty-ui/primitives/surfaces',
slug: 'surfaces/popover',
},
{
name: 'Tooltip',
source: 'primitives/surfaces/Tooltip/Tooltip.tsx',
entryPoint: 'twenty-ui/primitives/surfaces',
slug: 'surfaces/tooltip',
parts: ['Root', 'Trigger', 'Popup', 'Content', 'Provider'],
propDescriptions: TOOLTIP_PROP_DESCRIPTIONS,
propDefaults: { sideOffset: '10' },
partPropDescriptions: TOOLTIP_PART_PROP_DESCRIPTIONS,
},
{
name: 'Toast',
source: 'primitives/feedback/Toast/Toast.tsx',
entryPoint: 'twenty-ui/primitives/feedback',
slug: 'feedback/toast',
},
{
name: 'Text',
source: 'primitives/typography/Text/Text.tsx',
entryPoint: 'twenty-ui/primitives/typography',
slug: 'typography/text',
},
{
name: 'Avatar',
source: 'primitives/data-display/Avatar/Avatar.tsx',
entryPoint: 'twenty-ui/primitives/data-display',
slug: 'data-display/avatar',
propDescriptions: AVATAR_PROP_DESCRIPTIONS,
},
{
name: 'Chip',
source: 'primitives/data-display/Chip/Chip.tsx',
entryPoint: 'twenty-ui/primitives/data-display',
slug: 'data-display/chip',
propDescriptions: CHIP_PROP_DESCRIPTIONS,
},
{
name: 'Tag',
source: 'primitives/data-display/Tag/Tag.tsx',
entryPoint: 'twenty-ui/primitives/data-display',
slug: 'data-display/tag',
propDescriptions: TAG_PROP_DESCRIPTIONS,
},
{
name: 'Status',
source: 'primitives/data-display/Status/Status.tsx',
entryPoint: 'twenty-ui/primitives/data-display',
slug: 'data-display/status',
propDescriptions: STATUS_PROP_DESCRIPTIONS,
},
{
name: 'Heading',
source: 'primitives/typography/Heading/Heading.tsx',
entryPoint: 'twenty-ui/primitives/typography',
slug: 'typography/heading',
propDescriptions: HEADING_PROP_DESCRIPTIONS,
},
{
name: 'Section',
source: 'components/Section/Section.tsx',
entryPoint: 'twenty-ui/components',
slug: 'components/section',
partPropDescriptions: {
Root: SECTION_ROOT_PROP_DESCRIPTIONS,
Header: SECTION_HEADER_PROP_DESCRIPTIONS,
},
},
{
name: 'Dialog',
source: 'primitives/surfaces/Dialog/Dialog.tsx',
entryPoint: 'twenty-ui/primitives/surfaces',
slug: 'surfaces/dialog',
partPropDescriptions: { Title: DIALOG_TITLE_PROP_DESCRIPTIONS },
},
] as const;

View File

@@ -0,0 +1,7 @@
import { type DialogTitleProps } from '../src/primitives/surfaces/Dialog/types/DialogTitleProps';
import { HEADING_PROP_DESCRIPTIONS } from './headingPropDescriptions';
export const DIALOG_TITLE_PROP_DESCRIPTIONS = {
...HEADING_PROP_DESCRIPTIONS,
size: 'Visual font size, independent of the heading level. Defaults to `lg`.',
} satisfies Partial<Record<keyof DialogTitleProps, string>>;

View File

@@ -0,0 +1,71 @@
const FENCE_OPENING_PATTERN = /^(\s*)(`{3,}|~{3,})[ \t]*(\S*)/;
const FENCE_CLOSING_PATTERN = /^\s*(`{3,}|~{3,})\s*$/;
const EXAMPLE_LANGUAGES = ['ts', 'tsx'] as const;
type OpenFence = {
indentation: number;
marker: string;
language: string;
codeLines: string[];
};
const isExampleLanguage = (
language: string,
): language is (typeof EXAMPLE_LANGUAGES)[number] =>
EXAMPLE_LANGUAGES.some((exampleLanguage) => exampleLanguage === language);
const closesFence = (line: string, fence: OpenFence): boolean => {
const marker = FENCE_CLOSING_PATTERN.exec(line)?.[1];
return (
marker !== undefined &&
marker[0] === fence.marker[0] &&
marker.length >= fence.marker.length
);
};
const removeIndentation = (line: string, indentation: number): string => {
const leadingWhitespace = line.length - line.trimStart().length;
return line.slice(Math.min(leadingWhitespace, indentation));
};
export const extractDocumentationExamples = (
content: string,
): { language: 'ts' | 'tsx'; code: string }[] => {
const examples: { language: 'ts' | 'tsx'; code: string }[] = [];
let openFence: OpenFence | null = null;
for (const line of content.split(/\r?\n/)) {
if (openFence === null) {
const opening = FENCE_OPENING_PATTERN.exec(line);
if (opening) {
openFence = {
indentation: opening[1].length,
marker: opening[2],
language: opening[3].toLowerCase(),
codeLines: [],
};
}
continue;
}
if (!closesFence(line, openFence)) {
openFence.codeLines.push(removeIndentation(line, openFence.indentation));
continue;
}
if (isExampleLanguage(openFence.language)) {
examples.push({
language: openFence.language,
code: `${openFence.codeLines.join('\n')}\n`,
});
}
openFence = null;
}
return examples;
};

View File

@@ -0,0 +1,4 @@
const DATA_URI_PATTERN = /url\(data:([^,)]*),[^)]*\)/g;
export const formatDocumentationTokenValue = (value: string): string =>
value.replace(DATA_URI_PATTERN, 'url(data:$1,...)');

View File

@@ -0,0 +1,60 @@
import ts from 'typescript';
const isTwentyUiModule = (specifier: string): boolean =>
specifier === 'twenty-ui' || specifier.startsWith('twenty-ui/');
const describeDisallowedModule = (specifier: string): string =>
isTwentyUiModule(specifier)
? `${specifier} is not exported by twenty-ui/package.json.`
: `${specifier} is not a twenty-ui entry point or peer dependency. Documentation examples can only import those.`;
export const getDocumentationImportDiagnostics = ({
source,
allowedModules,
}: {
source: ts.SourceFile;
allowedModules: ReadonlySet<string>;
}): ts.Diagnostic[] => {
const diagnostics: ts.Diagnostic[] = [];
const visit = (node: ts.Node) => {
let specifier: ts.Node | undefined;
if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) {
specifier = node.moduleSpecifier;
} else if (
ts.isCallExpression(node) &&
(node.expression.kind === ts.SyntaxKind.ImportKeyword ||
(ts.isIdentifier(node.expression) &&
node.expression.text === 'require'))
) {
specifier = node.arguments[0];
} else if (
ts.isImportTypeNode(node) &&
ts.isLiteralTypeNode(node.argument)
) {
specifier = node.argument.literal;
}
if (
specifier &&
ts.isStringLiteralLike(specifier) &&
!allowedModules.has(specifier.text)
) {
diagnostics.push({
category: ts.DiagnosticCategory.Error,
code: 95000,
file: source,
start: specifier.getStart(source),
length: specifier.getWidth(source),
messageText: describeDisallowedModule(specifier.text),
});
}
ts.forEachChild(node, visit);
};
visit(source);
return diagnostics;
};

View File

@@ -0,0 +1,8 @@
import { type HeadingProps } from '../src/primitives/typography/Heading/types/HeadingProps';
export const HEADING_PROP_DESCRIPTIONS = {
level:
'Semantic heading level, from `h1` through `h6`. Does not change the visual size. Defaults to `2`.',
size: 'Visual font size, independent of the heading level. Defaults to `md`.',
color: 'Theme font color. Defaults to `primary`.',
} satisfies Partial<Record<keyof HeadingProps, string>>;

View File

@@ -0,0 +1,13 @@
import { type IconButtonProps } from '../src/components/IconButton/types/IconButtonProps';
import { BUTTON_PROP_DESCRIPTIONS } from './buttonPropDescriptions';
export const ICON_BUTTON_PROP_DESCRIPTIONS = {
...BUTTON_PROP_DESCRIPTIONS,
size: 'Square button size: `sm` (24px) or `md` (32px).',
children: 'Icon content. Decorative and hidden from assistive technology.',
tooltip: 'Text displayed when hovering or focusing the button.',
tooltipPlace: 'Preferred placement of the tooltip relative to the button.',
tooltipDelay: 'Delay before showing the tooltip.',
tooltipOffset: 'Distance in pixels between the button and the tooltip.',
'aria-label': 'Required accessible name describing the action.',
} satisfies Partial<Record<keyof IconButtonProps, string>>;

View File

@@ -0,0 +1,9 @@
import { type LightButtonProps } from '../src/components/LightButton/types/LightButtonProps';
import { BUTTON_PROP_DESCRIPTIONS } from './buttonPropDescriptions';
export const LIGHT_BUTTON_PROP_DESCRIPTIONS = {
...BUTTON_PROP_DESCRIPTIONS,
emphasis:
'Uses secondary or tertiary text for neutral buttons. Semantic colors and solid surfaces retain their contrast treatment.',
} satisfies Partial<Record<keyof LightButtonProps, string>>;

View File

@@ -0,0 +1,34 @@
import ts from 'typescript';
export const normalizeDocumentationDefaultValue = (
defaultValue: { value: unknown } | null,
): string | null => {
if (defaultValue === null || defaultValue.value === undefined) {
return null;
}
const value = String(defaultValue.value).trim();
if (value === 'undefined') {
return null;
}
const scanner = ts.createScanner(
ts.ScriptTarget.Latest,
true,
undefined,
value,
);
const token = scanner.scan();
const literalValue = scanner.getTokenValue();
if (
(token === ts.SyntaxKind.StringLiteral ||
token === ts.SyntaxKind.NoSubstitutionTemplateLiteral) &&
scanner.scan() === ts.SyntaxKind.EndOfFileToken
) {
return literalValue;
}
return value;
};

View File

@@ -0,0 +1,22 @@
const OPTIONAL_UNDEFINED_SUFFIX = ' | undefined';
export const normalizeDocumentationPropType = ({
type,
required,
}: {
type: { name: string; value?: { value: string }[] };
required: boolean;
}): string => {
if (type.name === 'enum' && type.value !== undefined) {
return type.value
.map((option) => option.value)
.filter((value) => required || value !== 'undefined')
.join(' | ');
}
if (!required && type.name.endsWith(OPTIONAL_UNDEFINED_SUFFIX)) {
return type.name.slice(0, -OPTIONAL_UNDEFINED_SUFFIX.length);
}
return type.name;
};

View File

@@ -0,0 +1,13 @@
import { type SectionHeaderProps } from '../src/components/Section/types/SectionHeaderProps';
import { HEADING_PROP_DESCRIPTIONS } from './headingPropDescriptions';
export const SECTION_HEADER_PROP_DESCRIPTIONS = {
...HEADING_PROP_DESCRIPTIONS,
title: 'Content of the section heading.',
description:
'Supporting text associated with the heading. Strings support links and overflow tooltips; React nodes render as supplied.',
adornment:
'Content alongside the heading, such as an action button or status.',
descriptionLineClamp:
'Maximum visible lines for a string description. Defaults to `5`. Overflowing descriptions can be read in a tooltip on hover or focus.',
} satisfies Partial<Record<keyof SectionHeaderProps, string>>;

View File

@@ -0,0 +1,8 @@
import { type SectionRootProps } from '../src/components/Section/types/SectionRootProps';
export const SECTION_ROOT_PROP_DESCRIPTIONS = {
align: 'Text alignment within the section. Defaults to `left`.',
color: 'Text color within the section. Defaults to `primary`.',
fullWidth:
'Whether the section fills the available width. Defaults to `true`.',
} satisfies Partial<Record<keyof SectionRootProps, string>>;

View File

@@ -0,0 +1,16 @@
import { type StatusProps } from '../src/primitives/data-display/Status/types/StatusProps';
export const STATUS_PROP_DESCRIPTIONS = {
color: 'Theme color used for the status background, text, and loader.',
weight: 'Font weight of the label.',
disabled:
'Applies disabled styling and disables activation when `onClick` is supplied.',
loading:
'Shows a loader after the label. Does not disable the control or announce a status change by itself.',
onClick:
'Handles activation and renders a native button by default. Without it, the default element is a span.',
nativeButton:
'Set to `false` when using `render` with an element other than a native button.',
render:
'Replaces the default element. Required when `nativeButton` is `false`.',
} satisfies Partial<Record<keyof StatusProps, string>>;

View File

@@ -0,0 +1,17 @@
import { type TagProps } from '../src/primitives/data-display/Tag/types/TagProps';
export const TAG_PROP_DESCRIPTIONS = {
color: 'Theme color for the tag, or `transparent` for an unfilled label.',
weight: 'Font weight of the label.',
disabled:
'Applies disabled styling and prevents pointer and keyboard activation.',
nativeButton:
'Set to `false` when a clickable tag uses `render` with an element other than a native button.',
variant: 'Visual treatment of the tag background and border.',
startIcon:
'Decorative icon before the label. Hidden from assistive technology.',
preventShrink:
'Keeps the tag from shrinking and disables string-label truncation and its tooltip.',
preventPadding: 'Removes the tag padding.',
borderStyle: 'Border style used by the outline variant.',
} satisfies Partial<Record<keyof TagProps, string>>;

View File

@@ -0,0 +1,13 @@
import { TOOLTIP_PROP_DESCRIPTIONS } from './tooltipPropDescriptions';
export const TOOLTIP_PART_PROP_DESCRIPTIONS = {
Popup: {
...TOOLTIP_PROP_DESCRIPTIONS,
children: 'Content displayed inside the popup.',
},
Content: {
children: 'Primary text displayed in the tooltip.',
description: 'Secondary explanation beneath the primary text.',
startIcon: 'An icon displayed before the text.',
},
};

View File

@@ -0,0 +1,27 @@
export const TOOLTIP_PROP_DESCRIPTIONS = {
children:
'A single trigger element. Custom components must forward their ref, native attributes, and event handlers.',
content: 'Supplementary content displayed in the tooltip.',
delay: 'Delay in milliseconds before opening on hover. Defaults to 600.',
closeDelay:
'Delay in milliseconds before closing after hover ends. Defaults to 0.',
side: 'Preferred side of the trigger. Defaults to top and may change to avoid collisions.',
align: 'Alignment relative to the trigger. Defaults to center.',
sideOffset: 'Distance from the trigger in pixels. Defaults to 10.',
alignOffset: 'Offset along the alignment axis in pixels.',
arrow: 'Displays an arrow pointing to the trigger. Defaults to false.',
maxWidth: 'Maximum popup width. Defaults to 300 pixels.',
positionMethod: 'CSS positioning method for the popup.',
open: 'Controlled visibility of the tooltip.',
defaultOpen: 'Initial visibility when the tooltip manages its own state.',
onOpenChange: 'Called when an interaction requests a visibility change.',
disabled: 'Prevents the tooltip from opening.',
disableHoverablePopup:
'Prevents hovering over the popup from keeping it open.',
className: 'Additional CSS class for the popup.',
style: 'Inline styles for the popup.',
ref: 'Ref forwarded to the popup element.',
container: 'Portal destination. Defaults to the current theme container.',
keepMounted: 'Keeps the popup mounted while closed.',
anchor: 'An explicit positioning anchor for the popup.',
};

View File

@@ -0,0 +1,24 @@
export type ComponentDocumentation = {
name: string;
entryPoint: string;
slug: string;
parts?: {
name: string;
props: ComponentDocumentation['props'];
}[];
props: {
name: string;
type: string;
required: boolean;
defaultValue: string | null;
description: string;
}[];
};
export type TokenDocumentation = {
path: string;
cssVariable: string;
light: string;
dark: string;
isNumber: boolean;
};