@codepress/design-kit 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,6 +19,86 @@ It runs on Node 20 or later. Playwright is a peer dependency, so the capture
19
19
  drives the Playwright and Chromium your project already has. The `kit`
20
20
  commands need neither.
21
21
 
22
+ ## Set it up with your agent
23
+
24
+ The quickest way in is to let your coding agent do the whole setup. Paste this
25
+ into Claude Code, Codex, Cursor or any agent that can run commands in your
26
+ repository:
27
+
28
+ ```text
29
+ Set up a design kit in this repository. Run
30
+ `npx --yes @codepress/design-kit setup-guide` and follow what it prints.
31
+ Open one pull request and don't merge it.
32
+ ```
33
+
34
+ `setup-guide` prints the setup skill that ships in this package, so the agent
35
+ needs nothing installed beforehand. Following it, the agent:
36
+
37
+ 1. Runs `init`, which detects your stack and writes the config, the daily
38
+ workflow and the agent skill (see [Set up in your repository](#set-up-in-your-repository)).
39
+ 2. Fills in the pages to capture: the command that starts your app, and three
40
+ to eight main screens, each with a selector that shows when it has loaded.
41
+ 3. Decides between Storybook stories and real pages. With Storybook, it
42
+ captures every story. Without it, it asks you whether to add Storybook,
43
+ capture your real pages, or both. When nobody answers, it captures pages and
44
+ writes stories for the components several screens share.
45
+ 4. Wires sign-in, when your pages need one, through a seeded test user and the
46
+ repository secrets `DESIGN_KIT_USERNAME` and `DESIGN_KIT_PASSWORD`. It never
47
+ writes a credential; the pull request says which secrets to add.
48
+ 5. Builds the kit once, checks what it captured, and opens the pull request
49
+ with the counts, any gaps and a screenshot of one composed screen.
50
+
51
+ No Storybook yet and you want one? Ask for it on its own, before or after the
52
+ kit:
53
+
54
+ ```text
55
+ Set up Storybook in this repository, with stories for our components. Run
56
+ `npx --yes @codepress/design-kit storybook-guide` and follow what it prints.
57
+ Open one pull request and don't merge it.
58
+ ```
59
+
60
+ `storybook-guide` prints a second skill. The agent installs Storybook 9 (8 for
61
+ older apps) without changing your React, Next.js or TypeScript versions,
62
+ writes a stories file next to each component covering every variant and the
63
+ empty, loading, error and long-text states, adds a tokens story, and lists
64
+ anything it skipped, with the reason. React with Vite or Next.js is supported
65
+ first; on another stack the agent says plainly what it did not try.
66
+
67
+ Once the pull request merges, the daily workflow uploads the kit, and the
68
+ `design-kit` skill it installed tells your agents to use it. Ask for a mockup
69
+ the way you would ask a designer:
70
+
71
+ ```text
72
+ Mock up a Billing tab on our settings page, using the design kit.
73
+ ```
74
+
75
+ The agent fetches the newest kit, composes the screen from your real frame and
76
+ components, and draws only what is new.
77
+
78
+ ## Keeping the kit in sync
79
+
80
+ Nothing needs re-running after setup.
81
+
82
+ - **It rebuilds itself.** The workflow `init` wrote
83
+ (`.github/workflows/design-kit.yml`) builds the kit every day, and on
84
+ demand from "Run workflow" in the Actions tab or with
85
+ `gh workflow run design-kit.yml`. A day with no new commits since the last
86
+ kit is skipped. Each kit is kept for 30 days.
87
+ - **It captures what exists at that commit.** Every build captures the
88
+ stories and pages that exist at the commit it runs on. It never writes
89
+ stories, so a new component shows up in the kit once it has a story. With
90
+ `gaps.componentGlob` set, every component without one is listed in the
91
+ kit's `gaps.json`. The `design-kit` skill and `storybook-guide` ask agents
92
+ to add or update a component's story in the same pull request as the
93
+ component.
94
+ - **Agents always use the newest kit.** The installed `design-kit` skill
95
+ fetches the newest kit each time. When UI commits have landed since that
96
+ kit was built, the mockup's caption says so.
97
+ - **Re-run `init` only to start over** (`--force`). To pick up a new release
98
+ of this package, update the pinned version in the workflow
99
+ (`DESIGN_KIT_PACKAGE`); the "Run workflow" form's `package` input tries
100
+ another version for one run.
101
+
22
102
  ## Set up in your repository
23
103
 
24
104
  `design-kit init` sets a kit up as one reviewable change. Run it in the
@@ -113,7 +193,7 @@ needs no config.
113
193
 
114
194
  ### `stories`
115
195
 
116
- Captures every story of a Storybook 7 or 8 static build (any renderer). The
196
+ Captures every story of a Storybook 7, 8 or 9 static build (any renderer). The
117
197
  build comes from `--storybook-dir`, `storybookDir`, or `buildCommand`, which
118
198
  writes `staticDir`; without `staticDir`, `{out}` in the command names a
119
199
  temporary folder that is removed afterwards.
@@ -172,15 +252,29 @@ design-kit capture pages [--config f] [--out dir] [--base-url url] [--only nam
172
252
  design-kit kit info|find|show|compose ... [--kit dir]
173
253
  design-kit validate [--config f]
174
254
  design-kit setup-guide
255
+ design-kit storybook-guide
175
256
  ```
176
257
 
177
258
  `setup-guide` prints the agent skill for setting a kit up in a repository
178
259
  that has none, as one reviewable pull request: run `init`, decide between
179
260
  Storybook stories and page capture, wire sign-in through repository secrets,
180
261
  build the kit once and report what it captured. An agent without the skill
181
- installed can run `npx --yes @codepress/design-kit@0.1.3 setup-guide` and
262
+ installed can run `npx --yes @codepress/design-kit setup-guide` and
182
263
  follow what it prints.
183
264
 
265
+ `storybook-guide` prints the agent skill for a repository with no Storybook,
266
+ or one with components that have no stories, as one reviewable pull request.
267
+ The agent surveys the components and tokens, installs Storybook 9 (8 for
268
+ older apps) pinned to the repository's React, Next.js and TypeScript, and fixes
269
+ the usual first-build failures: peer-dependency conflicts, modules that throw
270
+ on a missing environment variable, `next/font`, `next/image` and SVG imports,
271
+ and `public/` assets. It writes one stories file per component, covering
272
+ every variant and the empty, loading, error and long-text states, adds a
273
+ tokens story, and lists anything it skipped, with the reason. It typechecks,
274
+ builds Storybook and checks that `capture stories` captures it. An existing
275
+ Storybook is extended, never re-initialised. React with Vite or Next.js is
276
+ supported first. Run `npx --yes @codepress/design-kit storybook-guide`.
277
+
184
278
  `--only` re-captures just those stories (Storybook ids, with or without the
185
279
  `story:` prefix and width) and copies every other row from `--base`, byte for
186
280
  byte. The two captures share one kit folder and keep each other's files: run
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codepress/design-kit",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Capture your Storybook and real app pages as a static design kit, and compose self-contained mockups from it",
5
5
  "type": "module",
6
6
  "bin": {
@@ -66,7 +66,7 @@
66
66
  "stories": {
67
67
  "type": "object",
68
68
  "additionalProperties": false,
69
- "description": "`design-kit capture stories`: every story of a Storybook 7 or 8 static build.",
69
+ "description": "`design-kit capture stories`: every story of a Storybook 7, 8 or 9 static build.",
70
70
  "properties": {
71
71
  "root": {
72
72
  "type": "string",
@@ -53,10 +53,11 @@ locally (step 3); a kit with pages has frames that new content can go into.
53
53
  **No Storybook.** Propose one of these to the person, through the Orchestrator
54
54
  when you work for one, in a short message with your recommendation:
55
55
 
56
- - (a) **add Storybook** with stories for the components the main screens use,
57
- covering their default, empty, loading, error and long-content states. For
58
- React with Vite or Next.js, `npx storybook@8 init` sets it up; write the
59
- stories next to the components;
56
+ - (a) **add Storybook** with stories for the components, covering their
57
+ default, empty, loading, error and long-content states: follow
58
+ `npx --yes @codepress/design-kit storybook-guide`, which installs a pinned
59
+ Storybook, writes a stories file next to each component, and adds the
60
+ `stories` section to the config `init` wrote;
60
61
  - (b) **capture real pages** from the dev server (step 3);
61
62
  - (c) **both**.
62
63
 
@@ -64,7 +65,7 @@ When nobody answers, do (b), plus (a) for components that are clearly reusable
64
65
  (buttons, inputs, cards, dialogs, tables that several screens share). Say in the
65
66
  pull request which you did and why.
66
67
 
67
- **Supported first:** Storybook 7 and 8 static builds of any renderer, page
68
+ **Supported first:** Storybook 7, 8 and 9 static builds of any renderer, page
68
69
  capture of any URL, and new stories for React only. For another stack (Vue,
69
70
  Svelte, Angular, an older Storybook), capture pages and say honestly in the
70
71
  pull request that new stories were not written, and why.
@@ -0,0 +1,389 @@
1
+ ---
2
+ name: storybook-setup
3
+ description: "Add Storybook to a repository, or extend the one it has, with a stories file for every existing component and a tokens story, as one reviewable pull request: survey the components and tokens, install a pinned Storybook that matches the repo's React, Next and TypeScript, fix the usual first-build failures, write stories for every variant and state, typecheck, build, and check the stories capture in a design kit. Use when asked to set up Storybook, add Storybook, add stories for our components, backfill missing stories, or build a component catalog."
4
+ ---
5
+
6
+ # Set up Storybook with stories for your components
7
+
8
+ Your job is **one reviewable pull request** that gives this repository a
9
+ working Storybook with a stories file for every component it already has,
10
+ plus a tokens story, so people can browse the library and a design kit
11
+ (`@codepress/design-kit`) can capture it. You never merge it.
12
+
13
+ Run the steps in order. The survey comes first because the most common
14
+ failure is a Storybook that ignores what the repository already has: the wrong
15
+ folders, no styles, a second Storybook next to the first.
16
+
17
+ Supported first: **React with Vite or Next.js.** On another renderer (Vue,
18
+ Svelte, Angular, web components) you may still install Storybook and write
19
+ stories under the same rules, but say plainly in the pull request that this
20
+ guide has not been tried on that stack.
21
+
22
+ ## 1. Survey the repository
23
+
24
+ A bounded read, so you extend what exists instead of competing with it:
25
+
26
+ - **Stack and versions.** Read `react`, `react-dom`, `next`, `typescript`,
27
+ `vite` and the Node version (`engines`, `.nvmrc`, `.node-version`; when
28
+ none is recorded, the version its CI workflows use) from `package.json` and
29
+ the lockfile. In a monorepo, find the package that holds
30
+ the components; Storybook goes there.
31
+ - **Package manager.** Use the one the repository uses: the `packageManager`
32
+ field, or the lockfile (`pnpm-lock.yaml` pnpm, `yarn.lock` yarn,
33
+ `bun.lock`/`bun.lockb` bun, `package-lock.json` npm). Never add a second
34
+ lockfile.
35
+ - **The component library: every folder, not just `ui/`.** Components live in
36
+ `components/`, `ui/`, `features/*/components/`, `app/**/_components/`,
37
+ `src/shared/`, workspace packages and more. List every file that exports a
38
+ component that renders something, and note the conventions: file naming,
39
+ default or named exports, how props are typed.
40
+ - **The token layer.** CSS custom properties (`:root { --… }`), a Tailwind
41
+ theme (`tailwind.config.*`, or `@theme` in CSS for Tailwind 4), a theme
42
+ object for a CSS-in-JS `ThemeProvider`, or a design-tokens file.
43
+ - **The global stylesheet and providers.** What the app's entry imports
44
+ (`main.tsx`, `app/layout.tsx`, `pages/_app.tsx`): global CSS, fonts, and
45
+ providers components need to render (theme, router, i18n, data clients).
46
+ - **An existing Storybook.** `.storybook/`, `*.stories.*` files, `storybook`
47
+ or `@storybook/*` dependencies, a `storybook` script. **If Storybook already
48
+ exists, extend it: never run `storybook init` again** and never upgrade it
49
+ in this pull request (one older than Storybook 7 cannot be captured into a
50
+ design kit; say so). Match its story format exactly (CSF version, typing,
51
+ decorators, titles), keep its stories, and add stories only where they are
52
+ missing. A component with a stories file that lacks states gets those
53
+ states added to that file, never a second file.
54
+ - **A design kit.** A `design-kit.config.json` means stories will be captured
55
+ into a kit; step 6 checks they are.
56
+
57
+ Write the survey as one short paragraph (it goes in the pull request) before
58
+ you change anything.
59
+
60
+ ## 2. Install Storybook (only when there is none)
61
+
62
+ **Pick the version.** Use **Storybook 9** (`storybook@9`): it is the newest
63
+ major that `design-kit capture stories` is checked against, and it supports
64
+ Next.js 14.1 through 16. Never use `storybook@latest`. Use **Storybook 8**
65
+ (`storybook@8`) instead when the app is below Storybook 9's floors: Node 20,
66
+ Vite 5, Next.js 14.1 or TypeScript 4.9. Check a framework's peer ranges with
67
+ `npm view @storybook/<framework>@9 peerDependencies`.
68
+
69
+ **Pick the builder deliberately, and record the choice for the pull request.**
70
+
71
+ - Vite app: `@storybook/react-vite`.
72
+ - Next.js app: `@storybook/nextjs` (webpack) is the default and handles
73
+ `next/font`, `next/image`, `next/navigation` and the app's PostCSS and
74
+ Tailwind setup. `@storybook/nextjs-vite` is faster and fits when the app
75
+ has no custom `webpack()` in `next.config.*` that its components depend on
76
+ (SVGR, raw loaders, aliases). When unsure, take `@storybook/nextjs`.
77
+
78
+ **Run init with the repository's package manager**, in the package that holds
79
+ the components:
80
+
81
+ ```bash
82
+ pnpm dlx storybook@9 init --yes --no-dev --disable-telemetry --features docs
83
+ # npm: npx --yes storybook@9 init ... yarn: yarn dlx storybook@9 init ...
84
+ # bun: bunx storybook@9 init ...
85
+ # add --type nextjs, or --builder vite, when init detects the wrong one
86
+ ```
87
+
88
+ `--features docs` keeps init from adding its test-runner setup; step 3
89
+ removes docs (and the onboarding addon init adds anyway) unless the person
90
+ asked for docs pages. Ignore init's banner telling you to cancel and use
91
+ `@latest`: the pin is deliberate.
92
+
93
+ **Then check what init changed: `git diff package.json`.**
94
+
95
+ - Only Storybook packages may be added (`storybook`, `@storybook/*`, and
96
+ `eslint-plugin-storybook` when the repository uses ESLint). All of
97
+ them must be on the **same exact version**; write it without a `^` or `~`
98
+ range.
99
+ - `react`, `react-dom`, `next`, `typescript`, `vite` and every other existing
100
+ dependency must be unchanged. **Never downgrade or upgrade the app** to fit
101
+ Storybook; choose the Storybook version that fits the app.
102
+ - A `storybook` and a `build-storybook` script are fine, and so are the
103
+ `storybook-static` and `*storybook.log` lines init adds to `.gitignore`.
104
+
105
+ ## 3. Configure it
106
+
107
+ Keep the configuration small and make it render the components as the app
108
+ does. When Storybook already existed, change its configuration only where the
109
+ stories need it to render and build (styles, providers, env placeholders,
110
+ loaders, `staticDirs`), and keep its addons as they are.
111
+
112
+ - **Addons.** Keep only what init added for the framework itself. Remove the
113
+ onboarding addon (`@storybook/addon-onboarding`) and its package, and
114
+ delete init's example stories folder (`stories/` or `src/stories/`, with
115
+ its Button, Header and Page examples). Remove `@storybook/addon-docs` (from
116
+ `addons` and `package.json`), any `tags: ["autodocs"]` and the `*.mdx`
117
+ glob unless the person asked for docs pages. Add no other addons. Set
118
+ `core: { disableTelemetry: true }` in `main.*` so builds stay quiet (for
119
+ builds you run against an existing Storybook, set
120
+ `STORYBOOK_DISABLE_TELEMETRY=1` instead).
121
+ - **Story globs.** Point `stories` in `.storybook/main.*` at the real
122
+ component folders from the survey, for example
123
+ `["../src/**/*.stories.@(ts|tsx)"]`, or one entry per folder or package.
124
+ - **Styles and tokens.** Import the global stylesheet or token layer in
125
+ `.storybook/preview.*` (`import "../src/styles/globals.css";`). With
126
+ Tailwind 3, make sure its `content` globs cover the stories files too. If
127
+ the app sets fonts or a theme class in its layout, reproduce that with a
128
+ decorator in `preview.*` (rename init's `preview.ts` to `preview.tsx` for
129
+ JSX). Wrap stories in the providers components need, the same way the app
130
+ does. **An unstyled Storybook is worse than none**: check one built story
131
+ actually looks like the app.
132
+ - **Landing page.** Land the sidebar on a real story, not a docs page. The
133
+ tokens story from step 4 works well: in `preview.*`, set
134
+ `parameters.options.storySort` to `{ order: ["Foundations", "*"] }`.
135
+
136
+ **Fix the first build's failures yourself.** These four hit almost every
137
+ fresh Storybook; fix them rather than report them:
138
+
139
+ 1. **Peer-dependency conflicts.** Put every Storybook package on one exact
140
+ version, and pick the Storybook major whose peer ranges include the app's
141
+ React, Next and TypeScript (step 2). If init's own install fails, re-run
142
+ it with `--skip-install` and install with the repository's package manager.
143
+ Drop an addon that conflicts rather than force it. Never use `--force`,
144
+ and never change the app's versions. If a conflict is only in a transitive
145
+ Storybook dependency, an `overrides` (npm), `resolutions` (yarn) or
146
+ `pnpm.overrides` entry for that one package is acceptable; say so in the
147
+ pull request.
148
+ 2. **Modules that throw at import on a missing environment variable**, for
149
+ example a config module that throws when `NEXT_PUBLIC_API_URL` or
150
+ `VITE_API_URL` is unset. Give Storybook placeholder values. **Never edit
151
+ the app's own validation.** Bundlers inline these variables at build time,
152
+ so pass them through Storybook's `env` option in `.storybook/main.*`, which
153
+ reaches `process.env` and `import.meta.env` in both the webpack and Vite
154
+ builders. Setting `process.env` at the top of `main.*` does not: the
155
+ webpack builder replaces `process.env` in the bundle.
156
+
157
+ ```ts
158
+ // Storybook only: placeholders so modules that validate env at import
159
+ // time load. Never real values.
160
+ env: (config = {}) => ({
161
+ ...config,
162
+ NEXT_PUBLIC_API_URL: config.NEXT_PUBLIC_API_URL ?? "https://api.example.invalid",
163
+ }),
164
+ ```
165
+
166
+ Never commit a real key, and never copy the app's `.env` files.
167
+
168
+ 3. **`next/font`, `next/image` and SVGR imports.** Keep a Next.js framework
169
+ (`@storybook/nextjs` or `@storybook/nextjs-vite`), which handles
170
+ `next/font` and `next/image`. Components that use `next/navigation` need
171
+ `parameters: { nextjs: { appDirectory: true } }` in `preview.*`. A font
172
+ the app's layout applies (`className={inter.variable}` on `<html>`) needs
173
+ the same class in a `preview.*` decorator. With `next/font/google` the
174
+ font files load from Google when a story is viewed, so a captured kit
175
+ falls back to the system font; say so in the pull request
176
+ (`next/font/local` fonts are served by Storybook and captured). Storybook
177
+ does not run the app's custom `webpack()` from `next.config.*`, so an SVG
178
+ imported as a component (`import Logo from "./logo.svg"`) needs the loader
179
+ added in `webpackFinal`, the app's own `@svgr/webpack`:
180
+
181
+ ```ts
182
+ webpackFinal: async (config) => {
183
+ const rules = config.module?.rules ?? [];
184
+ for (const rule of rules)
185
+ if (rule && typeof rule === "object" && rule.test instanceof RegExp && rule.test.test(".svg"))
186
+ rule.exclude = /\.svg$/i;
187
+ rules.push({ test: /\.svg$/i, use: ["@svgr/webpack"] });
188
+ return config;
189
+ },
190
+ ```
191
+
192
+ With a Vite builder, the app's `vite.config.*` plugins (such as
193
+ `vite-plugin-svgr`) are merged in; add the plugin or alias in `viteFinal`
194
+ only when the app configures it somewhere Storybook does not read.
195
+
196
+ 4. **`public/` assets.** Images and fonts the components load by absolute
197
+ path (`/logo.svg`) 404 until `.storybook/main.*` has
198
+ `staticDirs: ["../public"]` (the path to the app's public folder).
199
+
200
+ ## 4. Write the stories
201
+
202
+ **One stories file per component, next to the component**, named the way
203
+ the repository names files (`Button.tsx` and `Button.stories.tsx`). Use CSF 3
204
+ in the repository's typing style, for example:
205
+
206
+ ```tsx
207
+ import type { Meta, StoryObj } from "@storybook/react-vite"; // or @storybook/nextjs, @storybook/nextjs-vite; @storybook/react on Storybook 8
208
+ import { Button } from "./Button";
209
+
210
+ const meta = {
211
+ component: Button,
212
+ args: { children: "Save" },
213
+ } satisfies Meta<typeof Button>;
214
+ export default meta;
215
+ type Story = StoryObj<typeof meta>;
216
+
217
+ export const Primary: Story = {};
218
+ export const Secondary: Story = { args: { variant: "secondary" } };
219
+ ```
220
+
221
+ Each file covers, where it applies:
222
+
223
+ - **the default**, and **every variant and every size** the props allow;
224
+ - **hover, focus and disabled** for anything interactive. Disabled is a prop.
225
+ Focus is a `play` function that focuses the element
226
+ (`play: async ({ canvasElement }) => canvasElement.querySelector("button")?.focus()`).
227
+ Hover that the component drives itself (a tooltip, a menu) is a `play`
228
+ function too. A pure CSS `:hover` cannot be shown without a pseudo-state
229
+ addon, so say so in the coverage note instead of adding one;
230
+ - **empty, loading and error** states for anything that shows data or
231
+ results;
232
+ - **long text or overflow** for anything that holds text: a long label, a
233
+ long unbroken word or address, many items.
234
+
235
+ Name state stories so they do not shadow globals: `ErrorState` with
236
+ `name: "Error"`, never `export const Error`. A captured kit is static HTML, so
237
+ focus rings and other live states show in Storybook but not in the kit.
238
+
239
+ Use made-up fixture data (`example.com` addresses, invented names), never
240
+ real customer data. Write stories through the component's props; do not
241
+ refactor the app to make a state reachable. A state no prop can reach is
242
+ skipped for cause and listed.
243
+
244
+ **Add a tokens (foundations) story**, for example
245
+ `src/foundations/Tokens.stories.tsx` with the title `Foundations/Tokens`.
246
+ It renders the design language from the token layer the survey found: the
247
+ palette as labelled swatches (`background: var(--color-primary)`, or Tailwind
248
+ classes), the type scale (each size with its name), and the spacing ramp
249
+ (bars of each width). Radii and shadows can go in too. List the token names
250
+ from the token source, so a new token is one line.
251
+
252
+ **"Every component" means the whole catalog**: the shared primitives and
253
+ the composites and feature components (lists, panels, cards, headers,
254
+ forms). Skip a component **only for cause**: it cannot render apart from
255
+ live data (it fetches on its own and has no way to pass data in), it is
256
+ deprecated, or it is an internal detail of another component that is
257
+ already covered. Route files (`page.tsx`, `layout.tsx`) and the app root are
258
+ screens, not catalog components: give one a story when it renders from props
259
+ alone, and otherwise list it as skipped. List every skip, with its reason, in
260
+ the pull request. A large backfill may be split into several pull requests by
261
+ component family; say which family each covers and what is left. Silently
262
+ leaving components out is not allowed.
263
+
264
+ While you read the screens, note **inline UI that should become shared
265
+ components**: the same markup repeated across pages. Name each one under
266
+ "Recommended next" in the pull request. Do not extract it in this pull
267
+ request.
268
+
269
+ ## 5. Typecheck, then build
270
+
271
+ 1. **Typecheck first.** It is cheaper than a build, and it catches story type
272
+ errors that `storybook build` lets through. Run the repository's own
273
+ typecheck (`pnpm typecheck`, `pnpm exec tsc --noEmit`, `tsc -b`). Check
274
+ that its `include` covers the stories files and `.storybook/`. TypeScript
275
+ skips dot-folders in wildcards, so name the files: add
276
+ `".storybook/*.ts", ".storybook/*.tsx"` to the `include` the typecheck
277
+ uses. Fix every error.
278
+ 2. **Build.** Run `storybook build` with the repository's package manager
279
+ (`pnpm exec storybook build --quiet`, `npx storybook build --quiet`). Fix
280
+ every error and warning that points at a story or the config. Then check
281
+ `storybook-static/index.json`: its story entries should match what you
282
+ wrote, and none of init's examples should be left.
283
+ 3. Run the repository's lint and its other pull request checks that the
284
+ change touches (ESLint on the stories, a format check), and fix what this
285
+ change broke.
286
+
287
+ ## 6. Check the design kit captures it
288
+
289
+ `design-kit capture stories` renders every story in a headless browser, so it
290
+ also proves each story renders without throwing. Write the kit to a scratch
291
+ folder **outside the repository**, never into it.
292
+
293
+ - **With a `design-kit.config.json`:** give it a `stories` section if it has
294
+ none:
295
+
296
+ ```json
297
+ "stories": {
298
+ "root": ".",
299
+ "buildCommand": "pnpm exec storybook build --quiet -o storybook-static",
300
+ "staticDir": "storybook-static",
301
+ "gaps": { "componentGlob": "src/**/[A-Z]*.{tsx,jsx}" }
302
+ }
303
+ ```
304
+
305
+ (`root` is the folder holding `.storybook/`, relative to the config; use
306
+ the repository's package manager in `buildCommand`.) If the repository's
307
+ `.github/workflows/design-kit.yml` and `.claude/skills/design-kit/SKILL.md`
308
+ were written before Storybook existed, they skip stories too. To update
309
+ them, copy the repository (without `node_modules`) to a scratch folder,
310
+ run `npx --yes @codepress/design-kit init --force` there, and port only
311
+ the Storybook parts of those two files back: the "Build Storybook and
312
+ capture stories" step and the stories capture line. Then run, from the
313
+ folder that holds `design-kit.config.json`:
314
+
315
+ ```bash
316
+ npx --yes @codepress/design-kit capture stories --out "$TMPDIR/design-kit-check"
317
+ ```
318
+
319
+ - **Without one:** check anyway with a scratch config outside the repository:
320
+
321
+ ```bash
322
+ cat > "$TMPDIR/design-kit-check.json" <<EOF
323
+ {"version": 1, "stories": {"root": "$PWD", "storybookDir": "$PWD/storybook-static",
324
+ "gaps": {"componentGlob": "src/**/[A-Z]*.{tsx,jsx}"}}}
325
+ EOF
326
+ npx --yes @codepress/design-kit capture stories --config "$TMPDIR/design-kit-check.json" --out "$TMPDIR/design-kit-check"
327
+ ```
328
+
329
+ Capture needs Playwright and Chromium. When the repository has neither,
330
+ run `npx --yes -p @playwright/test playwright install chromium`, then
331
+ `npx --yes -p @codepress/design-kit -p @playwright/test design-kit capture stories ...`;
332
+ install nothing into the repository for it.
333
+
334
+ Capture what you just built: the `buildCommand` rebuilds Storybook, and with
335
+ a `storybookDir` rebuild first, because a stale build hides missing stories.
336
+ Read what it printed (`stories N, ... failed M`) and
337
+ `$TMPDIR/design-kit-check/gaps.json`:
338
+
339
+ - a **failed story** (it threw, or never rendered) is a bug in the story or
340
+ the config: fix it and capture again;
341
+ - a **`no story`** row names a component file with no stories file: write
342
+ one, or make sure it is in your skip list with its reason. Its path is
343
+ relative to the config file's folder.
344
+
345
+ Aim for zero failures and every `no story` row explained. The files in
346
+ `html/` are bare markup without CSS; to look at one story styled, find its id
347
+ and compose it into a page, then open that page in a browser:
348
+
349
+ ```bash
350
+ KIT="$TMPDIR/design-kit-check"
351
+ node "$KIT/kit.mjs" --kit "$KIT" find <component name> # ids like story:<storybook-id>@1280
352
+ node "$KIT/kit.mjs" --kit "$KIT" compose --frame <id> --out "$TMPDIR/story.html"
353
+ ```
354
+
355
+ Check it looks like the app, and take a screenshot for the pull request.
356
+
357
+ ## 7. Open the pull request
358
+
359
+ One pull request; never merge it. When the survey and the checks found
360
+ nothing missing (Storybook builds, every component has its stories, the
361
+ capture has no failures and no unexplained `no story` rows), open no pull
362
+ request: report that proof instead. Otherwise the description says:
363
+
364
+ - **The survey**: where the components and tokens live, and whether
365
+ Storybook existed (extended, not re-initialised).
366
+ - **Versions and builder**: the Storybook version and why (9, or 8 because of
367
+ which floor), the framework package and why, and that React, Next and
368
+ TypeScript are unchanged.
369
+ - **First-build fixes**: each one you made (env placeholders, loaders,
370
+ `staticDirs`, overrides) and why.
371
+ - **Coverage**: the components covered, counted per folder ("14 of 15 in
372
+ `src/components`"), with the states each covers, and the tokens story.
373
+ - **Skipped**: every component or state left out, each with its reason.
374
+ - **Proof**: the typecheck and `storybook build` results, the capture's
375
+ story count, failures and `gaps.json` rows, and the screenshot.
376
+ - **Recommended next**: inline UI that should become shared components, and,
377
+ when the repository has no design kit yet, that
378
+ `npx --yes @codepress/design-kit setup-guide` sets one up.
379
+ - **Not tried**: anything this guide does not cover on this stack, said
380
+ plainly.
381
+
382
+ Never commit `storybook-static/`, a captured kit, or a real secret.
383
+
384
+ ## Keeping stories current
385
+
386
+ After this pull request, when you add a component or change what one
387
+ renders, add or update its story in the same pull request, covering the
388
+ states in step 4, so the next design kit captures it. Say in the pull request
389
+ which stories you added or changed.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `design-kit capture stories`: every story of a Storybook 7/8 static build
2
+ * `design-kit capture stories`: every story of a Storybook 7, 8 or 9 static build
3
3
  * rendered to static HTML, the CSS the preview loaded, the fonts, an index
4
4
  * and kit.mjs.
5
5
  *
package/src/cli.mjs CHANGED
@@ -17,12 +17,18 @@ const SETUP_GUIDE = new URL(
17
17
  import.meta.url,
18
18
  );
19
19
 
20
+ /** The `storybook-setup` skill, printed by `design-kit storybook-guide`. */
21
+ const STORYBOOK_GUIDE = new URL(
22
+ "../skills/storybook-setup/SKILL.md",
23
+ import.meta.url,
24
+ );
25
+
20
26
  const USAGE = `usage: design-kit <command> [options]
21
27
 
22
28
  init set a kit up in this repository: the config, a daily
23
29
  GitHub Actions build, and a skill for its agents
24
30
  [--root <dir>] [--dry-run] [--force]
25
- capture stories capture every story of a Storybook 7/8 static build
31
+ capture stories capture every story of a Storybook 7-9 static build
26
32
  [--config <file>] [--out <dir>] [--storybook-dir <dir>]
27
33
  [--only <id,...> | --only-file <file>] [--base <previous kit>]
28
34
  capture pages capture the configured pages of a running app
@@ -35,6 +41,9 @@ const USAGE = `usage: design-kit <command> [options]
35
41
  [--config <file>]
36
42
  setup-guide print the guide for setting a kit up in a repository as
37
43
  one reviewable pull request (an agent skill)
44
+ storybook-guide print the guide for adding Storybook, with stories for
45
+ every existing component, as one reviewable pull request
46
+ (an agent skill)
38
47
 
39
48
  The config is the nearest design-kit.config.json at or above the working
40
49
  directory unless --config names one. Exit codes: 0 done, 1 a capture could
@@ -183,6 +192,11 @@ export async function main(argv = process.argv.slice(2), env = process.env) {
183
192
  process.stdout.write(readFileSync(SETUP_GUIDE, "utf8"));
184
193
  return 0;
185
194
  }
195
+ if (command === "storybook-guide") {
196
+ parse(argv.slice(1), {});
197
+ process.stdout.write(readFileSync(STORYBOOK_GUIDE, "utf8"));
198
+ return 0;
199
+ }
186
200
  if (command === "validate") {
187
201
  const options = parse(argv.slice(1), { config: "value" });
188
202
  const config = loadConfig(options.config);
package/src/init.mjs CHANGED
@@ -916,11 +916,11 @@ function todo(found) {
916
916
  const sb = found.storybook;
917
917
  if (!sb)
918
918
  items.push(
919
- "No Storybook: the config captures pages only. Decide whether to add Storybook with stories for the components the main screens use, capture real pages, or both.",
919
+ "No Storybook: the config captures pages only. Decide whether to add Storybook with stories for the components the main screens use (`npx --yes @codepress/design-kit storybook-guide` prints a guide for that), capture real pages, or both.",
920
920
  );
921
- else if (sb.major && (sb.major < 7 || sb.major > 8))
921
+ else if (sb.major && (sb.major < 7 || sb.major > 9))
922
922
  items.push(
923
- `Storybook ${sb.version}: captures are supported for Storybook 7 and 8 static builds; check that \`capture stories\` works, or use page capture.`,
923
+ `Storybook ${sb.version}: captures are supported for Storybook 7, 8 and 9 static builds; check that \`capture stories\` works, or use page capture.`,
924
924
  );
925
925
  items.push(
926
926
  `Pages: replace the ${TODO} selectors in ${CONFIG_NAME} (pages[].ready and slots.main), add the app's main screens, and check startCommand and waitUrl. Until then the workflow skips page capture.`,
@@ -16,6 +16,12 @@ The kit is configured in `{{CONFIG}}` and built by the `Design kit` workflow
16
16
  (`.github/workflows/design-kit.yml`). The format and every command are in the
17
17
  `{{PACKAGE}}` README.
18
18
 
19
+ When this repository has Storybook and you add a component or change what
20
+ one renders, add or update its story in the same pull request, covering its
21
+ default, every variant and size, and the empty, loading, error and long-text
22
+ states that apply, so the next kit captures it. A component without a story
23
+ is missing from every kit until it gets one.
24
+
19
25
  ## 1. Fetch the newest kit
20
26
 
21
27
  The workflow runs once a day and on demand (`workflow_dispatch`), and uploads