Skip to content

docs: MVP-7 Badge pilot — full JSDoc contract + first composed README.mdx#6212

Open
caseyisonit wants to merge 5 commits into
caseyisonit/docs-mvp-5-cem-extensionfrom
caseyisonit/docs-mvp-7-badge-pilot
Open

docs: MVP-7 Badge pilot — full JSDoc contract + first composed README.mdx#6212
caseyisonit wants to merge 5 commits into
caseyisonit/docs-mvp-5-cem-extensionfrom
caseyisonit/docs-mvp-7-badge-pilot

Conversation

@caseyisonit
Copy link
Copy Markdown
Contributor

Description

End-to-end pilot of the new per-entity authoring shape on <swc-badge>. Badge is small, already migrated, and already referenced in .ai/rules/stories-documentation.md as the exemplar — exactly the right component to prove out the new contract before Phase 2 rolls it across all migrated entities.

Four parts, one PR:

1. Class JSDoc on Badge.ts — full contract

  • Existing @status preview / @since 0.0.1 preserved
  • New @summary (one-line subtitle, consumed by the new <Subtitle /> block from MVP-5)
  • New taxonomy: @genre component, @category status-display
  • New @related status-light,tag (sibling cross-links)
  • New @RSPparity partial (parity status against React Spectrum 2)
  • New @a11yPattern non-interactive-color-status — accurate to the component (Badge is non-interactive, conveys state via color + text). Diverged from the plan's suggested aria-describedby-owner because Badge is referenced by ARIA describedby, not the owner of one
  • 14 @cssproperty entries covering every public --swc-badge-* custom property surfaced by badge.css (each with a description)
  • Existing @example blocks preserved (code-only, per the new stories-have-no-prose contract); fixed an invalid fixed=\"fill\" value in the second example to fixed=\"block-start\" (fill is not in FIXED_VALUES)

@slot declarations stay on Badge.base.ts where they already live; CEM carries them through via inheritedFrom. No @fires (Badge dispatches no events) and no @csspart (no shadow parts exposed) — documenting what exists, not inventing surface.

2. New 2nd-gen/packages/swc/components/badge/README.mdx

The first composed-template entity README. Becomes Badge's docs page (Storybook's docs.defaultName is 'README'). Sections, in order:

  • <Title /> / <StatusBadge /> / <Subtitle /> (subtitle reads @summary from CEM)
  • <Description /> (class-level prose)
  • <GettingStarted tags={['migrated']} /> (install + import)
  • API<Primary />, <ApiTable />, <EventsTable /> (renders nothing for Badge), <CssPartsTable /> (also empty), <CssPropsTable />
  • Usage — three executable examples (Sizes, SemanticVariants, Outline) embedded via <EmbedStory of={Stories.X} />, each preceded by a keyword-first ### heading and ≤3 sentences of per-example prose
  • Accessibility — narrative + cross-link to consumer migration guide
  • Migration — pointer to existing consumer-migration-guide.mdx
  • <RelatedEntities /> (reads @related from CEM)

3. badge.stories.ts — prose stripped

JSDoc prose removed from every story export. Stories now describe executable configurations only; concept prose (anatomy, variant guidance, accessibility narrative) lives in the README or class JSDoc, not duplicated in story files. The component-level parameters.docs.subtitle was already absent — no change there.

4. eslint.config.js — JSDoc tag allowlist update

Extends jsdoc/check-tag-names.definedTags with the six new tags introduced by MVP-5's swcJsdocTagsPlugin (@summary, @genre, @category, @related, @RSPparity, @a11yPattern). Without this, the lint-staged hook rejects the new Badge JSDoc. The enforcement-side counterpart to MVP-5's parser changes.

Motivation and context

Per the docs-overhaul v2 plan, every entity (component, controller, pattern, token family) eventually adopts the same three-file shape: class JSDoc + README.mdx + optional executable-only stories. MVP-5 built the parser and block library; this PR exercises both end-to-end on Badge.

Without a real pilot, the CEM extension and block library are theoretical. After this lands, Badge is the canonical example other entities clone during Phase 2's per-entity rollout.

Related issue(s)

Stacks on #6211 (MVP-5 CEM extension). Unblocks Phase 2's per-entity rollout.

Author's checklist

  • I have read the CONTRIBUTING and PULL_REQUESTS documents.
  • I have reviewed the Accessibility Practices for this feature.
  • I have added automated tests to cover my changes. (N/A — pure docs/JSDoc/MDX changes; no runtime behavior change. Manual a11y checks below.)
  • I have included a well-written changeset if my change needs to be published. (N/A — no public package surface change.)
  • I have included updated documentation if my change required it.

