feat(site): add util reference pipeline (#537)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Darius Cepulis
2026-02-24 15:34:34 -06:00
committed by GitHub
co-authored by Claude Opus 4.6
parent c11395ece1
commit 78112fbefd
143 changed files with 7031 additions and 481 deletions
@@ -2,21 +2,20 @@
/**
* Renders the data attributes table for API reference.
*/
import MarkdownCode from '@/components/typography/MarkdownCode.astro';
import Table from '@/components/typography/Table.astro';
import Tbody from '@/components/typography/Tbody.astro';
import Td from '@/components/typography/Td.astro';
import Th from '@/components/typography/Th.astro';
import Thead from '@/components/typography/Thead.astro';
import Tr from '@/components/typography/Tr.astro';
import type { DataAttrDef } from '@/types/api-reference';
import InlineMarkdown from './InlineMarkdown.astro';
import type { DataAttrDef } from '@/types/component-reference';
import DataAttrRow from './DataAttrRow.astro';
interface Props {
dataAttributes: Record<string, DataAttrDef>;
componentName: string;
}
const { dataAttributes } = Astro.props;
const { dataAttributes, componentName } = Astro.props;
const attrs = Object.entries(dataAttributes);
---
@@ -25,18 +24,20 @@ const attrs = Object.entries(dataAttributes);
<Thead>
<Tr>
<Th>Attribute</Th>
<Th>Description</Th>
<Th>Type</Th>
<Th />
</Tr>
</Thead>
<Tbody>
{
attrs.map(([name, def]) => (
<Tr>
<Td class="align-top">
<MarkdownCode>{name}</MarkdownCode>
</Td>
<Td><InlineMarkdown content={def.description} /></Td>
</Tr>
<DataAttrRow
name={name}
type={def.type}
detailedType={def.detailedType}
description={def.description}
componentName={componentName}
/>
))
}
</Tbody>
@@ -9,7 +9,7 @@ import Tbody from '@/components/typography/Tbody.astro';
import Th from '@/components/typography/Th.astro';
import Thead from '@/components/typography/Thead.astro';
import Tr from '@/components/typography/Tr.astro';
import type { PropDef } from '@/types/api-reference';
import type { PropDef } from '@/types/component-reference';
import PropRow from './PropRow.astro';
interface Props {
@@ -35,7 +35,7 @@ const { props, componentName } = Astro.props;
<PropRow
name={name}
type={prop.type}
shortType={prop.shortType}
detailedType={prop.detailedType}
description={prop.description}
defaultValue={prop.default}
required={prop.required}
@@ -7,7 +7,7 @@ import Tbody from '@/components/typography/Tbody.astro';
import Th from '@/components/typography/Th.astro';
import Thead from '@/components/typography/Thead.astro';
import Tr from '@/components/typography/Tr.astro';
import type { StateDef } from '@/types/api-reference';
import type { StateDef } from '@/types/component-reference';
import StateRow from './StateRow.astro';
interface Props {
@@ -34,7 +34,7 @@ const stateEntries = Object.entries(state);
<StateRow
name={name}
type={def.type}
shortType={def.shortType}
detailedType={def.detailedType}
description={def.description}
componentName={componentName}
/>
@@ -7,9 +7,9 @@ import H3 from '@/components/typography/H3Markdown.astro';
import H4 from '@/components/typography/H4Markdown.astro';
import MarkdownCode from '@/components/typography/MarkdownCode.astro';
import P from '@/components/typography/P.astro';
import type { ComponentApiReference } from '@/types/api-reference';
import type { ComponentReference } from '@/types/component-reference';
import { isValidFramework } from '@/types/docs';
import { createApiReferenceModel } from '@/utils/apiReferenceModel';
import { createComponentReferenceModel } from '@/utils/componentReferenceModel';
import FrameworkCase from '../FrameworkCase.astro';
import ApiDataAttrsTable from './ApiDataAttrsTable.astro';
import ApiPropsTable from './ApiPropsTable.astro';
@@ -26,11 +26,11 @@ if (!framework || !isValidFramework(framework)) {
throw new Error(`Invalid or missing framework param.`);
}
const entry = await getEntry('apiReference', kebabCase(component));
const apiRef: ComponentApiReference | null = entry?.data ?? null;
const entry = await getEntry('componentReference', kebabCase(component));
const apiRef: ComponentReference | null = entry?.data ?? null;
if (!apiRef) return;
const apiReferenceModel = createApiReferenceModel(component, apiRef);
const apiReferenceModel = createComponentReferenceModel(component, apiRef);
if (!apiReferenceModel) return;
const singlePropsSection = !apiReferenceModel.hasParts
@@ -92,7 +92,7 @@ const singleDataAttributesSection = !apiReferenceModel.hasParts
{partDataAttributesSection && (
<>
<H4 id={partDataAttributesSection.id}>{partDataAttributesSection.title}</H4>
<ApiDataAttrsTable dataAttributes={part.data.dataAttributes} />
<ApiDataAttrsTable dataAttributes={part.data.dataAttributes} componentName={part.componentName} />
</>
)}
</>
@@ -128,7 +128,7 @@ const singleDataAttributesSection = !apiReferenceModel.hasParts
{singleDataAttributesSection && (
<>
<H3 id={singleDataAttributesSection.id}>{singleDataAttributesSection.title}</H3>
<ApiDataAttrsTable dataAttributes={apiReferenceModel.data.dataAttributes} />
<ApiDataAttrsTable dataAttributes={apiReferenceModel.data.dataAttributes} componentName={component} />
</>
)}
</>
@@ -0,0 +1,26 @@
---
import MarkdownCode from '@/components/typography/MarkdownCode.astro';
import Td from '@/components/typography/Td.astro';
import DetailRow from './DetailRow.astro';
interface Props {
name: string;
type?: string;
detailedType?: string;
description?: string;
componentName: string;
}
const { name, type, detailedType, description, componentName } = Astro.props;
const id = `${componentName}-attr-${name}`;
---
<DetailRow id={id} name={name} type={type ?? ""} detailedType={detailedType} description={description} colspan={3}>
<Td class="align-top">
<MarkdownCode>{name}</MarkdownCode>
</Td>
<Td class="align-top">
{type ? <MarkdownCode>{type}</MarkdownCode> : null}
</Td>
</DetailRow>
@@ -19,14 +19,14 @@ interface Props {
id: string;
name: string;
type: string;
shortType?: string;
detailedType?: string;
description?: string;
colspan: number;
}
const { id, name, type, shortType, description, colspan } = Astro.props;
const { id, name, type, detailedType, description, colspan } = Astro.props;
const hasDetail = Boolean(shortType || description);
const hasDetail = Boolean(detailedType || description);
---
<Tr
@@ -38,25 +38,22 @@ const hasDetail = Boolean(shortType || description);
)}
>
<slot />
{
hasDetail && (
<Td class="align-top">
<button
aria-expanded="false"
aria-controls={`${id}-detail`}
aria-label={`Details for ${name}`}
data-detail-toggle
<Td class="align-top">
{
hasDetail && (<button
aria-expanded="false"
aria-controls={`${id}-detail`}
aria-label={`Details for ${name}`}
data-detail-toggle
>
<span
aria-hidden="true"
class="inline-block group-data-expanded:rotate-90"
>
<span
aria-hidden="true"
class="inline-block group-data-expanded:rotate-90"
>
</span>
</button>
</Td>
)
}
</span>
</button>)}
</Td>
</Tr>
{
@@ -74,14 +71,14 @@ const hasDetail = Boolean(shortType || description);
</>
)}
{(type || shortType) && (
{detailedType && (
<>
<dt class="text-dark-40 dark:text-light-40">
Type
</dt>
<dd>
<MarkdownCode>
{type || shortType}
{detailedType}
</MarkdownCode>
</dd>
</>
@@ -6,20 +6,19 @@ import DetailRow from './DetailRow.astro';
interface Props {
name: string;
type: string;
shortType?: string;
detailedType?: string;
description?: string;
defaultValue?: string;
required?: boolean;
componentName: string;
}
const { name, type, shortType, description, defaultValue, required, componentName } = Astro.props;
const { name, type, detailedType, description, defaultValue, required, componentName } = Astro.props;
const displayType = shortType ?? type;
const id = `${componentName}-${name}`;
---
<DetailRow id={id} name={name} type={type} shortType={shortType} description={description} colspan={4}>
<DetailRow id={id} name={name} type={type} detailedType={detailedType} description={description} colspan={4}>
<Td class="align-top">
<MarkdownCode>
{name}
@@ -27,7 +26,7 @@ const id = `${componentName}-${name}`;
</MarkdownCode>
</Td>
<Td class="align-top">
<MarkdownCode>{displayType}</MarkdownCode>
<MarkdownCode>{type}</MarkdownCode>
</Td>
<Td class="align-top">
<MarkdownCode>
@@ -6,22 +6,21 @@ import DetailRow from './DetailRow.astro';
interface Props {
name: string;
type: string;
shortType?: string;
detailedType?: string;
description?: string;
componentName: string;
}
const { name, type, shortType, description, componentName } = Astro.props;
const { name, type, detailedType, description, componentName } = Astro.props;
const displayType = shortType ?? type;
const id = `${componentName}-state-${name}`;
---
<DetailRow id={id} name={name} type={type} shortType={shortType} description={description} colspan={3}>
<DetailRow id={id} name={name} type={type} detailedType={detailedType} description={description} colspan={3}>
<Td class="align-top">
<MarkdownCode>{name}</MarkdownCode>
</Td>
<Td class="align-top">
<MarkdownCode>{displayType}</MarkdownCode>
<MarkdownCode>{type}</MarkdownCode>
</Td>
</DetailRow>
@@ -0,0 +1,46 @@
---
/**
* Renders the parameters table for util reference.
* Reuses PropRow.astro since ParamDef has the same shape as PropDef.
*/
import Table from '@/components/typography/Table.astro';
import Tbody from '@/components/typography/Tbody.astro';
import Th from '@/components/typography/Th.astro';
import Thead from '@/components/typography/Thead.astro';
import Tr from '@/components/typography/Tr.astro';
import type { ParamDef } from '@/types/util-reference';
import PropRow from './PropRow.astro';
interface Props {
params: Record<string, ParamDef>;
utilName: string;
}
const { params, utilName } = Astro.props;
---
<Table maxWidth={false} outerClass="my-6">
<Thead>
<Tr>
<Th>Parameter</Th>
<Th>Type</Th>
<Th>Default</Th>
<Th />
</Tr>
</Thead>
<Tbody>
{
Object.entries(params).map(([name, param]) => (
<PropRow
name={name}
type={param.type}
detailedType={param.detailedType}
description={param.description}
defaultValue={param.default}
required={param.required}
componentName={utilName}
/>
))
}
</Tbody>
</Table>
@@ -0,0 +1,80 @@
---
import { getEntry } from 'astro:content';
import { kebabCase } from 'es-toolkit/string';
import ContentWidth from '@/components/frames/ContentWidth.astro';
import H2 from '@/components/typography/H2Markdown.astro';
import H3 from '@/components/typography/H3Markdown.astro';
import H4 from '@/components/typography/H4Markdown.astro';
import P from '@/components/typography/P.astro';
import type { UtilReference } from '@/types/util-reference';
import { createUtilReferenceModel } from '@/utils/utilReferenceModel';
import InlineMarkdown from './InlineMarkdown.astro';
import UtilParamsTable from './UtilParamsTable.astro';
import UtilReturnTable from './UtilReturnTable.astro';
interface Props {
util: string;
slug?: string;
}
const { util, slug } = Astro.props;
const entry = await getEntry('utilReference', slug ?? kebabCase(util));
const ref: UtilReference | null = entry?.data ?? null;
if (!ref) return;
const model = createUtilReferenceModel(util, ref);
if (!model) return;
---
<ContentWidth>
<H2 id={model.heading.id}>{model.heading.text}</H2>
{model.isMultiOverload ? (
model.overloads.map((overload) => {
const paramsSection = overload.sections.find((s) => s.key === 'parameters');
const returnSection = overload.sections.find((s) => s.key === 'returnValue');
const hasParams = Object.keys(overload.data.parameters).length > 0;
return (
<>
<H3 id={overload.id}>{overload.label ?? `Overload ${overload.index}`}</H3>
{overload.description && (
<P><InlineMarkdown content={overload.description} /></P>
)}
{paramsSection && hasParams && (
<>
<H4 id={paramsSection.id}>{paramsSection.title}</H4>
<UtilParamsTable params={overload.data.parameters} utilName={`${util}-${overload.id}`} />
</>
)}
{returnSection && (
<>
<H4 id={returnSection.id}>{returnSection.title}</H4>
<UtilReturnTable returnValue={overload.data.returnValue} utilName={`${util}-${overload.id}`} />
</>
)}
</>
);
})
) : (
<>
{model.sections.find((s) => s.key === 'parameters') && (
<>
<H3 id="parameters">Parameters</H3>
<UtilParamsTable params={model.overload.parameters} utilName={util} />
</>
)}
{model.sections.find((s) => s.key === 'returnValue') && (
<>
<H3 id="return-value">Return Value</H3>
<UtilReturnTable returnValue={model.overload.returnValue} utilName={util} />
</>
)}
</>
)}
</ContentWidth>
@@ -0,0 +1,88 @@
---
/**
* Renders the return value section for util reference.
*
* Three rendering modes:
* - Mode 1: Object return with `fields` → table using StateRow
* - Mode 2: Simple return with detailedType/description → single-row disclosure table
* - Mode 3: Simple return without detail → inline type text
*/
import MarkdownCode from '@/components/typography/MarkdownCode.astro';
import P from '@/components/typography/P.astro';
import Table from '@/components/typography/Table.astro';
import Tbody from '@/components/typography/Tbody.astro';
import Td from '@/components/typography/Td.astro';
import Th from '@/components/typography/Th.astro';
import Thead from '@/components/typography/Thead.astro';
import Tr from '@/components/typography/Tr.astro';
import type { ReturnValue } from '@/types/util-reference';
import DetailRow from './DetailRow.astro';
import InlineMarkdown from './InlineMarkdown.astro';
import StateRow from './StateRow.astro';
interface Props {
returnValue: ReturnValue;
utilName: string;
}
const { returnValue, utilName } = Astro.props;
const hasFields = returnValue.fields && Object.keys(returnValue.fields).length > 0;
const hasDetail = !hasFields && Boolean(returnValue.detailedType || returnValue.description);
---
{hasFields ? (
<Table maxWidth={false} outerClass="my-6">
<Thead>
<Tr>
<Th>Property</Th>
<Th>Type</Th>
<Th />
</Tr>
</Thead>
<Tbody>
{
Object.entries(returnValue.fields!).map(([name, field]) => (
<StateRow
name={name}
type={field.type}
detailedType={field.detailedType}
description={field.description}
componentName={`${utilName}-return`}
/>
))
}
</Tbody>
</Table>
) : hasDetail ? (
<Table maxWidth={false} outerClass="my-6">
<Thead>
<Tr>
<Th>Type</Th>
<Th />
</Tr>
</Thead>
<Tbody>
<DetailRow
id={`${utilName}-return-type`}
name="return type"
type={returnValue.type}
detailedType={returnValue.detailedType}
description={returnValue.description}
colspan={2}
>
<Td><MarkdownCode>{returnValue.type}</MarkdownCode></Td>
</DetailRow>
</Tbody>
</Table>
) : (
<P>
<MarkdownCode>{returnValue.type}</MarkdownCode>
{returnValue.description && (
<>
{" — "}
<InlineMarkdown content={returnValue.description} />
</>
)}
</P>
)}