@motion-proto/live-tokens 0.33.0 → 0.34.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/CHANGELOG.md ADDED
@@ -0,0 +1,1373 @@
1
+ # Changelog
2
+
3
+ ## 0.34.0 — Token-as-API contract guardrail; opt-in autoMigrate
4
+
5
+ ### Added
6
+
7
+ - **Token names are now a versioned API contract, with a guardrail.** Each
8
+ `tokens.css` migration declares `kind: 'additive' | 'breaking'`. A new
9
+ `check:token-contract` (wired into `prepublishOnly`, plus
10
+ `tokensCssMigrations/contract.test.ts`) verifies behaviorally that an additive
11
+ migration never removes or renames a token (catches a breaking change shipped
12
+ as backward-compatible), and gates breaking migrations on a major bump from
13
+ 1.0.0 (pre-1.0 it warns). See TOKENS.md and RELEASING.md.
14
+ - **`themeFileApi({ autoMigrate: true })`.** Opt-in: the dev server applies
15
+ pending **additive** token migrations to your `tokens.css` at startup and
16
+ writes the file (shown in git), so it stays current with the package without a
17
+ manual step. Breaking migrations are never auto-applied. Off by default, which
18
+ preserves the invariant that the plugin never writes `tokensCssPath` unless you
19
+ enable it.
20
+
21
+ ### Docs
22
+
23
+ - **`TOKENS.md`** gained a plain-language section on how token changes are
24
+ versioned (additive vs breaking, what an upgrade can and cannot change).
25
+
26
+ ## 0.33.1 — Ship the changelog in the package
27
+
28
+ ### Fixed
29
+
30
+ - **`CHANGELOG.md` now ships in the published package.** The `files` allowlist in
31
+ `package.json` omitted it, and npm only auto-includes `package.json` / `README` /
32
+ `LICENSE` on top of an allowlist, so every tarball through 0.33.0 shipped without a
33
+ changelog. Added it to `files`. Consumer tooling that diffs changelogs across versions
34
+ could not see one before this.
35
+
36
+ ## 0.33.0 — ImageLightbox maxZoom cap
37
+
38
+ ### Added
39
+
40
+ - **`ImageLightbox` `maxZoom` prop.** Caps how far the `extended` zoom controls can
41
+ magnify, as a multiple of the image's natural resolution: `maxZoom={1}` = 100% of the
42
+ source's real pixels (1 source px = 1 screen px), `maxZoom={2}` = 200%. The modal
43
+ always opens fitted to the viewport; this only bounds zoom-in. An image whose fitted
44
+ size already exceeds the cap can't be zoomed in (the control disables). Per image in a
45
+ gallery. Reads the natural pixel size from `width`/`height` or the loaded image; until
46
+ that's known the previous 5×-the-fit cap applies. The toolbar percent stays
47
+ fit-relative (fit = 100%).
48
+
49
+ ## 0.32.0 — Image grow-vs-mask zoom; canonical easing/color/type primitives
50
+
51
+ ### Added
52
+
53
+ - **`Image` `overflowScaling` prop.** When hover zoom is active, `overflowScaling`
54
+ decides what the scale grows. `true` (default) scales the content inside the fixed
55
+ frame, masked by overflow (the existing behavior). `false` scales the whole framed
56
+ image so it grows past its layout box. `undefined` inherits the editor's global
57
+ default. Set on its own (without `zoom`) it forces zoom on in the chosen mode. Backed
58
+ by a new `--image-grow-hover` token; at most one of `--image-zoom-hover` /
59
+ `--image-grow-hover` is ever active. The Image editor gains an "Overflow scaling (mask
60
+ zoom to frame)" checkbox alongside "Use zoom on hover".
61
+ - **Canonical Layer-1 primitives now ship in `tokens.css`** and are carried to vendored
62
+ copies by a paired migration (`2026-06-04-easing-color-and-typescale-additions`): the
63
+ full `--ease-*` easing scale (sine/quad/cubic/quart/quint/expo/circ/back plus
64
+ `linear()` elastic and bounce curves), the `--color-white` / `--color-black`
65
+ invariants, and `--font-size-7xl`. The migration is idempotent by presence (retuned
66
+ steps are kept; only absent ones are inserted) — run `npx live-tokens migrate` to
67
+ backfill a forked `tokens.css`. Fixes 0.31's Image zoom snapping with no ease when a
68
+ vendored `tokens.css` lacked `--ease-out-cubic`.
69
+ - **`--scale-*` tokens surfaced in the editor's Variables tab** (new "Scale" group).
70
+
71
+ ## 0.31.0 — Image Lightbox galleries; fixed overlays escape their ancestors
72
+
73
+ ### Added
74
+
75
+ - **`ImageLightbox` gallery mode.** Pass `images={[{ src, alt, width?, height? }]}`
76
+ (two or more) and the open modal gains left/right chevrons, an `i / n` counter
77
+ (bottom-right, mono), and `←`/`→` keyboard navigation. A single-entry array (or a
78
+ lone `src`) behaves exactly as before — no chevrons, no counter. Navigation runs a
79
+ directional slide+scale+crossfade: the incoming image enters from the side of the
80
+ pressed chevron (right/next → from the right), shifting 32px as it scales from 0.95 and
81
+ fades in (250ms, ease-out, 125ms stagger); the outgoing image leaves the opposite way
82
+ (250ms, ease-in). Differing aspect ratios resize the stage underneath the crossfade.
83
+ - **`ImageLightbox` self-measures.** `width`/`height` are now optional. The aspect ratio
84
+ is read from the loaded `<img>` (`naturalWidth`/`naturalHeight`); explicit dimensions,
85
+ when given, still win and avoid the pre-load reflow. Consumers without dimension
86
+ metadata no longer need glue. The inline thumbnail measures the cover image
87
+ independently of the open modal (aspect ratios are tracked per image), so paging a
88
+ gallery never resizes the thumbnail. A dimensionless image still has a brief pre-load
89
+ reflow; pass `width`/`height` to reserve its box.
90
+ - **`ImageLightbox` `fit` prop.** `fit="cover"` crops the closed thumbnail to fill its
91
+ box (the expanded modal always uses `contain`, so the whole image stays visible).
92
+ Backed by a new `--imagelightbox-tile-object-fit` token (default `contain`). `cover`
93
+ only crops when the thumbnail has its own box (an aspect from `width`/`height`, or a
94
+ CSS-constrained container).
95
+ - **Shared `portal` action** (`src/system/internal/portal.ts`) and a
96
+ **`check:overlay-portal`** publish gate. Any component whose `<style>` declares
97
+ `position: fixed` must portal that layer via `use:portal`, or the build fails. Anchored
98
+ `position: absolute` popovers (`Tooltip`) are exempt.
99
+
100
+ ### Fixed
101
+
102
+ - **Fixed-position overlays no longer get clipped or painted under other content.** A
103
+ `position: fixed` modal is only window-relative while no ancestor establishes a
104
+ containing block or stacking context for it; a transformed / `isolation: isolate` /
105
+ `contain` / `will-change` ancestor (common on real pages, and present on the editor's
106
+ own preview pane) silently traps it. `ImageLightbox`'s modal and `Dialog`'s backdrop
107
+ now portal to `<body>` (`use:portal`), escaping such ancestors. `Dialog`'s `inline`
108
+ preview variant stays in flow (`use:portal={!inline}`); `enabled` is read once at mount.
109
+ Because the layer lives at `<body>`: DOM events from it no longer bubble to a consumer
110
+ ancestor; a subtree-scoped CSS-variable theme no longer reaches it (this library themes
111
+ via `:root`, so unaffected in practice); and an SSR `show=true` renders in flow on the
112
+ server, then relocates on hydration.
113
+
114
+ ### Changed
115
+
116
+ - **`ImageLightbox` internals restructured.** The inline thumbnail is now its own
117
+ `<button>` that stays in flow; the overlay, morphing stage, and chrome render in a
118
+ separate body-portaled layer. The zoom-from-thumbnail open/close morph, drag/zoom
119
+ panning, and `extended` toolbar are unchanged. `prefers-reduced-motion` is now honored
120
+ (all transitions collapse to an instant swap).
121
+ - **`ImageLightbox` modal is now an accessible dialog.** It exposes `role="dialog"` +
122
+ `aria-modal` with a label (the image's `alt`, or `Image N of M` in a gallery), moves
123
+ focus into the modal on open and restores it to the thumbnail on close, traps `Tab`
124
+ within the modal, and announces the gallery position via a polite live region.
125
+
126
+ ## 0.30.0 — Images lazy-load and stay responsive; card titles truncate
127
+
128
+ ### Added
129
+
130
+ - **`Image` forwards the responsive-image attributes.** New optional props
131
+ `srcset`, `sizes`, `loading`, and `decoding` pass straight through to the
132
+ underlying `<img>`. `loading` defaults to `'lazy'` and `decoding` to
133
+ `'async'`, so content images defer off-screen work with no consumer change.
134
+ Pass `loading="eager"` for an above-the-fold hero.
135
+
136
+ ### Changed
137
+
138
+ - **`Card` titles truncate instead of wrapping.** The title now clips to a
139
+ single line with an ellipsis (`overflow: hidden; white-space: nowrap;
140
+ text-overflow: ellipsis`, plus `min-width: 0` so it can shrink inside the
141
+ flex header), keeping card headers to a fixed height regardless of title
142
+ length.
143
+
144
+ ## 0.29.0 — Image zoom-on-hover and a single slot-prose pin
145
+
146
+ ### Added
147
+
148
+ - **Images can zoom their contents on hover.** `Image` gains an optional `zoom`
149
+ prop and a global "Use zoom" editor intrinsic (the same gate-var + tri-state
150
+ pattern as Card hover): `zoom={undefined}` inherits the editor default,
151
+ `true`/`false` force one instance on or off. The frame stays fixed; only the
152
+ `<img>` scales, via `transform: scale(var(--image-zoom-scale))` with a
153
+ `--duration-300`/`--ease-out-cubic` transition. `CardEditor` and `ImageEditor`
154
+ now export `intrinsics`, registered in the component registry.
155
+ - **`--scale-{sm..2xl}` transform-multiplier scale in `tokens.css`** (1.05 → 1.25,
156
+ 5% per step), consumed by the image zoom above and surfaced in the editor as
157
+ the `SCALE` variant. Ships with a paired `tokens.css` migration
158
+ (`2026-06-03-transform-scale-additions`): run `npx live-tokens migrate` to add
159
+ the scale to a vendored `tokens.css`, or the picker shows a blank slot for
160
+ `--image-zoom-scale`.
161
+ - **`check:slot-prose` publish gate.** Fails the build if a slot-rendering
162
+ component hand-rolls the slot-typography pin (a `:global(p|ul|ol|li)` rule set
163
+ to the literal `inherit`) instead of `@include slot-prose`. Added to
164
+ `prepublishOnly`.
165
+
166
+ ### Fixed
167
+
168
+ - **Consumer global element rules no longer repaint slotted content.** Components
169
+ render the consumer's raw HTML in the same light-DOM tree, so a consumer's
170
+ global `p` / `ul li` rules (for example in `site.css`) matched slotted elements
171
+ and beat the container's body typography (the serif-card bug). The pin now
172
+ lives in one place, `src/system/styles/_slot-prose.scss`, applied via
173
+ `@include slot-prose` on `Card`, `CollapsibleSection`, and `Image`. Three
174
+ diverging hand-copies had shipped before; `check:slot-prose` keeps them out.
175
+
176
+ ### Changed
177
+
178
+ - **The slot-prose pin is per-axis, not `font: inherit`.** It pins only the axes
179
+ a component owns (family, size, weight, line-height, colour, plus spacing
180
+ rhythm) and leaves `font-style`, `letter-spacing`, and `text-transform` free,
181
+ so a consumer's italics or tracking survive inside a card or section.
182
+ - **`Card` and `CollapsibleSection` gain a `prose` prop (default `true`).** Set
183
+ `prose={false}` to drop the pin and fully own slotted-content styling.
184
+ - `fonts.css` (generated from the production theme) swaps Fraunces for Manrope.
185
+
186
+ ## 0.28.1 — Docs load from the published package
187
+
188
+ ### Fixed
189
+
190
+ - **Guide chapters no longer fail to load in tarball consumers.** The `/docs`
191
+ page loaded chapter bodies with `import.meta.glob('./content/*.md', '?raw')`,
192
+ a Vite compile-time transform that esbuild's `optimizeDeps` leaves unexpanded
193
+ inside a pre-bundled `node_modules` dependency. Installed-package consumers
194
+ got an empty module, so every chapter threw "Chapter not found" (the package's
195
+ own demo app and `npm link`ed consumers were unaffected, which is why it
196
+ surfaced only once a consumer ran the package-owned `/docs` from the tarball).
197
+ Bodies now ship as a generated ES module (`content.generated.ts`) built from
198
+ the same `src/editor/docs/content/*.md` sources via `npm run sync:docs`, with
199
+ `check:docs-content` gating drift in CI. No consumer action required.
200
+
201
+ ## 0.28.0 — Dynamic routes without a router
202
+
203
+ ### Added
204
+
205
+ - **`<LiveTokensRouter>` gains a `resolve` prop for routes you can't enumerate.**
206
+ Pass `resolve: (path) => RouteEntry | null` to match params (`/module/:id`),
207
+ prefixes, or conditionally-gated paths in plain code, with no route syntax to
208
+ learn. Resolution order is `pages[path]`, then `resolve(path)`, then the
209
+ `pages['/']` fallback, so existing `pages`-only consumers are unaffected.
210
+ - **`RouteEntry` gains `props`.** A static or resolved entry can pass props to
211
+ its page, so one component can serve many paths (for example the matched id
212
+ or slug). The entry's `source` now drives "Page Source" on dynamic routes
213
+ too, so it can't desync from the dispatched page.
214
+
215
+ ## 0.27.0 — Docs ship with the package
216
+
217
+ ### Added
218
+
219
+ - **The user guide now ships with the package and renders in the editor
220
+ overlay.** `LiveTokensRouter` auto-owns a dev-only `/docs` route and adds a
221
+ "Docs" tab to the overlay nav (alongside "Components"), so every consumer can
222
+ reference the guide while building without vendoring a copy. A new
223
+ `@motion-proto/live-tokens/docs` export lets manual-overlay consumers mount
224
+ the same page. Disable or relocate via `editorRoutes={{ docs: false }}` (or a
225
+ string path), matching the existing `editor` / `components` overrides.
226
+
227
+ ### Changed
228
+
229
+ - The docs renderer and markdown content moved from the demo app into the
230
+ package at `src/editor/docs/` (chapters under `src/editor/docs/content/`), so
231
+ the guide is a single source of truth that ships in the tarball.
232
+ - `marked` and `highlight.js` are now runtime dependencies (the docs renderer
233
+ needs them at the consumer).
234
+
235
+ ## 0.26.0 — Default theme + manifest live from the package
236
+
237
+ ### Changed
238
+
239
+ - **The default theme and default manifest now resolve live from the installed
240
+ package** instead of a vendored local copy. The dev plugin's resource server
241
+ gained a read-only package-directory fallback, so a consumer whose pointer is
242
+ `default` picks up the library's updated defaults on `npm upgrade`, while a
243
+ consumer on a custom theme or manifest is left untouched and keeps a current
244
+ baseline to restore to. Component defaults are unchanged: they still derive
245
+ from each component's shipped `.svelte` `:global(:root)` block.
246
+ - **`themes/default` is now read-only (PUT returns 403)**, symmetric with the
247
+ existing manifest and component-config guards. The default is owned by the
248
+ package, not the consumer.
249
+
250
+ ### Added
251
+
252
+ - Ship `themes/default.json` and `manifests/default.json` in the package tarball
253
+ (the live source for the fallback above).
254
+ - `check:production-is-default` publish gate: the shipped production baseline
255
+ (theme, manifest, and every component) must resolve to `default`, so a
256
+ production-only consumer never inherits a maintainer's custom palette.
257
+
258
+ ### Removed
259
+
260
+ - The empty-seed writers that wrote a local `themes/default.json` and
261
+ `manifests/default.json` on first dev-server start. Those would shadow the
262
+ package default under the new model. Also removed the dead `presets/` to
263
+ `manifests/` one-shot migration.
264
+
265
+ ## 0.25.1 — Drop unused Mermaid dependency
266
+
267
+ ### Removed
268
+
269
+ - **`mermaid` devDependency and `MermaidDiagram.svelte`.** The docs site stopped
270
+ rendering Mermaid when the developer-reference chapters moved to
271
+ `docs/archive/` (off the non-recursive `docs/*.md` glob in `chapters.ts`). The
272
+ only remaining ` ```mermaid ` fences live in those archived chapters, which no
273
+ longer load, so the lazy-loaded `mermaid` package (~700kB) was unreachable.
274
+ Removed the dependency, the `MermaidDiagram` component, and the mermaid
275
+ handling in `Docs.svelte`. No consumer impact: `mermaid` was a
276
+ devDependency and never shipped in the tarball.
277
+
278
+ ## 0.25.0 — Panel component; structural group-key derivation
279
+
280
+ ### Added
281
+
282
+ - **New `Panel` component.** A bordered, centered stage for showcasing other
283
+ components against a subtle gradient surface. Registered in the catalogue and
284
+ editable in the editor (frame border/radius, stage surface/padding/gap). Props
285
+ are `style`, an optional `minHeight` to fix the stage height so it never
286
+ reflows, and a `children` snippet.
287
+ - **`SideNavigation` gains `lead` and `actions` snippets.** `lead` renders at
288
+ the top of the rail above the title (e.g. a logo or company name); `actions`
289
+ renders at the foot of the nav list. Both hide while the rail is collapsed and
290
+ impose no spacing of their own — the consumer controls it.
291
+ - **New scaffolding exports** from `@motion-proto/live-tokens/component-editor`:
292
+ `buildTypeGroupColorTokens`, `buildTypeGroupFontTokens`,
293
+ `buildTypeGroupShareableContexts`, `structuralGroupKey`, and the
294
+ `TypeGroupConfig` type. Custom-component authors can now reach the individual
295
+ pieces of the type-group scaffolding instead of only the bundled
296
+ `buildTypeGroupTokens`.
297
+
298
+ ### Changed
299
+
300
+ - **Group-key derivation is now structural.** `buildTypeGroupTokens` no longer
301
+ infers a token's group from its last dash-segment; it derives the key by
302
+ stripping the component prefix and the variant/state segments declared in the
303
+ new `{ component, variants }` config. All 11 type-group editors were migrated
304
+ to pass this config, and the bespoke SideNavigation/Table workarounds were
305
+ removed. Existing editors' sibling partitions are verified unchanged; this
306
+ matters only for a custom editor that relied on the old last-dash fallback —
307
+ a token with no derivable group now resolves to a solo color token instead of
308
+ being silently grouped.
309
+ - `bin/check-component` now warns (non-fatal) when a component uses a bare font
310
+ helper across multiple slots.
311
+
312
+ ### Changed (breaking)
313
+
314
+ These shift the rendered defaults of shipped components. Consumers who edited
315
+ the affected tokens keep their values; unedited tokens fall through to the new
316
+ defaults on upgrade.
317
+
318
+ - **Button text and icon scale up.** Default text font-size `md → lg` and icon
319
+ size `sm → md` across every variant (primary, secondary, outline, success,
320
+ danger, warning).
321
+ - **Section Divider small variant restyled.** Title is now brand-colored and
322
+ center-aligned, the hairline is off by default, title font-size `2xl → 3xl`
323
+ at medium (was bold) weight, and the outer padding is removed. The large and
324
+ medium variants are unchanged apart from dropping their `space-4` outer
325
+ padding.
326
+
327
+ ### Fixed
328
+
329
+ - **CodeSnippet no longer shows a spurious horizontal scrollbar.** Added a
330
+ `box-sizing: border-box` reset so the snippet's own padding and border stay
331
+ inside `max-width: 100%`. Its code text now uses `--text-brand` (was
332
+ `--text-brand-secondary`).
333
+
334
+ ### Docs
335
+
336
+ - Documentation reorganized: the numbered chapter set moved under
337
+ `docs/archive/`, and the consumer-facing guides (`getting-started`,
338
+ `creating-components`, `editing-tokens`, `themes-workflow`, `01-overview`)
339
+ were rewritten. The demo landing page was restructured (new footer and
340
+ get-started sections; the old "live" section removed).
341
+
342
+ ## 0.24.2 — Demo cosmetic tweaks
343
+
344
+ ### Changed
345
+
346
+ - Minor color tweaks to the demo landing page (hero tagline contrast and the
347
+ floating token-tag text color). No catalogue component, token, or API change.
348
+
349
+ ## 0.24.1 — Section Divider editor controls match rendered defaults
350
+
351
+ ### Fixed
352
+
353
+ - **Section Divider editor controls no longer default to a state the component
354
+ never renders.** The alignment dropdown defaulted to "Center" while an
355
+ unedited divider rendered left-aligned, so choosing "Center" fired no change
356
+ event and appeared to do nothing. The eyebrow / description visibility and
357
+ hairline controls had the same per-variant disagreement. The editor's
358
+ read-back now sources each per-variant default from the runtime
359
+ `:global(:root)`, so the controls reflect what the page actually shows.
360
+
361
+ ### Added
362
+
363
+ - **Intrinsics are now a tested surface.** Structural / display properties an
364
+ editor drives outside the token grid (alignment, visibility, position) are
365
+ declared as `intrinsics: IntrinsicSpec[]` and pinned to the runtime
366
+ `:global(:root)` defaults by a universal contract test, so an editor default
367
+ can't silently drift from what the component renders. `IntrinsicSpec` is
368
+ exported from `@motion-proto/live-tokens/component-editor`.
369
+
370
+ ## 0.24.0 — Grouped editor token lists; CodeSnippet horizontal scroll
371
+
372
+ ### Added
373
+
374
+ - **CodeSnippet scrolls long lines horizontally.** Long code no longer truncates
375
+ with an ellipsis; it scrolls on the x-axis behind a thin styled scrollbar, and
376
+ the copy button stays pinned to the top-right. Two new tokens style the
377
+ scrollbar, both editable in the CodeSnippet panel:
378
+ `--codesnippet-scrollbar-thumb` (thumb color) and
379
+ `--codesnippet-scrollbar-border-width` (scrollbar thickness).
380
+
381
+ ### Changed
382
+
383
+ - **Editor token lists are now split into labeled element groups.** Ten
384
+ component editors (Callout, CodeSnippet, InlineEditActions, Input, MenuSelect,
385
+ ProgressBar, SegmentedControl, TabBar, Toggle, Tooltip) group their tokens
386
+ into labeled sections (frame / text / icon and structural parts like track,
387
+ thumb, divider, indicator, scrollbar) via the `element` field instead of one
388
+ flat list per state. Editor-only change: rendered output for existing tokens,
389
+ token names, and component APIs are unchanged, so existing themes and
390
+ component-configs are unaffected.
391
+
392
+ ## 0.23.0 — Extend the spacing scale at the top end
393
+
394
+ ### Added
395
+
396
+ - **`--space-40` (2.5rem) and `--space-128` (8rem).** The spacing scale gained a
397
+ step between 32 and 48, and a new large value above 96, for section- and
398
+ page-level layout. `--space-64` and `--space-96` (already defined but not
399
+ surfaced) now appear in the editor's Spacing panel too. Displayed scale is now
400
+ `2 4 6 8 10 12 16 20 24 32 40 48 64 96 128`.
401
+
402
+ ### Removed
403
+
404
+ - **`--space-80` (5rem).** Defined but unused and never surfaced in the editor;
405
+ it broke the monotonic step growth at the top of the scale. Direct consumers
406
+ of `--space-80` should remap to `--space-64`, `--space-96`, or `--space-128`.
407
+
408
+ ## 0.22.1 — Add LICENSE files
409
+
410
+ ### Added
411
+
412
+ - **`LICENSE` (MIT).** The package already declared `"license": "MIT"` in
413
+ `package.json` but shipped without the license text. Both
414
+ `@motion-proto/live-tokens` and `@motion-proto/create-live-tokens` now include
415
+ an MIT `LICENSE` file in their published tarballs. No code changes.
416
+
417
+ ## 0.22.0 — Component defaults synced to the reference demo
418
+
419
+ ### Changed
420
+
421
+ - **Baked-in component defaults refreshed to match the reference demo.** The
422
+ `:global(:root)` defaults in 8 shipped components (Badge, CollapsibleSection,
423
+ CornerBadge, MenuSelect, Notification, ProgressBar, SectionDivider,
424
+ SegmentedControl) had drifted from the project's tuned config; they now match,
425
+ so a fresh install renders like the demo. Visual default change only — no
426
+ token names, aliases, or APIs changed, so existing themes and
427
+ component-configs keep overriding exactly as before.
428
+ - **SegmentedControl**: selected pill uses brand surface/border (was success
429
+ green); disabled surface is transparent; hover surface softened.
430
+ - **SectionDivider**: backgrounds are transparent (the demo's gradients are
431
+ `type: none`); titles, eyebrows, and hairlines retuned.
432
+
433
+ ### Added
434
+
435
+ - **`sync:component-defaults` + `check:component-defaults`.** The sync script
436
+ pushes editor-tuned config values back into the component `.svelte` source
437
+ (the "adopt to source" step), and `check:component-defaults` — wired into
438
+ `prepublishOnly` — fails the release if any component's baked default drifts
439
+ from its config. The `.svelte` default and the editor config stay one source.
440
+
441
+ ## 0.21.2 — Export the scaffolding engine
442
+
443
+ ### Added
444
+
445
+ - **`@motion-proto/live-tokens/create` export** exposing `createApp`
446
+ (plus `runCreate` / `formatCreateResult`), the engine behind the `create`
447
+ subcommand. This lets the `@motion-proto/create-live-tokens` initializer
448
+ reuse the exact template and version-matched token seeds without duplicating
449
+ them — the groundwork for `npm create @motion-proto/live-tokens`. No change
450
+ to the `create` subcommand itself.
451
+
452
+ ## 0.21.1 — Recommended project layout
453
+
454
+ ### Added
455
+
456
+ - **README "Recommended project layout" section.** Documents the integration
457
+ surface `create` produces (vendored `tokens.css`, editor state under `src/`,
458
+ `vitePreprocess`, clean peer resolution with no `legacy-peer-deps`) and the
459
+ invariant that keeps upgrades non-destructive: all editable state is committed
460
+ under `src/`, never inside `node_modules`. The `create` template's README
461
+ links to it.
462
+
463
+ ## 0.21.0 — Scaffold a new app with `create`
464
+
465
+ ### Added
466
+
467
+ - **`npx @motion-proto/live-tokens create <dir>` scaffolds a working app.**
468
+ It generates a thin Svelte + Vite project that *depends on* the package
469
+ (`vite.config.ts` with `themeFileApi`, `main.ts` calling `bootLiveTokens`,
470
+ an `App.svelte` using `<LiveTokensRouter>`, and a placeholder
471
+ `src/pages/Home.svelte`), then seeds `tokens.css`, `tokens.generated.css`,
472
+ and `site.css` from the installed package so they never drift from the
473
+ version you scaffolded against. `init` is an alias. Replaces the old
474
+ `npx degit motionproto/live-tokens` route, which cloned the entire package
475
+ repo (source, tests, and all) instead of producing a consumer app.
476
+ - **`check:smoke-create` release gate.** Packs the tarball, runs the shipped
477
+ `create`, installs the generated app against the tarball with no
478
+ `--legacy-peer-deps`, and builds it. Wired into `prepublishOnly`, so a
479
+ broken scaffold or a template missing from the tarball cannot ship.
480
+
481
+ ## 0.20.1 — Color opacity is a property of a token
482
+
483
+ ### Changed
484
+
485
+ - **Internal: translucent colors are modeled as a token plus an optional
486
+ opacity, not a separate value kind.** The editor's `CssVarRef` now has three
487
+ kinds (`token`, `literal`, `gradient`); a color below 100% is a `token`
488
+ carrying an `opacity`, and one serialize/parse pair
489
+ (`color-mix(in srgb, var(--token) NN%, transparent)`) backs every read and
490
+ write of a color value. No change to the on-disk config format, the generated
491
+ CSS, or any public API, so no migration is needed.
492
+
493
+ ### Fixed
494
+
495
+ - **Linked-block grouping no longer collapses distinct gradients into one
496
+ bucket.** Gradient refs were keyed by a stringified object, so every gradient
497
+ hashed to the same key; refs are now bucketed by their rendered CSS value.
498
+
499
+ ## 0.20.0 — Refreshed shipped component defaults
500
+
501
+ ### Changed
502
+
503
+ - **Baked-in component defaults updated across the shipped set.** The
504
+ `:global(:root)` defaults inside `src/system/components/*.svelte` (what a
505
+ fresh consumer sees before they touch the editor) were refreshed. This is a
506
+ visual default change: components installed at this version look different out
507
+ of the box, but no token names, aliases, or APIs changed, so existing themes
508
+ and component-configs keep overriding exactly as before.
509
+ - **Button** (`Button.svelte`): primary/secondary/outline/success/danger/warning
510
+ text steps up to `--font-size-md` / `--font-weight-semibold`, radius to
511
+ `--radius-xl`, and success/danger/warning border width drops to
512
+ `--border-width-1`. Small variant font size moves to `--font-size-sm`.
513
+ - **Callout** (`Callout.svelte`): label and body switch from `--font-serif` to
514
+ `--font-sans` at `--font-size-lg`; info border firms up to
515
+ `--border-info-medium`.
516
+ - **Card** (`Card.svelte`): translucent `color-mix` surfaces, per-side header
517
+ and body padding, larger title (`--font-size-2xl` / `--font-weight-medium`)
518
+ and body (`--font-size-xl`), icon at `--icon-size-2xl`.
519
+ - **CodeSnippet** (`CodeSnippet.svelte`): translucent surface, neutral border,
520
+ code text in `--text-brand-secondary` at `--font-size-md`.
521
+ - **Image** (`Image.svelte`): radius to `--radius-2xl`.
522
+ - **ImageLightbox** (`ImageLightbox.svelte`): overlay surface to a translucent
523
+ `color-mix` of `--color-neutral-950`.
524
+ - **Table** (`Table.svelte`): translucent neutral wrapper/header surfaces,
525
+ heavier wrapper border, larger header (`--font-size-lg` / semibold) and cell
526
+ (`--font-size-md` / medium) type, visible column dividers.
527
+ - **Tooltip** (`Tooltip.svelte`): translucent surface, visible
528
+ `--border-width-1` border.
529
+
530
+ ### Fixed
531
+
532
+ - **Dev-server plugin now round-trips translucent surfaces.** When a component's
533
+ `:global(:root)` declares a color at reduced opacity
534
+ (`color-mix(in srgb, var(--token) NN%, transparent)`, the form the color
535
+ picker emits below 100% opacity), the plugin's `default.json` regeneration
536
+ preserves it. Previously only plain `var(--token)` aliases were captured, so
537
+ regeneration silently dropped translucent properties from the seed config,
538
+ leaving them blank in the editor and absent from adopt defaults.
539
+
540
+ ### Migration
541
+
542
+ - Consumers who want the previous look can pin their theme or component-config
543
+ values; nothing is removed, so no edits are required to keep an existing
544
+ setup working. The change only affects components rendered with the shipped
545
+ defaults.
546
+
547
+ ## 0.19.1 — Fresh install no longer needs `--legacy-peer-deps`
548
+
549
+ ### Fixed
550
+
551
+ - **`npm install @motion-proto/live-tokens` resolves cleanly on a fresh
552
+ machine.** `vite@8` declares an optional `sugarss@^5` peer while
553
+ `svelte-preprocess@6` declares `sugarss@^2 || ^3 || ^4`. The ranges don't
554
+ overlap, so npm rejected the whole tree with `ERESOLVE` even though `sugarss`
555
+ is never installed. We no longer depend on `svelte-preprocess`, so the
556
+ conflict is gone — no `--legacy-peer-deps`, no `.npmrc` workaround.
557
+
558
+ ### Changed
559
+
560
+ - **Preprocessing moved from `svelte-preprocess` to `vitePreprocess`** (bundled
561
+ in `@sveltejs/vite-plugin-svelte`). `svelte-preprocess` is removed from
562
+ `peerDependencies`; `@sveltejs/vite-plugin-svelte` (`^7.0`) is now a declared
563
+ peer. `sass` stays a peer — it compiles the components' `<style lang="scss">`
564
+ blocks under `vitePreprocess` exactly as before. The build-time PRUNE_FOR
565
+ pass that relied on svelte-preprocess's `replace` option now runs through a
566
+ local `replacePreprocess` helper (`vite-plugin/pruneMarkers/`).
567
+
568
+ ### Migration
569
+
570
+ - **Consumer `vite.config.ts`:** preprocess with `vitePreprocess()` instead of
571
+ a bare `svelte()`. The bare form never compiled the shipped components' scss
572
+ blocks, so this also closes a latent gap. Keep `sass` installed.
573
+
574
+ ```ts
575
+ import { svelte, vitePreprocess } from '@sveltejs/vite-plugin-svelte';
576
+ // ...
577
+ plugins: [svelte({ preprocess: vitePreprocess() }), themeFileApi({ /* ... */ })]
578
+ ```
579
+
580
+ Consumers who explicitly configured `svelte-preprocess` themselves can keep
581
+ it — nothing forces the switch — but it's no longer required or installed for
582
+ you.
583
+
584
+ ## 0.19.0 — Toggle, TabBar, SegmentedControl token model updates
585
+
586
+ ### Changed (breaking)
587
+
588
+ - **`Toggle` track dimensions are derived, not authored.** The runtime
589
+ now computes `track-width = thumb-size * 2 + track-padding * 2` and
590
+ `track-height = thumb-size + track-padding * 2`, so the explicit
591
+ `--toggle-track-width` and `--toggle-track-thickness` tokens are gone.
592
+ A new `--toggle-track-padding` knob controls the gap between thumb and
593
+ track edge. Auto-migrated: the `2026-05-29-toggle-derive-track-from-thumb`
594
+ component-config migration drops the two old tokens and seeds
595
+ `--toggle-track-padding` with `--space-2` when absent. Consumers who
596
+ customised track width will see geometry derive from their
597
+ `--toggle-thumb-size` after upgrade.
598
+ - **`TabBar` indicator stroke width is now per-state.** The bar-level
599
+ `--tabbar-bar-indicator-thickness` is replaced by
600
+ `--tabbar-{default,hover,active,disabled}-indicator-border-width`,
601
+ mirroring how indicator color already rebinds per state. The
602
+ `-border-width` suffix also lets the editor's picker classify the
603
+ token correctly (the old `-thickness` suffix rendered as a colour
604
+ picker). Auto-migrated by
605
+ `2026-05-29-tabbar-indicator-thickness-to-per-state-width`: the old
606
+ bar-level value seeds all four states, so the visual default is
607
+ preserved. Unset falls back to `--border-width-2`.
608
+ - **`SegmentedControl` small-size divider tokens renamed.**
609
+ `--segmentedcontrol-divider-small-thickness` →
610
+ `--segmentedcontrol-small-divider-thickness`, and the matching
611
+ `-inset` token. The picker recognises the value by suffix, so the
612
+ rename puts `-thickness` / `-inset` at the tail where the editor
613
+ classifies them as stroke width and inset instead of colour. Auto-
614
+ migrated by `2026-05-29-segmentedcontrol-small-divider-rename`.
615
+
616
+ ### Added
617
+
618
+ - **Three new component-config migrations** covering the renames above,
619
+ with regression tests in `migrations.test.ts`.
620
+
621
+ ## 0.18.2 — Publish workflow switches to `npm install`
622
+
623
+ ### Fixed
624
+
625
+ - **Publish workflow uses `npm install --include=optional` instead of
626
+ `npm ci`.** Releases are tagged from macOS, where `package-lock.json`
627
+ cannot capture the linux-only optional binaries that rolldown
628
+ (bundled with Vite 8) pulls in for the wasm32-wasi fallback path.
629
+ `npm ci` strict-checked the lockfile and exited EUSAGE on missing
630
+ `@emnapi/*` nodes; `npm install` resolves the tree per-platform from
631
+ `package.json`. Tag-matches-package.json gate remains the source of
632
+ truth for the publish identity. 0.18.0 and 0.18.1 both tagged but
633
+ never reached the publish step because of this.
634
+
635
+ ## 0.18.0 — Vite 8 / TypeScript 6 toolchain bump
636
+
637
+ ### Changed
638
+
639
+ - **Peer dependency: `vite` is now `^8`** (was `^6 || ^7`). Consumers
640
+ must upgrade to Vite 8 before installing this version. The
641
+ `@sveltejs/vite-plugin-svelte` v7 peer enforces this — v7 requires
642
+ Vite 8, and Vite 8's CSS pipeline (rolldown + lightningcss by default)
643
+ may surface latent CSS issues that the v7 pipeline tolerated.
644
+ - **Dev toolchain bumped to current majors:** `vite ^8.0.14`,
645
+ `@sveltejs/vite-plugin-svelte ^7.1.2`, `typescript ~6.0.3`,
646
+ `@types/node ^25.9.1`. Smoke-install consumer in
647
+ `scripts/smoke-install.sh` follows the same versions so the test
648
+ exercises the declared peer.
649
+ - **`tsconfig.json` adds `"ignoreDeprecations": "6.0"`** to silence the
650
+ TypeScript 6 deprecation warning emitted by `tsup`'s internal DTS
651
+ build (which injects `baseUrl`). Cosmetic only; no behaviour change.
652
+
653
+ ## 0.17.1 — SideNavigation re-toggles on current page
654
+
655
+ ### Fixed
656
+
657
+ - **`SideNavigation` collapses when its label is clicked on the current
658
+ page.** Previously, clicking a section label whose route was already
659
+ current produced a no-op navigation, so users had to chase the chevron
660
+ to collapse the section they had just opened. The label now intercepts
661
+ that click and toggles the section instead. Modified-click
662
+ (cmd/ctrl/shift/alt) and middle-click still fall through to the link,
663
+ and the chevron's own click is untouched.
664
+
665
+ ### Changed
666
+
667
+ - **Editor: removed hidden per-side padding entries** from
668
+ `CornerBadgeEditor`, `InputEditor`, `MenuSelectEditor`, and
669
+ `SegmentedControlEditor`. Each editor previously declared a `padding`
670
+ token alongside four `padding-top` / `-right` / `-bottom` / `-left`
671
+ entries flagged `hidden: true`. The hidden entries never reached the UI
672
+ and their `--*-padding-{top,right,bottom,left}` variables are not
673
+ referenced by the shipped components, so this is a cleanup of dead
674
+ configuration with no consumer-visible effect.
675
+
676
+ ## 0.17.0 — tokens.css migrations for Layer-1 drift
677
+
678
+ Layer-1 primitives live in the consumer's developer-authored
679
+ `tokens.css`, which the in-browser JSON migration system deliberately
680
+ never touches. When the package evolves its token vocabulary, a forked
681
+ `tokens.css` falls behind and components reference primitives that
682
+ resolve to nothing, surfacing as blank or `—` editor slots. This release
683
+ adds a Node-side, idempotent migration system that reconciles
684
+ `tokens.css` on demand, plus a boot guardrail that flags drift before it
685
+ shows up as empty slots.
686
+
687
+ ### Added
688
+
689
+ - **`live-tokens migrate` CLI.** `npx live-tokens migrate` applies
690
+ pending `tokens.css` migrations and writes the file in place as a
691
+ reviewable git diff. `npx live-tokens migrate --check` reports without
692
+ writing and exits 1 when changes are pending, so CI can gate on it.
693
+ The file is located via `--tokens <path>`, then the `tokensCssPath`
694
+ key in `live-tokens.config.json`, then a short default scan.
695
+ - **`tokensCssPath` config key.** Added to `live-tokens.config.json` so
696
+ the CLI can locate `tokens.css` without plugin options.
697
+ - **Boot guardrail.** The dev-server plugin (`themeFileApi`) runs a
698
+ read-only `validateTokensCss` check on boot. It scans every
699
+ component's `:global(:root)` block for `var(--…)` references and warns
700
+ about any primitive not defined in `tokens.css`, the generated
701
+ sidecar, or another component, naming the tokens and pointing at `npx
702
+ live-tokens migrate`. It never writes anything, so the "plugin never
703
+ writes `tokens.css`" invariant is preserved.
704
+ - **First migrations.** Add `--line-height-{xs..xl}`,
705
+ `--letter-spacing-*`, and `--ease-out-quart`. Remove legacy
706
+ `--sectiondivider-*` tokens that are not on the `lg`/`md`/`sm` axis.
707
+ Migrations are idempotent by presence (no `schemaVersion` to stamp on
708
+ CSS), so re-running the whole set is always safe.
709
+
710
+ ### Docs
711
+
712
+ - `docs/04-tokens-and-themes.md` gains a "tokens.css migrations
713
+ (Layer-1)" section covering the engine, the CLI, the guardrail, and
714
+ how to author a new migration.
715
+
716
+ ## 0.16.2 — CollapsibleSection collapses linked headers
717
+
718
+ ### Fixed
719
+
720
+ - **`CollapsibleSection` with `href` can now collapse.** When `href` was
721
+ set, the header rendered as a single `<a>` with no toggle handler, so
722
+ consumers like SideNavigation lost the ability to collapse sections
723
+ that were also routes. Click only ever navigated, and the chevron's
724
+ rotate was decorative. The `href` branch now renders the chevron as a
725
+ standalone `<button>` that fires `ontoggle`, with the label as a
726
+ sibling `<a>` link inside the same flex row. Hover, indicator, and
727
+ expanded paint still land on the row. The no-`href` branch is
728
+ unchanged.
729
+
730
+ ## 0.16.1 — SideNavigation header restructure
731
+
732
+ The SideNavigation title bar is now a single flex card hosting the label
733
+ box and the persistent toggle button as siblings. Previously the toggle
734
+ was an absolutely-positioned child of the rail with calc'd left/top
735
+ coordinates derived from the panel-width tokens. The new structure
736
+ removes that coupling: the header's `justify-content` plus `flex:1` on
737
+ the label naturally positions the toggle to the right of the label when
738
+ open and centres it in the rail when collapsed.
739
+
740
+ ### Changed (breaking)
741
+
742
+ - **SideNavigation title indicator and divider no longer render.** The
743
+ `border-left` accent strip and `border-bottom` divider on the title
744
+ bar were removed in favour of a card-shaped header driven by per-state
745
+ `surface` + `border` + `radius` chrome. Consumers who set
746
+ `--sidenavigation-title-<state>-accent` /
747
+ `--sidenavigation-title-<state>-accent-width` will see no rendered
748
+ effect; the tokens remain in shipped configs for backward compatibility
749
+ but no longer drive any pixels. Move customizations onto
750
+ `--sidenavigation-title-<state>-surface` /
751
+ `-border` / `-border-width` instead. The editor's "Title" sections
752
+ surface these (relabeled from "divider color / divider width /
753
+ indicator color / indicator width" to "border color / border width";
754
+ the two indicator rows are gone).
755
+
756
+ ### Added
757
+
758
+ - **Stateless Title Layout tokens.**
759
+ `--sidenavigation-title-gap` (space between label box and toggle box)
760
+ and `--sidenavigation-title-radius` (outer card corner radius). Exposed
761
+ in the editor under a new "Title Layout" section.
762
+ - **Stateless Title Label tokens.**
763
+ `--sidenavigation-title-label-surface`,
764
+ `--sidenavigation-title-label-radius`, and
765
+ `--sidenavigation-title-label-padding` style the inner label box that
766
+ sits beside the toggle in the open state. Exposed in the editor under
767
+ a new "Title Label" section.
768
+
769
+ ### Changed
770
+
771
+ - **Shipped `sidenavigation/default.json` tightened.** Drops the legacy
772
+ split `padding-top/right/bottom/left` keys (superseded by the
773
+ four-tuple `padding` tokens) and adjusts default text sizes (item and
774
+ footer text → `--font-size-sm` + `--font-weight-light` for
775
+ default/hover), icon sizes (footer → `--icon-size-xs`), and accent
776
+ widths (`--border-width-3` instead of `4`). Consumers with their own
777
+ `default.json` are unaffected; consumers relying on the shipped
778
+ default see a denser nav rail.
779
+
780
+ ### CI
781
+
782
+ - Bumped `actions/checkout` and `actions/setup-node` to `v6` in
783
+ `publish.yml` and `verify.yml`.
784
+
785
+ ## 0.15.0 — One-call boot + router wrapper
786
+
787
+ The library now provides two opt-in wrappers that collapse the boilerplate
788
+ every consumer used to copy out of the README: a single `bootLiveTokens`
789
+ call for `main.ts` and a `<LiveTokensRouter>` component for `App.svelte`.
790
+ Together they take a typical consumer's integration from ~80 lines of
791
+ hand-orchestrated init + overlay + route-dispatch to ~12 lines.
792
+
793
+ The library's own demo app (`src/app/main.ts`, `src/app/App.svelte`) has
794
+ been migrated to use the new wrappers as a dogfooded reference.
795
+
796
+ ### Added
797
+
798
+ - **`bootLiveTokens(App, target, opts?)`** — one-call bootstrap. Runs the
799
+ five idempotent `init*` hooks in the documented order, fetches the
800
+ active theme in dev, registers any consumer-authored components passed
801
+ via `opts.components` (dev-only), and mounts the app. Side-effect-
802
+ imports FontAwesome so the overlay's icons are present without the
803
+ consumer having to remember a separate import. Exported from the
804
+ package root.
805
+ - **`<LiveTokensRouter pages={…}>`** — overlay + columns + route
806
+ dispatch in one component. Drives `<LiveEditorOverlay>` and
807
+ `<ColumnsOverlay>` automatically, dynamic-imports `/editor` and
808
+ `/components` (so editor chrome stays out of non-editor route
809
+ bundles), auto-injects `Components` into the dev nav rail and the
810
+ page-source hide list, intercepts in-app `<a href="/…">` clicks for
811
+ client-side routing. Page entries can be eager (`component:
812
+ PageComponent`) or code-split (`lazy: () => import('./Page.svelte')`);
813
+ use `lazy` for any page that side-effect-imports a stylesheet at the
814
+ top of its module so those side effects stay out of the editor routes.
815
+ Pages without a `label` are reachable by URL but absent from the nav
816
+ rail (matches the existing playground pattern). `editorRoutes.editor`
817
+ and `editorRoutes.components` accept a string to relocate the default
818
+ route or `false` to disable it entirely (no dispatch and, for
819
+ `components`, no auto-injected nav-rail entry). Exported from the
820
+ package root along with `RouteEntry` and `EditorRouteOverrides` types.
821
+
822
+ ### Changed
823
+
824
+ - **`themeFileApi` default `componentsSrcDir` now scans both
825
+ `src/components` and `src/system/components`** when no explicit option
826
+ is passed. The Vite/Svelte convention is `src/components`, so new
827
+ consumers don't need an override; existing consumers with components in
828
+ `src/system/components` keep working without changes.
829
+ - **The component scanner skips `.svelte` files without a
830
+ `:global(:root) {}` block.** Previously any `.svelte` file in the scan
831
+ dir was treated as a runtime component, which meant editor companion
832
+ files (e.g. `Foo.editor.svelte` or `FooEditor.svelte`) co-located with
833
+ their runtime sibling would get a spurious `component-configs/foo.editor/`
834
+ entry and show up in the editor's components list. Theme-aware
835
+ components declare their tokens in a `:global(:root)` block; the
836
+ presence of that block is now the marker for "register as a component."
837
+ No filename convention required.
838
+
839
+ ### Lower-level APIs unchanged
840
+
841
+ `LiveEditorOverlay`, `ColumnsOverlay`, `initCssVarSync`, `initRouter`,
842
+ `initColumnsOverlay`, `initEditorStore`, `initializeTheme`,
843
+ `registerComponent`, and the editor page exports
844
+ (`@motion-proto/live-tokens/editor`,
845
+ `@motion-proto/live-tokens/component-editor-page`) all remain exported.
846
+ The new wrappers are pure composition over them — use them directly if
847
+ you need a custom shell or non-standard route dispatch.
848
+
849
+ ### README
850
+
851
+ The Quick install section now leads with `bootLiveTokens` +
852
+ `<LiveTokensRouter>`. The manual-orchestration pattern is documented
853
+ under a "Lower-level API" heading for consumers who need it.
854
+
855
+ ## 0.14.1 — Drop unused local font files
856
+
857
+ Cleanup of leftover state from the Google Fonts switch in 0.14.0.
858
+
859
+ ### Changed
860
+
861
+ - **Local `.woff2` font files removed.** 0.14.0 already excluded them from the
862
+ published package via the `files` list, so this is a repository cleanup
863
+ rather than a consumer-facing change. The `!src/system/styles/fonts/**`
864
+ exclusion is dropped (no longer needed). Published bundle size is unchanged
865
+ versus 0.14.0.
866
+ - **"Add local font" instruction updated.** The editor's font-add help text
867
+ used to direct users to drop `.woff2` files into
868
+ `src/system/styles/fonts/<Family>/` and claim the folder shipped with the
869
+ production build, which was the exact assumption that broke for consumers
870
+ pre-0.14.0. New copy points at `public/fonts/<Family>/`, a portable Vite
871
+ convention that works the same whether you're in a consumer or in this repo.
872
+
873
+ ## 0.14.0 — Multi-dir component scan, Google Fonts for defaults
874
+
875
+ ### Changed (breaking — automatic migration on theme load)
876
+
877
+ - **Default font sources moved to Google Fonts.** Manrope and Fraunces were
878
+ shipped as local woff2 files with `@font-face` blocks pointing at them. The
879
+ url() resolution for those refs was fragile when consumed via the published
880
+ package (paths leaked through Vite's CSS pipeline unrewritten). Defaults now
881
+ use Google Fonts CDN URL imports (`@import url('https://fonts.googleapis.com/...')`),
882
+ which sidesteps the rewriting entirely. Local woff2 font files are no longer
883
+ published with the package; consumers who depended on them via direct path
884
+ references will need to vendor their own or switch to Google Fonts too.
885
+ - **`migrateThemeFonts` auto-converts legacy local-font sources.** Any
886
+ `fontSources` entry with `kind: 'font-face'` whose cssText is a font-face
887
+ block for `Manrope` or `Fraunces` is rewritten to a Google Fonts URL source
888
+ on next theme load. Source ids and family ids are preserved so existing
889
+ fontStacks keep working.
890
+ - **Plugin `componentsSrcDir` scan now auto-includes the package's first-party
891
+ components dir.** Previously the scan only walked the consumer-provided dir,
892
+ so the editor's "registered components vs disk scan" validator would warn on
893
+ every first-party component (Badge, Button, …) when a consumer pointed
894
+ `componentsSrcDir` at their own components folder. Both dirs are scanned
895
+ now; consumer entries shadow first-party ones on name collision. The option
896
+ remains a single string for consumer code.
897
+
898
+ ## 0.13.3 — Diagnostic logging (temporary)
899
+
900
+ Adds `console.log` traces inside `LiveEditorOverlay` for the route↔editorView
901
+ pairing rule and for editorView subscriptions, prefixed `[lt-debug:parent]` /
902
+ `[lt-debug:iframe]`. Will be removed in 0.13.4. Use this only if you're
903
+ helping diagnose the components-view flicker reported on 0.13.1/0.13.2.
904
+
905
+ ## 0.13.2 — Fix font 404s for consumers
906
+
907
+ The bundled `fonts.css` and the default `fontSources[].cssText` both used
908
+ absolute URLs like `/src/system/styles/fonts/Manrope/Manrope-latin.woff2`,
909
+ resolved via Vite `?url` imports against the live-tokens repo layout. Those
910
+ paths only existed in this repo's own dev server; for any consumer importing
911
+ `@motion-proto/live-tokens/app/fonts.css`, the browser asked for them at the
912
+ consumer's server root and got back the dev HTML fallback (visible as `OTS
913
+ parsing error: invalid sfntVersion` in the console).
914
+
915
+ ### Fixed
916
+
917
+ - **Bundled `fonts.css` and default font sources now use package-relative
918
+ paths** (`./fonts/Fraunces/...`, `./fonts/Manrope/...`). The css file and
919
+ the `fonts/` directory ship colocated under `src/system/styles/` in the
920
+ package, so the relative url() resolves correctly whether served from
921
+ `node_modules` in a consumer, from this repo's dev server, or as a hashed
922
+ asset in a production build.
923
+ - **`migrateThemeFonts` auto-rewrites legacy absolute font paths.** Themes
924
+ saved before this change (with `fontSources[].cssText` containing
925
+ `/src/system/styles/fonts/...` or `/src/live-tokens/system/styles/fonts/...`)
926
+ are normalised to `./fonts/...` on next theme load and re-saved by the
927
+ editor. No consumer action required.
928
+
929
+ ## 0.13.1 — Fix /components route pairing flicker
930
+
931
+ The pairing rule introduced in 0.12.1 fired on every `editorView` change, not
932
+ just on route change. Combined with the cross-window `storage` sync between
933
+ parent and overlay iframe, a single click on the components toggle would
934
+ trigger a feedback cascade: store write → storage event → handler runs
935
+ subscribers → rule re-fires → another store write, etc. Each step pulled
936
+ heavy editor re-renders along with it (the storage handler regularly took
937
+ >1s in practice), producing a visible bounce as the view flickered between
938
+ tokens and components.
939
+
940
+ ### Fixed
941
+
942
+ - **`LiveEditorOverlay` route pairing now fires once per route change.** The
943
+ rule still sets the initial pairing when entering `/components` (overlay
944
+ flips to tokens to avoid stacking with the full-page editor), but does not
945
+ re-fire when the user toggles `editorView` while on that route. The user
946
+ can interact with the overlay's view switcher freely, no flicker.
947
+
948
+ ## 0.13.0 — Generated CSS lives with editor data
949
+
950
+ The plugin now writes `tokens.generated.css` to `<dataDir>/tokens.generated.css`
951
+ by default, alongside themes, manifests, and component-configs. Previously it
952
+ defaulted to `<tokensCssPath dir>/tokens.generated.css`, which silently landed
953
+ inside `node_modules/` for any consumer that pointed `tokensCssPath` at the
954
+ installed package — a path `npm ci` would happily wipe.
955
+
956
+ The generated file is editor-managed user content, conceptually the same as
957
+ themes and manifests, so it belongs in the data directory rather than coupled
958
+ to the read-only base tokens.css location.
959
+
960
+ ### Changed (breaking — one-line config or file move)
961
+
962
+ - **`tokensGeneratedCssPath` default moved from `<tokensCssPath dir>` to
963
+ `<dataDir>`.** No automatic migration; pick one:
964
+ - **Move the file** (recommended): relocate your existing
965
+ `tokens.generated.css` from wherever it lived (often
966
+ `src/system/styles/tokens.generated.css`) to `<dataDir>/tokens.generated.css`
967
+ and update your `main.ts` import to match.
968
+ - **Pin the old path**: pass
969
+ `tokensGeneratedCssPath: 'src/system/styles/tokens.generated.css'` (or your
970
+ previous location) explicitly to `themeFileApi()` in `vite.config.ts`.
971
+ - **Bundled `tokens.generated.css` relocated inside the package.** The
972
+ `@motion-proto/live-tokens/app/tokens.generated.css` export now resolves to
973
+ `./src/live-tokens/data/tokens.generated.css` (was
974
+ `./src/system/styles/tokens.generated.css`). Consumers importing via the
975
+ package export are unaffected; only the on-disk path inside `node_modules`
976
+ changed.
977
+
978
+ ## 0.12.1 — Overlay owns the /components route pairing
979
+
980
+ The mutual-exclusion rule that flips the overlay to Tokens view whenever the
981
+ page route is `/components` now lives inside `LiveEditorOverlay` itself.
982
+ Consumer App shells no longer need to import `editorView` or wire up the
983
+ pairing block by hand.
984
+
985
+ ### Changed
986
+
987
+ - **`LiveEditorOverlay` self-handles the /components route pairing.** Previously
988
+ each consumer's `App.svelte` had to subscribe to `route` + `editorView` and
989
+ force `editorView.set('tokens')` when the route hit `/components`, otherwise
990
+ the full-page component editor and the overlay's components view would stack.
991
+ The rule now fires from inside the overlay component, so any host that mounts
992
+ `<LiveEditorOverlay />` gets the behaviour for free. The starter's
993
+ `src/app/App.svelte` is updated to drop the duplicated block.
994
+
995
+ ## 0.12.0 — Toggle, CodeSnippet, and a Claude skill suite
996
+
997
+ Two new shipped components (`Toggle`, `CodeSnippet`) and a `live-tokens` CLI
998
+ that installs the bundled Claude Code skills into a consumer project in one
999
+ command. The single `live-tokens-add-component` skill is replaced by three
1000
+ focused skills covering page composition, component selection, and new-component
1001
+ authoring.
1002
+
1003
+ ### Added
1004
+
1005
+ - **`Toggle` component** (`src/system/components/Toggle.svelte` + editor).
1006
+ On/off switch with tokenised track, thumb, label, and disabled state.
1007
+ - **`CodeSnippet` component** (`src/system/components/CodeSnippet.svelte` +
1008
+ editor). Syntax-highlighted code block with tokenised chrome and copy button.
1009
+ - **`live-tokens` CLI** (`bin/cli.mjs`). Two subcommands:
1010
+ - `npx @motion-proto/live-tokens setup-claude` — copies all bundled skills
1011
+ into `./.claude/skills/` in the consumer project. `--force` overwrites
1012
+ existing skill directories.
1013
+ - `npx @motion-proto/live-tokens check-component <id>` — static validator
1014
+ that enforces file layout, `:global(:root)` block, token-suffix vocabulary,
1015
+ state-before-property rule, no-raw-colour-defaults rule, public-imports
1016
+ rule, and `registerComponent({ id })` call. Useful as a post-authoring
1017
+ check or pre-commit guard.
1018
+
1019
+ ### Changed
1020
+
1021
+ - **Claude Code skill suite reshaped.** The single `live-tokens-add-component`
1022
+ skill is removed; three focused skills take its place:
1023
+ - `live-tokens-build-page` — composes pages from the shipped components.
1024
+ - `live-tokens-pick-component` — decides between confusable pairs (TabBar
1025
+ vs SegmentedControl, Card vs CollapsibleSection, Callout vs Notification,
1026
+ etc.) with decision tables per family.
1027
+ - `live-tokens-create-component` — authors a new editable component against
1028
+ the naming, state-model, and public-imports rules.
1029
+ Each auto-triggers from natural-language requests; no slash commands.
1030
+ - **Docs.** `docs/adding-components.md` renamed to `docs/creating-components.md`
1031
+ to align with the new skill name; cross-references updated.
1032
+ - **README.** Component count bumped from ~19 to ~24; new "Claude Code skills"
1033
+ section documents the suite and CLI install path.
1034
+
1035
+ ## 0.11.0 — Overlay scale trim and release pipeline cleanup
1036
+
1037
+ The overlay scale drops from seven stops to three. CI is now the only thing
1038
+ that publishes to npm; local `npm publish` is no longer part of the flow.
1039
+
1040
+ ### Changed (breaking for direct consumers of the dropped overlay tokens; auto-migrated for saved configs)
1041
+
1042
+ - **`--overlay-lowest` / `--overlay-lower` / `--overlay-higher` / `--overlay-highest` removed.**
1043
+ The kept stops are `--overlay-low`, `--overlay`, and `--overlay-high`.
1044
+ Saved theme files and component aliases are rebound automatically by
1045
+ `2026-05-26-drop-overlay-extra-stops` (theme v2 to v3, component-config v16 to v17).
1046
+ Consumers who reference the dropped tokens in their own CSS need to point
1047
+ at the nearest kept stop (`-lowest` and `-lower` to `-low`, `-higher` and
1048
+ `-highest` to `-high`).
1049
+
1050
+ ### Added
1051
+
1052
+ - **`--color-white` and `--color-black` invariants** in `tokens.css`. Hard
1053
+ constants outside any ramp; never themed.
1054
+
1055
+ ### Changed (internal, no consumer-visible API impact)
1056
+
1057
+ - Overlays editor section rewritten; `OverlaysSection.svelte` net 550
1058
+ lines lighter.
1059
+ - `UIPaletteSelector` and `UIRelinkConfirmPopover` refactored internally;
1060
+ the latter renamed to `UIRelinkConfirmDialog` (not part of any public export).
1061
+ - Release pipeline migrated to OIDC Trusted Publishing. `RELEASING.md`
1062
+ rewritten so the local steps stop at `git push --tags`; CI handles
1063
+ `npm publish` with provenance attestation. See the new "Publishing (how it
1064
+ actually happens)" section for the full picture.
1065
+
1066
+ ## 0.10.0 — Plugin acts like a dev tool, not a co-tenant
1067
+
1068
+ Live Tokens no longer squats on multiple top-level folders at a consumer's
1069
+ repo root. By default, all data (`themes/`, `manifests/`, `component-configs/`)
1070
+ lives under one folder: `src/live-tokens/data/`. A consumer's root looks like
1071
+ a normal project root again. This release also adds three new system
1072
+ components (`Input`, `SideNavigation`, `ImageLightbox`), a full set of named
1073
+ easing tokens, and several component-config schema cleanups (auto-migrated).
1074
+
1075
+ ### Added
1076
+
1077
+ - **`Input` component** (`src/system/components/Input.svelte` + editor).
1078
+ Supports `text` / `number` / `search` / `password` types, with `label`,
1079
+ `hint`, `error`, password reveal, search-clear, and a `forceFocus` preview
1080
+ hook for the editor.
1081
+ - **`SideNavigation` component** (`src/system/components/SideNavigation.svelte`
1082
+ + editor). Tokenised side-nav with collapsible groups, item icons, and
1083
+ active/hover states.
1084
+ - **`ImageLightbox` component** (`src/system/components/ImageLightbox.svelte`
1085
+ + editor). Click-to-zoom image with backdrop, escape-to-close, and
1086
+ tokenised overlay/chrome.
1087
+ - **Named easing tokens.** 28 curves added to `tokens.css` covering
1088
+ easings.net (`--ease-in-sine` through `--ease-in-out-back`, plus
1089
+ `linear()`-based `--ease-{in,out,in-out}-{elastic,bounce}` and
1090
+ `--ease-linear`).
1091
+ - **`UIEasingSelector`** editor control for picking from the named easing
1092
+ tokens.
1093
+
1094
+ ### Changed (breaking for consumers passing no data-folder options)
1095
+
1096
+ - **`themesDir` is no longer required.** It joins `componentConfigsDir` and
1097
+ `manifestsDir` as optional. Zero-config consumers now get
1098
+ `src/live-tokens/data/{themes,manifests,component-configs}` instead of the
1099
+ previous root-level defaults.
1100
+ - **New `dataDir` option** on `themeFileApi(opts)`. Sets the parent directory
1101
+ for all three subfolders. Default: `src/live-tokens/data`.
1102
+ - **New `live-tokens.config.json`** (optional, at project root). Accepts the
1103
+ same four data-folder keys. Resolution order per folder: explicit
1104
+ `themeFileApi(opts)` argument > matching key in `live-tokens.config.json` >
1105
+ `<dataDir>/<sub>` where dataDir comes from opts > config file > package
1106
+ default. Read once at plugin construction; restart vite to pick up changes.
1107
+ - **Build-time pruning shares the same resolution.** `loadProductionConfig`
1108
+ (used by `buildPruneReplace`) reads through the shared resolver, so
1109
+ `componentConfigsDir` stays consistent across the dev plugin and the
1110
+ preprocessor.
1111
+ - **API routes namespaced.** The default `apiBase` moved from `/api` to
1112
+ `/api/live-tokens`, so the plugin's routes can't collide with the consumer's
1113
+ own `/api/themes` / `/api/manifests`. The client side picks up the
1114
+ resolved base via a `__LIVE_TOKENS_API_BASE__` Vite define so client and
1115
+ server can't drift. Consumers who explicitly passed `apiBase: '/api'` are
1116
+ unaffected.
1117
+ - **Unknown-key warning** on `live-tokens.config.json`. The reader now logs
1118
+ one warning per unrecognised key so `themesDr` doesn't silently degrade to
1119
+ defaults. `$schema` is ignored.
1120
+
1121
+ ### Changed (breaking for saved component configs; auto-migrated on load)
1122
+
1123
+ Five component schemas were tightened. Migrations ship in the same release
1124
+ and run automatically when a stored config is first read, so consumers don't
1125
+ need to edit JSON by hand. Any per-state customisations on the dropped axes
1126
+ are discarded; the default-state value remains authoritative.
1127
+
1128
+ - **Button.** `StandardButtonsEditor` renamed to `ButtonEditor`. Per-state
1129
+ shape tokens (`padding`, `radius`, `border-width`) dropped for `hover` and
1130
+ `disabled` across all variants. They were always linked to the default
1131
+ state at runtime, so the per-state rows in the editor were dead UI.
1132
+ Migration: `2026-05-24-promote-state-shared-tokens`.
1133
+ - **ProgressBar.** Collapsed from a per-variant token namespace
1134
+ (`primary` / `success` / `warning` / `danger` / `info`) to a single flat
1135
+ token set. Fill color is now a runtime `fill` prop on the consumer side,
1136
+ not a variant axis. The `primary` namespace's values become the canonical
1137
+ defaults; non-primary customisations are dropped.
1138
+ Migration: `2026-05-24-progressbar-collapse-variants`.
1139
+ - **SegmentedControl.** `--segmentedcontrol-divider-height` retired in
1140
+ favour of `--segmentedcontrol-divider-inset` (margin-block on a stretched
1141
+ divider, so `Full` = 0 inset = bar-height). Value semantic flipped, so
1142
+ saved customisations are dropped rather than copied. Per-state icon-size
1143
+ tokens for `selected` / `option-hover` / `disabled` also dropped (always
1144
+ linked at runtime).
1145
+ Migrations: `2026-05-24-segmentedcontrol-divider-inset`,
1146
+ `2026-05-24-promote-state-shared-tokens`.
1147
+ - **CollapsibleSection.** Dropped the `active` header state and the matching
1148
+ `&.active` CSS branch. No consumer was using it.
1149
+ Migration: `2026-05-24-collapsiblesection-drop-active-state`.
1150
+ - **CornerBadge.** Per-variant token axis collapsed to a single flat set.
1151
+ Variants only ever carried shape/spacing/type aliases (never colours),
1152
+ and every variant's defaults were identical, so the strip was 10×
1153
+ duplication with no semantic gain.
1154
+ Migration: `2026-05-25-cornerbadge-flatten-variants`.
1155
+
1156
+ ### Migration for existing consumers
1157
+
1158
+ Either keep your current root-level layout by passing explicit options, or
1159
+ relocate your data folders and let defaults take over.
1160
+
1161
+ Keep root layout (one-line config file or explicit option):
1162
+
1163
+ ```json
1164
+ // live-tokens.config.json
1165
+ { "dataDir": "." }
1166
+ ```
1167
+
1168
+ Or move to the new default and drop any data-folder options from
1169
+ `themeFileApi(opts)`:
1170
+
1171
+ ```bash
1172
+ mkdir -p src/live-tokens/data
1173
+ git mv themes src/live-tokens/data/themes
1174
+ git mv manifests src/live-tokens/data/manifests
1175
+ git mv component-configs src/live-tokens/data/component-configs
1176
+ ```
1177
+
1178
+ Stop the vite dev server first — its HMR will pre-create the destination
1179
+ dirs if it picks up the plugin reload mid-move. The source repo itself ships
1180
+ with data at the new default location.
1181
+
1182
+ ## 0.6.0 — Editor CSS isolation
1183
+
1184
+ The editor now self-contains its chrome. A second consumer can `npm install
1185
+ @motion-proto/live-tokens`, import only their own `tokens.css`, mount
1186
+ `<Editor />` or `<ComponentEditorPage />`, and have everything render — no
1187
+ remembered side-imports, no theme-token bleed into editor controls.
1188
+
1189
+ ### Changed (breaking)
1190
+
1191
+ - **`form-controls.css` → `ui-form-controls.css`** with classes renamed
1192
+ `.form-*` → `.ui-form-*` and every theme token re-tokened to the `--ui-*`
1193
+ namespace. Consumers using `.form-input` / `.form-select` directly need to
1194
+ rename. (The only known consumer is `runegoblin-site`, which uses these
1195
+ only via `live-tokens`' own editor components, so no migration needed
1196
+ there.)
1197
+ - **Editor pages auto-load their own CSS.** `Editor.svelte` and
1198
+ `ComponentEditorPage.svelte` now script-import `ui-editor.css`,
1199
+ `ui-form-controls.css`, and `@fortawesome/fontawesome-free/css/all.min.css`.
1200
+ Consumers no longer need to import these in `main.ts`.
1201
+ - **Editor font invariant.** Editor chrome resolves only `--ui-font-*`
1202
+ tokens (a pure system stack defined in `ui-editor.css`). Theme fonts
1203
+ (`--font-sans`, `--font-serif`, `--font-display`, `--font-mono`) can no
1204
+ longer leak into editor controls — `ui-form-controls.css` was the last
1205
+ surface that referenced them.
1206
+
1207
+ ### Removed exports
1208
+
1209
+ | Removed | Replacement |
1210
+ |---|---|
1211
+ | `./styles/form-controls.css` | Auto-loaded; not exported |
1212
+ | `./styles/fonts.css` | `./starter/fonts.css` |
1213
+ | *(implicit)* | `./starter/tokens.css`, `./starter/site.css` |
1214
+
1215
+ `./styles/ui-editor.css` is kept as a read-only window onto the editor token
1216
+ contract; it's no longer a required consumer import.
1217
+
1218
+ ### Added
1219
+
1220
+ - `scripts/check-no-style-imports.mjs` — fails the build if any published
1221
+ `.svelte` `<style>` block contains an `@import`. (This regression killed
1222
+ v0.5.0 under the consumer's `css: 'injected'` workaround.)
1223
+ - `scripts/check-editor-font-isolation.mjs` — fails the build if editor
1224
+ chrome references theme-side font tokens.
1225
+ - `scripts/smoke-install.sh` — packs the library, installs into a temp
1226
+ consumer, and runs `vite build` with no special config. Required to pass
1227
+ in `prepublishOnly`.
1228
+
1229
+ ## 0.5.0 — Svelte 5 migration
1230
+
1231
+ ### Changed (breaking, but with deprecation bridges)
1232
+
1233
+ - Components are now authored in Svelte 5 runes (`$props`, `$state`, `$derived`,
1234
+ `$effect`, snippets). Existing consumer code on Svelte 4 idioms continues to
1235
+ work for one release thanks to the bridges below; both forms are valid in
1236
+ 0.5.0, the legacy form is removed in 0.6.0.
1237
+
1238
+ - **Event dispatch → callback props.** Each public component grew an
1239
+ `oncamelcase` callback prop alongside its existing `createEventDispatcher`
1240
+ event:
1241
+
1242
+ | Component | Legacy `<Comp on:event={fn}>` | Preferred `<Comp onevent={fn}>` |
1243
+ | -------------------- | ----------------------------- | -------------------------------- |
1244
+ | `Button` | `on:click` | `onclick(event: MouseEvent)` |
1245
+ | `SegmentedControl` | `on:change` | `onchange(value: string)` |
1246
+ | `CollapsibleSection` | `on:toggle` | `ontoggle()` |
1247
+ | `TabBar` | `on:tabChange` | `ontabChange(id: string)` |
1248
+ | `RadioButton` | `on:click` | `onclick()` |
1249
+ | `Notification` | `on:dismiss` | `ondismiss()` |
1250
+ | `Dialog` | `on:close` | `onclose()` |
1251
+
1252
+ Both are fired in 0.5.0 (dual-fire). The `createEventDispatcher` calls and
1253
+ the `on:event` legacy bridge are removed in 0.6.0.
1254
+
1255
+ - **Slots → snippets.** Most slots translate one-to-one (default slot →
1256
+ `children` snippet). The hyphenated slots that the `sv migrate` codemod
1257
+ refused to rename automatically were hand-renamed to camelCase identifiers
1258
+ (consumers must rename their `<svelte:fragment slot="x">` to
1259
+ `{#snippet x()}` and update the slot name):
1260
+
1261
+ - `Badge` / `CornerBadge`: `slot="icon"` → `iconSlot` (the `icon` prop's
1262
+ name was kept; the slot was renamed to resolve the collision)
1263
+ - `Dialog`: `slot="footer-left"` → `footerLeft`
1264
+ - `UITokenSelector`: `trigger-preview` → `triggerPreview`,
1265
+ `trigger-text` → `triggerText`, `trigger-title` → `triggerTitle`,
1266
+ `trigger-meta` → `triggerMeta`
1267
+ - `VariantGroup` (component-editor): `state-actions` → `stateActions`,
1268
+ `composite-controls` → `compositeControls`
1269
+
1270
+ Unlike the event bridge, the legacy `<slot>` form cannot coexist with
1271
+ snippets in a runes-mode component, so this part is a hard rename in
1272
+ 0.5.0 — there's no compat window.
1273
+
1274
+ ### Peer ranges
1275
+
1276
+ - `svelte`: `^4.2 || ^5` → `^5` (drops Svelte 4 entirely)
1277
+ - `vite`: `^5 || ^6 || ^7` → `^6 || ^7` (the chosen `@sveltejs/vite-plugin-svelte@^6` peers Vite 6.3+)
1278
+
1279
+ ### Internal
1280
+
1281
+ - Toolchain bumped to `svelte@5.55+`, `vite@7`, `@sveltejs/vite-plugin-svelte@6`,
1282
+ `svelte-check@4`. `compatibility.componentApi: 4` is enabled in
1283
+ `svelte.config.js` so `new Component({ target, props })` (used by tests and
1284
+ by consumers using the Svelte-4 imperative API) keeps working until 0.6.0.
1285
+ - `publicSurface.test.ts` (the green bar from 0.4.0) is still 27/27.
1286
+
1287
+ ## 0.4.0
1288
+
1289
+ ### Changed
1290
+
1291
+ - **Peer ranges widened** so consumers can install on modern toolchains without `--legacy-peer-deps`:
1292
+ - `svelte`: `^4.2` → `^4.2 || ^5`
1293
+ - `vite`: `^5.0` → `^5 || ^6 || ^7`
1294
+ - Components remain authored in Svelte 4 idioms (`export let`, `createEventDispatcher`, `<slot>`). On Svelte 5 they compile in **legacy mode** — the consumer-facing API (`on:event`, named slots, `bind:value`) is preserved. A full migration to runes is planned for a future major.
1295
+
1296
+ ### Internal
1297
+
1298
+ - Added a public-surface test (`src/components/__tests__/publicSurface.test.ts`) that pins the event-dispatch, slot, bind, and mount contracts for every shipped component. This is the green bar the upcoming Svelte 5 rune migration must keep passing.
1299
+
1300
+ ## 0.3.7
1301
+
1302
+ ### Internal
1303
+
1304
+ - Stop shipping colocated `*.test.ts` / `*.spec.ts` files in the npm tarball (negation patterns in `package.json#files`). Drops 8 files / ~57 KB; consumers see no change.
1305
+ - Added `.github/workflows/verify.yml` (lockfile drift, type-check, tests, plugin build, packaging dry-run) — runs on every push to main and on PRs, so release failures surface before tagging.
1306
+ - `publish.yml` now refuses to republish an existing version, runs `npm pack --dry-run` before the irreversible publish, and uses the npm cache.
1307
+
1308
+ ## 0.3.6
1309
+
1310
+ First release published via the GitHub Actions OIDC trusted publisher workflow. `0.3.3`–`0.3.5` were tagged but never reached npm — the lockfile carried stale resolutions from a non-clean local `npm install` and failed `npm ci` in CI. `0.3.6` regenerates the lockfile from a clean state and pins CI to Node 24.
1311
+
1312
+ ### Fixed
1313
+
1314
+ - `GradientCard` (Section Divider gradient editor) now renders the ribbon and stop handles correctly when a stop's color is still at the component's CSS default. Previously the ribbon and unselected diamond handles fell back to gray (`#888`) because the card read `aliases[…]` directly, which only contains user overrides. Stop colors now reference the CSS var so the cascade fills in component defaults (and live edits) the same way `UIPaletteSelector`'s swatch already did.
1315
+
1316
+ ### Internal
1317
+
1318
+ - Added `.github/workflows/publish.yml`: tag push (`v*`) triggers an OIDC-authenticated `npm publish --provenance --access public`. No `NPM_TOKEN` secret; npm trusts this workflow via Trusted Publisher.
1319
+
1320
+ ## 0.3.2
1321
+
1322
+ ### Docs
1323
+
1324
+ - Reframed README around the package as a library-first foundational design system for microsites. Real-time editing of tokens and components is now the headline; the `npx degit` starter is presented as a greenfield convenience rather than the primary consumption path. Added a "File ownership" section documenting which files the vite plugin writes (and when).
1325
+
1326
+ ### Internal
1327
+
1328
+ - Flattened lingering multi-config state in `component-configs/`: removed the unused `callout/default_01.json`, `cornerbadge/default_01.json`, and `segmentedcontrol/green-segment-control.json` and repointed all `_active`/`_production` pointers to `default`. Every shipped component now has a single canonical config.
1329
+
1330
+ ## 0.3.1
1331
+
1332
+ First published release in the 0.3.x line — 0.3.0 was bumped locally but never pushed to npm. No code changes from 0.3.0.
1333
+
1334
+ ## 0.3.0
1335
+
1336
+ ### Breaking
1337
+
1338
+ - Rename "token file" → "theme" throughout, since the saved JSON files are themes (groupings of tokens, fonts, palettes), not individual tokens.
1339
+ - Vite plugin: `tokenFileApi` → `themeFileApi`, options `tokensDir` → `themesDir`, `variablesCssPath` → `tokensCssPath`. Type `TokenFileApiOptions` → `ThemeFileApiOptions`.
1340
+ - Default directory: `tokens/` → `themes/`. Stylesheet: `src/styles/variables.css` → `src/styles/tokens.css`.
1341
+ - API routes: `/api/tokens/*` → `/api/themes/*`. Backup type discriminator `'tokens'` → `'themes'`.
1342
+ - Library exports: `TokenFile` → `Theme`, `TokenFileMeta` → `ThemeMeta`. Service functions renamed (`listTokenFiles` → `listThemes`, `loadTokenFile` → `loadTheme`, `saveTokenFile` → `saveTheme`, `deleteTokenFile` → `deleteTheme`, `getActiveTokens` → `getActiveTheme`, `migrateTokenFileFonts` → `migrateThemeFonts`, `initializeTokens` → `initializeTheme`).
1343
+ - Showcase: `TokenFileManager` component → `ThemeFileManager`.
1344
+ - "design token" terminology preserved for individual CSS variables (`tokenRegistry`, package name, `design-tokens` keyword).
1345
+
1346
+ ## 0.2.0
1347
+
1348
+ Repositioning release: the repo is now officially both a starter template (via `degit`) and a library (via `npm install`). The starter's home route is now an empty stub authors replace, and the old `Landing.svelte` demo content moves to `/kit`.
1349
+
1350
+ ### Breaking
1351
+
1352
+ - `src/pages/Landing.svelte` → renamed to `src/pages/KitDemo.svelte`. The `/` route is now `Home.svelte` (starter stub); the kit demo lives at `/kit`. Starter consumers upgrading a clone should rename their own landing file or rebase onto the new layout.
1353
+ - `src/showcase/index.ts` — `defaultSections` is now a runtime export (re-added after an accidental removal in the 0.1.x line). It also moved out of `ComponentsTab.svelte` into a standalone `src/showcase/defaultSections.ts` so it can be imported without loading all demo components.
1354
+ - `package.json` exports — dropped the unused `./showcase-page`, `./overlay`, and `./columns-overlay` subpaths. `LiveEditorOverlay` and `ColumnsOverlay` are still available from the root import. Consumers who hand-declared ambient `declare module` entries for these in their own `vite-env.d.ts` can delete them.
1355
+ - `LiveEditorOverlay` — the `open` prop is now optional. When unbound, the component self-persists the open/closed state in localStorage. Consumers binding `open` get the same behavior as before.
1356
+
1357
+ ### Added
1358
+
1359
+ - `./admin` export now ships with a `types` branch (`Admin.svelte.d.ts`). Consumers can delete their hand-written `declare module '@motion-proto/live-tokens/admin'` shims.
1360
+ - `tokenFileApi` Vite plugin now auto-injects `__PROJECT_ROOT__` as a `define`. Consumers no longer need to add it to their own `vite.config.ts`.
1361
+ - `LiveEditorOverlay` self-gates dev/iframe/editor-route visibility. Consumers can drop `<LiveEditorOverlay />` without wrapping it in `{#if import.meta.env.DEV && !isInIframe}` boilerplate.
1362
+ - `ColumnsOverlay` self-gates on dev + iframe for the same reason.
1363
+ - Admin "Back to site" button now navigates to the last non-admin route (via `sessionStorage`), falling back to `/kit`.
1364
+ - New `src/pages/Home.svelte` starter stub and `src/pages/KitDemo.svelte` marketing/demo page.
1365
+
1366
+ ### Internal
1367
+
1368
+ - Reworked README with separate "Use as a starter" and "Use as a library" sections.
1369
+ - `src/styles/fonts/` font system, `fontLoader`, `fontMigration`, `fontParse`, `FontStackEditor`, `ProjectFontsSection` added in the 0.1.x line are now documented.
1370
+
1371
+ ## 0.1.1
1372
+
1373
+ Initial scoped-package release extracted from RuneGoblin.