Manual review test cases

  • Badge docs page renders the new README.

    1. Check out the branch
    2. From 2nd-gen/packages/swc, run yarn analyze && yarn storybook
    3. Navigate to Components → Badge → README
    4. Verify the page renders in this order: title, status badge, subtitle ("Short, color-coded status or category indicator." — sourced from @summary), description prose, install snippet, API section with property/attribute table + CSS custom properties table (no events table, no CSS parts table — Badge has none), Usage section with three embedded canvases (Sizes, SemanticVariants, Outline), Accessibility section, Migration pointer, Related entities list.
  • CSS custom property descriptions surface.

    1. On the Badge README, scroll to the CSS custom properties table
    2. Verify all 14 --swc-badge-* props appear, each with its description from the JSDoc
  • Storybook subtitle now reads from CEM.

    1. Open the Badge README docs page
    2. Verify the subtitle reads "Short, color-coded status or category indicator." (from @summary)
    3. Visit any other migrated component's docs page (e.g. <swc-status-light>)
    4. Verify those subtitles still render via Storybook's built-in fallback (<Subtitle /> block from MVP-5 falls back when @summary is absent)
  • Stories sidebar still works.

    1. Click into Badge → Sizes (or SemanticVariants, or Outline)
    2. Verify the canvas renders the same as before; sidebar entries unchanged
  • Lint and analyze pass cleanly.

    1. From repo root, run yarn lint:eslint -- --no-error-on-unmatched-pattern 2nd-gen/packages/swc/components/badge
    2. From 2nd-gen/packages/swc, run yarn analyze
    3. Both should complete without errors

Device review

  • Did it pass in Desktop?
  • Did it pass in (emulated) Mobile?
  • Did it pass in (emulated) iPad?

Accessibility testing checklist

Required: Complete each applicable item and document your testing steps.

  • Keyboard (required — document steps below)

    Badge is a non-interactive, non-focusable element. The new README adds no new interactive surface — all blocks render static HTML (tables, headings, links, embedded canvas iframes). Confirm no regressions in surrounding examples.

    1. Open the Badge README docs page in Storybook
    2. Tab through the page
    3. Expect: focus order is unchanged from the pre-PR baseline; the only focusable items are the embedded story canvas links/buttons (Storybook chrome) and the migration-guide cross-link; native focus indicators are visible
  • Screen reader (required — document steps below)

    Tables, headings, and links use semantic HTML; no custom ARIA on the README itself. The Badge component's a11y model (already documented in the existing consumer migration guide and now in the README accessibility section) is unchanged.

    1. Open the Badge README in Storybook with VoiceOver active
    2. Read through the page top-to-bottom
    3. Expect: subtitle is announced as a paragraph; section headings ("API", "Usage", "Accessibility", "Migration") are announced as level 2; example sub-headings ("Sizes", "Semantic variants", "Outline") as level 3; tables (CSS custom properties) are announced with row/column structure; cross-links announce their text label
    4. Navigate to one of the embedded canvas examples and inspect a single <swc-badge variant=\"positive\">Approved</swc-badge> — VoiceOver announces "Approved" as static text (no role, not focusable), confirming the non-interactive a11y contract

End-to-end pilot of the new per-entity authoring shape on `<swc-badge>`.
Four parts, one PR:

1. Class JSDoc on `Badge.ts` — extended to the full contract:

   - existing `@status preview` / `@since 0.0.1` preserved
   - new `@summary` (one-line subtitle, consumed by the new `<Subtitle />`
     block from MVP-5)
   - new taxonomy: `@genre component`, `@category status-display`
   - new `@related status-light,tag` (sibling cross-links)
   - new `@RSPparity partial` (parity status against React Spectrum 2)
   - new `@a11yPattern non-interactive-color-status` (accurate to the
     component — badge is non-interactive, conveys state via color + text)
   - 14 `@cssproperty` entries covering every public `--swc-badge-*`
     custom property surfaced by `badge.css`
   - existing `@example` blocks preserved (code-only, per the new
     stories-have-no-prose contract); fixed an invalid `fixed="fill"` value
     in the second example to `fixed="block-start"` (`fill` is not in
     `FIXED_VALUES`)

   `@slot` declarations stay on `Badge.base.ts` where they already live;
   CEM carries them through via `inheritedFrom`. No `@fires` (Badge
   dispatches no events) and no `@csspart` (no shadow parts exposed) —
   documenting what exists, not inventing surface.

