@takazudo/zdtp 0.4.14 → 0.5.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 +163 -0
- package/PORTABLE-CONTRACT.md +386 -91
- package/README.md +268 -95
- package/dist/apply/build-apply-overrides.d.ts +2 -2
- package/dist/apply/compute-hunks.d.ts +23 -0
- package/dist/apply/last-applied.d.ts +5 -0
- package/dist/apply/reconcile-applied.d.ts +19 -0
- package/dist/apply-modal.d.ts +2 -48
- package/dist/astro/host-adapter.js +3 -3
- package/dist/astro/index.js +2 -2
- package/dist/{autoload-state-IlkEci88.js → autoload-state-DmTY6tRy.js} +1 -1
- package/dist/bin/server.js +52 -50
- package/dist/bulk/bulk-actions.d.ts +45 -0
- package/dist/bulk/index.d.ts +2 -0
- package/dist/chain/index.d.ts +2 -0
- package/dist/chain/token-chain-context.d.ts +19 -0
- package/dist/chain/token-chain-popover.d.ts +22 -0
- package/dist/changed/contribution.d.ts +32 -0
- package/dist/changed/footer-content.d.ts +16 -0
- package/dist/changed/index.d.ts +4 -0
- package/dist/changed/tab-badge.d.ts +8 -0
- package/dist/changed/tab-filter.d.ts +8 -0
- package/dist/config/panel-config.d.ts +23 -7
- package/dist/constants.d.ts +66 -0
- package/dist/constants.js +30 -0
- package/dist/controls/actions-menu-popover.d.ts +2 -0
- package/dist/controls/role-button.d.ts +5 -2
- package/dist/controls/tooltip.d.ts +8 -4
- package/dist/element-inspect/element-inspect-context.d.ts +22 -0
- package/dist/element-inspect/element-inspect-orchestrator.d.ts +17 -0
- package/dist/element-inspect/element-inspect-overlay.d.ts +16 -0
- package/dist/element-inspect/element-inspect-toggle-button.d.ts +3 -0
- package/dist/element-inspect/element-inspect-view.d.ts +6 -0
- package/dist/element-inspect/find-tokens-for-element.d.ts +23 -0
- package/dist/element-inspect/index.d.ts +8 -0
- package/dist/highlight/find-elements.d.ts +14 -3
- package/dist/highlight/highlight-orchestrator.d.ts +7 -3
- package/dist/highlight/highlight-state.d.ts +3 -2
- package/dist/highlight/highlight-toggle-button.d.ts +3 -0
- package/dist/highlight/walk-css-rules.d.ts +2 -0
- package/dist/history/buttons.d.ts +28 -0
- package/dist/history/index.d.ts +3 -0
- package/dist/history/rail.d.ts +13 -0
- package/dist/history/snapshots.d.ts +57 -0
- package/dist/host/host-mutations.d.ts +23 -0
- package/dist/{index-EdhZv8Ru.js → index-By6zFdp4.js} +2 -2
- package/dist/index-CHzTi0y5.js +12184 -0
- package/dist/index.js +35 -34
- package/dist/load-routing-BtCE1hGI.js +547 -0
- package/dist/{manifest-DCReQE0k.js → manifest-DvuKi7I4.js} +11 -7
- package/dist/{panel-config-SgA84Uqe.js → panel-config-BSu6TUht.js} +391 -317
- package/dist/picker/alt-click-picker.d.ts +10 -2
- package/dist/picker/arming-coordinator.d.ts +2 -0
- package/dist/picker/index.d.ts +2 -2
- package/dist/search/command-palette.d.ts +21 -0
- package/dist/search/contribution.d.ts +7 -0
- package/dist/search/fuzzy.d.ts +10 -0
- package/dist/search/index.d.ts +4 -0
- package/dist/search/match-bar.d.ts +14 -0
- package/dist/search/search-header.d.ts +7 -0
- package/dist/search/token-search.d.ts +36 -0
- package/dist/server/create-apply-handler.d.ts +33 -0
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.js +1 -1
- package/dist/shell/dock-mode-switch.d.ts +6 -0
- package/dist/shell/footer.d.ts +1 -0
- package/dist/shell/ghost-idle.d.ts +24 -0
- package/dist/shell/header.d.ts +4 -0
- package/dist/shell/layer-activity.d.ts +6 -0
- package/dist/shell/mini-pill.d.ts +21 -0
- package/dist/shell/regions.d.ts +26 -0
- package/dist/shell/shortcut-dispatcher.d.ts +17 -0
- package/dist/shell/tab-bar.d.ts +17 -0
- package/dist/shell/tab-overflow-popover.d.ts +13 -0
- package/dist/specimen/on-page-specimen.d.ts +19 -0
- package/dist/specimen/preview-glyphs.d.ts +2 -0
- package/dist/specimen/specimen-state.d.ts +12 -0
- package/dist/specimen/specimen-tab-body.d.ts +18 -0
- package/dist/specimen/specimen-toolbar.d.ts +10 -0
- package/dist/specimen/specimen-values.d.ts +9 -0
- package/dist/state/history.d.ts +64 -0
- package/dist/state/persist.d.ts +10 -14
- package/dist/state/transaction.d.ts +24 -0
- package/dist/state/tweak-state.d.ts +16 -0
- package/dist/styles/z-index-tokens.d.ts +2 -0
- package/dist/tabs/color-tab.d.ts +10 -1
- package/dist/tabs/flat/flat-tab.d.ts +27 -0
- package/dist/tabs/flat/index.d.ts +8 -0
- package/dist/tabs/flat/scroll-to-token-row.d.ts +3 -0
- package/dist/tabs/flat/tier-section.d.ts +17 -0
- package/dist/tabs/flat/token-controller.d.ts +23 -0
- package/dist/tabs/flat/token-row.d.ts +12 -0
- package/dist/tabs/flat/types.d.ts +25 -0
- package/dist/tabs/font-tab.d.ts +13 -12
- package/dist/tabs/generic-tab.d.ts +8 -38
- package/dist/tabs/palette/palette-check-view.d.ts +5 -1
- package/dist/tabs/palette/palette-edit-view.d.ts +9 -1
- package/dist/tabs/palette/palette-tab.d.ts +12 -1
- package/dist/tabs/size-tab.d.ts +7 -10
- package/dist/tabs/spacing-tab.d.ts +7 -13
- package/dist/testing.js +3 -3
- package/dist/tokens/tier-model.d.ts +6 -0
- package/dist/{tweak-state-DGLrzIwq.js → tweak-state-B7ok3Ob3.js} +473 -423
- package/dist/utils/numeric-transform.d.ts +32 -0
- package/dist/utils/token-diff.d.ts +25 -0
- package/dist/utils/token-graph.d.ts +23 -0
- package/dist/utils/token-index.d.ts +30 -0
- package/dist/zdtp.css +1 -1
- package/package.json +8 -1
- package/dist/controls/pill-slider-row.d.ts +0 -36
- package/dist/controls/select-row.d.ts +0 -25
- package/dist/controls/slider-row.d.ts +0 -29
- package/dist/controls/text-row.d.ts +0 -27
- package/dist/index-Ds4bCeiC.js +0 -7591
- package/dist/load-routing-D4H2VOl5.js +0 -426
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @takazudo/zdtp
|
|
2
2
|
|
|
3
|
-
A live-tweak design-token panel for Astro sites. Drop a single `<DesignTokenPanelHost>` component into your layout, hand it a `PanelConfig`, and your users get an in-page UI for adjusting CSS custom properties (spacing, typography, sizing, color palette + semantic roles). Changes apply to `:root`
|
|
3
|
+
A live-tweak design-token panel for Astro sites. Drop a single `<DesignTokenPanelHost>` component into your layout, hand it a `PanelConfig`, and your users get an in-page UI for adjusting CSS custom properties (spacing, typography, sizing, color palette + semantic roles). Changes apply instantly to the default `:root` target (or to a configured `applySink`), persist to `localStorage`, and survive view transitions and hard reloads.
|
|
4
4
|
|
|
5
|
-
The package is portable: every project-specific identifier is driven by the host's `PanelConfig`. Storage keys, console namespace, modal class prefix, schema id, and the entire tab configuration (tiers, items, color cluster extras) are all configured by the consumer. Every config field is JSON-serializable so the configuration crosses the Astro frontmatter → client island boundary without losing fidelity.
|
|
5
|
+
The package is portable: every project-specific identifier is driven by the host's `PanelConfig`. Storage keys, console namespace, modal class prefix, schema id, and the entire tab configuration (tiers, items, color cluster extras) are all configured by the consumer. Every config field except the function-valued `applySink` is JSON-serializable, so the configuration crosses the Astro frontmatter → client island boundary without losing fidelity.
|
|
6
6
|
|
|
7
7
|
The panel uses an **abstract token tier model**: all token categories — spacing, typography, size, and color — are expressed as `TabConfig` / `TierConfig` / `TierItem` structures on `PanelConfig.tabs`. A "ref tier" mechanism lets semantic tokens reference base tokens, and the apply pipeline emits `var(--base-cssvar)` for ref-tier items. See `PORTABLE-CONTRACT.md` §3 for the full tier model spec.
|
|
8
8
|
|
|
@@ -10,23 +10,53 @@ The authoritative API spec is [`PORTABLE-CONTRACT.md`](./PORTABLE-CONTRACT.md).
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
- Token tabs and tiers for spacing, typography, sizing, color, and host-defined
|
|
16
|
+
token families, with reference-tier aliases and kind-specific editors.
|
|
17
|
+
- Fuzzy token search, cross-tab counts, and a `Cmd/Ctrl+K` command palette.
|
|
18
|
+
- Changed-row markers, per-row revert, tab badges, **Changed only**, **Copy
|
|
19
|
+
diff**, and **Revert all**.
|
|
20
|
+
- Undo/redo history plus persisted A/B snapshots.
|
|
21
|
+
- Numeric ramp selection and bulk multiply, add, round-to-step, or set-all
|
|
22
|
+
operations.
|
|
23
|
+
- Resolution-chain popovers with dependents, ramp siblings, blast radius, and
|
|
24
|
+
on-demand used-on-page counts.
|
|
25
|
+
- Ten-slot token-user highlights, element inspect, element path, and the
|
|
26
|
+
optional DOM Tweaker, coordinated around one Alt+click owner.
|
|
27
|
+
- In-panel type, line-height, family, weight, bar, radius, and duration
|
|
28
|
+
previews, plus a host-page specimen rendered with the site's real font.
|
|
29
|
+
- Float, right-dock, bottom-dock, mini-pill, ghost-idle, and optional
|
|
30
|
+
body-margin reflow modes.
|
|
31
|
+
- Debounced apply previews with file digests and hunks, stale-write protection,
|
|
32
|
+
partial reconciliation, and JSON export/import when disk apply is not
|
|
33
|
+
configured.
|
|
34
|
+
- Owner autoload for developer-only loading across page visits.
|
|
35
|
+
|
|
36
|
+
See the [Panel UX tour](/docs/recipes/panel-ux-tour) for a feature-by-feature
|
|
37
|
+
walkthrough and the shortcut table.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
13
41
|
## 0. Architecture at a glance
|
|
14
42
|
|
|
15
|
-
The design-token panel is a browser-based UI that writes token overrides to
|
|
43
|
+
The design-token panel is a browser-based UI that writes token overrides to
|
|
44
|
+
`:root` by default (or through `PanelConfig.applySink`), with an optional
|
|
45
|
+
**apply pipeline** for persisting those overrides back to disk source files.
|
|
16
46
|
|
|
17
47
|
```
|
|
18
48
|
┌─ Your dev server (Astro / Vite / any host) ──────┐
|
|
19
49
|
│ │
|
|
20
50
|
│ Panel UI (browser) ←─────────────────────────> │ Host adapter (side-effect import)
|
|
21
51
|
│ ↓ (user tweaks) │
|
|
22
|
-
│ POST /apply (
|
|
52
|
+
│ POST /apply (preview, then confirmed write) │ Apply endpoint (routes tokens to files)
|
|
23
53
|
│ ↓ │
|
|
24
54
|
└──────────────────────────────────────────────────┘
|
|
25
55
|
│
|
|
26
56
|
│ (HTTP)
|
|
27
57
|
↓
|
|
28
58
|
┌─ design-token-panel bin server ───────────────┐
|
|
29
|
-
│ Receives POST /apply
|
|
59
|
+
│ Receives POST /apply preview/write requests │
|
|
30
60
|
│ Validates tokens & paths │
|
|
31
61
|
│ Rewrites source CSS files atomically │
|
|
32
62
|
│ (respects --write-root sandbox) │
|
|
@@ -44,7 +74,7 @@ A Preact-rendered side panel that:
|
|
|
44
74
|
- Reads a host-supplied **tab configuration** (`PanelConfig.tabs`) — an array of `TabConfig` entries where each tab owns one or more `TierConfig` objects, each holding an array of `TierItem` entries. Sliders (`length` / `number`), selects, text inputs, color pickers, and pill toggles are all supported via a discriminated `TierValueKind`.
|
|
45
75
|
- Supports **abstract tier references**: a `TierConfig` can carry `referencesTier` to point at a base tier; the apply pipeline emits `var(--base-cssvar)` for each ref-tier item, encoding semantic → base token aliasing in the config data model.
|
|
46
76
|
- Renders a **color tab** (id `'color'`) from the same tab model — palette and semantic tokens are `TierItem` arrays, and the structural metadata (base roles, scheme registry, panel settings) lives in `TabConfig.colorExtras`.
|
|
47
|
-
- Writes every override to `document.documentElement.style.setProperty(...)` against the consumer-supplied CSS-var names — so your stylesheet can be plain CSS, CSS Modules, Tailwind, or anything else.
|
|
77
|
+
- Writes every override to the default `document.documentElement.style.setProperty(...)` target (or to the configured `applySink`) against the consumer-supplied CSS-var names — so your stylesheet can be plain CSS, CSS Modules, Tailwind, or anything else.
|
|
48
78
|
- Persists state to `localStorage` under a host-chosen prefix and re-applies overrides synchronously on next page load (no FOUT — this is a hard requirement of the contract).
|
|
49
79
|
- Exposes a small console API (`window.<namespace>.showDesignPanel()` etc.) so a developer can pop the panel without it being mounted on every page.
|
|
50
80
|
- Plugs into Astro's view-transition lifecycle (`astro:before-swap` / `astro:page-load`) so soft navigation does not double-mount the panel.
|
|
@@ -111,13 +141,13 @@ pnpm exec zdtp-server --help
|
|
|
111
141
|
|
|
112
142
|
| Flag | Required | Purpose | Default |
|
|
113
143
|
|---|---|---|---|
|
|
114
|
-
| `--routing <path>` | yes | Path to the routing JSON file (
|
|
144
|
+
| `--routing <path>` | yes | Path to the routing JSON file (CSS-var prefix family → repo-relative CSS file path). Absolute, or relative to `--root`. See §3.2. | — |
|
|
115
145
|
| `--write-root <dir>` | yes | Required write boundary: the only directory tree the bin is allowed to write into. Absolute, or relative to `--root`. | — |
|
|
116
146
|
| `--root <dir>` | no | CWD/resolution base used to resolve `--routing` and `--write-root`. | `process.cwd()` |
|
|
117
147
|
| `--port <number>` | no | TCP port to bind. `0` asks the OS for an ephemeral port (the bin logs the assigned port on startup). | `24681` |
|
|
118
148
|
| `--host <addr>` | no | Bind address. Use `0.0.0.0` to expose on the LAN (off by default). | `127.0.0.1` |
|
|
119
149
|
| `--allow-origin <origin>` | repeatable | Origin allowed to POST to `/apply` (scheme + host + port, no trailing slash). At least one is required for any browser to apply. | none (all origins denied) |
|
|
120
|
-
| `--quiet` | no | Suppress the startup banner and
|
|
150
|
+
| `--quiet` | no | Suppress the startup banner, no-allow-origin warning, and per-request summary logs. | off |
|
|
121
151
|
| `--help`, `-h` | no | Print usage and exit 0. | — |
|
|
122
152
|
|
|
123
153
|
Generic invocation, run from your consumer repo root:
|
|
@@ -133,7 +163,7 @@ The bin reads the routing JSON once at startup and does not hot-reload it. Resta
|
|
|
133
163
|
|
|
134
164
|
### 3.2 Routing configuration
|
|
135
165
|
|
|
136
|
-
The routing JSON is a top-level object mapping **
|
|
166
|
+
The routing JSON is a top-level object mapping a **CSS-var prefix family** (without the leading `--` and trailing `-`) to a **repo-relative CSS file path**. Each path receives the apply pipeline's serialised writes for that prefix family. The keys must match the keys used in your `PanelConfig.applyRouting` (the panel UI loads from this same JSON file — see §5).
|
|
137
167
|
|
|
138
168
|
Generic example:
|
|
139
169
|
|
|
@@ -181,7 +211,7 @@ While the bin is running it exposes a tiny HTTP surface:
|
|
|
181
211
|
|
|
182
212
|
- **`GET /healthz`** — returns `200 OK` with `{"ok":true,"writeRoot":"…","routing":"…","port":…}` once the listener is up. Useful for dev-server readiness checks.
|
|
183
213
|
- **`OPTIONS /apply`** — CORS preflight. Returns `204` with `Access-Control-Allow-{Origin,Methods,Headers,Max-Age}` headers when the request's `Origin` is on the allow-list, and `403` otherwise.
|
|
184
|
-
- **`POST /apply`** — applies a token-overrides payload via the apply pipeline. The body is `application/json` with a top-level `tokens` object whose keys are CSS-var names (e.g. `--brand-primary`) and whose values are CSS values. See §6 for the full token-manifest schema and §6.
|
|
214
|
+
- **`POST /apply`** — applies a token-overrides payload via the apply pipeline. The body is `application/json` with a top-level `tokens` object whose keys are CSS-var names (e.g. `--brand-primary`) and whose values are CSS values. See §6 for the full token-manifest schema and §6.5 for apply-time behaviour. A non-JSON content type returns `415`; an unallowed origin returns `403`.
|
|
185
215
|
- **Anything else** — `404` for unknown paths and `405` for unsupported methods on `/apply`.
|
|
186
216
|
|
|
187
217
|
The bin is intended to run as a subprocess of your dev server (`concurrently`, `npm-run-all`, a custom Node wrapper, etc.) and exits cleanly under host control:
|
|
@@ -260,7 +290,6 @@ const spacingTier: TierConfig = {
|
|
|
260
290
|
id: 'spacing-md',
|
|
261
291
|
cssVar: '--myapp-spacing-md',
|
|
262
292
|
label: 'Spacing M',
|
|
263
|
-
group: 'hsp',
|
|
264
293
|
default: '1rem',
|
|
265
294
|
type: { kind: 'length', step: 0.0625, unit: 'rem' },
|
|
266
295
|
},
|
|
@@ -313,7 +342,7 @@ import { myPanelConfig } from '../lib/my-panel-config';
|
|
|
313
342
|
</html>
|
|
314
343
|
|
|
315
344
|
<script>
|
|
316
|
-
// Required side-effect load — see §
|
|
345
|
+
// Required side-effect load — see §12.1 for the rationale. Use a dynamic
|
|
317
346
|
// `void import(...)` here, NOT a top-level `import '...';` statement.
|
|
318
347
|
void import('@takazudo/zdtp/astro/host-adapter');
|
|
319
348
|
</script>
|
|
@@ -377,7 +406,7 @@ The Astro recipe above shows the case where a host owns the config import and th
|
|
|
377
406
|
|
|
378
407
|
**Worked example:** the [Astro](https://github.com/Takazudo/zudo-design-token-panel-example-astro), [Vite + React](https://github.com/Takazudo/zudo-design-token-panel-example-vite-react), and [Next.js](https://github.com/Takazudo/zudo-design-token-panel-example-nextjs) example repos prove the contract end-to-end. Each ships:
|
|
379
408
|
|
|
380
|
-
- A host-side config file with deliberately different names (e.g. `--astro-palette-
|
|
409
|
+
- A host-side config file with deliberately different names (e.g. explicit `--astro-palette-0` / `--astro-palette-1` items, `astro` namespace).
|
|
381
410
|
- A routing JSON file at the example's root.
|
|
382
411
|
- A bin invocation via `concurrently` in the dev script, pointing at that routing file.
|
|
383
412
|
|
|
@@ -385,6 +414,57 @@ Copy an example's structure when porting the panel into a new host.
|
|
|
385
414
|
|
|
386
415
|
If you are building a **Rust SSG** or other non-Node host, the bin still runs as a sidecar Node.js subprocess (started by your host's build orchestration). The same routing JSON and host-adapter setup applies — the only difference is your host ships its own config format (not TypeScript) and you invoke the bin via your build system's subprocess spawner rather than npm scripts.
|
|
387
416
|
|
|
417
|
+
#### Pre-import activation from a custom host
|
|
418
|
+
|
|
419
|
+
The side-effect-free `@takazudo/zdtp/constants` subpath exposes
|
|
420
|
+
`DEFAULT_STORAGE_PREFIX`, `DEFAULT_TOGGLE_EVENT`, and
|
|
421
|
+
`resolveToggleEventName` without importing the panel. It also exports the
|
|
422
|
+
machine-readable eager-load metadata (`EAGER_LOAD_GATE_KEY_SUFFIXES` and
|
|
423
|
+
`EAGER_LOAD_GATE_STATE_FAMILY`); the exact gate contract lives in
|
|
424
|
+
[`PORTABLE-CONTRACT.md`](./PORTABLE-CONTRACT.md) §6.2.
|
|
425
|
+
|
|
426
|
+
A custom host can use those constants to register its toggle listener in the
|
|
427
|
+
initial bundle and fetch the panel only when activated. Keep the stylesheet
|
|
428
|
+
setup from §4.2 (or import `@takazudo/zdtp/styles` in your host stylesheet
|
|
429
|
+
pipeline):
|
|
430
|
+
|
|
431
|
+
```ts
|
|
432
|
+
import type { PanelConfig } from '@takazudo/zdtp';
|
|
433
|
+
import { resolveToggleEventName } from '@takazudo/zdtp/constants';
|
|
434
|
+
|
|
435
|
+
// Call once with your complete config (for example myPanelConfig in §4.1.1).
|
|
436
|
+
export function installLazyPanel(config: PanelConfig): void {
|
|
437
|
+
const toggleEvent = resolveToggleEventName(config);
|
|
438
|
+
let loading: Promise<void> | undefined;
|
|
439
|
+
|
|
440
|
+
function loadOnToggle(): void {
|
|
441
|
+
if (loading) return;
|
|
442
|
+
loading = import('@takazudo/zdtp')
|
|
443
|
+
.then(({ configurePanel }) => {
|
|
444
|
+
configurePanel(config);
|
|
445
|
+
window.removeEventListener(toggleEvent, loadOnToggle);
|
|
446
|
+
window.dispatchEvent(new CustomEvent(toggleEvent));
|
|
447
|
+
})
|
|
448
|
+
.catch((error: unknown) => {
|
|
449
|
+
loading = undefined;
|
|
450
|
+
console.error('Failed to load @takazudo/zdtp', error);
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
window.addEventListener(toggleEvent, loadOnToggle);
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
The default `DEFAULT_STORAGE_PREFIX` is
|
|
459
|
+
`'zudo-design-token-panel'`, and its `DEFAULT_TOGGLE_EVENT` is
|
|
460
|
+
`'toggle-design-token-panel'`. `resolveToggleEventName` preserves that
|
|
461
|
+
historical event even when a default-prefix config supplies `toggleEvent`; a
|
|
462
|
+
non-default prefix uses its supplied `toggleEvent`, or derives
|
|
463
|
+
`toggle-${storagePrefix}` when the override is omitted. The same config
|
|
464
|
+
resolves the listener event and configures the loaded panel. This activation-only
|
|
465
|
+
example does not implement the saved-state eager-load gate; see §6.2 of the
|
|
466
|
+
contract when building a complete host adapter.
|
|
467
|
+
|
|
388
468
|
### 4.3 Recipe — Rust SSG (zfb)
|
|
389
469
|
|
|
390
470
|
Worked example for the case where the host is a Rust dev server (e.g. [zfb / zudo-front-builder](https://github.com/Takazudo/zudo-front-builder)) rather than a Node-based runner. The bin itself is unchanged — it remains a Node.js subprocess invoked as `node path/to/dist/bin/server.js ...`. The Rust host's only job is to spawn that Node process, forward shutdown signals to it, and configure `--allow-origin` so the browser POST from the panel UI is accepted.
|
|
@@ -504,12 +584,17 @@ default instance only.
|
|
|
504
584
|
| `storagePrefix` | `string` | Base for every derived `localStorage` key. Also the instance id. See §9. |
|
|
505
585
|
| `consoleNamespace` | `string` | Global object the package installs `showDesignPanel` / `hideDesignPanel` / `toggleDesignPanel` on (e.g. `consoleNamespace: 'myapp'` → `window.myapp.showDesignPanel`). |
|
|
506
586
|
| `modalClassPrefix` | `string` | BEM root class for every modal the panel owns (export, import, apply). Emits `${prefix}__overlay`, `${prefix}__panel`, etc. |
|
|
507
|
-
| `schemaId` | `string` | **Display-only** label
|
|
587
|
+
| `schemaId` | `string` | **Display-only** label returned by `getDesignTokenSchema()`. The built-in import/export UI does not read it; `serialize()` emits canonical `SCHEMA_V2`/`SCHEMA_V3` and `deserialize()` validates canonical `SCHEMA_V1`/`V2`/`V3`. See §14's migration recipe. |
|
|
508
588
|
| `exportFilenameBase` | `string` | Default download filename base — exports save as `${exportFilenameBase}.json`. |
|
|
509
589
|
| `toggleEvent` | `string` (optional) | Window-event name that toggles THIS instance. Defaults to `toggle-${storagePrefix}` for non-default instances; the default instance keeps `toggle-design-token-panel`. |
|
|
510
590
|
| `tabs` | `readonly TabConfig[]` | **Required.** Tab strip data — each entry is a tab with one or more `TierConfig` objects. The color tab (id `'color'`) additionally requires `colorExtras`. See §6. |
|
|
511
591
|
| `colorPresets` | `Record<string, ColorScheme>` (optional) | Optional named scheme presets surfaced in the Color tab "Scheme..." dropdown. Defaults to `{}`. See §7.5. |
|
|
592
|
+
| `applyEndpoint` | `string` (optional) | Browser POST target for apply previews and confirmed writes. See §3 and [Apply pipeline reference](/docs/reference/apply-pipeline). |
|
|
593
|
+
| `applyRouting` | `Record<string, string>` (optional) | CSS-var prefix-family to repo-relative CSS-file routing map used by the apply endpoint. |
|
|
512
594
|
| `applySink` | `ApplySink` (optional) | Optional sink that routes this instance's CSS-var writes off `:root`. See §5.4. Not JSON-serializable — do not include in Astro inline config. |
|
|
595
|
+
| `domTweaker` | `DomTweakerConfig` (optional) | Enables the development-only Tailwind class editor and its Alt+click owner. See [DOM Tweaker reference](/docs/reference/dom-tweaker). |
|
|
596
|
+
| `dock` | `PanelDockConfig` (optional) | Controls right/bottom host reflow. Defaults to `{ reflow: 'body-margin' }`; see [configurePanel](/docs/reference/configure-panel#dock--optional-host-reflow). |
|
|
597
|
+
| `legacyIdRenameMap` | `Record<string, string \| null>` (optional) | Maps renamed persisted ids to new ids, or drops ids with `null`, during load. |
|
|
513
598
|
| `autoRememberOnOpen` | `boolean` (optional) | Whether opening the panel (any of the auto-remember call sites — see §10.1) writes the `:autoload` flag with `'auto'` provenance. Defaults to `true`. Set `false` for a public site that wants a panel-open button visible to every visitor without arming owner-mode for whoever clicks it. `enableAutoload()`'s explicit `'1'` write is unaffected either way. See §10.1's Auto-remember footgun. |
|
|
514
599
|
|
|
515
600
|
### 5.4 `applySink` — optional write target
|
|
@@ -561,10 +646,10 @@ const handle = configurePanel({
|
|
|
561
646
|
The Astro entry point (`<DesignTokenPanelHost>`) handles mounting for you. Internally:
|
|
562
647
|
|
|
563
648
|
- The console API (`showDesignPanel` etc.) is **always installed eagerly**, even when the panel module has not loaded — calling them is what triggers the lazy import for cold-start users.
|
|
564
|
-
- The panel module is **dynamically imported on first need**: when the user calls a console helper, OR when first-paint detects any of these gate signals in `localStorage` — `${storagePrefix}:visible` set to `1` or its `${storagePrefix}-open` mirror set to `1`, persisted overrides (a content check across the `${storagePrefix}-state` family — `-state` (v1) through every `-state-vN` — rather than a presence check on a specific version key; see §9), the owner-autoload flag (`${storagePrefix}:autoload` set to `'1'` or `'auto'`), or the element-path inspector enabled.
|
|
565
|
-
- This gating keeps the panel out of the initial JS
|
|
649
|
+
- The panel module is **dynamically imported on first need**: when the user calls a console helper, OR when first-paint detects any of these gate signals in `localStorage` — `${storagePrefix}:visible` set to `1` or its `${storagePrefix}-open` mirror set to `1`, persisted overrides (a content check across the `${storagePrefix}-state` family — `-state` (v1) through every `-state-vN` — rather than a presence check on a specific version key; see §9), the owner-autoload flag (`${storagePrefix}:autoload` set to `'1'` or `'auto'`), or the element-path inspector enabled. `${storagePrefix}-domtweaker-enabled` is also a gate signal when `domTweaker` is configured.
|
|
650
|
+
- This gating keeps the panel bundle out of the initial JS payload for first-time visitors while still re-applying overrides on hard reload for users who have tweaked things. **General visitors** (none of these signals set) pay no panel-bundle cost; the small host adapter/config bootstrap still runs.
|
|
566
651
|
|
|
567
|
-
For a Vite-only / non-Astro host, mount it yourself by importing the adapter module after `configurePanel(...)`. See §
|
|
652
|
+
For a Vite-only / non-Astro host, mount it yourself by importing the adapter module after `configurePanel(...)`. See §8.5.
|
|
568
653
|
|
|
569
654
|
### 5.6 First-open geometry
|
|
570
655
|
|
|
@@ -589,24 +674,22 @@ spec; this section is the consumer-oriented summary.
|
|
|
589
674
|
|
|
590
675
|
```ts
|
|
591
676
|
export type TierValueKind =
|
|
592
|
-
| { kind: 'length'; step: number; unit: string }
|
|
593
|
-
| { kind: 'number'; step: number }
|
|
677
|
+
| { kind: 'length'; step: number; unit: string; units?: readonly string[] }
|
|
678
|
+
| { kind: 'number'; step: number; unit?: string }
|
|
594
679
|
| { kind: 'select'; options: readonly string[] }
|
|
595
680
|
| { kind: 'text' }
|
|
596
681
|
| { kind: 'cursor' }
|
|
597
682
|
| { kind: 'content' }
|
|
598
683
|
| { kind: 'mask-image' }
|
|
599
|
-
| { kind: 'color' };
|
|
684
|
+
| { kind: 'color'; format?: 'hex' | 'oklch' };
|
|
600
685
|
|
|
601
686
|
export interface TierItem {
|
|
602
687
|
/** Stable id used as the key in persisted state (e.g. `hsp-2xs`). */
|
|
603
688
|
id: string;
|
|
604
|
-
/** CSS custom property written to
|
|
689
|
+
/** CSS custom property written to the default root or configured apply sink (e.g. `--myapp-spacing-md`). */
|
|
605
690
|
cssVar: string;
|
|
606
691
|
/** Display label shown in the panel row. */
|
|
607
692
|
label: string;
|
|
608
|
-
/** Optional manifest group — tab components use this for section headers. */
|
|
609
|
-
group?: string;
|
|
610
693
|
/** Default value as a CSS string (`0.125rem`, `12px`, etc.). */
|
|
611
694
|
default: string;
|
|
612
695
|
/** Discriminated union describing the control kind and its metadata. */
|
|
@@ -631,16 +714,29 @@ export interface TierConfig {
|
|
|
631
714
|
* apply pipeline emits `var(--target-cssvar)` for ref-tier items.
|
|
632
715
|
*/
|
|
633
716
|
referencesTier?: string;
|
|
717
|
+
/** Marks a color tier as semantic data rather than a palette tier. */
|
|
718
|
+
semantic?: true;
|
|
719
|
+
/** Allowed ramp sources for per-row semantic references on color tabs. */
|
|
720
|
+
referencesRamps?: readonly { tab?: string; tier: string }[];
|
|
721
|
+
/** Optional visual preview rendered for this tier in the panel. */
|
|
722
|
+
preview?: 'size' | 'line-height' | 'family' | 'weight' | 'bar' | 'radius' | 'duration';
|
|
723
|
+
/** CSS variable used as the base for a preview, when supplied. */
|
|
724
|
+
previewBase?: string;
|
|
634
725
|
}
|
|
635
726
|
|
|
636
727
|
export interface TabConfig {
|
|
637
728
|
id: string;
|
|
638
729
|
label: string;
|
|
639
730
|
tiers: readonly TierConfig[];
|
|
640
|
-
/** Tier ids hidden behind an Advanced disclosure. */
|
|
641
|
-
advancedTiers?: readonly string[];
|
|
642
731
|
/** Required on color tabs (id 'color' / 'color-secondary'). */
|
|
643
732
|
colorExtras?: ColorClusterExtras;
|
|
733
|
+
/** Required on the reserved 'notes' tab; forbidden on other tabs. */
|
|
734
|
+
notesExtras?: NotesExtras;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
export interface NotesExtras {
|
|
738
|
+
title: string;
|
|
739
|
+
html: string;
|
|
644
740
|
}
|
|
645
741
|
```
|
|
646
742
|
|
|
@@ -662,7 +758,6 @@ export const spacingTab: TabConfig = {
|
|
|
662
758
|
id: 'spacing-md',
|
|
663
759
|
cssVar: '--myapp-spacing-md',
|
|
664
760
|
label: 'Spacing M',
|
|
665
|
-
group: 'hsp',
|
|
666
761
|
default: '1rem',
|
|
667
762
|
type: { kind: 'length', step: 0.0625, unit: 'rem' },
|
|
668
763
|
},
|
|
@@ -747,8 +842,8 @@ export interface ColorScheme {
|
|
|
747
842
|
cursor: number | string;
|
|
748
843
|
selectionBg: number | string;
|
|
749
844
|
selectionFg: number | string;
|
|
750
|
-
palette: readonly string[]; //
|
|
751
|
-
shikiTheme
|
|
845
|
+
palette: readonly string[]; // the public type requires exactly 16 entries
|
|
846
|
+
shikiTheme?: string;
|
|
752
847
|
semantic?: Record<string, number | string>;
|
|
753
848
|
}
|
|
754
849
|
```
|
|
@@ -798,9 +893,13 @@ the JSON round-trip.
|
|
|
798
893
|
|
|
799
894
|
For each palette `TierItem` in the palette tier, the panel writes
|
|
800
895
|
`item.cssVar` ← `palette[i]` from the active scheme / user override. For
|
|
801
|
-
each declared base role,
|
|
802
|
-
|
|
803
|
-
|
|
896
|
+
each declared base role, the live DOM apply path writes the role's CSS-var ←
|
|
897
|
+
`palette[state[roleKey]]`. The disk `buildApplyOverrides` payload
|
|
898
|
+
intentionally contains palette and semantic CSS variables only; base roles are
|
|
899
|
+
runtime wiring and are not emitted into source-file rewrites.
|
|
900
|
+
For each semantic `TierItem`, it resolves the mapping and writes the emitted
|
|
901
|
+
CSS value: `var(...)` for a palette/reference mapping, a literal string for a
|
|
902
|
+
literal mapping, or `light-dark(light, dark)` for a per-mode literal.
|
|
804
903
|
|
|
805
904
|
Roles absent from `colorExtras.baseRoles` are not written, so a minimalist
|
|
806
905
|
cluster (just `background` + `foreground`) is fine.
|
|
@@ -809,7 +908,7 @@ cluster (just `background` + `foreground`) is fine.
|
|
|
809
908
|
|
|
810
909
|
The Color tab's "Scheme..." dropdown surfaces named `ColorScheme` entries. Two sources feed it:
|
|
811
910
|
|
|
812
|
-
1. **`
|
|
911
|
+
1. **`colorExtras.colorSchemes`** — the color tab's bundled scheme registry. Always present, typically holds your default scheme(s) (`"Default"`, `"Default Light"` / `"Default Dark"`).
|
|
813
912
|
2. **`PanelConfig.colorPresets`** — an optional, host-supplied preset map for an additional, larger preset library. Defaults to `{}` — the package itself ships zero presets.
|
|
814
913
|
|
|
815
914
|
This split exists so a host that just wants the panel for a single scheme (zero or one cluster scheme) does not pay for a long preset blob, while a host that wants to ship a "playground" of curated schemes (Dracula / Solarized / Tokyo Night / etc.) drops them into a single config field.
|
|
@@ -829,7 +928,7 @@ const myPresets: Record<string, ColorScheme> = {
|
|
|
829
928
|
selectionBg: '#44475a',
|
|
830
929
|
selectionFg: '#ffffff',
|
|
831
930
|
palette: [
|
|
832
|
-
// 16 hex strings —
|
|
931
|
+
// 16 hex strings — the ColorScheme type's fixed palette length
|
|
833
932
|
'#21222c',
|
|
834
933
|
'#ff5555',
|
|
835
934
|
'#50fa7b',
|
|
@@ -854,7 +953,7 @@ const myPresets: Record<string, ColorScheme> = {
|
|
|
854
953
|
};
|
|
855
954
|
|
|
856
955
|
export const myPanelConfig: PanelConfig = {
|
|
857
|
-
// ... storagePrefix,
|
|
956
|
+
// ... storagePrefix, tabs (including the color tab), etc.
|
|
858
957
|
colorPresets: myPresets,
|
|
859
958
|
};
|
|
860
959
|
```
|
|
@@ -868,7 +967,7 @@ export const myPanelConfig: PanelConfig = {
|
|
|
868
967
|
|
|
869
968
|
**Key collision** — if a `colorPresets` key matches a `colorExtras.colorSchemes` key, the bundled scheme wins for `handleLoadPreset`. Rename one of the keys if you want both to be selectable.
|
|
870
969
|
|
|
871
|
-
**JSON-serializable** — every `ColorScheme` is plain JSON, same as the rest of the config (§
|
|
970
|
+
**JSON-serializable** — every `ColorScheme` is plain JSON, same as the rest of the config (§8.2). The host-supplied preset map crosses the Astro frontmatter → island boundary as part of the serialised `PanelConfig`.
|
|
872
971
|
|
|
873
972
|
> **Note on preset libraries.** The package ships zero baked-in scheme presets — the long preset blob (Dracula / Solarized / Tokyo Night / etc.) historically baked into earlier internal versions has been moved out of the package so consumers do not pay for a preset library they do not use. Hosts that want a curated preset list ship it themselves through `panelConfig.colorPresets`.
|
|
874
973
|
|
|
@@ -903,7 +1002,7 @@ Astro stringifies props at render time. **Functions, class instances, and `undef
|
|
|
903
1002
|
When the consumer site renders Astro's `<ClientRouter />`, the panel's host adapter automatically wires:
|
|
904
1003
|
|
|
905
1004
|
- `astro:before-swap` → unmount the Preact tree (`render(null, root)`), remove the host node, snapshot visibility intent so the remount decision survives the body swap.
|
|
906
|
-
- `astro:page-load` → re-apply persisted overrides + re-materialise the shell when
|
|
1005
|
+
- `astro:page-load` → re-apply persisted overrides + re-materialise the shell when any visibility, autoload, enabled-feature, or non-empty persisted-state signal is set.
|
|
907
1006
|
|
|
908
1007
|
No additional wiring needed in your layout beyond importing `<ClientRouter />` from `astro:transitions`.
|
|
909
1008
|
|
|
@@ -962,10 +1061,24 @@ Behaviour notes:
|
|
|
962
1061
|
| `state-v3` | `${storagePrefix}-state-v3` | Legacy pre-v4 format (flat, single-slot `color`). Migrated into `state-v4` on first load; the v3 key itself is left in place (not deleted) so a downgrade can still read it. |
|
|
963
1062
|
| `state-v2` | `${storagePrefix}-state-v2` | Legacy pre-v3 format. Migrated into `state-v3` (and from there into `state-v4`) on first load, then deleted. |
|
|
964
1063
|
| `state-v1` | `${storagePrefix}-state` | Legacy pre-v2 flat-state format (Color-only). Migrated into `state-v3` (and from there into `state-v4`) on first load, then deleted. |
|
|
965
|
-
| `open` | `${storagePrefix}-open` | Mirror of the panel's `open` boolean
|
|
966
|
-
| `position` | `${storagePrefix}-position` | Drag position `{ top, left }` so the panel reappears where the user left it.
|
|
967
|
-
| `
|
|
968
|
-
| `
|
|
1064
|
+
| `open` | `${storagePrefix}-open` | Mirror of the panel's `open` boolean, read synchronously at mount so user intent survives reloads. |
|
|
1065
|
+
| `position` | `${storagePrefix}-position` | Drag position `{ top, left }` so the panel reappears where the user left it. |
|
|
1066
|
+
| `size` | `${storagePrefix}-size` | Floating shell dimensions `{ width, height }` in pixels. |
|
|
1067
|
+
| `dock` | `${storagePrefix}-dock` | Presentation mode: `'float'`, `'right'`, `'bottom'`, or `'mini'`. |
|
|
1068
|
+
| `dock-size` | `${storagePrefix}-dock-size` | Right/bottom dock dimensions `{ right, bottom }`, defaulting to `{ right: 440, bottom: 340 }`. |
|
|
1069
|
+
| `density` | `${storagePrefix}-density` | Tab-grid density preference (`0`, `1`, or `2`). |
|
|
1070
|
+
| `ghost` | `${storagePrefix}-ghost` | Ghost-when-idle preference (`'1'` when enabled). |
|
|
1071
|
+
| `specimen` | `${storagePrefix}-specimen` | Font specimen toolbar JSON `{ text, preset, overridden, width }`; width is clamped to 240–720. |
|
|
1072
|
+
| `snapshot-a` | `${storagePrefix}-snapshot-a` | Persisted A snapshot `{ state, identity, savedAt, edits }`. |
|
|
1073
|
+
| `snapshot-b` | `${storagePrefix}-snapshot-b` | Persisted B snapshot `{ state, identity, savedAt, edits }`. |
|
|
1074
|
+
| `last-applied` | `${storagePrefix}-last-applied` | Flat comparison baseline; a successful apply resets it to `{}` while unconfirmed overrides remain in live state. |
|
|
1075
|
+
| `visible` | `${storagePrefix}:visible` | Adapter-level visibility-intent flag, owned by the lazy-load gate. |
|
|
1076
|
+
| `autoload` | `${storagePrefix}:autoload` | Owner-mode autoload flag: `'1'` for explicit opt-in or `'auto'` for auto-remember. |
|
|
1077
|
+
| `elpath-enabled` | `${storagePrefix}-elpath-enabled` | Element-path picker enabled bit. |
|
|
1078
|
+
| `domtweaker-enabled` | `${storagePrefix}-domtweaker-enabled` | DOM Tweaker enabled bit; meaningful only when `domTweaker` is configured. |
|
|
1079
|
+
| `highlight-slots` | `${storagePrefix}-highlight-slots` | Ten highlight slot colors in local storage. |
|
|
1080
|
+
| `highlight-outline-width` | `${storagePrefix}-highlight-outline-width` | Global highlight outline width in local storage, clamped to 1–20. |
|
|
1081
|
+
| `highlight-active` | `${storagePrefix}-highlight-active` | Active CSS-variable-to-slot map in session storage. |
|
|
969
1082
|
|
|
970
1083
|
For example, with `storagePrefix: 'myapp-design-token-panel'`:
|
|
971
1084
|
|
|
@@ -976,8 +1089,22 @@ myapp-design-token-panel-state-v2
|
|
|
976
1089
|
myapp-design-token-panel-state
|
|
977
1090
|
myapp-design-token-panel-open
|
|
978
1091
|
myapp-design-token-panel-position
|
|
1092
|
+
myapp-design-token-panel-size
|
|
1093
|
+
myapp-design-token-panel-dock
|
|
1094
|
+
myapp-design-token-panel-dock-size
|
|
1095
|
+
myapp-design-token-panel-density
|
|
1096
|
+
myapp-design-token-panel-ghost
|
|
1097
|
+
myapp-design-token-panel-specimen
|
|
1098
|
+
myapp-design-token-panel-snapshot-a
|
|
1099
|
+
myapp-design-token-panel-snapshot-b
|
|
1100
|
+
myapp-design-token-panel-last-applied
|
|
979
1101
|
myapp-design-token-panel:visible
|
|
980
1102
|
myapp-design-token-panel:autoload
|
|
1103
|
+
myapp-design-token-panel-elpath-enabled
|
|
1104
|
+
myapp-design-token-panel-domtweaker-enabled
|
|
1105
|
+
myapp-design-token-panel-highlight-slots
|
|
1106
|
+
myapp-design-token-panel-highlight-outline-width
|
|
1107
|
+
myapp-design-token-panel-highlight-active # sessionStorage
|
|
981
1108
|
```
|
|
982
1109
|
|
|
983
1110
|
### Note: colon vs dash — `visible` and `autoload`
|
|
@@ -1008,11 +1135,11 @@ When the host dispatches a `color-scheme-changed` event (e.g. a light/dark toggl
|
|
|
1008
1135
|
- If that identity already has a persisted slot, the slot's stored `color` (and `secondary`) state is loaded and re-applied — a per-scheme tweak now **survives** a round-trip through another scheme and back.
|
|
1009
1136
|
- If the identity has no slot yet (never tweaked under this scheme before), the panel cold-seeds from that scheme's defaults instead — the pre-existing "adopt the new scheme's palette" behavior for a scheme you haven't touched.
|
|
1010
1137
|
|
|
1011
|
-
Editing color under scheme A only ever overwrites scheme A's slot (`writeMergedV4` merge-saves: it reads the existing envelope, replaces just the active identity's slot, and preserves every other identity's slot untouched) — it never mutates scheme B's stored state. A full panel reset (Reset
|
|
1138
|
+
Editing color under scheme A only ever overwrites scheme A's slot (`writeMergedV4` merge-saves: it reads the existing envelope, replaces just the active identity's slot, and preserves every other identity's slot untouched) — it never mutates scheme B's stored state. A full panel reset (Reset) still wipes every slice via `clearAppliedStyles`; a disk Apply only reconciles confirmed-written variables and does not reset other identities or slices.
|
|
1012
1139
|
|
|
1013
|
-
**Migration.** On first load with no `state-v4` key, the legacy v1/v2/v3 chain runs unchanged (v3 wins over v2 over v1, exactly as before) and the resulting single flat `TweakState` is filed into `state-v4` under whichever identity is active at that moment — every subsequent load reads `state-v4` first. The legacy v3
|
|
1140
|
+
**Migration.** On first load with no `state-v4` key, the legacy v1/v2/v3 chain runs unchanged (v3 wins over v2 over v1, exactly as before); v2 and v1 are normalised to v3 as that chain requires, and the resulting single flat `TweakState` is filed into `state-v4` under whichever identity is active at that moment — every subsequent load reads `state-v4` first. The legacy v3 key is left in place by the v4 migration step so a host that needs to downgrade can still read it; the lower v2/v1 keys follow the legacy chain's deletion rules.
|
|
1014
1141
|
|
|
1015
|
-
**Host-owned `color-scheme` is never touched.** A host that manages its own `<html style="color-scheme">` (e.g. a site-level light/dark toggle) has that inline style tracked separately from the panel's own writes; the panel's mount/clear paths only ever remove a `color-scheme` value that the panel itself applied, never a host-owned one
|
|
1142
|
+
**Host-owned `color-scheme` is never touched.** A host that manages its own `<html style="color-scheme">` (e.g. a site-level light/dark toggle) has that inline style tracked separately from the panel's own writes; the panel's mount/clear paths only ever remove a `color-scheme` value that the panel itself applied, never a host-owned one.
|
|
1016
1143
|
|
|
1017
1144
|
Two consequences worth knowing as a host integrator:
|
|
1018
1145
|
|
|
@@ -1074,7 +1201,7 @@ There is no default `consoleNamespace` exposed to consumers — the field is req
|
|
|
1074
1201
|
|
|
1075
1202
|
### 10.1 Owner-autoload — loading the panel only for you
|
|
1076
1203
|
|
|
1077
|
-
**Use case:** you are deploying a public site and want the design-token panel available to yourself (the site owner) without
|
|
1204
|
+
**Use case:** you are deploying a public site and want the design-token panel available to yourself (the site owner) without fetching the panel bundle or injecting its stylesheet for general visitors. The small host adapter/config bootstrap still runs. Once armed, every page load fetches the bundle eagerly and mounts the panel CLOSED — the Alt+click element-path inspector is ready immediately, and you can open the panel UI at any time.
|
|
1078
1205
|
|
|
1079
1206
|
#### API surface
|
|
1080
1207
|
|
|
@@ -1083,14 +1210,14 @@ Both the Astro host-adapter (`window[consoleNamespace].*`) and the package-root
|
|
|
1083
1210
|
| Call | Effect |
|
|
1084
1211
|
|------|--------|
|
|
1085
1212
|
| `window.myapp.enableAutoload()` | Sets `${storagePrefix}:autoload` to `'1'`, arms the element-path inspector (`-elpath-enabled`), loads the panel bundle, mounts CLOSED. |
|
|
1086
|
-
| `window.myapp.disableAutoload()` |
|
|
1213
|
+
| `window.myapp.disableAutoload()` | Removes `:autoload`, writes `'0'` to `:visible` and `-elpath-enabled`, removes the open-state key, and unmounts the panel. |
|
|
1087
1214
|
| `enableAutoload()` (package-root export) | Same as the console form — for non-Astro hosts. |
|
|
1088
1215
|
| `disableAutoload()` (package-root export) | Same as the console form — for non-Astro hosts. |
|
|
1089
1216
|
| `shouldAutoload()` (package-root export) | Returns `true` iff the flag is currently set. |
|
|
1090
1217
|
|
|
1091
1218
|
#### The `${storagePrefix}:autoload` flag
|
|
1092
1219
|
|
|
1093
|
-
Stored in `localStorage` as `'1'` (explicit — set by `enableAutoload()`) or `'auto'` (auto-remembered — set by opening the panel; see "Auto-remember on open" below), removed or `'0'` otherwise. The host-adapter's lazy-load gate honours **either** value — when the flag is `'1'` or `'auto'`, the panel bundle loads eagerly (the same as when the panel was previously visible, via either the `:visible` flag or its `-open` mirror, or overrides are persisted, checked as a content check across the `${storagePrefix}-state` family rather than a presence check on a specific version key — see §9). **General visitors** who have never opened the panel or called `enableAutoload()` have no flag and pay
|
|
1220
|
+
Stored in `localStorage` as `'1'` (explicit — set by `enableAutoload()`) or `'auto'` (auto-remembered — set by opening the panel; see "Auto-remember on open" below), removed or `'0'` otherwise. The host-adapter's lazy-load gate honours **either** value — when the flag is `'1'` or `'auto'`, the panel bundle loads eagerly (the same as when the panel was previously visible, via either the `:visible` flag or its `-open` mirror, or overrides are persisted, checked as a content check across the `${storagePrefix}-state` family rather than a presence check on a specific version key — see §9). **General visitors** who have never opened the panel or called `enableAutoload()` have no flag and pay no panel-bundle cost; the small host adapter/config bootstrap still runs.
|
|
1094
1221
|
|
|
1095
1222
|
**Downstream-host recipe.** A host that writes its own lazy-load probe (e.g. to decide whether to eagerly fetch something else alongside the panel) can read the flag directly and test `=== '1'` to match only the explicit-owner population, excluding visitors who merely opened the panel once.
|
|
1096
1223
|
|
|
@@ -1098,11 +1225,11 @@ Stored in `localStorage` as `'1'` (explicit — set by `enableAutoload()`) or `'
|
|
|
1098
1225
|
|
|
1099
1226
|
#### Auto-remember on open
|
|
1100
1227
|
|
|
1101
|
-
Opening the panel by any means — `showDesignPanel()`, `toggleDesignPanel()`,
|
|
1228
|
+
Opening the panel by any means — `showDesignPanel()`, `toggleDesignPanel()`, the instance handle's `open()` / `toggle()`, the fixed-name `zdtp.show()` / `zdtp.toggle()` global, or an instance toggle event — **automatically sets the `:autoload` flag to `'auto'`** (auto-remembered provenance, distinct from the `'1'` that `enableAutoload()` writes). This means once you open the panel you will be in owner-mode on subsequent page loads without calling `enableAutoload()` explicitly. An existing explicit `'1'` is never downgraded — an owner who armed autoload deliberately keeps that provenance even after opening the panel again.
|
|
1102
1229
|
|
|
1103
1230
|
#### Element-path coupling
|
|
1104
1231
|
|
|
1105
|
-
`enableAutoload()` arms the Alt+click element-path inspector by writing `-elpath-enabled = '1'`. The inspector runs inside the Preact shell; mounting the shell CLOSED (rather than unmounted) keeps the inspector functional even while the panel UI is hidden. You can still turn the inspector off via the in-panel toggle — `disableAutoload()`
|
|
1232
|
+
`enableAutoload()` arms the Alt+click element-path inspector by writing `-elpath-enabled = '1'`. The inspector runs inside the Preact shell; mounting the shell CLOSED (rather than unmounted) keeps the inspector functional even while the panel UI is hidden. You can still turn the inspector off via the in-panel toggle — `disableAutoload()` writes `'0'` as part of full teardown.
|
|
1106
1233
|
|
|
1107
1234
|
#### Auto-remember footgun
|
|
1108
1235
|
|
|
@@ -1116,48 +1243,95 @@ Because **any open trigger sets `:autoload`** (to `'auto'`), a visible "open pan
|
|
|
1116
1243
|
|
|
1117
1244
|
---
|
|
1118
1245
|
|
|
1246
|
+
### 10.2 Shared Alt+click picker ownership
|
|
1247
|
+
|
|
1248
|
+
Element path, DOM Tweaker, and element inspect use one per-window coordinator
|
|
1249
|
+
for the Alt+click gesture. Enabling or arming one feature revokes the previous
|
|
1250
|
+
owner; the three features do not run simultaneously. Panel surfaces and the
|
|
1251
|
+
on-page specimen are excluded from picker hits.
|
|
1252
|
+
|
|
1253
|
+
| Feature | Activation | Result |
|
|
1254
|
+
| --- | --- | --- |
|
|
1255
|
+
| Element path | Owner autoload or its panel toggle, then `Alt+click` a host element | Copies the annotated selector/path block. |
|
|
1256
|
+
| DOM Tweaker | Enable the configured DOM Tweaker, then `Alt+click` a host element | Opens the Tailwind class editor and live utility preview. |
|
|
1257
|
+
| Element inspect | Toggle inspect or press `I`, then click a host element; `Alt` also arms the shared picker | Opens the reserved inspect tab with token-backed and inherited rows. |
|
|
1258
|
+
|
|
1259
|
+
The most recently armed feature owns the gesture and receives subsequent page
|
|
1260
|
+
clicks. Owner autoload's element-path arm therefore does not block a later DOM
|
|
1261
|
+
Tweaker or element-inspect arm.
|
|
1262
|
+
|
|
1263
|
+
---
|
|
1264
|
+
|
|
1119
1265
|
## 11. Tailwind not required
|
|
1120
1266
|
|
|
1121
|
-
The panel ships its own bundled CSS scoped under a panel-private namespace
|
|
1267
|
+
The panel ships its own bundled CSS scoped under a panel-private namespace. The
|
|
1268
|
+
chrome palette is a self-contained OKLCH ramp; it does not read host
|
|
1269
|
+
`--color-*` or `--font-mono` variables. A host can opt into a different chrome
|
|
1270
|
+
theme by assigning the same `--tokentweak-*` variables on a listed scope.
|
|
1122
1271
|
|
|
1123
1272
|
```css
|
|
1124
1273
|
:where(.tokenpanel-shell, [data-design-token-panel-modal]) {
|
|
1125
|
-
|
|
1126
|
-
--tokentweak-
|
|
1127
|
-
--tokentweak-
|
|
1128
|
-
--tokentweak-
|
|
1129
|
-
--tokentweak-
|
|
1130
|
-
--tokentweak-
|
|
1131
|
-
--tokentweak-
|
|
1132
|
-
--tokentweak-
|
|
1133
|
-
--
|
|
1134
|
-
|
|
1274
|
+
/* base-0 is the darkest ground; stops ascend toward the foreground. */
|
|
1275
|
+
--tokentweak-palette-base-0: oklch(0.18 0 0);
|
|
1276
|
+
--tokentweak-palette-base-1: oklch(0.25 0 0);
|
|
1277
|
+
--tokentweak-palette-base-2: oklch(0.34 0 0);
|
|
1278
|
+
--tokentweak-palette-base-3: oklch(0.536 0 0);
|
|
1279
|
+
--tokentweak-palette-base-4: oklch(0.66 0 0);
|
|
1280
|
+
--tokentweak-palette-base-5: oklch(0.8 0 0);
|
|
1281
|
+
--tokentweak-palette-base-6: oklch(0.91 0 0);
|
|
1282
|
+
--tokentweak-color-fg: var(--tokentweak-palette-base-5);
|
|
1283
|
+
--tokentweak-color-bg: var(--tokentweak-palette-base-0);
|
|
1284
|
+
--tokentweak-color-muted: var(--tokentweak-palette-base-4);
|
|
1285
|
+
--tokentweak-color-border: var(--tokentweak-palette-base-3);
|
|
1286
|
+
--tokentweak-color-surface: var(--tokentweak-palette-base-1);
|
|
1287
|
+
--tokentweak-color-accent: #d69a66;
|
|
1288
|
+
--tokentweak-color-accent-bar: #efb477;
|
|
1289
|
+
--tokentweak-color-accent-hover: #a7c0e3;
|
|
1290
|
+
--tokentweak-color-code-bg: var(--tokentweak-palette-base-2);
|
|
1291
|
+
--tokentweak-color-code-fg: var(--tokentweak-palette-base-6);
|
|
1292
|
+
--tokentweak-color-success: #93bb77;
|
|
1293
|
+
--tokentweak-color-danger: #da6871;
|
|
1294
|
+
--tokentweak-color-warning: #dfbb77;
|
|
1295
|
+
--tokentweak-font-mono: Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
|
|
1296
|
+
/* pad-*, gap-*, text-*, radius, and z-* tokens are also declared here. */
|
|
1135
1297
|
}
|
|
1136
1298
|
```
|
|
1137
1299
|
|
|
1138
|
-
|
|
1300
|
+
Hosts may override a `--tokentweak-palette-base-*` stop to move all semantic
|
|
1301
|
+
roles that alias it, or continue assigning a `--tokentweak-color-*` role
|
|
1302
|
+
directly. The direct semantic assignment still wins. Borders now use
|
|
1303
|
+
`--tokentweak-color-border`; a host that previously assigned
|
|
1304
|
+
`--tokentweak-color-muted` to recolor both secondary text and 1px dividers must
|
|
1305
|
+
also assign the border role.
|
|
1306
|
+
|
|
1307
|
+
- **Naming:** panel-private color, font, spacing, typography, and z-index variables use the `--tokentweak-*` prefix; the shared radius token is `--radius-tokentweak`. Consumer-namespaced identifiers do not appear in the panel chrome — `panel.css` reads only package-owned tokens and component-local layout hints.
|
|
1139
1308
|
- **Files:** `panel.css` (chrome layout / typography / controls) + `panel-tokens.css` (the `--tokentweak-*` declarations). Both ship from the package and the consumer pulls them in via `sideEffects`.
|
|
1140
1309
|
- **No Tailwind dependency in the consumer.** The panel chrome uses hand-authored CSS classes backed by `--tokentweak-*` variables. You can integrate the panel into a Tailwind site, a CSS Modules site, a vanilla CSS site, or anything in between.
|
|
1141
1310
|
|
|
1142
|
-
### 11.1
|
|
1143
|
-
|
|
1144
|
-
The panel-chrome color tokens (`--tokentweak-color-fg`, `--tokentweak-color-bg`, `--tokentweak-color-muted`, `--tokentweak-color-surface`, `--tokentweak-color-accent`, `--tokentweak-color-accent-hover`, `--tokentweak-color-code-bg`, `--tokentweak-color-code-fg`, `--tokentweak-color-success`, `--tokentweak-color-danger`, `--tokentweak-color-warning`, `--tokentweak-font-mono`) are declared as a `var(--host, fallback)` ladder. This gives hosts two override layers and works out-of-the-box when neither is supplied:
|
|
1311
|
+
### 11.1 Chrome scopes and host overrides
|
|
1145
1312
|
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1313
|
+
The declarations cover `.tokenpanel-shell`, `.tokenpanel-mini-pill`,
|
|
1314
|
+
`[data-design-token-panel-modal]`, the highlight-settings and chain popovers,
|
|
1315
|
+
the color picker, tooltip, element-path label/toast, and element-inspect box,
|
|
1316
|
+
label, and view. `:where()` keeps their specificity at zero, so a host can
|
|
1317
|
+
override a token with a single-class rule on the relevant surface. The host
|
|
1318
|
+
theme variables are never read by the panel chrome.
|
|
1151
1319
|
|
|
1152
|
-
|
|
1320
|
+
The CSS variables the panel **writes to** (the `cssVar` field on each
|
|
1321
|
+
`TierItem`, palette/base-role names, and semantic CSS names) are entirely
|
|
1322
|
+
consumer-controlled. The package only writes those variables through the
|
|
1323
|
+
default `document.documentElement` target or a configured `applySink`.
|
|
1153
1324
|
|
|
1154
|
-
|
|
1325
|
+
Dock integration publishes `--zdtp-dock-inset-right` and
|
|
1326
|
+
`--zdtp-dock-inset-bottom` on the host root while a claim is active. The
|
|
1327
|
+
page-level specimen uses the `.tokenpanel-on-page-specimen` class and
|
|
1328
|
+
`[data-zdtp-specimen]` marker; it is host-page content, not panel chrome.
|
|
1155
1329
|
|
|
1156
1330
|
### 11.2 Apply-to-disk for a Tailwind v4 `@theme` block
|
|
1157
1331
|
|
|
1158
1332
|
The section above is about the panel's OWN chrome — it never needed Tailwind. This section is about the opposite direction: a Tailwind v4 **consumer** whose design tokens live inside `@theme { ... }` (so Tailwind can generate utility classes from them) rather than `:root`.
|
|
1159
1333
|
|
|
1160
|
-
The apply-to-disk rewriter (§3.2) scans the first top-level `:root` block AND the first top-level `@theme` block, so a Tailwind v4 token file like this applies out of the box
|
|
1334
|
+
The apply-to-disk rewriter (§3.2) scans the first top-level `:root` block AND the first top-level `@theme` block, so a Tailwind v4 token file like this applies out of the box:
|
|
1161
1335
|
|
|
1162
1336
|
```css
|
|
1163
1337
|
:root {
|
|
@@ -1224,7 +1398,7 @@ Net effect: the consumer MUST own the host-adapter import in their wrapper layou
|
|
|
1224
1398
|
</script>
|
|
1225
1399
|
```
|
|
1226
1400
|
|
|
1227
|
-
This is the second half of the paired-unit contract from §
|
|
1401
|
+
This is the second half of the paired-unit contract from §4.1.2 (`<DesignTokenPanelHost>` AND the host-adapter `<script>` block — always together). If you forget it, the `<DesignTokenPanelHost>` JSON config payload still ships, but no JS reads it, so calling `window.<consoleNamespace>.showDesignPanel()` throws `ReferenceError`.
|
|
1228
1402
|
|
|
1229
1403
|
For the regression-guard tests that pin this contract, see `package-exports.test.ts` under the package's test suite.
|
|
1230
1404
|
|
|
@@ -1236,25 +1410,25 @@ For the regression-guard tests that pin this contract, see `package-exports.test
|
|
|
1236
1410
|
|
|
1237
1411
|
**Symptom:** on first paint after a hard reload, the page renders with the consumer's default token values for a beat before snapping to the user's saved overrides.
|
|
1238
1412
|
|
|
1239
|
-
**Resolution:** the host adapter eagerly re-applies persisted overrides during the lazy-load gate (
|
|
1413
|
+
**Resolution:** the host adapter eagerly re-applies persisted overrides during the lazy-load gate (it content-checks the exact `${storagePrefix}-state` / `${storagePrefix}-state-vN` family and the visibility, autoload, and enabled-feature signals synchronously from `localStorage`). If you still see a flash, your `<DesignTokenPanelHost>` is being rendered too late in the document (e.g. inside a deferred island) — move it to the layout's `<body>` and verify the inline `<script type="application/json" id="tokenpanel-config">` is in the initial HTML.
|
|
1240
1414
|
|
|
1241
1415
|
### 13.2 Auto-mount race on first reload
|
|
1242
1416
|
|
|
1243
1417
|
**Symptom:** the panel does not re-open on the first reload after the user closed it, even though `${storagePrefix}-open` is set in `localStorage`.
|
|
1244
1418
|
|
|
1245
|
-
**Resolution:** the open boolean is mirrored to `localStorage` synchronously and read at mount time so the next mount opens directly into the user's last state without a post-render toggle dispatch. If the symptom persists, confirm the storage key matches what the contract derives (§
|
|
1419
|
+
**Resolution:** the open boolean is mirrored to `localStorage` synchronously and read at mount time so the next mount opens directly into the user's last state without a post-render toggle dispatch. If the symptom persists, confirm the storage key matches what the contract derives (§9) and that nothing else in the page is clearing the key on load.
|
|
1246
1420
|
|
|
1247
1421
|
### 13.3 Live-apply regression test approach
|
|
1248
1422
|
|
|
1249
|
-
**Symptom:** after a panel-package change, you want to confirm the live-apply pipeline (storage → adapter → `:root`) is unbroken end-to-end.
|
|
1423
|
+
**Symptom:** after a panel-package change, you want to confirm the live-apply pipeline (storage → adapter → default `:root` or `applySink`) is unbroken end-to-end.
|
|
1250
1424
|
|
|
1251
|
-
**Resolution:** the canonical regression test is each external example repo's `apply-roundtrip.spec.ts` Playwright spec under `tests/e2e/`. It boots the example's preview build, seeds a
|
|
1425
|
+
**Resolution:** the canonical regression test is each external example repo's `apply-roundtrip.spec.ts` Playwright spec under `tests/e2e/`. It boots the example's preview build, seeds a compatible state envelope under the example's storage prefix, hard-reloads, and asserts the adapter rehydrated and applied the override against the example's palette and semantic CSS variable names. The contract: storage prefix, `TierItem.cssVar` names, semantic CSS names — change one of those and this spec fails first. See §15 for links to the five external example repos.
|
|
1252
1426
|
|
|
1253
1427
|
---
|
|
1254
1428
|
|
|
1255
1429
|
## 14. Migration recipe — adopting the panel into an existing consumer
|
|
1256
1430
|
|
|
1257
|
-
This recipe walks through wiring the panel into a project that does not currently use it. If you previously consumed an internal pre-OSS snapshot of the panel where storage keys, console namespace, modal class prefix, and
|
|
1431
|
+
This recipe walks through wiring the panel into a project that does not currently use it. If you previously consumed an internal pre-OSS snapshot of the panel where storage keys, console namespace, modal class prefix, and token identifiers were hardcoded literals, the same steps apply — lift those literals into a `PanelConfig` value and a host-owned tab manifest.
|
|
1258
1432
|
|
|
1259
1433
|
1. **Install the package.**
|
|
1260
1434
|
|
|
@@ -1264,9 +1438,9 @@ This recipe walks through wiring the panel into a project that does not currentl
|
|
|
1264
1438
|
|
|
1265
1439
|
2. **Define your `PanelConfig` literals.**
|
|
1266
1440
|
|
|
1267
|
-
Pick identifiers for `storagePrefix`, `consoleNamespace`, `modalClassPrefix`, `schemaId`,
|
|
1441
|
+
Pick identifiers for `storagePrefix`, `consoleNamespace`, `modalClassPrefix`, `schemaId`, and `exportFilenameBase`. Pull these into a host-side config file (e.g. `src/lib/panel-config.ts`). If you are migrating from an internal snapshot fork and want to preserve users' saved state across the migration, keep the legacy values verbatim; otherwise pick fresh, neutral identifiers (e.g. `myapp-design-token-panel`).
|
|
1268
1442
|
|
|
1269
|
-
`schemaId` is display-only (see §5.3) — it never gates import/export, so picking any string here is safe. If
|
|
1443
|
+
`schemaId` is display-only (see §5.3) — it never gates import/export, so picking any string here is safe. If a host-facing label should name the actual schema your export/import round-trips through, import `SCHEMA_V1` / `SCHEMA_V2` / `SCHEMA_V3` from the package root and set `schemaId` to one of them instead of an arbitrary string:
|
|
1270
1444
|
|
|
1271
1445
|
```ts
|
|
1272
1446
|
import { SCHEMA_V3 } from '@takazudo/zdtp';
|
|
@@ -1279,21 +1453,20 @@ This recipe walks through wiring the panel into a project that does not currentl
|
|
|
1279
1453
|
|
|
1280
1454
|
3. **Author your token manifest in the host project.**
|
|
1281
1455
|
|
|
1282
|
-
The package itself ships zero baked-in manifest data. Define `
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1456
|
+
The package itself ships zero baked-in manifest data. Define `TabConfig`
|
|
1457
|
+
values in your project and place them in `PanelConfig.tabs`. Every
|
|
1458
|
+
`TierItem.cssVar` is an explicit string, including one string per palette
|
|
1459
|
+
slot; there is no palette-name callback to survive the Astro JSON boundary.
|
|
1460
|
+
Add `preview` / `previewBase` to tiers that should render specimen or glyph
|
|
1461
|
+
previews.
|
|
1287
1462
|
|
|
1288
|
-
|
|
1289
|
-
// wrong (function — does not survive Astro frontmatter → island handoff)
|
|
1290
|
-
// paletteCssVar: (i) => `--myapp-p${i}`,
|
|
1291
|
-
|
|
1292
|
-
// right (string template, JSON-serializable)
|
|
1293
|
-
paletteCssVarTemplate: '--myapp-p{n}',
|
|
1294
|
-
```
|
|
1463
|
+
4. **Author the color tab in the host project.**
|
|
1295
1464
|
|
|
1296
|
-
|
|
1465
|
+
Build a `TabConfig` with `id: 'color'`, palette and semantic `TierItem`
|
|
1466
|
+
entries, and the `colorExtras` structural metadata (base roles, scheme
|
|
1467
|
+
registry, and panel settings). If you need a secondary color cluster, add
|
|
1468
|
+
a companion `TabConfig` with `id: 'color-secondary'` and its own
|
|
1469
|
+
`colorExtras`. Keep all of this metadata plain JSON data.
|
|
1297
1470
|
|
|
1298
1471
|
5. **Drop `<DesignTokenPanelHost>` into your layout.**
|
|
1299
1472
|
|
|
@@ -1310,11 +1483,11 @@ This recipe walks through wiring the panel into a project that does not currentl
|
|
|
1310
1483
|
|
|
1311
1484
|
6. **Verify storage keys derive to the expected literals.**
|
|
1312
1485
|
|
|
1313
|
-
Open devtools → Application → Local Storage. Confirm you see keys derived under your `storagePrefix` and that any pre-existing user state (under the legacy prefix, if you preserved it) is migrated
|
|
1486
|
+
Open devtools → Application → Local Storage. Confirm you see keys derived under your `storagePrefix` and that any pre-existing user state (under the legacy prefix, if you preserved it) is migrated through the v1/v2/v3 → v4 compatibility path on first load.
|
|
1314
1487
|
|
|
1315
1488
|
7. **Run the live-apply e2e spec.**
|
|
1316
1489
|
|
|
1317
|
-
Use any of the external example repos' Playwright spec at `tests/e2e/apply-roundtrip.spec.ts` (see §15 for the five repo links) as a template: seed a `${storagePrefix}-state-
|
|
1490
|
+
Use any of the external example repos' Playwright spec at `tests/e2e/apply-roundtrip.spec.ts` (see §15 for the five repo links) as a template: seed a compatible `${storagePrefix}-state-v4` payload, hard-reload, and assert your palette and semantic CSS variables on the default `:root` (or your configured `applySink`) reflect the seeded values.
|
|
1318
1491
|
|
|
1319
1492
|
For edge cases hit during the migration, see CONTRIBUTING and the doc-site reference pages for each `PanelConfig` field.
|
|
1320
1493
|
|
|
@@ -1324,7 +1497,7 @@ For edge cases hit during the migration, see CONTRIBUTING and the doc-site refer
|
|
|
1324
1497
|
|
|
1325
1498
|
The canonical worked examples live in five dedicated sibling repos. Each is an independent consumer app that demonstrates the panel against a different host framework. Each renders a tiny page with cards, buttons, and palette swatches whose styles reference its own demo CSS variables, and each ships a Playwright spec at `tests/e2e/apply-roundtrip.spec.ts` that asserts the live-apply pipeline.
|
|
1326
1499
|
|
|
1327
|
-
- [`zudo-design-token-panel-example-astro`](https://github.com/Takazudo/zudo-design-token-panel-example-astro) — Astro + Preact island. Uses `storagePrefix: 'astro-example-tokens'`, `consoleNamespace: 'astro'`, `
|
|
1500
|
+
- [`zudo-design-token-panel-example-astro`](https://github.com/Takazudo/zudo-design-token-panel-example-astro) — Astro + Preact island. Uses `storagePrefix: 'astro-example-tokens'`, `consoleNamespace: 'astro'`, and explicit `TierItem.cssVar` names such as `--astro-palette-0`.
|
|
1328
1501
|
- [`zudo-design-token-panel-example-vite-react`](https://github.com/Takazudo/zudo-design-token-panel-example-vite-react) — Vite + React (panel mounted as a Preact island, React tree untouched). Uses the `vr` namespace.
|
|
1329
1502
|
- [`zudo-design-token-panel-example-nextjs`](https://github.com/Takazudo/zudo-design-token-panel-example-nextjs) — Next.js (App Router) + React, panel as a `'use client'` boundary. Uses the `nx` namespace.
|
|
1330
1503
|
- [`zudo-design-token-panel-example-zfb`](https://github.com/Takazudo/zudo-design-token-panel-example-zfb) — [zfb](https://github.com/Takazudo/zudo-front-builder) (Preact host). Uses the `devMiddleware` plugin hook for the apply proxy.
|