Files
cadence-ui/apps/docs/src/component-authoring.stories.tsx
T

254 lines
12 KiB
TypeScript

import {
authoringChecklist,
commonSlotNames,
commonStateNames,
cvaConventions
} from "@ai-ui/ui";
import type { Meta, StoryObj } from "@storybook/react";
const docsCoverage = [
{
name: "Playground",
note: "One opinionated default example that shows the component in its most typical role."
},
{
name: "States",
note: "Only when the component has meaningful disabled, invalid, checked, selected, or open-state behavior worth comparing."
},
{
name: "Anatomy",
note: "Name the stable slots and public data attributes that designers and engineers can style against."
},
{
name: "Accessibility or Motion",
note: "Choose the dimension that is most likely to be misunderstood by contributors and consumers."
}
] as const;
const docsWritingRules = [
"Use `docs.description.component` to explain when the component should be chosen, not to restate its name.",
"Show real product language instead of lorem ipsum so states and hierarchy feel intentional.",
"Keep examples narrow. One good scenario teaches more than six generic permutations.",
"If a story exists only to explain slots or motion, say that directly in the story description."
] as const;
function ComponentAuthoringGuide() {
return (
<div className="min-h-screen bg-[var(--color-background)] px-6 py-10 text-[var(--color-foreground)] sm:px-10">
<div className="mx-auto flex w-full max-w-6xl flex-col gap-8">
<header className="max-w-4xl space-y-3">
<p className="text-sm uppercase tracking-[var(--tracking-caps)] text-[var(--color-muted-foreground)]">
AI UI / Docs Guide
</p>
<h1
className="font-semibold tracking-[var(--tracking-tight)]"
style={{
fontFamily: "var(--font-display)",
fontSize: "var(--text-4xl)",
lineHeight: "var(--leading-tight)"
}}
>
Component docs should explain usage, structure, and behavior without drifting
away from the actual source contract.
</h1>
<p className="text-[var(--text-lg)] leading-[var(--leading-loose)] text-[var(--color-muted-foreground)]">
This page turns the repo&apos;s component contract into a repeatable Storybook
recipe. The goal is not maximum story count. The goal is a small set of stories
that makes API, anatomy, and behavioral intent obvious to the next contributor.
</p>
</header>
<section className="grid gap-4 lg:grid-cols-[minmax(0,1.1fr)_minmax(0,0.9fr)]">
<article className="rounded-[var(--radius-lg)] border border-[var(--color-border)] bg-[var(--color-card)] p-6 shadow-[var(--shadow-sm)]">
<h2 className="text-2xl font-semibold">Minimum Story Recipe</h2>
<div className="mt-5 grid gap-3">
{docsCoverage.map((item) => (
<div
key={item.name}
className="rounded-[var(--radius-sm)] border border-[var(--color-border)] bg-[var(--color-background)] px-4 py-3"
>
<div className="flex items-center justify-between gap-3">
<p className="text-sm font-medium">{item.name}</p>
<span className="text-xs uppercase tracking-[var(--tracking-caps)] text-[var(--color-muted-foreground)]">
docs lane
</span>
</div>
<p className="mt-2 text-sm leading-6 text-[var(--color-muted-foreground)]">
{item.note}
</p>
</div>
))}
</div>
</article>
<article className="rounded-[var(--radius-lg)] border border-[var(--color-border)] bg-[var(--color-card)] p-6 shadow-[var(--shadow-sm)]">
<h2 className="text-2xl font-semibold">Writing Rules</h2>
<div className="mt-5 grid gap-3">
{docsWritingRules.map((rule) => (
<div
key={rule}
className="rounded-[var(--radius-sm)] border border-[var(--color-border)] bg-[var(--color-background)] px-4 py-3"
>
<p className="text-sm leading-6 text-[var(--color-foreground)]">{rule}</p>
</div>
))}
</div>
</article>
</section>
<section className="grid gap-4 lg:grid-cols-2">
<article className="rounded-[var(--radius-lg)] border border-[var(--color-border)] bg-[var(--color-card)] p-6 shadow-[var(--shadow-sm)]">
<h2 className="text-2xl font-semibold">Component Contract Inputs</h2>
<p className="mt-1 text-sm text-[var(--color-muted-foreground)]">
The docs should mirror the same public hooks that the components expose in
source.
</p>
<div className="mt-5 grid gap-3">
{authoringChecklist.map((item) => (
<div
key={item}
className="rounded-[var(--radius-sm)] border border-[var(--color-border)] bg-[var(--color-background)] px-4 py-3"
>
<p className="text-sm leading-6 text-[var(--color-foreground)]">{item}</p>
</div>
))}
</div>
</article>
<article className="rounded-[var(--radius-lg)] border border-[var(--color-border)] bg-[var(--color-card)] p-6 shadow-[var(--shadow-sm)]">
<h2 className="text-2xl font-semibold">CVA Guardrails</h2>
<p className="mt-1 text-sm text-[var(--color-muted-foreground)]">
Docs should reinforce the variant surface that engineering already considers
stable.
</p>
<div className="mt-5 grid gap-3">
{cvaConventions.map((item) => (
<div
key={item}
className="rounded-[var(--radius-sm)] border border-[var(--color-border)] bg-[var(--color-background)] px-4 py-3"
>
<p className="text-sm leading-6 text-[var(--color-foreground)]">{item}</p>
</div>
))}
</div>
</article>
</section>
<section className="grid gap-4 lg:grid-cols-2">
<article className="rounded-[var(--radius-lg)] border border-[var(--color-border)] bg-[var(--color-card)] p-6 shadow-[var(--shadow-sm)]">
<h2 className="text-2xl font-semibold">Slots Worth Calling Out</h2>
<p className="mt-1 text-sm text-[var(--color-muted-foreground)]">
Anatomy stories should name only the slots a consumer can reasonably style or
inspect in tests.
</p>
<div className="mt-5 grid gap-3">
{commonSlotNames.map((item) => (
<div
key={item.slot}
className="rounded-[var(--radius-sm)] border border-[var(--color-border)] bg-[var(--color-background)] px-4 py-3"
>
<div className="flex items-center justify-between gap-3">
<code className="text-sm font-medium">{`data-slot="${item.slot}"`}</code>
<span className="text-xs uppercase tracking-[var(--tracking-caps)] text-[var(--color-muted-foreground)]">
slot
</span>
</div>
<p className="mt-2 text-sm leading-6 text-[var(--color-muted-foreground)]">
{item.guidance}
</p>
</div>
))}
</div>
</article>
<article className="rounded-[var(--radius-lg)] border border-[var(--color-border)] bg-[var(--color-card)] p-6 shadow-[var(--shadow-sm)]">
<h2 className="text-2xl font-semibold">States Worth Explaining</h2>
<p className="mt-1 text-sm text-[var(--color-muted-foreground)]">
State stories should match the durable `data-*` surface, not one-off visual
tweaks.
</p>
<div className="mt-5 grid gap-3">
{commonStateNames.map((item) => (
<div
key={item.state}
className="rounded-[var(--radius-sm)] border border-[var(--color-border)] bg-[var(--color-background)] px-4 py-3"
>
<div className="flex items-center justify-between gap-3">
<code className="text-sm font-medium">{`data-${item.state}`}</code>
<span className="text-xs uppercase tracking-[var(--tracking-caps)] text-[var(--color-muted-foreground)]">
state
</span>
</div>
<p className="mt-2 text-sm leading-6 text-[var(--color-muted-foreground)]">
{item.guidance}
</p>
</div>
))}
</div>
</article>
</section>
<section className="rounded-[var(--radius-lg)] border border-[var(--color-border)] bg-[var(--color-card)] p-6 shadow-[var(--shadow-sm)]">
<h2 className="text-2xl font-semibold">Before Opening The PR</h2>
<div className="mt-5 grid gap-3 md:grid-cols-2">
<div className="rounded-[var(--radius-sm)] border border-[var(--color-border)] bg-[var(--color-background)] px-4 py-3">
<p className="text-sm font-medium text-[var(--color-foreground)]">
Ask if the docs tell a consumer when to choose the component.
</p>
<p className="mt-2 text-sm leading-6 text-[var(--color-muted-foreground)]">
If the answer is &quot;not really&quot;, the component description is still too
generic.
</p>
</div>
<div className="rounded-[var(--radius-sm)] border border-[var(--color-border)] bg-[var(--color-background)] px-4 py-3">
<p className="text-sm font-medium text-[var(--color-foreground)]">
Ask if the anatomy story names the real public styling hooks.
</p>
<p className="mt-2 text-sm leading-6 text-[var(--color-muted-foreground)]">
If the story only explains visuals, it is not yet useful to another engineer.
</p>
</div>
<div className="rounded-[var(--radius-sm)] border border-[var(--color-border)] bg-[var(--color-background)] px-4 py-3">
<p className="text-sm font-medium text-[var(--color-foreground)]">
Ask if the most failure-prone behavior is explicitly documented.
</p>
<p className="mt-2 text-sm leading-6 text-[var(--color-muted-foreground)]">
For overlays that usually means accessibility. For animated surfaces it may
be motion.
</p>
</div>
<div className="rounded-[var(--radius-sm)] border border-[var(--color-border)] bg-[var(--color-background)] px-4 py-3">
<p className="text-sm font-medium text-[var(--color-foreground)]">
Ask if the story count stayed disciplined.
</p>
<p className="mt-2 text-sm leading-6 text-[var(--color-muted-foreground)]">
The docs should feel intentional, not encyclopedic.
</p>
</div>
</div>
</section>
</div>
</div>
);
}
const meta = {
title: "Foundation/Component Authoring",
component: ComponentAuthoringGuide,
parameters: {
docs: {
description: {
component:
"Use this page as the Storybook-side companion to the repo's component contract. It defines the minimum documentation recipe for a new component and keeps docs work aligned with slots, states, variants, and motion semantics that already exist in source."
}
},
layout: "fullscreen"
}
} satisfies Meta<typeof ComponentAuthoringGuide>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Overview: Story = {};