2. New `2nd-gen/packages/swc/components/badge/README.mdx` — the first
   composed-template entity README. Becomes Badge's docs page (Storybook's
   `docs.defaultName` is `'README'`). Sections, in order:

   - `<Title />` / `<StatusBadge />` / `<Subtitle />` (subtitle reads
     `@summary` from CEM)
   - `<Description />` (class-level prose)
   - `<GettingStarted tags={['migrated']} />` (install + import)
   - **API** — `<Primary />`, `<ApiTable />`, `<EventsTable />` (renders
     nothing for badge), `<CssPartsTable />` (also empty), `<CssPropsTable />`
   - **Usage** — three executable examples (`Sizes`, `SemanticVariants`,
     `Outline`) embedded via `<EmbedStory of={Stories.X} />`, each preceded
     by a keyword-first `###` heading and ≤3 sentences of per-example prose
   - **Accessibility** — narrative + cross-link to consumer migration guide
   - **Migration** — pointer to existing `consumer-migration-guide.mdx`
   - `<RelatedEntities />` (reads `@related` from CEM)

3. `badge.stories.ts` — JSDoc prose stripped from every story export.
   Stories now describe **executable configurations only**; concept prose
   (anatomy, variant guidance, accessibility narrative) lives in the
   README or class JSDoc, not duplicated in story files. The component-
   level `parameters.docs.subtitle` was already absent — no change there.

4. `eslint.config.js` — extends the `jsdoc/check-tag-names` allowlist with
   the six new tags introduced by MVP-5's `swcJsdocTagsPlugin` (`@summary`,
   `@genre`, `@category`, `@related`, `@RSPparity`, `@a11yPattern`).
   Without this, the lint hook rejects the new Badge JSDoc. The
   enforcement-side counterpart to the parser changes that landed in
   MVP-5.

Smoke-tested:
- `yarn analyze` — CEM emits all new fields on Badge: `summary`, `genre`,
  `category`, `related`, `RSPparity`, `a11yPattern`, plus
  `cssProperties[]` with all 14 `--swc-badge-*` props (each with its
  description). Existing `status`/`since`/`slots`/`tagName` preserved.
- `npx tsc --noEmit` — no new type errors (only the pre-existing
  unrelated `@vitest/browser` typings issue).
- `yarn generate:contributor-docs` — docs pipeline healthy.

Stacks on `caseyisonit/docs-mvp-5-cem-extension`. After merge, badge
serves as the canonical example other entities clone in Phase 2.
@caseyisonit caseyisonit requested a review from a team as a code owner April 24, 2026 23:27
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 24, 2026

⚠️ No Changeset found

Latest commit: 212a40f

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

caseyisonit and others added 3 commits April 24, 2026 17:44
The leading copyright comment used backslash-escaped asterisks
inside a JSX expression (`{/\*...\*/}`), which acorn cannot parse
as valid JavaScript. Replace with a standard JSX comment
(`{/* ... */}`) so the file indexes correctly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous fix that converted the JSX-comment copyright header to
plain `{/* */}` syntax was reverted by prettier in the lint-staged
pre-commit hook — prettier's markdown plugin escapes the `*` chars
back to `\*`, which makes acorn unable to parse the JSX expression.

Other handwritten MDX in this repo (DocumentTemplate.mdx, the four
learn-about-swc/*.mdx pages) carry no copyright header at all; the
LICENSE file at the repo root covers them. Match that convention so
prettier has nothing to mangle.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
With the new README.mdx defining the canonical docs page for
'Components/Badge' via <Meta of={Stories} />, the Playground
story can no longer also opt into autodocs at the same kind ID
— Storybook 10 errors with 'created a component docs page ...
but also tagged the CSF file with autodocs'.

The Playground keeps its 'dev' tag so it stays visible in the
local sidebar; production builds drop it as before.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 27, 2026

📚 Branch Preview Links

🔍 First Generation Visual Regression Test Results

When a visual regression test fails (or has previously failed while working on this branch), its results can be found in the following URLs:

Deployed to Azure Blob Storage: pr-6212

If the changes are expected, update the current_golden_images_cache hash in the circleci config to accept the new images. Instructions are included in that file.
If the changes are unexpected, you can investigate the cause of the differences and update the code accordingly.

@caseyisonit caseyisonit added do-not-merge NO MERGE-Y! Component:Documentation Issues or PRs involving changes to docs or docs website. Component prefix is for Jira integration. 2nd gen These issues or PRs map to our 2nd generation work to modernizing infrastructure. labels May 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

2nd gen These issues or PRs map to our 2nd generation work to modernizing infrastructure. Component:Documentation Issues or PRs involving changes to docs or docs website. Component prefix is for Jira integration. do-not-merge NO MERGE-Y!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant