diff --git a/packages/react/src/ui/controls/controls-group.tsx b/packages/react/src/ui/controls/controls-group.tsx index dc54db97..1f3e3e29 100644 --- a/packages/react/src/ui/controls/controls-group.tsx +++ b/packages/react/src/ui/controls/controls-group.tsx @@ -12,6 +12,7 @@ export interface ControlsGroupProps extends UIComponentProps<'div', GroupState> children?: ReactNode | undefined; } +/** Layout group for related controls; sets `role="group"` when labeled. */ export const ControlsGroup = forwardRef(function ControlsGroup( componentProps: ControlsGroupProps, forwardedRef: ForwardedRef diff --git a/packages/react/src/ui/controls/controls-root.tsx b/packages/react/src/ui/controls/controls-root.tsx index 76c26fe4..0c764b97 100644 --- a/packages/react/src/ui/controls/controls-root.tsx +++ b/packages/react/src/ui/controls/controls-root.tsx @@ -13,6 +13,7 @@ export interface ControlsRootProps extends UIComponentProps<'div', ControlsCore. children?: ReactNode | undefined; } +/** Root container for player controls state and rendered control content. */ export const ControlsRoot = forwardRef(function ControlsRoot( componentProps: ControlsRootProps, forwardedRef: ForwardedRef diff --git a/site/scripts/api-docs-builder/src/index.ts b/site/scripts/api-docs-builder/src/index.ts index 0c038a61..68740553 100644 --- a/site/scripts/api-docs-builder/src/index.ts +++ b/site/scripts/api-docs-builder/src/index.ts @@ -265,6 +265,7 @@ function discoverParts(source: ComponentSource, program: ts.Program): PartSource const part: PartSource = { name: partExport.name, + localName: partExport.localName, kebab, isPrimary, htmlPath: hasSubPartElement ? subPartElementFile : isPrimary ? source.htmlPath : undefined, @@ -310,7 +311,10 @@ function buildMultiPartApiReference( for (const part of parts) { // Extract JSDoc description from React component file - const description = part.reactPath ? extractPartDescription(part.reactPath, program, part.name) : undefined; + const description = part.reactPath + ? (extractPartDescription(part.reactPath, program, part.localName) ?? + extractPartDescription(part.reactPath, program, part.name)) + : undefined; if (part.isPrimary) { // Primary part: extract from shared core and data-attrs diff --git a/site/scripts/api-docs-builder/src/parts-handler.ts b/site/scripts/api-docs-builder/src/parts-handler.ts index 34926929..28f1282b 100644 --- a/site/scripts/api-docs-builder/src/parts-handler.ts +++ b/site/scripts/api-docs-builder/src/parts-handler.ts @@ -2,8 +2,10 @@ import * as ts from 'typescript'; import * as tae from 'typescript-api-extractor'; export interface PartExport { - /** PascalCase export name (e.g., "Value", "Group", "Separator"). */ + /** PascalCase exported part name (e.g., "Value", "Group", "Separator"). */ name: string; + /** Local symbol name in the source module before aliasing. */ + localName: string; /** Source path (e.g., "./time-value", "./time-group"). */ source: string; } @@ -39,8 +41,10 @@ export function extractParts(filePath: string, program: ts.Program): PartExport[ // Skip type-only specifiers (e.g., `type GroupProps`) if (element.isTypeOnly) continue; + const localName = element.propertyName?.text ?? element.name.text; parts.push({ name: element.name.text, + localName, source, }); } diff --git a/site/scripts/api-docs-builder/src/tests/parts-handler.test.ts b/site/scripts/api-docs-builder/src/tests/parts-handler.test.ts index 39a2fde2..fb9cf26e 100644 --- a/site/scripts/api-docs-builder/src/tests/parts-handler.test.ts +++ b/site/scripts/api-docs-builder/src/tests/parts-handler.test.ts @@ -24,9 +24,9 @@ describe('extractParts', () => { const result = extractParts('test.ts', program); expect(result).toEqual([ - { name: 'Group', source: './time-group' }, - { name: 'Separator', source: './time-separator' }, - { name: 'Value', source: './time-value' }, + { name: 'Group', localName: 'Group', source: './time-group' }, + { name: 'Separator', localName: 'Separator', source: './time-separator' }, + { name: 'Value', localName: 'Value', source: './time-value' }, ]); }); @@ -38,7 +38,7 @@ describe('extractParts', () => { const program = createTestProgram(code); const result = extractParts('test.ts', program); - expect(result).toEqual([{ name: 'Group', source: './time-group' }]); + expect(result).toEqual([{ name: 'Group', localName: 'Group', source: './time-group' }]); }); it('returns empty array for file with no exports', () => { @@ -57,8 +57,8 @@ describe('extractParts', () => { const result = extractParts('test.ts', program); expect(result).toEqual([ - { name: 'Foo', source: './source' }, - { name: 'Bar', source: './source' }, + { name: 'Foo', localName: 'Foo', source: './source' }, + { name: 'Bar', localName: 'Bar', source: './source' }, ]); }); @@ -69,7 +69,17 @@ describe('extractParts', () => { const program = createTestProgram(code); const result = extractParts('test.ts', program); - expect(result).toEqual([{ name: 'Value', source: './time-value' }]); + expect(result).toEqual([{ name: 'Value', localName: 'Value', source: './time-value' }]); + }); + + it('captures local symbol name for aliased exports', () => { + const code = ` + export { ControlsRoot as Root, type ControlsRootProps as RootProps } from './controls-root'; + `; + const program = createTestProgram(code); + const result = extractParts('test.ts', program); + + expect(result).toEqual([{ name: 'Root', localName: 'ControlsRoot', source: './controls-root' }]); }); }); @@ -110,6 +120,24 @@ describe('extractPartDescription', () => { expect(result).toBe('Container for composed time displays.'); }); + it('extracts JSDoc description from a local (non-aliased) symbol name', () => { + const program = createTestProgram(''); + mockParseFromProgram.mockReturnValue({ + exports: [ + { + name: 'ControlsRoot', + documentation: { + description: 'Root container for player controls.', + }, + }, + ], + }); + + const result = extractPartDescription('test.tsx', program, 'ControlsRoot'); + + expect(result).toBe('Root container for player controls.'); + }); + it('returns undefined when export is not found', () => { const program = createTestProgram(''); mockParseFromProgram.mockReturnValue({ diff --git a/site/scripts/api-docs-builder/src/types.ts b/site/scripts/api-docs-builder/src/types.ts index dfaba5e9..be163d89 100644 --- a/site/scripts/api-docs-builder/src/types.ts +++ b/site/scripts/api-docs-builder/src/types.ts @@ -18,6 +18,8 @@ export { ComponentApiReferenceSchema, PartApiReferenceSchema } from '../../../sr export interface PartSource { /** PascalCase name (e.g., "Value", "Group", "Separator"). */ name: string; + /** Local symbol name in the source module (before any aliasing). */ + localName: string; /** Kebab-case segment (e.g., "value", "group", "separator"). */ kebab: string; /** True if this part gets the shared core/data-attrs. */