"use client"
import { Link } from "react-router-dom"
import type {
ComponentDocAccessibilityItem,
ComponentDocAnatomyPart,
ComponentDocFeatureGroup,
ComponentDocGuidelines,
ComponentDocSpec,
ComponentDocSpecAccessibility,
ComponentDocUx,
} from "@/lib/design-system/component-doc-types"
import {
A11Y_PRINCIPLE_LABEL,
A11Y_PRINCIPLE_ORDER,
A11Y_PRINCIPLE_SUMMARY,
isStructuredAccessibility,
} from "@/lib/design-system/component-doc-a11y"
import { SelectionTileShowcase } from "@/components/ui/selection-tile-grid"
import { Badge } from "@/components/ui/badge"
import { ComponentDocApiTable } from "@/components/design-system/component-doc-api-table"
import { DS_DOC_BODY, DS_DOC_BODY_EMPHASIS, DS_DOC_CODE_LABEL, DS_DOC_GUIDELINE_DO_ICON, DS_DOC_GUIDELINE_DONT_ICON, DS_DOC_GUIDELINE_ICON, DS_DOC_LINK, DS_DOC_SECTION_TITLE, DS_DOC_SUBSECTION_TITLE } from "@/lib/design-system/doc-typography"
import { cn } from "@/lib/utils"
import { useProductDashboardHref } from "@/contexts/product-route-sync"
function AnatomyList({ parts }: { parts: ComponentDocAnatomyPart[] }) {
return (
{parts.map((row) => (
-
{row.part}
{row.description}
))}
)
}
function AnatomyBlock({ parts }: { parts: ComponentDocAnatomyPart[] }) {
return (
)
}
function featureOptionValue(part: string) {
return part.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "")
}
function FeaturesBlock({ groups }: { groups: ComponentDocFeatureGroup[] }) {
return (
Features
{groups.map((group) => (
({
value: featureOptionValue(item.part),
label: item.part,
icon: item.icon ?? "fa-circle-info",
description: item.description,
}))}
/>
))}
)
}
function CriterionHeading({ item }: { item: ComponentDocAccessibilityItem }) {
const title = item.criterionTitle ? ` ${item.criterionTitle}` : ""
return (
{item.criterion}
{title}
{item.level ? (
Level {item.level}
) : null}
)
}
function AccessibilityBlock({ items }: { items: ComponentDocSpecAccessibility }) {
if (isStructuredAccessibility(items)) {
const grouped = A11Y_PRINCIPLE_ORDER.map((principle) => ({
principle,
items: items.filter((row) => row.principle === principle),
})).filter((group) => group.items.length > 0)
return (
Accessibility
WCAG 2.1 Level AA floor, grouped by POUR (Perceivable, Operable, Understandable, Robust).
{grouped.map(({ principle, items: principleItems }) => (
{A11Y_PRINCIPLE_LABEL[principle]}
{A11Y_PRINCIPLE_SUMMARY[principle]}
{principleItems.map((item) => (
))}
))}
)
}
return (
Accessibility
{items.map((item) => (
- {item}
))}
)
}
function GuidelineListItem({
item,
iconClassName,
iconToneClassName,
}: {
item: string
iconClassName: string
iconToneClassName: string
}) {
return (
{item}
)
}
function ImplementationBlock({ guidelines }: { guidelines: ComponentDocGuidelines }) {
return (
Implementation
How to compose and configure the primitive. Technical and structural rules, not product UX.
Do
{guidelines.do.map((item) => (
))}
Avoid
{guidelines.dont.map((item) => (
))}
)
}
function WhenToUseColumns({ ux }: { ux: ComponentDocUx }) {
return (
{ux.whenToUse?.length ? (
When to use
{ux.whenToUse.map((item) => (
))}
) : null}
{ux.whenNotToUse?.length ? (
When not to use
{ux.whenNotToUse.map((item) => (
))}
) : null}
)
}
function ConstraintsBlock({
budgets,
}: {
budgets: NonNullable
}) {
return (
Constraints
Quantitative design limits for scanning and density. These are IA and layout budgets, not WCAG
criteria.
{budgets.map((row) => (
-
{row.label}:
{row.value}. {row.rationale}
))}
)
}
/** Product UX only — job, when to pick this primitive, references. */
function UxGuidelinesBlock({ ux }: { ux: ComponentDocUx }) {
const hasWhenToUse = Boolean(ux.whenToUse?.length || ux.whenNotToUse?.length)
return (
UX guidelines
{ux.job ? {ux.job}
: null}
{hasWhenToUse ? : null}
{ux.principles?.length ? (
Principles:
{ux.principles.join(", ")}
) : null}
{ux.modernReferences?.length ? (
Modern references:
{ux.modernReferences.join("; ")}
) : null}
{(ux.patternDoc || ux.rulePath) ? (
{ux.patternDoc ? (
<>
Pattern:
{ux.patternDoc}
>
) : null}
{ux.patternDoc && ux.rulePath ? " · " : null}
{ux.rulePath ? (
<>
Rule:
{ux.rulePath}
>
) : null}
) : null}
)
}
function RelatedBlock({ slugs }: { slugs: string[] }) {
const dashboardHref = useProductDashboardHref()
const productBase = dashboardHref.replace(/\/dashboard$/, "")
const basePath = `${productBase}/design-system`
return (
Related
{slugs.map((slug) => (
-
{slug}
))}
)
}
/** Live previews → UX → Implementation → Constraints → Accessibility → reference sections. */
export function ComponentDocDetails({ spec }: { spec: ComponentDocSpec }) {
const showUx = Boolean(
spec.ux?.job ||
spec.ux?.whenToUse?.length ||
spec.ux?.whenNotToUse?.length ||
spec.ux?.principles?.length,
)
return (
{showUx && spec.ux ?
: null}
{spec.guidelines ?
: null}
{spec.ux?.budgets?.length ?
: null}
{spec.accessibility?.length ?
: null}
{spec.anatomy?.length ?
: null}
{spec.features?.length ?
: null}
{spec.api?.length ?
: null}
{spec.relatedSlugs?.length ?
: null}
)
}