@jfrader/storybook-docs 0.0.0-stage → 0.4.4
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/LICENSE +21 -0
- package/README.md +138 -2
- package/dist/app.d.ts +1 -0
- package/dist/base.d.ts +3 -0
- package/dist/build/catalog.d.ts +20 -0
- package/dist/build/code.d.ts +2 -0
- package/dist/build/global-styles.d.ts +1 -0
- package/dist/build/guidance.d.ts +4 -0
- package/dist/build/module-ids.d.ts +2 -0
- package/dist/build/props.d.ts +10 -0
- package/dist/build/releases.d.ts +7 -0
- package/dist/build/site.d.ts +2 -0
- package/dist/build/storybook-test.d.ts +2 -0
- package/dist/build/tokens.d.ts +2 -0
- package/dist/code.d.ts +16 -0
- package/dist/component-demo.d.ts +23 -0
- package/dist/config.d.ts +98 -0
- package/dist/controls.d.ts +49 -0
- package/dist/css.d.ts +1 -0
- package/dist/guidance-model.d.ts +74 -0
- package/dist/guidance.d.ts +9 -0
- package/dist/index.css +420 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +1971 -0
- package/dist/pages/component-page.d.ts +4 -0
- package/dist/pages/foundations-color.d.ts +3 -0
- package/dist/pages/foundations-effects.d.ts +3 -0
- package/dist/pages/foundations-spacing.d.ts +3 -0
- package/dist/pages/foundations-type.d.ts +3 -0
- package/dist/pages/overview.d.ts +3 -0
- package/dist/pages/releases.d.ts +3 -0
- package/dist/prop-docs.d.ts +20 -0
- package/dist/props.d.ts +4 -0
- package/dist/scan.d.ts +19 -0
- package/dist/search-match.d.ts +21 -0
- package/dist/search.d.ts +5 -0
- package/dist/sections.d.ts +52 -0
- package/dist/skeleton.d.ts +11 -0
- package/dist/start.d.ts +4 -0
- package/dist/story-view.d.ts +20 -0
- package/dist/styles.css +685 -0
- package/dist/toc.d.ts +19 -0
- package/dist/virtual.d.ts +42 -0
- package/dist/vite-plugin.d.ts +10 -0
- package/dist/vite-plugin.js +697 -0
- package/docs/CONFIG.md +287 -0
- package/docs/RELEASING.md +153 -0
- package/package.json +75 -3
package/docs/CONFIG.md
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# Configuration reference
|
|
2
|
+
|
|
3
|
+
The consumer contract is `StorybookDocsConfig` in `src/config.ts`. Export a plain
|
|
4
|
+
object from `docs.config.mjs` and pass it to `storybookDocs({ config })` in Vite.
|
|
5
|
+
Only `site` and `stories` are required. Defaults below describe the current engine,
|
|
6
|
+
not values copied from the reference consumer.
|
|
7
|
+
|
|
8
|
+
## Site and stories
|
|
9
|
+
|
|
10
|
+
| Key | Type | Default | Effect |
|
|
11
|
+
| --- | --- | --- | --- |
|
|
12
|
+
| `site` | object | Required | Branding and header content. |
|
|
13
|
+
| `site.title` | `string` | Required | Header brand and overview heading. |
|
|
14
|
+
| `site.mark` | `string` | First character of `site.title`, uppercased | Header mark. |
|
|
15
|
+
| `site.tagline` | `string` | Built-in paragraph about generated documentation | Overview introduction. |
|
|
16
|
+
| `site.links` | `Array<{ label: string; href: string }>` | `[]` | Header links. `label` is the visible text; `href` is the destination; both are required per item. |
|
|
17
|
+
| `stories` | object | Required | Story discovery source. |
|
|
18
|
+
| `stories.from` | `string` | Required | Installed package name, absolute directory, or relative directory holding story sources. |
|
|
19
|
+
| `stories.pattern` | `string` | Required | Glob relative to the story root, for example `src/components/*/*.stories.tsx`. Matches determine navigation, examples and API tables. |
|
|
20
|
+
|
|
21
|
+
Package roots are resolved by walking up from the consumer root for
|
|
22
|
+
`node_modules/<package>`. Relative paths resolve against the Vite project root
|
|
23
|
+
(normally the directory containing the config), not the engine's directory.
|
|
24
|
+
The plugin option `root?: string` overrides that consumer root; it is not a
|
|
25
|
+
`StorybookDocsConfig` key. Keep the config and Vite root together, or set `root`
|
|
26
|
+
explicitly. Published packages must include their story sources, or
|
|
27
|
+
`stories.from` must point at a checkout. The scanner supports `*` within one path
|
|
28
|
+
segment and `**` across directories.
|
|
29
|
+
|
|
30
|
+
### Authored documentation already in the stories
|
|
31
|
+
|
|
32
|
+
The following authored documentation parameters are rendered without a second copy of the prose:
|
|
33
|
+
|
|
34
|
+
| Storybook parameter | Where it appears |
|
|
35
|
+
| --- | --- |
|
|
36
|
+
| `parameters.docs.description.component` | Page introduction under the title. |
|
|
37
|
+
| `parameters.docs.description.story` | Blurb on that story's example. |
|
|
38
|
+
| `parameters.docs.usage` | Usage section, rendered as Markdown (headings, lists, tables, callouts) above the examples. |
|
|
39
|
+
| `parameters.docs.source.code` | The example's Code panel, and the page-level snippet when authored, instead of the snippet derived from default arguments. |
|
|
40
|
+
| `parameters.docs.source.language` | Language id handed to the consumer's code renderer; the derived snippet is `tsx`. |
|
|
41
|
+
| `tags: ['!autodocs']` | Story is left off docs pages, as in Storybook. Meta and story tags both apply. |
|
|
42
|
+
|
|
43
|
+
Meta parameters apply to every story; a story's own parameters win.
|
|
44
|
+
|
|
45
|
+
### Rendering code with the design system's own block
|
|
46
|
+
|
|
47
|
+
Code renders in the engine's plain block unless the consumer names a renderer:
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
export default {
|
|
51
|
+
// …
|
|
52
|
+
code: { module: './src/code.tsx' },
|
|
53
|
+
};
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
// src/code.tsx — the module's default export receives { code, language, label }.
|
|
58
|
+
// `label` is optional and names the panel for assistive tech; forward it to your renderer
|
|
59
|
+
// (a design system's code block usually takes a `label`) so a page with many examples does not
|
|
60
|
+
// expose several landmarks with the same name.
|
|
61
|
+
import { CodeBlock } from '@acme/ui';
|
|
62
|
+
import { loadShikiHighlight } from '@acme/ui/code-block/shiki';
|
|
63
|
+
|
|
64
|
+
export default function Code({ code, language }: { code: string; language?: string }) {
|
|
65
|
+
return <CodeBlock code={code} language={language} highlight={loadShikiHighlight} copyable />;
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The same renderer is used for the page snippet, every example's Code panel and every fenced block
|
|
70
|
+
in authored Markdown. A design system that highlights code opt-in per component (a `highlight`
|
|
71
|
+
loader, as Storybook does) wires it here once for the whole docs site. If the renderer throws, that
|
|
72
|
+
block falls back to plain text rather than failing the page.
|
|
73
|
+
|
|
74
|
+
## Groups
|
|
75
|
+
|
|
76
|
+
| Key | Type | Default | Effect |
|
|
77
|
+
| --- | --- | --- | --- |
|
|
78
|
+
| `groups` | object | Omitted | Optional ordering and display-name changes. |
|
|
79
|
+
| `groups.order` | `string[]` | See below | Places named groups first, in this order. Unlisted groups follow; components within a group sort by name. |
|
|
80
|
+
| `groups.rename` | `Record<string, string>` | `{}` | Maps authored group names to display names before sorting. Use renamed names in `order`. |
|
|
81
|
+
|
|
82
|
+
Default order: `Getting started`, `Foundations`, `Actions`, `Forms`, `Inputs`,
|
|
83
|
+
`Data display`, `Feedback`, `Navigation`, `Surfaces`, `Pickers`, `Layout`,
|
|
84
|
+
`Content`, `Components`. Passing `[]` disables this preferred order.
|
|
85
|
+
Groups and component names come from story meta titles such as `Inputs/Button`;
|
|
86
|
+
there is no separate component registry.
|
|
87
|
+
|
|
88
|
+
## Theme
|
|
89
|
+
|
|
90
|
+
| Key | Type | Default | Effect |
|
|
91
|
+
| --- | --- | --- | --- |
|
|
92
|
+
| `theme` | object | Omitted | Optional bridge from docs chrome to consumer theme. |
|
|
93
|
+
| `theme.attribute` | `string` | `'data-theme'` | Attribute set on `document.documentElement` by the theme toggle. |
|
|
94
|
+
| `theme.values` | `[string, string]` | `['dark', 'light']` | Initial and alternate theme attribute values, also used as toggle labels. |
|
|
95
|
+
| `theme.vars` | `Partial<Record<ThemeRole, string>>` | `{}` | CSS values assigned to the engine's semantic roles. Unmapped roles keep the defaults in `src/styles.css`. |
|
|
96
|
+
|
|
97
|
+
Each value is a complete CSS value, typically `var(--acme-bg)`, not a bare custom
|
|
98
|
+
property name. These are all supported `ThemeRole` keys (each is an optional
|
|
99
|
+
`string`, with the corresponding stylesheet role as its fallback):
|
|
100
|
+
|
|
101
|
+
| Key | CSS property | Role |
|
|
102
|
+
| --- | --- | --- |
|
|
103
|
+
| `theme.vars.bg` | `--sd-bg` | Page background. |
|
|
104
|
+
| `theme.vars.surface` | `--sd-surface` | Cards and panels. |
|
|
105
|
+
| `theme.vars.surfaceRaised` | `--sd-surface-raised` | Raised surfaces. |
|
|
106
|
+
| `theme.vars.surfaceHover` | `--sd-surface-hover` | Hovered surfaces. |
|
|
107
|
+
| `theme.vars.border` | `--sd-border` | Standard boundaries. |
|
|
108
|
+
| `theme.vars.borderSubtle` | `--sd-border-subtle` | Subtle separators. |
|
|
109
|
+
| `theme.vars.text` | `--sd-text` | Primary text. |
|
|
110
|
+
| `theme.vars.textMuted` | `--sd-text-muted` | Secondary text. |
|
|
111
|
+
| `theme.vars.textSubtle` | `--sd-text-subtle` | Low-emphasis text. |
|
|
112
|
+
| `theme.vars.accent` | `--sd-accent` | Accent surfaces and decoration. |
|
|
113
|
+
| `theme.vars.accentText` | `--sd-accent-text` | Accent text. |
|
|
114
|
+
| `theme.vars.accentSoft` | `--sd-accent-soft` | Subdued accent surfaces. |
|
|
115
|
+
| `theme.vars.accentContrast` | `--sd-accent-contrast` | Text on accent surfaces. |
|
|
116
|
+
| `theme.vars.danger` | `--sd-danger` | Error boundaries and tinted callouts. |
|
|
117
|
+
| `theme.vars.dangerText` | `--sd-danger-text` | Danger **text**; use a tone that passes 4.5:1 on your surface (axe checks it). |
|
|
118
|
+
| `theme.vars.focusRing` | `--sd-focus-ring` | Keyboard focus outlines. |
|
|
119
|
+
|
|
120
|
+
## Tokens and guidance
|
|
121
|
+
|
|
122
|
+
| Key | Type | Default | Effect |
|
|
123
|
+
| --- | --- | --- | --- |
|
|
124
|
+
| `tokens` | object | Omitted | Enables Foundations navigation. Without it the virtual token object is `{}`. |
|
|
125
|
+
| `tokens.varsModule` | `string` | Required when `tokens` is supplied | Module specifier exporting the token object. |
|
|
126
|
+
| `tokens.varsExport` | `string` | `'vars'` | Named export to read from that module. |
|
|
127
|
+
| `tokens.css` | `string[]` | `[]` | CSS module specifiers imported globally, in order, after engine styles. |
|
|
128
|
+
| `guidance` | object | Omitted | Optional Markdown prose; without it no authored content loads. Component pages can still show their built-in placeholder. |
|
|
129
|
+
| `guidance.dir` | `string` | Required when `guidance` is supplied | Directory resolved against the consumer root. Files named `<component-slug>.md` render on that component's page; `index.md` renders on the overview. A missing directory or file loads no authored content. |
|
|
130
|
+
|
|
131
|
+
Foundations read string-valued maps from the exported token object: `color`;
|
|
132
|
+
`font`, `fontWeight`, `textSize`; `space`, `radius`, `size`; and `shadow`,
|
|
133
|
+
`motion.duration`, `motion.ease` (or `motion.easing`). Values can be CSS variable
|
|
134
|
+
references. Missing maps produce empty sections, not a crash. Guidance is authored
|
|
135
|
+
Markdown rendered with `marked`; there is no built-in prose editor.
|
|
136
|
+
|
|
137
|
+
## Page switches
|
|
138
|
+
|
|
139
|
+
| Key | Type | Default | Effect |
|
|
140
|
+
| --- | --- | --- | --- |
|
|
141
|
+
| `pages` | object | Omitted | Optional switches. |
|
|
142
|
+
| `pages.overview` | `boolean` | `true` | Exposed in page settings; currently the shell still shows the overview link and fallback route when `false`. |
|
|
143
|
+
| `pages.color` | `boolean` | `true` with tokens, otherwise `false` | Shows Color in Foundations navigation. |
|
|
144
|
+
| `pages.typography` | `boolean` | `true` with tokens, otherwise `false` | Shows Typography in Foundations navigation. |
|
|
145
|
+
| `pages.spacing` | `boolean` | `true` with tokens, otherwise `false` | Shows Spacing & shape in Foundations navigation. |
|
|
146
|
+
| `pages.effects` | `boolean` | `true` with tokens, otherwise `false` | Shows Elevation & motion in Foundations navigation. |
|
|
147
|
+
| `pages.api` | `boolean` | `true` | Exposed in page settings; currently component pages still show API tables when `false`. |
|
|
148
|
+
|
|
149
|
+
Setting a Foundations switch to `true` does not enable it without
|
|
150
|
+
`tokens.varsModule`. These switches hide navigation entries, not direct routes.
|
|
151
|
+
|
|
152
|
+
## Add your design system in five minutes
|
|
153
|
+
|
|
154
|
+
Use a docs app with React, React DOM, Vite, `@vitejs/plugin-react`, this engine,
|
|
155
|
+
and your design system installed. Add these four files, matching the README's
|
|
156
|
+
consumer contract:
|
|
157
|
+
|
|
158
|
+
1. **`docs.config.mjs`** — point at the story sources:
|
|
159
|
+
|
|
160
|
+
```js
|
|
161
|
+
export default {
|
|
162
|
+
site: { title: 'acme/ui', mark: 'a' },
|
|
163
|
+
stories: { from: '@acme/ui', pattern: 'src/components/*/*.stories.tsx' },
|
|
164
|
+
// Optional: tokens: { varsModule: '@acme/tokens/vars', css: ['@acme/tokens/tokens.css'] },
|
|
165
|
+
// Optional: guidance: { dir: './guidance' },
|
|
166
|
+
};
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
2. **`vite.config.ts`** — register the engine and React plugins:
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
import react from '@vitejs/plugin-react';
|
|
173
|
+
import { defineConfig } from 'vite';
|
|
174
|
+
import { storybookDocs } from '@jfrader/storybook-docs/vite';
|
|
175
|
+
import config from './docs.config.mjs';
|
|
176
|
+
|
|
177
|
+
export default defineConfig({ plugins: [storybookDocs({ config }), react()] });
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
3. **`index.html`** — mount the app:
|
|
181
|
+
|
|
182
|
+
```html
|
|
183
|
+
<!doctype html>
|
|
184
|
+
<html lang="en">
|
|
185
|
+
<head><meta charset="UTF-8"><title>acme/ui docs</title></head>
|
|
186
|
+
<body><div id="root"></div><script type="module" src="/src/main.tsx"></script></body>
|
|
187
|
+
</html>
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
4. **`src/main.tsx`** — start the engine:
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
import { start } from '@jfrader/storybook-docs';
|
|
194
|
+
start();
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Run `pnpm exec vite` in the docs app. Match your stories' JSX runtime and install
|
|
198
|
+
their imports in the consumer. The reference consumer is `examples/jfrader-ui`.
|
|
199
|
+
|
|
200
|
+
### When the design system is linked rather than installed
|
|
201
|
+
|
|
202
|
+
Stories are rendered from the design system's own files, so its imports resolve
|
|
203
|
+
next to those files, not next to your app. Three things follow, and all three
|
|
204
|
+
show up as stories that render wrong rather than as errors:
|
|
205
|
+
|
|
206
|
+
- **Dedupe the styling runtime.** If the design system ships its own copy of
|
|
207
|
+
Emotion, styled-components or similar, a story that provides a cache or reads
|
|
208
|
+
a context sees a different instance than the components do. Add the runtime to
|
|
209
|
+
`resolve.dedupe` in the consumer so it resolves from your app.
|
|
210
|
+
- **Provide optional peers.** A story may import a package the design system
|
|
211
|
+
treats as optional (its own Storybook installs it, your app does not). Install
|
|
212
|
+
it in the consumer and dedupe it too; an unresolved import fails the whole
|
|
213
|
+
story module, not just the story.
|
|
214
|
+
- **Generate the design system's CSS.** Token CSS is usually generated and
|
|
215
|
+
gitignored, so a linked checkout can hold a build from before your tokens
|
|
216
|
+
changed. Regenerate it before `vite` (`pnpm --dir <design-system>/packages/tokens
|
|
217
|
+
generate` in the reference setup). A stale file loses variables silently:
|
|
218
|
+
every component that sizes itself from a token collapses to zero.
|
|
219
|
+
|
|
220
|
+
## Known limits
|
|
221
|
+
|
|
222
|
+
- Compound parts hidden from docgen (including `Object.assign` compounds and
|
|
223
|
+
`Dialog.Content = …`) rely on exported `*Props` types. Parts without exported
|
|
224
|
+
props types remain invisible.
|
|
225
|
+
- Meta and story args, globals, argTypes and parameters are composed with story-level precedence.
|
|
226
|
+
Parameters and argTypes merge recursively; arrays replace rather than concatenate.
|
|
227
|
+
Explicit args win over deprecated argType defaults. Docgen defaults describe controls only;
|
|
228
|
+
they are not evaluated or passed into the component. Render functions receive the composed
|
|
229
|
+
context, and decorators can call `Story({ args })` to override arguments.
|
|
230
|
+
- Controls support boolean, number, text/string, select, radio/inline-radio (as a select),
|
|
231
|
+
range and object (JSON, applied on blur). ArgType mappings apply to rendered arguments.
|
|
232
|
+
Custom renders accept controls too. Check/inline-check, multi-select, color, date and file
|
|
233
|
+
editors are not provided; their authored args still render unchanged.
|
|
234
|
+
- Story `name` supplies the example heading; export names remain the stable identifiers.
|
|
235
|
+
`!dev` and `!test` affect Storybook's sidebar/test runner, not this docs front.
|
|
236
|
+
Custom tags have no filtering effect here. `!autodocs` hides docs examples.
|
|
237
|
+
- Meta and story decorators are applied in Storybook's order. Project-level
|
|
238
|
+
decorators from `.storybook/preview` are not recreated: theme, global styles
|
|
239
|
+
and layout come from the docs config instead. A story that throws shows its
|
|
240
|
+
error in place rather than disappearing.
|
|
241
|
+
- Play functions and accessibility checks do not run here. Loaders and beforeEach hooks
|
|
242
|
+
are not executed: test hooks can modify clocks, preferences and shared browser state,
|
|
243
|
+
which cannot safely be isolated across simultaneous examples. Affected frames show a notice.
|
|
244
|
+
Loader-dependent examples may not render correctly. Project globals/initialGlobals and
|
|
245
|
+
Storybook-specific context APIs (hooks, canvas, mount, step) are not recreated.
|
|
246
|
+
Addon parameters such as viewport and backgrounds are not applied; viewport frames show
|
|
247
|
+
a notice. Layout supports centered, padded and fullscreen (an unpadded docs frame,
|
|
248
|
+
not a separate viewport-sized canvas).
|
|
249
|
+
- Search scans the in-memory catalog's component, group and story names. There is
|
|
250
|
+
no generated full-text search index for guidance, props or rendered content.
|
|
251
|
+
|
|
252
|
+
### Checking a running site
|
|
253
|
+
|
|
254
|
+
The engine ships a frame check for the thing unit tests cannot see: whether the examples a docs site
|
|
255
|
+
renders are actually right. From a directory where `playwright` resolves:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
node scripts/check-example-frames.mjs http://localhost:4320 [--json report.json]
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
It reports stories that fail to render (including modules that never loaded), content painted outside
|
|
262
|
+
its frame, zero-size interactive controls, and component roots that collapsed to nothing. Invisible
|
|
263
|
+
helpers — measure probes, closed dialogs, top-layer overlays, aria-hidden duplicates — are ignored, so
|
|
264
|
+
findings are real. Exit code is 1 when a component has a finding.
|
|
265
|
+
|
|
266
|
+
## Verification and CI
|
|
267
|
+
|
|
268
|
+
From the engine root, run `pnpm test`, `pnpm typecheck` (engine and tests), and
|
|
269
|
+
`pnpm build` (the reference consumer). The reference consumer's link dependencies
|
|
270
|
+
expect a sibling `jfrader-ui` checkout, with UI dependencies installed and token
|
|
271
|
+
CSS generated: run `pnpm --filter @jfrader/ui... install --frozen-lockfile --prefer-offline`
|
|
272
|
+
then `pnpm --filter @jfrader/tokens generate` in that checkout, and
|
|
273
|
+
`pnpm --dir examples/jfrader-ui install --frozen-lockfile --prefer-offline` in the
|
|
274
|
+
engine checkout.
|
|
275
|
+
|
|
276
|
+
CI runs on pushes and pull requests targeting `master`. It uses Node 22.23.3 (the
|
|
277
|
+
`engines.node` minimum major), the root's pinned `pnpm@10.12.1`, cached package
|
|
278
|
+
downloads and frozen, prefer-offline installs. It tests and typechecks before
|
|
279
|
+
checking out the reference design system at
|
|
280
|
+
`c990db09c143a183f5666d404c35cf2fe324cf9d`, installing its UI/token dependencies,
|
|
281
|
+
generating tokens, installing the consumer and running the build.
|
|
282
|
+
|
|
283
|
+
Set the repository secret `REFERENCE_UI_TOKEN` to a token with read-only contents
|
|
284
|
+
access to `jfrader/jfrader-ui`. Checkout does not persist its credentials.
|
|
285
|
+
Fork PRs do not receive this secret and fail the credential check; verify them on
|
|
286
|
+
a trusted branch instead. CI never uses `pull_request_target` to run PR code with
|
|
287
|
+
elevated permissions.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Publishing @jfrader/storybook-docs
|
|
2
|
+
|
|
3
|
+
## Check a release
|
|
4
|
+
|
|
5
|
+
Use Node 22.18+ for the maintainer's TypeScript tests and the pinned `pnpm@10.12.1`.
|
|
6
|
+
Use Node 24 and npm 11.18.0 for publishing, matching `publish.yml`.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pnpm install --frozen-lockfile
|
|
10
|
+
pnpm test
|
|
11
|
+
pnpm typecheck
|
|
12
|
+
pnpm build:package
|
|
13
|
+
pnpm smoke:package
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The smoke command runs `pnpm pack` (including `prepack`), prints and checks the
|
|
17
|
+
tarball contents, installs that tarball with npm into a temporary directory under
|
|
18
|
+
`node_modules`, and typechecks/builds a synthetic consumer. It checks both public
|
|
19
|
+
entries, all virtual declarations without `skipLibCheck`, and emitted engine CSS.
|
|
20
|
+
It needs registry access and `tar`; it removes the temporary directory on success
|
|
21
|
+
or failure. It uses the installed development versions of React, Vite and TypeScript,
|
|
22
|
+
not a peer-version matrix. It does not run a browser.
|
|
23
|
+
|
|
24
|
+
Both checkout and tarball exports currently point at `dist`, not `src`. Linked
|
|
25
|
+
consumers must rebuild the engine after edits. The browser entry imports its CSS
|
|
26
|
+
automatically and its declaration references `virtual.d.ts`; consumers importing
|
|
27
|
+
the root entry need no extra CSS import or triple-slash reference. A consumer
|
|
28
|
+
importing virtual modules alone must also import a type from the root entry to load
|
|
29
|
+
those ambient declarations. The Node-only plugin remains at `@jfrader/storybook-docs/vite`.
|
|
30
|
+
|
|
31
|
+
## First publish: the owner's interactive login
|
|
32
|
+
|
|
33
|
+
Trusted publishing is configured in an existing npm package's settings. If the
|
|
34
|
+
package does not exist yet, the owner must create it by publishing locally first.
|
|
35
|
+
|
|
36
|
+
1. Confirm the checkout is the reviewed release commit on `master` and clean.
|
|
37
|
+
Check `npm view @jfrader/storybook-docs versions --json --registry=https://registry.npmjs.org`.
|
|
38
|
+
An `E404` can mean the public package does not exist yet. If `0.2.1` already
|
|
39
|
+
exists, do not retry that version: npm versions are immutable.
|
|
40
|
+
2. Run the checks above. Pack the release outside the checkout:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
release_dir=$(mktemp -d /tmp/opencode/storybook-docs-release-XXXXXX)
|
|
44
|
+
pnpm pack --pack-destination "$release_dir"
|
|
45
|
+
tar -tzf "$release_dir"/*.tgz
|
|
46
|
+
npm login --registry=https://registry.npmjs.org
|
|
47
|
+
npm whoami --registry=https://registry.npmjs.org
|
|
48
|
+
npm publish "$release_dir"/*.tgz --access public --registry=https://registry.npmjs.org
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`whoami` must be the owner (`jfrader`) or an authorized package maintainer.
|
|
52
|
+
Complete npm's interactive 2FA challenge. `EOTP` means authorization requires
|
|
53
|
+
a fresh second factor; it is not a build failure. Retry interactively with a
|
|
54
|
+
fresh code/challenge, never disable 2FA or commit an OTP/token. If needed, npm's
|
|
55
|
+
`--otp` option accepts a fresh code, but keep it out of shared shell history.
|
|
56
|
+
Do not request `--provenance` from a local shell: local publishing has no
|
|
57
|
+
supported CI OIDC identity. This initial version will lack CI provenance.
|
|
58
|
+
3. Verify `npm view @jfrader/storybook-docs@0.2.1 version dist.integrity --registry=https://registry.npmjs.org`.
|
|
59
|
+
Delete the temporary release directory when finished.
|
|
60
|
+
4. Do not push a `v0.2.1` tag after publishing it manually: the tag workflow would
|
|
61
|
+
try to publish the same immutable version again. Configure trust before the next
|
|
62
|
+
release; its new version/tag is the first automated publish.
|
|
63
|
+
|
|
64
|
+
## Later publishes: trusted publishing (recommended)
|
|
65
|
+
|
|
66
|
+
On npmjs.com, open the package's **Settings → Trusted publishing** and add GitHub
|
|
67
|
+
Actions with these exact, case-sensitive values:
|
|
68
|
+
|
|
69
|
+
| Field | Value |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| Organization or user | `jfrader` |
|
|
72
|
+
| Repository | `storybook-docs` |
|
|
73
|
+
| Workflow filename | `publish.yml` (not `.github/workflows/publish.yml`) |
|
|
74
|
+
| Environment name | Leave empty; this workflow has no environment |
|
|
75
|
+
| Allowed actions, if shown | Allow direct `npm publish` |
|
|
76
|
+
|
|
77
|
+
The workflow uses GitHub-hosted Ubuntu, Node 24, npm 11.18.0, `id-token: write`,
|
|
78
|
+
and `npm publish --provenance`. It needs no `NPM_TOKEN` or `NODE_AUTH_TOKEN`.
|
|
79
|
+
If npm shows a validation deadline for a new trust configuration, complete an
|
|
80
|
+
unpublished release within that deadline (currently two days), or recreate the
|
|
81
|
+
configuration. After validating trust, select **Require two-factor authentication
|
|
82
|
+
and disallow tokens** in the package's Publishing access settings. OIDC still works.
|
|
83
|
+
|
|
84
|
+
For each release:
|
|
85
|
+
|
|
86
|
+
1. Choose a new, unpublished version. Update `package.json` without creating a
|
|
87
|
+
tag (`npm version <version> --no-git-tag-version`), reconcile the pnpm lockfile
|
|
88
|
+
if needed, and run the checks above. Review and merge the version commit to
|
|
89
|
+
`master` through the repository's normal review process.
|
|
90
|
+
2. From the merged, clean `master` commit, create and push its matching tag:
|
|
91
|
+
`git tag v<version>` then `git push origin v<version>`.
|
|
92
|
+
3. Watch **Publish package** in GitHub Actions. The workflow rejects a tag/version
|
|
93
|
+
mismatch or a release commit not contained in `origin/master`, then checks,
|
|
94
|
+
packs and publishes. Confirm the registry version, integrity and provenance.
|
|
95
|
+
|
|
96
|
+
`workflow_dispatch` also publishes; it is not a dry run. Dispatch only an
|
|
97
|
+
unpublished version from a reviewed commit contained in `master`. Rerunning a
|
|
98
|
+
successful publish fails because that version already exists.
|
|
99
|
+
|
|
100
|
+
## Token publishing: explicit fallback, not the current configuration
|
|
101
|
+
|
|
102
|
+
The committed workflow uses OIDC only. A token secret alone will not make it use
|
|
103
|
+
token authentication. If trusted publishing cannot be used, a maintainer must
|
|
104
|
+
explicitly change the publish step to supply `NODE_AUTH_TOKEN` from a repository
|
|
105
|
+
secret. Use a short-lived granular token restricted to this package with publish
|
|
106
|
+
permission and **Bypass 2FA** enabled; ordinary tokens trigger `EOTP` in CI. The
|
|
107
|
+
package's publishing access must permit such tokens. Account/organization policy
|
|
108
|
+
may forbid this fallback. Never put an interactive OTP into CI, never use a
|
|
109
|
+
read-only token for publishing, and remove/revoke the write token after moving
|
|
110
|
+
to OIDC. Keep `--provenance` and GitHub-hosted runners for the fallback too.
|
|
111
|
+
|
|
112
|
+
## Version hygiene
|
|
113
|
+
|
|
114
|
+
The current version is `0.2.1`. Packed dependencies installed by filename or URL
|
|
115
|
+
remain on that exact tarball until consumers update their manifest and lockfile;
|
|
116
|
+
a version bump does not update them automatically. Do not replace an existing
|
|
117
|
+
version, reuse a tag, or remove `.`/`./vite`. Treat configuration, virtual module,
|
|
118
|
+
CSS delivery, Node/peer minimum and declaration changes as compatibility changes.
|
|
119
|
+
Before `1.0`, document any breaking changes and use a minor version bump rather
|
|
120
|
+
than hiding them in a patch. Consumers must retain React 19, React DOM 19 and a
|
|
121
|
+
compatible Vite, and supply their own story sources and story dependencies: a
|
|
122
|
+
design system tarball containing only built components cannot supply source stories.
|
|
123
|
+
|
|
124
|
+
Official npm references (check them when changing authentication):
|
|
125
|
+
[trusted publishers](https://docs.npmjs.com/trusted-publishers/),
|
|
126
|
+
[provenance](https://docs.npmjs.com/generating-provenance-statements/),
|
|
127
|
+
[granular tokens](https://docs.npmjs.com/creating-and-viewing-access-tokens/).
|
|
128
|
+
|
|
129
|
+
## First publish of a new package name
|
|
130
|
+
|
|
131
|
+
Established procedure, after a morning spent rediscovering it:
|
|
132
|
+
|
|
133
|
+
1. **`npm trust` works before the package exists.** `npm trust github <pkg> --repo <owner>/<repo> --file publish.yml --allow-publish`
|
|
134
|
+
returns **201** even for a name that has never been published, as long as you are authenticated. Do this first; it is
|
|
135
|
+
what lets every later `v*` tag publish itself through OIDC with provenance, no tokens.
|
|
136
|
+
2. **Workflows that set `NODE_AUTH_TOKEN` cannot use trusted publishing.** An empty secret sends an
|
|
137
|
+
unauthenticated request and npm answers `404` on the `PUT`, which reads like a missing package. This workflow
|
|
138
|
+
therefore sets no token.
|
|
139
|
+
3. **The first publish has to happen once from a machine** — the registry has no artifact yet:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
cd <the package checkout>
|
|
143
|
+
npm login --registry https://registry.npmjs.org # prints a browser URL; no OTP code needed
|
|
144
|
+
NPM_CONFIG_USERCONFIG=<config> npm publish # browser URL again, then "+ <pkg>@<version>"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
A `~/.npmrc` that maps the scope to another registry (e.g. `@scope:registry=https://npm.pkg.github.com/`) makes a
|
|
148
|
+
plain `npm publish` target that registry instead and fail with `403`. Point the scope at npmjs in the config used
|
|
149
|
+
for the publish.
|
|
150
|
+
4. **Verify from the registry, not from the local output:** `curl -s https://registry.npmjs.org/<scope>%2f<pkg>`
|
|
151
|
+
must list the version. Until it does, nothing is published.
|
|
152
|
+
5. After that, releases are tags: `git tag -a vX.Y.Z && git push origin vX.Y.Z`, and the publish workflow does the
|
|
153
|
+
rest. Do **not** push a tag for a version you already published by hand — npm rejects the duplicate.
|
package/package.json
CHANGED
|
@@ -1,6 +1,78 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jfrader/storybook-docs",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
3
|
+
"version": "0.4.4",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "A documentation front for any design system that has Storybook: navigation, live examples and API tables are generated from the story files themselves.",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"./vite": {
|
|
12
|
+
"types": "./dist/vite-plugin.d.ts",
|
|
13
|
+
"import": "./dist/vite-plugin.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"peerDependencies": {
|
|
17
|
+
"react": "^19.0.0",
|
|
18
|
+
"react-dom": "^19.0.0",
|
|
19
|
+
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "^22.20.5",
|
|
23
|
+
"@types/react": "^19.3.0",
|
|
24
|
+
"@types/react-dom": "^19.3.0",
|
|
25
|
+
"esbuild": "^0.28.2",
|
|
26
|
+
"react": "^19.3.0",
|
|
27
|
+
"react-dom": "^19.3.0",
|
|
28
|
+
"vite": "^8.3.4"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"marked": "^18.1.1",
|
|
32
|
+
"react-docgen-typescript": "^2.4.0",
|
|
33
|
+
"typescript": "^5.9.3"
|
|
34
|
+
},
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/jfrader/storybook-docs.git"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/jfrader/storybook-docs",
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/jfrader/storybook-docs/issues"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public",
|
|
46
|
+
"registry": "https://registry.npmjs.org"
|
|
47
|
+
},
|
|
48
|
+
"keywords": [
|
|
49
|
+
"storybook",
|
|
50
|
+
"react",
|
|
51
|
+
"vite",
|
|
52
|
+
"design-system",
|
|
53
|
+
"documentation",
|
|
54
|
+
"props",
|
|
55
|
+
"docs"
|
|
56
|
+
],
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=22.12.0"
|
|
59
|
+
},
|
|
60
|
+
"files": [
|
|
61
|
+
"dist",
|
|
62
|
+
"docs/CONFIG.md",
|
|
63
|
+
"docs/RELEASING.md",
|
|
64
|
+
"LICENSE",
|
|
65
|
+
"README.md"
|
|
66
|
+
],
|
|
67
|
+
"sideEffects": [
|
|
68
|
+
"**/*.css"
|
|
69
|
+
],
|
|
70
|
+
"scripts": {
|
|
71
|
+
"test": "node --test test/*.test.ts",
|
|
72
|
+
"typecheck": "tsc --noEmit",
|
|
73
|
+
"build": "pnpm build:package && pnpm --dir examples/jfrader-ui build",
|
|
74
|
+
"build:package": "node scripts/build.mjs",
|
|
75
|
+
"smoke:package": "node scripts/smoke-package.mjs",
|
|
76
|
+
"check:frames": "node scripts/check-example-frames.mjs"
|
|
77
|
+
}
|
|
6
78
|
}
|