$npx -y skills add strongeron/storybook-workbench --skill sb-storiesWrite a CSF3 story for ONE React component, covering only its materially-different states (no Cartesian), with a factory when 3+ stories share a shape. Use for 'write a story for X', 'document this component', 'add a Storybook story'.
| 1 | # sb-stories — one component, its real states |
| 2 | |
| 3 | The default Build mode. The component exists in `src/components/`; you write its visible-states story. |
| 4 | |
| 5 | ## Before authoring (ask yourself) |
| 6 | |
| 7 | - **Is it actually used?** Check `components.real[]` in `.storybook/project-inventory.json`. If it's |
| 8 | in `dead[]`, remove it — don't write a story. If it's `vendor` (shadcn `ui/`), deprioritize. |
| 9 | - **Which states change behavior/appearance materially?** Refuse Cartesian combinations. Per-primitive |
| 10 | minimum tables in `references/anti-patterns.md` (Button 8, Input 8, Modal 5, Form 6). |
| 11 | Read `.storybook/component-states.json` instead of guessing — **if it's missing, generate it first:** |
| 12 | `scripts/extract-states.sh`. (Bigger extraction context: `references/extraction-workflow.md`.) |
| 13 | To render all those states on **one canvas**, use the `StateGrid` wrapper (variants × states → |
| 14 | `StateMatrix`) from `sb-wrappers` — don't hand-roll the grid. These are the component-time wrappers; |
| 15 | the data wrappers (ProjectInventory / DesignSystemHealth / AppFlowGraph …) come after their own steps. |
| 16 | - **Which states does THIS app actually ship?** Read `.storybook/component-usage.json` (`sb-inventory`'s |
| 17 | `extract-component-usage.sh` — generate it if missing). Use `props.<prop>.values` to **prioritize** the |
| 18 | variants real call sites pass; for anything in `declaredButUnused` (e.g. `variant=danger` never used), |
| 19 | still author the state for completeness but **tag it `['usage:unused']`** and note "not used in this app" |
| 20 | — don't pad the catalog with states prod never renders. |
| 21 | - **You don't author per-component docs by hand — they're composed once.** Every component's autodocs |
| 22 | page already gains a **"Real usage in this app"** band: the `UsageSection` block (wired once into |
| 23 | `preview.ts` `docs.page` by `sb-setup`) renders a **"Where it's used"** map per component — the pages it |
| 24 | lands on, what nests it, what it renders, the tokens it pulls — read from the usage graph |
| 25 | (`component-pages.json`). So when you add a story, **don't hand-add a usage block**; just run |
| 26 | `refresh-usage.sh` so the graph is current and the band populates. To explore the whole graph |
| 27 | interactively (any token / component / page → everywhere it's used, clickable), scaffold the |
| 28 | **`UsageExplorer`** wrapper (`sb-wrappers`). Details + the docs.page composition live in `sb-inventory` |
| 29 | (§ "Real usage in autodocs") and `sb-setup` (docs-page composition). |
| 30 | - **Factory?** YES if 3+ stories share a data shape. Read `.storybook/prop-shapes.json` (candidates |
| 31 | flagged with `liveUsages`) — **if missing, run `scripts/extract-prop-shapes.sh` first.** Then |
| 32 | `scripts/scaffold-factory.sh <Type> <import-path>` and fill the deterministic stub |
| 33 | (`references/factory-patterns.md`); otherwise inline `args`. |
| 34 | - **Title taxonomy?** Match `storySort.order`; if the project has none, pick one via |
| 35 | `references/directory-structure.md`. |
| 36 | - **Does a `play` actually earn its place?** Only write one for an interaction, async data, |
| 37 | a portal, a CSS-driven state, or accessibility — never a bare `toBeVisible()` (anti-pattern 34). |
| 38 | And the **project needs exactly one `CssCheck`** (anti-pattern 33): one story asserting a real |
| 39 | `getComputedStyle` token value, the only proof the shared preview loaded the app's CSS. Both come |
| 40 | from `npx storybook ai setup`'s prompt; `validate-stories.sh` check 13 + the project tally enforce them. |
| 41 | - **A "playground" / showcase story is Controls-driven, not click/hover.** If a reviewer asks "what is |
| 42 | this playground story — can I click or hover it?": a playground is the **default story with its Controls |
| 43 | panel** — you change `args` (variant, size, state) in the Cont |