handoff-app 2.0.0-6 → 2.0.0-7
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 +129 -41
- package/UPGRADE.md +198 -0
- package/config/config.template.js +1 -4
- package/config/config.template.ts +1 -2
- package/dist/app-builder/build.js +2 -4
- package/dist/app-builder/config-diff/strategies/pattern.js +3 -3
- package/dist/app-builder/watchers/component.js +5 -5
- package/dist/app-builder/watchers/utils.d.ts +2 -3
- package/dist/app-builder/watchers.d.ts +8 -15
- package/dist/app-builder/watchers.js +53 -54
- package/dist/cache/build-cache.js +18 -22
- package/dist/catalog/define.d.ts +6 -0
- package/dist/catalog/define.js +72 -0
- package/dist/catalog/implementation.d.ts +27 -0
- package/dist/catalog/implementation.js +133 -0
- package/dist/catalog/index.d.ts +6 -0
- package/dist/catalog/index.js +22 -0
- package/dist/catalog/normalize.d.ts +16 -0
- package/dist/catalog/normalize.js +115 -0
- package/dist/catalog/previews.d.ts +18 -0
- package/dist/catalog/previews.js +106 -0
- package/dist/catalog/renderers.d.ts +43 -0
- package/dist/catalog/renderers.js +62 -0
- package/dist/catalog/types.d.ts +63 -0
- package/dist/cli/make.d.ts +0 -5
- package/dist/cli/make.js +22 -67
- package/dist/cli/scaffold.js +25 -33
- package/dist/commands/checkout/index.d.ts +7 -4
- package/dist/commands/checkout/index.js +9 -6
- package/dist/commands/compat/push-args.d.ts +2 -2
- package/dist/commands/index.js +0 -2
- package/dist/commands/publish/index.d.ts +9 -6
- package/dist/commands/publish/index.js +11 -8
- package/dist/commands/pull/index.js +1 -1
- package/dist/commands/push/index.js +1 -1
- package/dist/commands/utils.d.ts +15 -4
- package/dist/commands/utils.js +19 -6
- package/dist/config/catalog-include.d.ts +43 -0
- package/dist/config/catalog-include.js +203 -0
- package/dist/config/index.d.ts +2 -2
- package/dist/config/index.js +5 -5
- package/dist/config/loader.js +9 -1
- package/dist/config/runtime.d.ts +5 -6
- package/dist/config/runtime.js +154 -154
- package/dist/handlebars.d.ts +9 -0
- package/dist/handlebars.js +16 -0
- package/dist/index.d.ts +15 -4
- package/dist/index.js +29 -15
- package/dist/pattern.d.ts +7 -0
- package/dist/pattern.js +13 -0
- package/dist/react.d.ts +43 -0
- package/dist/react.js +11 -0
- package/dist/registry/asset-storage/define.d.ts +1 -1
- package/dist/registry/asset-storage/define.js +1 -1
- package/dist/registry/checkout/index.d.ts +9 -0
- package/dist/registry/checkout/index.js +335 -149
- package/dist/registry/db/schema.d.ts +34 -0
- package/dist/registry/db/schema.js +2 -0
- package/dist/registry/publish/index.d.ts +13 -2
- package/dist/registry/publish/index.js +109 -25
- package/dist/registry/publish/package.js +14 -1
- package/dist/registry/selection.d.ts +20 -0
- package/dist/registry/selection.js +37 -1
- package/dist/store/filesystem.d.ts +1 -1
- package/dist/store/filesystem.js +7 -7
- package/dist/store/registry.js +24 -3
- package/dist/transformers/plugins/csf-render.js +4 -2
- package/dist/transformers/plugins/ssr-render.js +14 -5
- package/dist/transformers/preview/component/api.d.ts +8 -0
- package/dist/transformers/preview/component/api.js +11 -15
- package/dist/transformers/preview/component/artifacts.d.ts +1 -1
- package/dist/transformers/preview/component/artifacts.js +11 -7
- package/dist/transformers/preview/component/builder.js +15 -18
- package/dist/transformers/preview/component/css.d.ts +2 -0
- package/dist/transformers/preview/component/css.js +8 -11
- package/dist/transformers/preview/component/html.js +18 -16
- package/dist/transformers/preview/component/javascript.js +2 -4
- package/dist/transformers/preview/pattern/builder.js +31 -18
- package/dist/transformers/preview/types.d.ts +15 -1
- package/dist/types/config.d.ts +29 -11
- package/docs/api.md +3 -0
- package/docs/cli.md +1 -1
- package/drizzle/0006_add_component_source_format.sql +3 -0
- package/drizzle/meta/0006_snapshot.json +1941 -0
- package/drizzle/meta/_journal.json +8 -1
- package/package.json +34 -1
- package/src/app/components/Component/Preview.tsx +36 -50
- package/src/app/components/Markdown/CodeHighlight.tsx +73 -70
- package/src/app/components/context/PreviewContext.tsx +5 -5
- package/src/app/components/util/index.ts +7 -15
- package/src/app/lib/mcp/shape.ts +6 -5
- package/src/app/lib/registry-api/transfer.ts +7 -5
- package/src/app-builder/build.ts +3 -6
- package/src/app-builder/config-diff/strategies/pattern.ts +1 -1
- package/src/app-builder/watchers/component.ts +3 -3
- package/src/app-builder/watchers/utils.ts +2 -3
- package/src/app-builder/watchers.ts +46 -50
- package/src/cache/build-cache.ts +11 -14
- package/src/catalog/README.md +92 -0
- package/src/catalog/define.ts +79 -0
- package/src/catalog/implementation.ts +145 -0
- package/src/catalog/index.ts +31 -0
- package/src/catalog/normalize.ts +143 -0
- package/src/catalog/previews.ts +111 -0
- package/src/catalog/renderers.ts +94 -0
- package/src/catalog/types.ts +74 -0
- package/src/cli/README.md +1 -1
- package/src/cli/make.ts +20 -72
- package/src/cli/scaffold.ts +25 -31
- package/src/commands/README.md +1 -1
- package/src/commands/checkout/index.ts +17 -7
- package/src/commands/compat/push-args.ts +2 -2
- package/src/commands/index.ts +0 -2
- package/src/commands/publish/index.ts +19 -9
- package/src/commands/pull/index.ts +2 -2
- package/src/commands/push/index.ts +2 -2
- package/src/commands/utils.ts +22 -7
- package/src/config/README.md +2 -1
- package/src/config/catalog-include.ts +227 -0
- package/src/config/index.ts +3 -3
- package/src/config/loader.ts +12 -0
- package/src/config/runtime.ts +186 -191
- package/src/handlebars.ts +18 -0
- package/src/index.ts +39 -26
- package/src/pattern.ts +14 -0
- package/src/react.ts +52 -0
- package/src/registry/asset-storage/define.ts +1 -1
- package/src/registry/checkout/index.ts +416 -152
- package/src/registry/db/schema.ts +2 -0
- package/src/registry/publish/index.ts +123 -26
- package/src/registry/publish/package.ts +14 -1
- package/src/registry/selection.ts +44 -0
- package/src/store/filesystem.ts +4 -4
- package/src/store/registry.ts +13 -2
- package/src/transformers/plugins/csf-render.ts +4 -2
- package/src/transformers/plugins/ssr-render.ts +15 -5
- package/src/transformers/preview/component/api.ts +13 -1
- package/src/transformers/preview/component/artifacts.ts +8 -4
- package/src/transformers/preview/component/builder.ts +17 -4
- package/src/transformers/preview/component/css.ts +6 -10
- package/src/transformers/preview/component/html.ts +30 -19
- package/src/transformers/preview/component/javascript.ts +1 -3
- package/src/transformers/preview/pattern/builder.ts +33 -20
- package/src/transformers/preview/types.ts +15 -1
- package/src/types/config.ts +31 -11
- package/templates/default/components/button/button.react.handoff.js.tpl +19 -23
- package/templates/default/components/button/button.react.handoff.ts.tpl +22 -22
- package/templates/default/handoff.config.js.tpl +5 -15
- package/templates/default/handoff.config.ts.tpl +5 -15
- package/templates/default/handoff.config.with-examples.js.tpl +6 -13
- package/templates/default/handoff.config.with-examples.ts.tpl +6 -13
- package/config/templates/component/template.json +0 -49
- package/config/templates/template.html +0 -7
- package/dist/commands/make/template.d.ts +0 -8
- package/dist/commands/make/template.js +0 -43
- package/dist/config/entries.d.ts +0 -47
- package/dist/config/entries.js +0 -162
- package/dist/config/normalizers/declaration.d.ts +0 -11
- package/dist/config/normalizers/declaration.js +0 -122
- package/dist/config/normalizers/pattern.d.ts +0 -8
- package/dist/config/normalizers/pattern.js +0 -41
- package/dist/declarations/helpers.d.ts +0 -6
- package/dist/declarations/helpers.js +0 -19
- package/dist/declarations/index.d.ts +0 -2
- package/dist/declarations/index.js +0 -9
- package/dist/declarations/types.d.ts +0 -60
- package/src/commands/make/template.ts +0 -46
- package/src/config/entries.ts +0 -175
- package/src/config/normalizers/declaration.ts +0 -179
- package/src/config/normalizers/pattern.ts +0 -59
- package/src/declarations/helpers.ts +0 -36
- package/src/declarations/index.ts +0 -19
- package/src/declarations/types.ts +0 -70
- /package/dist/{declarations → catalog}/types.js +0 -0
package/README.md
CHANGED
|
@@ -66,11 +66,16 @@ my-handoff-project/
|
|
|
66
66
|
└─ out/ # build output; gitignored
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
##
|
|
69
|
+
## Catalog items
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
Every documented UI entry is a catalog item. Each item declares either an implementation or a composition of other items.
|
|
72
|
+
An implementation names its renderer. `defineCatalogItem` comes from the module for that renderer.
|
|
73
|
+
The declaration supplies stable identity, documentation metadata, source entries, and previews.
|
|
74
|
+
|
|
75
|
+
### React
|
|
76
|
+
|
|
77
|
+
Handoff finds the implementation file from its import, so you do not need to repeat the path.
|
|
78
|
+
Previews are named exports. `Preview<typeof item>` gives them the implementation's argument type.
|
|
74
79
|
|
|
75
80
|
```tsx
|
|
76
81
|
// components/example/Component.tsx
|
|
@@ -83,61 +88,136 @@ export default function Component({ label }: ComponentProps) {
|
|
|
83
88
|
}
|
|
84
89
|
```
|
|
85
90
|
|
|
86
|
-
```
|
|
87
|
-
// components/example/
|
|
88
|
-
import {
|
|
91
|
+
```tsx
|
|
92
|
+
// components/example/example.handoff.ts
|
|
93
|
+
import { defineCatalogItem, type Preview } from 'handoff-app/react';
|
|
89
94
|
import Component from './Component';
|
|
90
95
|
|
|
91
|
-
|
|
96
|
+
const item = defineCatalogItem({
|
|
92
97
|
id: 'component-id',
|
|
93
98
|
name: 'Component name',
|
|
94
99
|
description: 'Usage guidance for the component.',
|
|
95
100
|
group: 'Group name',
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
},
|
|
101
|
+
implementation: Component,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
export default item;
|
|
105
|
+
|
|
106
|
+
type ComponentPreview = Preview<typeof item>;
|
|
107
|
+
|
|
108
|
+
export const Default = {
|
|
109
|
+
args: { label: 'Example' },
|
|
110
|
+
} satisfies ComponentPreview;
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The export name is the preview name. Use `name` to set a different display title.
|
|
114
|
+
|
|
115
|
+
### Handlebars
|
|
116
|
+
|
|
117
|
+
The implementation is the path to the template. Arguments are `Record<string, unknown>` by default;
|
|
118
|
+
an explicit argument type is supplied through `defineCatalogItem<BadgeArgs>`.
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
// components/badge/badge.handoff.ts
|
|
122
|
+
import { defineCatalogItem, type Preview } from 'handoff-app/handlebars';
|
|
123
|
+
|
|
124
|
+
const item = defineCatalogItem({
|
|
125
|
+
id: 'badge',
|
|
126
|
+
name: 'Badge',
|
|
127
|
+
implementation: './Badge.hbs',
|
|
105
128
|
});
|
|
129
|
+
|
|
130
|
+
export default item;
|
|
131
|
+
|
|
132
|
+
type BadgePreview = Preview<typeof item>;
|
|
133
|
+
|
|
134
|
+
export const Primary = {
|
|
135
|
+
args: { variant: 'primary', children: 'New' },
|
|
136
|
+
} satisfies BadgePreview;
|
|
106
137
|
```
|
|
107
138
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
139
|
+
### CSF
|
|
140
|
+
|
|
141
|
+
CSF is a source format. A story file uses the renderer from the module that declares it. A React item references an existing CSF file with `fromCSF`.
|
|
142
|
+
The CSF file stays unchanged and defines its previews through named exports. Each story's `args` merge with and override `meta.args`.
|
|
143
|
+
Handoff preserves story names, `argTypes`, and `render` functions.
|
|
144
|
+
It finds the React component through `meta.component`, then documents and publishes it with the story file.
|
|
111
145
|
|
|
112
146
|
```ts
|
|
113
|
-
//
|
|
114
|
-
import {
|
|
147
|
+
// components/card/card.handoff.ts
|
|
148
|
+
import { defineCatalogItem, fromCSF } from 'handoff-app/react';
|
|
115
149
|
|
|
116
|
-
export default
|
|
150
|
+
export default defineCatalogItem({
|
|
151
|
+
id: 'card',
|
|
152
|
+
name: 'Card',
|
|
153
|
+
implementation: fromCSF('./Card.stories.tsx'),
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`Meta` and `StoryObj` are exported from `handoff-app/react`, so a story file type-checks without a
|
|
158
|
+
Storybook dependency. A project that already has Storybook keeps using its own types.
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
// components/card/Card.stories.tsx
|
|
162
|
+
import { type Meta, type StoryObj } from 'handoff-app/react';
|
|
163
|
+
import Card from './Card';
|
|
164
|
+
|
|
165
|
+
const meta = { component: Card } satisfies Meta<typeof Card>;
|
|
166
|
+
export default meta;
|
|
167
|
+
|
|
168
|
+
export const Primary: StoryObj<typeof meta> = {
|
|
169
|
+
args: { title: 'Example' },
|
|
170
|
+
};
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
A CSF preview is rendered on the server and is not hydrated. A direct React implementation is
|
|
174
|
+
hydrated in the browser.
|
|
175
|
+
|
|
176
|
+
### Compositions
|
|
177
|
+
|
|
178
|
+
A composition references other items by stable id. A named preview can be selected and its arguments
|
|
179
|
+
can be overridden by each reference. A composition needs no renderer, so it is declared with
|
|
180
|
+
`defineCatalogItem` from `handoff-app/pattern`.
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
// patterns/example/example.handoff.ts
|
|
184
|
+
import { defineCatalogItem } from 'handoff-app/pattern';
|
|
185
|
+
|
|
186
|
+
export default defineCatalogItem({
|
|
117
187
|
id: 'pattern-id',
|
|
118
188
|
name: 'Pattern name',
|
|
119
189
|
description: 'Purpose and usage of the composition.',
|
|
120
190
|
group: 'Group name',
|
|
121
|
-
|
|
122
|
-
{
|
|
123
|
-
|
|
124
|
-
preview: 'default',
|
|
125
|
-
args: { label: 'Pattern example' },
|
|
126
|
-
},
|
|
191
|
+
composition: [
|
|
192
|
+
{ ref: 'component-id', preview: 'Default' },
|
|
193
|
+
{ ref: 'badge', args: { children: 'Send' } },
|
|
127
194
|
],
|
|
128
195
|
});
|
|
129
196
|
```
|
|
130
197
|
|
|
131
|
-
|
|
198
|
+
An item declares `implementation` or `composition`, never both. Terms such as atom, element, and
|
|
199
|
+
block stay optional classification metadata on `type` and `categories`.
|
|
200
|
+
|
|
201
|
+
The `id` addresses the item everywhere: its artifacts, its documentation URL, and its publish and
|
|
202
|
+
checkout commands. Components and patterns share one namespace, so each id must be unique across
|
|
203
|
+
both.
|
|
204
|
+
|
|
205
|
+
If two declarations claim one id, Handoff keeps the first and skips the second. The warning names
|
|
206
|
+
both files. `publish` refuses to run until each id is unique.
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
### Registration
|
|
210
|
+
|
|
211
|
+
Catalog directories are registered in one place. A path is either an item directory or a collection
|
|
212
|
+
directory whose subdirectories are each treated as an item.
|
|
132
213
|
|
|
133
214
|
```ts
|
|
134
215
|
// handoff.config.ts
|
|
135
216
|
import { defineConfig } from 'handoff-app';
|
|
136
217
|
|
|
137
218
|
export default defineConfig({
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
patterns: ['patterns'],
|
|
219
|
+
catalog: {
|
|
220
|
+
include: ['components', 'patterns'],
|
|
141
221
|
},
|
|
142
222
|
runtime: {
|
|
143
223
|
workspace: {
|
|
@@ -147,6 +227,11 @@ export default defineConfig({
|
|
|
147
227
|
});
|
|
148
228
|
```
|
|
149
229
|
|
|
230
|
+
### Upgrade from version 1.x.x to version 2.x.x
|
|
231
|
+
|
|
232
|
+
See the [version 1.x.x to version 2.x.x migration guide](UPGRADE.md#version-1xx-to-version-2xx)
|
|
233
|
+
for breaking changes, migration steps, and upgrade verification.
|
|
234
|
+
|
|
150
235
|
Custom documentation pages are Markdown files under `pages/`. Their relative
|
|
151
236
|
paths become their routes and registry IDs.
|
|
152
237
|
|
|
@@ -340,20 +425,23 @@ npm run publish -- all
|
|
|
340
425
|
A single kind is published on its own:
|
|
341
426
|
|
|
342
427
|
```bash
|
|
343
|
-
npm run publish --
|
|
344
|
-
npm run publish -- patterns
|
|
428
|
+
npm run publish -- catalog
|
|
345
429
|
npm run publish -- pages
|
|
346
430
|
npm run publish -- tokens
|
|
347
431
|
npm run publish -- assets
|
|
348
432
|
```
|
|
349
433
|
|
|
434
|
+
`catalog` covers every catalog item. An item is stored as a component or as a
|
|
435
|
+
pattern, and its declaration decides which. The command names items and never a
|
|
436
|
+
kind.
|
|
437
|
+
|
|
350
438
|
Publishing tokens or assets runs the Figma data pipeline before upload, so the
|
|
351
439
|
documented Figma credentials must be available.
|
|
352
440
|
|
|
353
441
|
One or more IDs can be appended to narrow a publish to those entities:
|
|
354
442
|
|
|
355
443
|
```bash
|
|
356
|
-
npm run publish --
|
|
444
|
+
npm run publish -- catalog item-id another-id
|
|
357
445
|
```
|
|
358
446
|
|
|
359
447
|
`--dry-run` reports what would be uploaded and contacts no registry at all, so
|
|
@@ -363,16 +451,16 @@ the existing output, and the two combine to leave the workspace untouched:
|
|
|
363
451
|
|
|
364
452
|
```bash
|
|
365
453
|
npm run publish -- all --dry-run
|
|
366
|
-
npm run publish --
|
|
454
|
+
npm run publish -- catalog --no-build
|
|
367
455
|
```
|
|
368
456
|
|
|
369
457
|
`checkout` takes the same `all`, multi-ID, and `--dry-run` forms. A dry-run
|
|
370
458
|
checkout reads from the registry, lists the files it would create or overwrite,
|
|
371
459
|
and writes nothing.
|
|
372
460
|
|
|
373
|
-
After the registry is reloaded, the published
|
|
374
|
-
|
|
375
|
-
|
|
461
|
+
After the registry is reloaded, the published catalog items and foundations are
|
|
462
|
+
visible. Published database records are read by registry pages; the local
|
|
463
|
+
workspace is never read directly.
|
|
376
464
|
|
|
377
465
|
For CI, a registry connection and user-issued token are configured:
|
|
378
466
|
|
|
@@ -473,7 +561,7 @@ both.
|
|
|
473
561
|
| `npm run build -- [--target static\|registry]` | The static site or standalone registry bundle is built |
|
|
474
562
|
| `npm run db:migrate` | Registry database migrations are applied |
|
|
475
563
|
| `npm run validate` | Configured components are validated |
|
|
476
|
-
| `npm run publish -- <kind\|all> [id...]` |
|
|
564
|
+
| `npm run publish -- <kind\|all> [id...]` | Catalog items, pages, tokens, or assets are published |
|
|
477
565
|
| `npm run checkout -- <kind\|all> [id...]` | Published content is pulled into a workspace |
|
|
478
566
|
| `npm run login -- --url <url>` | The CLI is authorized through the registry device flow |
|
|
479
567
|
| `npm run logout -- [--url <url>]` | A saved CLI credential is revoked and removed |
|
package/UPGRADE.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Upgrade Handoff
|
|
2
|
+
|
|
3
|
+
This document contains migration steps for each major version upgrade.
|
|
4
|
+
|
|
5
|
+
## Version 1.x.x to version 2.x.x
|
|
6
|
+
|
|
7
|
+
This guide describes how to upgrade a Handoff project from version 1.x.x to version 2.x.x.
|
|
8
|
+
Each feature section identifies the affected projects and the required changes.
|
|
9
|
+
|
|
10
|
+
### Before you start
|
|
11
|
+
|
|
12
|
+
1. Verify that the project builds with its current Handoff version.
|
|
13
|
+
2. Save the project files, package version, and lockfile in version control.
|
|
14
|
+
3. Install the version 2.x.x package that you plan to use.
|
|
15
|
+
4. Apply the migration sections that affect your project.
|
|
16
|
+
|
|
17
|
+
### Breaking changes
|
|
18
|
+
|
|
19
|
+
| Change | Affected projects |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| [Catalog items](#catalog-items) | Projects with component or pattern declarations |
|
|
22
|
+
|
|
23
|
+
<!-- Add future breaking changes as feature sections before "Verify the upgrade". Add each section to this table. -->
|
|
24
|
+
|
|
25
|
+
### Catalog items
|
|
26
|
+
|
|
27
|
+
#### Affected projects
|
|
28
|
+
|
|
29
|
+
This change affects projects that use the old component or pattern registration API.
|
|
30
|
+
It also affects projects that use the deprecated API from an earlier version 2.x.x prerelease.
|
|
31
|
+
Version 2.x.x requires `defineCatalogItem` for implementations and compositions.
|
|
32
|
+
|
|
33
|
+
#### Register catalog directories
|
|
34
|
+
|
|
35
|
+
Move component and pattern directories from `entries` to `catalog.include`.
|
|
36
|
+
|
|
37
|
+
Version 1.x.x:
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
entries: { components: ['components'], patterns: ['patterns'], scss: 'styles/main.scss' }
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Version 2.x.x:
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
catalog: { include: ['components', 'patterns'] },
|
|
47
|
+
entries: { scss: 'styles/main.scss' }
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Each path can name one item directory or a collection of item directories. Global `entries.js` and `entries.scss` still work.
|
|
51
|
+
|
|
52
|
+
#### Convert declaration files
|
|
53
|
+
|
|
54
|
+
Use `<name>.handoff.ts`, `<name>.handoff.js`, or `<name>.handoff.cjs`.
|
|
55
|
+
Replace legacy filenames such as `button.json` or `button.js`.
|
|
56
|
+
|
|
57
|
+
Version 2.x.x does not support JSON item declarations, including `.handoff.json`.
|
|
58
|
+
JSON project config (`handoff.config.json`) remains supported.
|
|
59
|
+
|
|
60
|
+
If `runtime.workspace.declarationFormat` is `json`, change it to `ts`, `js`, or `cjs`. The default remains `ts`.
|
|
61
|
+
|
|
62
|
+
#### Replace declaration helpers
|
|
63
|
+
|
|
64
|
+
| Removed API | Replacement |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| `defineReactComponent(Component, config)` | `defineCatalogItem({ ...config, implementation: Component })` from `handoff-app/react` |
|
|
67
|
+
| `defineHandlebarsComponent(config)` | `defineCatalogItem({ ...config, implementation: './Button.hbs' })` from `handoff-app/handlebars` |
|
|
68
|
+
| `defineCsfComponent(config)` | `defineCatalogItem({ ...config, implementation: fromCSF('./Button.stories.tsx') })` from `handoff-app/react` |
|
|
69
|
+
| `defineComponent(config)` | `defineCatalogItem({ ...config, implementation: './Button.tsx' })` from the module for its renderer |
|
|
70
|
+
| `definePattern({ components })` | `defineCatalogItem({ composition })` from `handoff-app/pattern` |
|
|
71
|
+
|
|
72
|
+
Remove the old `renderer`, `entries.component`, `entries.template`, and `entries.story` fields.
|
|
73
|
+
The implementation supplies the renderer and source file.
|
|
74
|
+
Keep the supporting `entries.js`, `entries.scss`, `entries.schema`, and `entries.templates` paths that your item uses.
|
|
75
|
+
Rename the metadata fields:
|
|
76
|
+
|
|
77
|
+
| Old field | Version 2.x.x field |
|
|
78
|
+
| --- | --- |
|
|
79
|
+
| `title` | `name` |
|
|
80
|
+
| `should_do` | `shouldDo` |
|
|
81
|
+
| `should_not_do` | `shouldNotDo` |
|
|
82
|
+
|
|
83
|
+
##### React
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
import { defineCatalogItem, type Preview } from 'handoff-app/react';
|
|
87
|
+
import Button from './Button';
|
|
88
|
+
|
|
89
|
+
const item = defineCatalogItem({
|
|
90
|
+
name: 'Button',
|
|
91
|
+
implementation: Button,
|
|
92
|
+
entries: { scss: './button.scss' },
|
|
93
|
+
});
|
|
94
|
+
export default item;
|
|
95
|
+
export const Primary = { args: { children: 'Save' } } satisfies Preview<typeof item>;
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Imported components retain their prop types. A file path also works: `implementation: './Button.tsx'`.
|
|
99
|
+
Keep implementation files inside the item directory to publish them.
|
|
100
|
+
|
|
101
|
+
##### Handlebars and CommonJS
|
|
102
|
+
|
|
103
|
+
```js
|
|
104
|
+
const { defineCatalogItem } = require('handoff-app/handlebars');
|
|
105
|
+
|
|
106
|
+
exports.default = defineCatalogItem({
|
|
107
|
+
name: 'Badge',
|
|
108
|
+
implementation: './Badge.hbs',
|
|
109
|
+
});
|
|
110
|
+
exports.Primary = { args: { children: 'New' } };
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Use this form in `.handoff.js` or `.handoff.cjs`. JavaScript declarations can also use `import` and `export`.
|
|
114
|
+
|
|
115
|
+
##### CSF
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import { defineCatalogItem, fromCSF } from 'handoff-app/react';
|
|
119
|
+
|
|
120
|
+
export default defineCatalogItem({
|
|
121
|
+
name: 'Button',
|
|
122
|
+
implementation: fromCSF('./Button.stories.tsx'),
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
CSF is a React source format. The story file supplies the previews.
|
|
127
|
+
The filename does not select CSF automatically.
|
|
128
|
+
|
|
129
|
+
##### Compositions
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import { defineCatalogItem } from 'handoff-app/pattern';
|
|
133
|
+
|
|
134
|
+
export default defineCatalogItem({
|
|
135
|
+
name: 'Toolbar',
|
|
136
|
+
composition: [{ ref: 'button', preview: 'Primary', args: { children: 'Save' } }],
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Rename `components` to `composition`.
|
|
141
|
+
Rename each member's `id` to `ref`.
|
|
142
|
+
Keep item IDs stable.
|
|
143
|
+
|
|
144
|
+
#### Export previews
|
|
145
|
+
|
|
146
|
+
Remove the inline `previews` map.
|
|
147
|
+
Export each preview beside the default catalog item.
|
|
148
|
+
Rename preview `title` to `name`.
|
|
149
|
+
Rename `values` to `args`:
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
export const Primary = { name: 'Primary action', args: { children: 'Save' } };
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
If a preview key is a valid export name, preserve its spelling and capitalization.
|
|
156
|
+
If a key is not a valid export name, rename it.
|
|
157
|
+
Update composition references to each renamed preview.
|
|
158
|
+
|
|
159
|
+
Previews appear in source export order.
|
|
160
|
+
|
|
161
|
+
For CommonJS declarations, use `exports.default` for the item.
|
|
162
|
+
Use a named export such as `exports.Primary` for each preview.
|
|
163
|
+
|
|
164
|
+
#### Replace declaration types
|
|
165
|
+
|
|
166
|
+
Replace imports of the removed types:
|
|
167
|
+
|
|
168
|
+
| Removed type | Replacement |
|
|
169
|
+
| --- | --- |
|
|
170
|
+
| `Component` | `CatalogItem` |
|
|
171
|
+
| `DeclarationPreview` | `CatalogPreview` or `Preview<typeof item>` |
|
|
172
|
+
| `PatternComponentRef` | `CompositionRef` |
|
|
173
|
+
| `ReactDeclarationConfig`, `HandlebarsDeclarationConfig`, `CsfDeclarationConfig` | The catalog helper's input type |
|
|
174
|
+
| `GenericDeclarationConfig`, `GenericPatternDeclarationConfig` | The catalog helper's input type, or `CatalogItemMeta` for shared metadata |
|
|
175
|
+
|
|
176
|
+
`RendererKind` comes from the catalog API and contains `react` and `handlebars`.
|
|
177
|
+
CSF uses `renderer: 'react'` with `format: 'csf'` inside `implementation`.
|
|
178
|
+
|
|
179
|
+
#### Registry projects
|
|
180
|
+
|
|
181
|
+
Checkout writes only catalog declarations.
|
|
182
|
+
Registry records require explicit renderer and source-format metadata where applicable.
|
|
183
|
+
|
|
184
|
+
### Verify the upgrade
|
|
185
|
+
|
|
186
|
+
After you apply the required migrations, verify the project:
|
|
187
|
+
|
|
188
|
+
1. Build the project with version 2.x.x.
|
|
189
|
+
2. Verify that all expected catalog items appear in the documentation.
|
|
190
|
+
3. Verify the preview order, arguments, and composition references.
|
|
191
|
+
4. Start the workspace with file watchers.
|
|
192
|
+
5. Edit a declaration to verify that its previews update.
|
|
193
|
+
|
|
194
|
+
If the project uses a registry, verify the published items:
|
|
195
|
+
|
|
196
|
+
1. Publish the migrated items.
|
|
197
|
+
2. Verify that checkout produces valid declarations.
|
|
198
|
+
3. Rebuild the checked-out items.
|
|
@@ -54,13 +54,10 @@ const config = {
|
|
|
54
54
|
ports: { app: 3000, websocket: 3001 },
|
|
55
55
|
},
|
|
56
56
|
// These are the entry points used to compile the target application
|
|
57
|
+
catalog: { include: ['./components'] },
|
|
57
58
|
entries: {
|
|
58
59
|
scss: './sass/main.scss',
|
|
59
60
|
js: './js/main.js',
|
|
60
|
-
components: ['./components'],
|
|
61
|
-
// Uncomment to enable pattern documentation pages.
|
|
62
|
-
// Patterns compose component previews into single-page views.
|
|
63
|
-
// patterns: ['./patterns'],
|
|
64
61
|
},
|
|
65
62
|
// These are the asset zip file download links
|
|
66
63
|
assetsZipLinks: {
|
|
@@ -34,11 +34,10 @@ export default defineConfig({
|
|
|
34
34
|
},
|
|
35
35
|
ports: { app: 3000, websocket: 3001 },
|
|
36
36
|
},
|
|
37
|
+
catalog: { include: ['./components'] },
|
|
37
38
|
entries: {
|
|
38
39
|
scss: './sass/main.scss',
|
|
39
40
|
js: './js/main.js',
|
|
40
|
-
components: ['./components'],
|
|
41
|
-
// patterns: ['./patterns'],
|
|
42
41
|
},
|
|
43
42
|
assetsZipLinks: {
|
|
44
43
|
icons: null,
|
|
@@ -695,14 +695,12 @@ const watchApp = (handoff) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
695
695
|
pendingHandlers: new Map(),
|
|
696
696
|
runtimeComponentsWatcher: null,
|
|
697
697
|
runtimeConfigurationWatcher: null,
|
|
698
|
-
|
|
699
|
-
patternDirectoriesWatcher: null,
|
|
698
|
+
catalogDirectoriesWatcher: null,
|
|
700
699
|
};
|
|
701
700
|
(0, watchers_1.watchPublicDirectory)(handoff, wss, state, chokidarConfig);
|
|
702
701
|
(0, watchers_1.watchRuntimeComponents)(handoff, state, (0, watchers_1.getRuntimeComponentsPathsToWatch)(handoff));
|
|
703
702
|
(0, watchers_1.watchRuntimeConfiguration)(handoff, state);
|
|
704
|
-
(0, watchers_1.
|
|
705
|
-
(0, watchers_1.watchPatternDirectories)(handoff, state, chokidarConfig);
|
|
703
|
+
(0, watchers_1.watchCatalogDirectories)(handoff, state, chokidarConfig);
|
|
706
704
|
(0, watchers_1.watchGlobalEntries)(handoff, state, chokidarConfig);
|
|
707
705
|
(0, watchers_1.watchPages)(handoff, chokidarConfig);
|
|
708
706
|
});
|
|
@@ -43,12 +43,12 @@ const snapshot_1 = require("../snapshot");
|
|
|
43
43
|
* components. Outer key is component id, inner key is synthetic preview key.
|
|
44
44
|
*/
|
|
45
45
|
const snapshotPatternSynthetics = (handoff, patternId) => {
|
|
46
|
-
var _a, _b, _c
|
|
47
|
-
const components = (
|
|
46
|
+
var _a, _b, _c;
|
|
47
|
+
const components = (_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.components) !== null && _b !== void 0 ? _b : {};
|
|
48
48
|
const prefix = `__pattern_${patternId}_`;
|
|
49
49
|
const result = new Map();
|
|
50
50
|
for (const [componentId, component] of Object.entries(components)) {
|
|
51
|
-
const previews = (
|
|
51
|
+
const previews = (_c = component.internalPatternPreviews) !== null && _c !== void 0 ? _c : {};
|
|
52
52
|
const entries = new Map();
|
|
53
53
|
for (const [key, preview] of Object.entries(previews)) {
|
|
54
54
|
if (key.startsWith(prefix)) {
|
|
@@ -23,11 +23,11 @@ const mapEntryTypeToSegment = (type) => {
|
|
|
23
23
|
};
|
|
24
24
|
exports.mapEntryTypeToSegment = mapEntryTypeToSegment;
|
|
25
25
|
const resolveComponentIdForChangedFile = (handoff, changedFilePath) => {
|
|
26
|
-
var _a, _b, _c
|
|
26
|
+
var _a, _b, _c;
|
|
27
27
|
const normalizedChangedPath = (0, path_2.normalizePathForCompare)(changedFilePath);
|
|
28
|
-
const runtimeComponents = (
|
|
28
|
+
const runtimeComponents = (_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.components) !== null && _b !== void 0 ? _b : {};
|
|
29
29
|
for (const [componentId, componentDef] of Object.entries(runtimeComponents)) {
|
|
30
|
-
const entries = (
|
|
30
|
+
const entries = (_c = componentDef.entries) !== null && _c !== void 0 ? _c : {};
|
|
31
31
|
for (const entryPath of Object.values(entries)) {
|
|
32
32
|
if (!entryPath)
|
|
33
33
|
continue;
|
|
@@ -49,8 +49,8 @@ exports.resolveComponentIdForChangedFile = resolveComponentIdForChangedFile;
|
|
|
49
49
|
const getRuntimeComponentsPathsToWatch = (handoff) => {
|
|
50
50
|
var _a, _b, _c;
|
|
51
51
|
const result = new Map();
|
|
52
|
-
for (const runtimeComponentId of Object.keys((_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.
|
|
53
|
-
const runtimeComponent = handoff.runtimeConfig.
|
|
52
|
+
for (const runtimeComponentId of Object.keys((_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.components) !== null && _b !== void 0 ? _b : {})) {
|
|
53
|
+
const runtimeComponent = handoff.runtimeConfig.entities.components[runtimeComponentId];
|
|
54
54
|
for (const [runtimeComponentEntryType, runtimeComponentEntryPath] of Object.entries((_c = runtimeComponent.entries) !== null && _c !== void 0 ? _c : {})) {
|
|
55
55
|
const normalizedComponentEntryPath = runtimeComponentEntryPath;
|
|
56
56
|
if (fs_extra_1.default.existsSync(normalizedComponentEntryPath)) {
|
|
@@ -4,9 +4,8 @@ export interface WatcherState {
|
|
|
4
4
|
pendingHandlers: Map<string, () => Promise<void>>;
|
|
5
5
|
runtimeComponentsWatcher: chokidar.FSWatcher | null;
|
|
6
6
|
runtimeConfigurationWatcher: chokidar.FSWatcher | null;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
patternDirectoriesWatcher: chokidar.FSWatcher | null;
|
|
7
|
+
/** Watches every registered catalog directory for newly created item subdirectories. */
|
|
8
|
+
catalogDirectoriesWatcher: chokidar.FSWatcher | null;
|
|
10
9
|
}
|
|
11
10
|
/**
|
|
12
11
|
* Schedules a handler for execution with mutual exclusion and per-source
|
|
@@ -36,19 +36,12 @@ export declare const watchRuntimeComponents: (handoff: Handoff, state: WatcherSt
|
|
|
36
36
|
*/
|
|
37
37
|
export declare const watchRuntimeConfiguration: (handoff: Handoff, state: WatcherState) => void;
|
|
38
38
|
/**
|
|
39
|
-
* Watches
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* reference it.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Watches the parent pattern directories from config.entries.patterns for new
|
|
48
|
-
* patterns being added. The rebuild sequence intentionally differs from
|
|
49
|
-
* watchComponentDirectories because the dependency arrow is reversed: a new
|
|
50
|
-
* pattern references existing components, so we rebuild only the preview
|
|
51
|
-
* segment of those components (to produce the __pattern_* HTML files that
|
|
52
|
-
* injectPatternPreviews registered) before composing the pattern itself.
|
|
39
|
+
* Watches `catalog.include` directories for a new item. A single watcher covers implementations
|
|
40
|
+
* and compositions; the declaration determines which pipeline builds the item.
|
|
41
|
+
*
|
|
42
|
+
* The rebuild differs by kind, and the dependency arrow is reversed between them. A new item with
|
|
43
|
+
* an implementation builds itself, then the compositions that reference it. A new composition
|
|
44
|
+
* rebuilds the preview segment of the items it references, so the synthetic `__pattern_*` HTML
|
|
45
|
+
* exists, and only then composes itself.
|
|
53
46
|
*/
|
|
54
|
-
export declare const
|
|
47
|
+
export declare const watchCatalogDirectories: (handoff: Handoff, state: WatcherState, chokidarConfig: chokidar.WatchOptions) => void;
|