@takazudo/zdtp 0.4.13 → 0.4.15
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 +143 -0
- package/PORTABLE-CONTRACT.md +366 -94
- package/README.md +218 -96
- 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-CfL2VUe1.js → autoload-state-7BQYXI7Y.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 +22 -25
- 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-BOOmFtJh.js +12165 -0
- package/dist/{index-BAY1JOUl.js → index-C2DIYD0d.js} +2 -2
- package/dist/index.js +14 -14
- package/dist/load-routing-BtCE1hGI.js +547 -0
- package/dist/{manifest-DCReQE0k.js → manifest-DvuKi7I4.js} +11 -7
- package/dist/{panel-config-COHesW2B.js → panel-config-CRf-ONSV.js} +404 -308
- 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 +5 -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-BKNxtHzb.js → tweak-state-BGp_7Tfh.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 +3 -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-U7Ol7tgA.js +0 -7591
- package/dist/load-routing-D4H2VOl5.js +0 -426
package/PORTABLE-CONTRACT.md
CHANGED
|
@@ -25,6 +25,11 @@ one page: call it with a distinct `storagePrefix` to register a new instance;
|
|
|
25
25
|
call it with the same prefix and equal config for an idempotent no-op.
|
|
26
26
|
|
|
27
27
|
```ts
|
|
28
|
+
export interface PanelDockConfig {
|
|
29
|
+
/** Reserve host-document space for a right/bottom dock. Defaults to body-margin. */
|
|
30
|
+
reflow?: 'body-margin' | 'none';
|
|
31
|
+
}
|
|
32
|
+
|
|
28
33
|
export interface PanelConfig {
|
|
29
34
|
/** Base for every derived storage key. Also the instance id. See §2. */
|
|
30
35
|
storagePrefix: string;
|
|
@@ -32,7 +37,7 @@ export interface PanelConfig {
|
|
|
32
37
|
consoleNamespace: string;
|
|
33
38
|
/** BEM-style prefix used by every modal in the panel (export / import / apply). */
|
|
34
39
|
modalClassPrefix: string;
|
|
35
|
-
/**
|
|
40
|
+
/** Display-only label returned by getDesignTokenSchema(); not used by built-in UI or serde validation. */
|
|
36
41
|
schemaId: string;
|
|
37
42
|
/** Default filename base — exports save as `${exportFilenameBase}.json`. */
|
|
38
43
|
exportFilenameBase: string;
|
|
@@ -63,10 +68,9 @@ export interface PanelConfig {
|
|
|
63
68
|
*/
|
|
64
69
|
colorPresets?: Record<string, ColorScheme>;
|
|
65
70
|
/**
|
|
66
|
-
* Optional dev-API endpoint URL. When
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* the Apply button stays disabled with a tooltip.
|
|
71
|
+
* Optional dev-API endpoint URL. When supplied together with a non-empty
|
|
72
|
+
* `applyRouting` map, the Apply button POSTs its diff payload to it. When
|
|
73
|
+
* either field is absent, the button stays disabled with a tooltip.
|
|
70
74
|
*/
|
|
71
75
|
applyEndpoint?: string;
|
|
72
76
|
/**
|
|
@@ -96,10 +100,12 @@ export interface PanelConfig {
|
|
|
96
100
|
/** Optional host Tailwind v4 theme CSS used by the lazy side for suggestions. */
|
|
97
101
|
themeCss?: string;
|
|
98
102
|
};
|
|
103
|
+
/** Optional dock integration; omitted values use body-margin host reflow. */
|
|
104
|
+
dock?: PanelDockConfig;
|
|
99
105
|
/**
|
|
100
106
|
* Optional apply sink. Routes this instance's CSS-var writes and clears
|
|
101
107
|
* through the caller-supplied object instead of `document.documentElement`.
|
|
102
|
-
* See §3.
|
|
108
|
+
* See §3.6 for the full sink contract.
|
|
103
109
|
*
|
|
104
110
|
* NOTE: this field carries a function reference and is therefore NOT
|
|
105
111
|
* JSON-serializable. It cannot pass through Astro's inline JSON config.
|
|
@@ -126,7 +132,7 @@ export interface PanelConfig {
|
|
|
126
132
|
|
|
127
133
|
/**
|
|
128
134
|
* Apply sink — routes CSS-var writes for one panel instance somewhere other
|
|
129
|
-
* than the host `:root`. See §3.
|
|
135
|
+
* than the host `:root`. See §3.6.
|
|
130
136
|
*/
|
|
131
137
|
export interface ApplySink {
|
|
132
138
|
/** Upsert the given var name→value pairs on the sink target. */
|
|
@@ -270,9 +276,22 @@ derives the keys at runtime from this single base.
|
|
|
270
276
|
| `state-v1` | `${storagePrefix}-state` | tweak-state (legacy) | Pre-v2 flat-state format (Color-only). When selected, it is written to `state-v3` and the v1 key is deleted, then the result is copied into v4. |
|
|
271
277
|
| `open` | `${storagePrefix}-open` | panel | Mirror of the panel's `open` boolean state (so the next mount opens directly into the user's last state without a post-render toggle dispatch). |
|
|
272
278
|
| `position` | `${storagePrefix}-position` | panel | Drag position (`{ top, left }`) so the panel reappears where the user left it. |
|
|
279
|
+
| `size` | `${storagePrefix}-size` | panel | Floating shell dimensions (`{ width, height }`) in pixels. |
|
|
280
|
+
| `dock` | `${storagePrefix}-dock` | panel | Presentation mode: `'float'`, `'right'`, `'bottom'`, or `'mini'`. |
|
|
281
|
+
| `dock-size` | `${storagePrefix}-dock-size` | panel | Right/bottom dock dimensions (`{ right, bottom }`), defaulting to `{ right: 440, bottom: 340 }`. |
|
|
282
|
+
| `density` | `${storagePrefix}-density` | panel | Tab-grid density preference (`0`, `1`, or `2`). |
|
|
283
|
+
| `ghost` | `${storagePrefix}-ghost` | shell | Ghost-when-idle preference (`'1'` when enabled). |
|
|
284
|
+
| `specimen` | `${storagePrefix}-specimen` | specimen | Font specimen toolbar JSON: `{ text, preset, overridden, width }`; width is clamped to 240–720. |
|
|
285
|
+
| `snapshot-a` | `${storagePrefix}-snapshot-a` | snapshots | Persisted A snapshot: `{ state, identity, savedAt, edits }`. |
|
|
286
|
+
| `snapshot-b` | `${storagePrefix}-snapshot-b` | snapshots | Persisted B snapshot: `{ state, identity, savedAt, edits }`. |
|
|
287
|
+
| `last-applied` | `${storagePrefix}-last-applied` | apply | Flat comparison baseline; a successful apply resets it to `{}` while unconfirmed overrides remain in live state. |
|
|
273
288
|
| `visible` | `${storagePrefix}:visible` | adapter | Adapter-level visibility-intent flag, owned by the lazy-load gate (§6). |
|
|
274
289
|
| `autoload` | `${storagePrefix}:autoload` | autoload-state | Owner-mode autoload flag. `'1'` (explicit, set by `enableAutoload()`) or `'auto'` (auto-remembered, set by opening the panel — see §6.2) both mean "load the panel bundle eagerly and mount CLOSED on every page load." `enableAutoload()` / `disableAutoload()` manage the explicit value; `disableAutoload()` clears either. See §6.2. |
|
|
290
|
+
| `elpath-enabled` | `${storagePrefix}-elpath-enabled` | element-path-state | Element-path picker enabled bit. |
|
|
275
291
|
| `domtweaker-enabled` | `${storagePrefix}-domtweaker-enabled` | dom-tweaker-state | DOM Tweaker enabled bit. `'1'` means "mount the closed shell and load the DOM Tweaker lazy boundary." Only meaningful when `PanelConfig.domTweaker` is present. |
|
|
292
|
+
| `highlight-slots` | `${storagePrefix}-highlight-slots` | highlight-state | Ten highlight slot colors in local storage. |
|
|
293
|
+
| `highlight-outline-width` | `${storagePrefix}-highlight-outline-width` | highlight-state | Global highlight outline width in local storage, clamped to 1–20. |
|
|
294
|
+
| `highlight-active` | `${storagePrefix}-highlight-active` | highlight-state | Active CSS-variable-to-slot map in session storage. |
|
|
276
295
|
|
|
277
296
|
**Constraint — colon, not dash, for `visible` and `autoload`.** Both adapter-
|
|
278
297
|
level flags use a `:` separator; every other derived key uses `-`. The colon
|
|
@@ -290,9 +309,22 @@ myapp-design-token-panel-state-v2
|
|
|
290
309
|
myapp-design-token-panel-state
|
|
291
310
|
myapp-design-token-panel-open
|
|
292
311
|
myapp-design-token-panel-position
|
|
312
|
+
myapp-design-token-panel-size
|
|
313
|
+
myapp-design-token-panel-dock
|
|
314
|
+
myapp-design-token-panel-dock-size
|
|
315
|
+
myapp-design-token-panel-density
|
|
316
|
+
myapp-design-token-panel-ghost
|
|
317
|
+
myapp-design-token-panel-specimen
|
|
318
|
+
myapp-design-token-panel-snapshot-a
|
|
319
|
+
myapp-design-token-panel-snapshot-b
|
|
320
|
+
myapp-design-token-panel-last-applied
|
|
293
321
|
myapp-design-token-panel:visible
|
|
294
322
|
myapp-design-token-panel:autoload
|
|
323
|
+
myapp-design-token-panel-elpath-enabled
|
|
295
324
|
myapp-design-token-panel-domtweaker-enabled
|
|
325
|
+
myapp-design-token-panel-highlight-slots
|
|
326
|
+
myapp-design-token-panel-highlight-outline-width
|
|
327
|
+
myapp-design-token-panel-highlight-active # sessionStorage
|
|
296
328
|
```
|
|
297
329
|
|
|
298
330
|
Unit tests in the package verify these derivations with literal-equality
|
|
@@ -387,14 +419,14 @@ public surface:
|
|
|
387
419
|
```ts
|
|
388
420
|
// Value-kind discriminated union — describes how a tier item is edited.
|
|
389
421
|
export type TierValueKind =
|
|
390
|
-
| { kind: 'length'; step: number; unit: string }
|
|
391
|
-
| { kind: 'number'; step: number }
|
|
422
|
+
| { kind: 'length'; step: number; unit: string; units?: readonly string[] }
|
|
423
|
+
| { kind: 'number'; step: number; unit?: string }
|
|
392
424
|
| { kind: 'select'; options: readonly string[] }
|
|
393
425
|
| { kind: 'text' }
|
|
394
426
|
| { kind: 'cursor' }
|
|
395
427
|
| { kind: 'content' }
|
|
396
428
|
| { kind: 'mask-image' }
|
|
397
|
-
| { kind: 'color' };
|
|
429
|
+
| { kind: 'color'; format?: 'hex' | 'oklch' };
|
|
398
430
|
|
|
399
431
|
export interface PillSpec {
|
|
400
432
|
value: string;
|
|
@@ -414,12 +446,10 @@ export type SemanticValue =
|
|
|
414
446
|
export interface TierItem {
|
|
415
447
|
/** Stable id used as the key in persisted state (e.g. `hsp-2xs`). */
|
|
416
448
|
id: string;
|
|
417
|
-
/** CSS custom property written to
|
|
449
|
+
/** CSS custom property written to the default root or configured apply sink (e.g. `--myapp-spacing-hgap-2xs`). */
|
|
418
450
|
cssVar: string;
|
|
419
451
|
/** Display label shown in the panel row. */
|
|
420
452
|
label: string;
|
|
421
|
-
/** Optional manifest group — tab components use this for section headers. */
|
|
422
|
-
group?: string;
|
|
423
453
|
/** Default value as a CSS string (`0.125rem`, `12px`, etc.). */
|
|
424
454
|
default: string;
|
|
425
455
|
/** Discriminated union describing the control kind and its metadata. */
|
|
@@ -459,6 +489,10 @@ export interface TierConfig {
|
|
|
459
489
|
* this is a multi-source allow-list for individual semantic mappings.
|
|
460
490
|
*/
|
|
461
491
|
referencesRamps?: readonly { tab?: string; tier: string }[];
|
|
492
|
+
/** Optional visual treatment rendered for this tier's values. */
|
|
493
|
+
preview?: 'size' | 'line-height' | 'family' | 'weight' | 'bar' | 'radius' | 'duration';
|
|
494
|
+
/** CSS variable used as the font-size base for a preview, when supplied. */
|
|
495
|
+
previewBase?: string;
|
|
462
496
|
}
|
|
463
497
|
|
|
464
498
|
For the full `SemanticValue` mapping and emission behavior, see the maintained
|
|
@@ -477,38 +511,78 @@ export interface ColorClusterExtras {
|
|
|
477
511
|
defaultShikiTheme: string;
|
|
478
512
|
colorSchemes: Record<string, ColorScheme>;
|
|
479
513
|
panelSettings: ClusterPanelSettings;
|
|
514
|
+
/** Optional semantic-item-id → SemanticValue defaults override map. */
|
|
515
|
+
semanticDefaults?: Record<string, SemanticValue>;
|
|
480
516
|
}
|
|
481
517
|
|
|
482
518
|
/** Top-level tab entry on PanelConfig.tabs. */
|
|
483
519
|
export interface TabConfig {
|
|
484
|
-
/** Stable id.
|
|
520
|
+
/** Stable id. Dedicated panel ids are 'color', 'font', 'spacing', 'size', 'palette', and 'notes'. */
|
|
485
521
|
id: string;
|
|
486
522
|
/** Display label rendered on the tab strip. */
|
|
487
523
|
label: string;
|
|
488
524
|
/** Ordered list of tiers within this tab. */
|
|
489
525
|
tiers: readonly TierConfig[];
|
|
490
|
-
/** Tier ids whose rows are hidden behind an Advanced <details> disclosure. */
|
|
491
|
-
advancedTiers?: readonly string[];
|
|
492
526
|
/**
|
|
493
|
-
* Required on color
|
|
527
|
+
* Required on color entries (id 'color' / 'color-secondary'). Carries the
|
|
494
528
|
* structural metadata (base roles, scheme registry, panel settings) for the
|
|
495
529
|
* color tab's palette picker and semantic table. Absent on non-color tabs.
|
|
496
530
|
*/
|
|
497
531
|
colorExtras?: ColorClusterExtras;
|
|
532
|
+
/** Required on the reserved `notes` tab; forbidden on other tabs. */
|
|
533
|
+
notesExtras?: NotesExtras;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
export interface NotesExtras {
|
|
537
|
+
title: string;
|
|
538
|
+
html: string;
|
|
498
539
|
}
|
|
499
540
|
```
|
|
500
541
|
|
|
501
|
-
### 3.2
|
|
542
|
+
### 3.2 Preview matrix
|
|
543
|
+
|
|
544
|
+
`preview` is opt-in. Omitting it preserves the ordinary flat tier rows, and a
|
|
545
|
+
tier remains one visible heading; previews do not introduce a collapsed or
|
|
546
|
+
progressive-disclosure tier. The current values are:
|
|
547
|
+
|
|
548
|
+
| `preview` | Valid value kind | Runtime treatment |
|
|
549
|
+
| --- | --- | --- |
|
|
550
|
+
| `'size'` | `length`, or a `referencesTier` resolving to `length` | One type-size sample per item, sorted by resolved pixel size. |
|
|
551
|
+
| `'line-height'` | `number` | Paragraph sample with a leading guide; `previewBase` selects a font-size CSS variable when supplied. |
|
|
552
|
+
| `'family'` | `text` | The first item's font-family value supplies the style for every size and line-height sample. |
|
|
553
|
+
| `'weight'` | `select` or `number` | The first item's font-weight value supplies the style for every sample. |
|
|
554
|
+
| `'bar'` | `length` | Compact bar sized from the token value. |
|
|
555
|
+
| `'radius'` | `length` | Compact rounded-corner glyph. |
|
|
556
|
+
| `'duration'` | `length` or `number` with unit `ms` or `s` | Compact timing glyph using the token's duration value. |
|
|
557
|
+
|
|
558
|
+
The font specimen toolbar persists `{ text, preset, overridden, width }` under
|
|
559
|
+
`${storagePrefix}-specimen`; width is clamped to 240–720 pixels. **Render on
|
|
560
|
+
page** mounts a read-only specimen in the host document under
|
|
561
|
+
`.tokenpanel-on-page-specimen[data-zdtp-specimen]`, temporarily forces the
|
|
562
|
+
right dock, and restores the prior mode when the specimen is disabled, closed,
|
|
563
|
+
unmounted, or loses its dock claim. The specimen is excluded from token scans
|
|
564
|
+
and page pickers.
|
|
565
|
+
|
|
566
|
+
### 3.3 Reserved tab ids
|
|
502
567
|
|
|
503
568
|
| Tab id | Meaning |
|
|
504
569
|
| ------------------ | -------------------------------------------------- |
|
|
505
570
|
| `color` | Primary color tab — palette + base roles + semantics + scheme picker. Requires `colorExtras`. |
|
|
506
|
-
| `
|
|
571
|
+
| `font` | Dedicated typography tab with family/weight previews and the host-page specimen option. |
|
|
572
|
+
| `spacing` | Dedicated spacing tab with the numeric bulk editor. |
|
|
573
|
+
| `size` | Dedicated size tab with the numeric bulk editor. |
|
|
574
|
+
| `palette` | Dedicated palette editor for a generic palette tab. |
|
|
575
|
+
| `notes` | Dedicated notes tab; it renders content but carries no token state or apply/export overrides. |
|
|
576
|
+
|
|
577
|
+
The panel always prepends a synthetic `Inspect` tab for element inspection; it
|
|
578
|
+
is not supplied in `PanelConfig.tabs`. A configured `color-secondary` entry is
|
|
579
|
+
the companion color-cluster data source consumed by the primary Color tab (and
|
|
580
|
+
requires `colorExtras`); it is not an additional dedicated body dispatcher.
|
|
507
581
|
|
|
508
|
-
Any other id dispatches to `GenericTab`, which renders the tab's
|
|
509
|
-
using kind-appropriate editors.
|
|
582
|
+
Any other configured id dispatches to `GenericTab`, which renders the tab's
|
|
583
|
+
`tiers` using kind-appropriate editors.
|
|
510
584
|
|
|
511
|
-
### 3.
|
|
585
|
+
### 3.4 Validation rules
|
|
512
586
|
|
|
513
587
|
`assertValidPanelConfig` enforces these structural rules at the host-adapter
|
|
514
588
|
trust boundary:
|
|
@@ -523,7 +597,7 @@ trust boundary:
|
|
|
523
597
|
- `referencesTier` must name an existing tier in the same tab, and the
|
|
524
598
|
referencing tier's kind must match the referenced tier's kind.
|
|
525
599
|
|
|
526
|
-
### 3.
|
|
600
|
+
### 3.5 Apply behaviour for ref-tier items
|
|
527
601
|
|
|
528
602
|
When a `TierConfig` carries `referencesTier`, the apply pipeline treats each
|
|
529
603
|
item's persisted value as the id of an item in the referenced tier. The
|
|
@@ -532,9 +606,9 @@ emitted CSS override is `var(--target-cssvar)` where `target-cssvar` is the
|
|
|
532
606
|
|
|
533
607
|
By default the write target is `:root` (`document.documentElement`). When a
|
|
534
608
|
`PanelConfig.applySink` is configured for the instance, writes are routed
|
|
535
|
-
through the sink instead — see §3.
|
|
609
|
+
through the sink instead — see §3.6.
|
|
536
610
|
|
|
537
|
-
### 3.
|
|
611
|
+
### 3.6 `applySink` — optional CSS-var write target
|
|
538
612
|
|
|
539
613
|
When `PanelConfig.applySink` is set, all CSS-var writes and clears for that
|
|
540
614
|
panel instance route through the sink rather than `document.documentElement`.
|
|
@@ -596,7 +670,7 @@ const handle = configurePanel({
|
|
|
596
670
|
});
|
|
597
671
|
```
|
|
598
672
|
|
|
599
|
-
### 3.
|
|
673
|
+
### 3.7 Helpers (re-exported from the package root)
|
|
600
674
|
|
|
601
675
|
```ts
|
|
602
676
|
export function isLengthKind(v: TierValueKind): boolean;
|
|
@@ -609,6 +683,23 @@ export function isContentKind(v: TierValueKind): boolean;
|
|
|
609
683
|
export function isMaskImageKind(v: TierValueKind): boolean;
|
|
610
684
|
```
|
|
611
685
|
|
|
686
|
+
### 3.8 Canonical state transaction
|
|
687
|
+
|
|
688
|
+
All panel mutations use one transaction path, including ordinary row edits,
|
|
689
|
+
bulk actions, imports, snapshot restore, undo, redo, and reset. A transaction
|
|
690
|
+
applies the new state and CSS-variable writes, saves the persisted envelope,
|
|
691
|
+
updates component state, and then records the history entry in that order.
|
|
692
|
+
History is identity-aware and held in memory only; the persisted A/B snapshots
|
|
693
|
+
and token envelope are separate storage concerns. After a disk apply, the
|
|
694
|
+
implementation resets the last-applied baseline to `{}` and reconciles only
|
|
695
|
+
variables confirmed as written, so retained or unrouted overrides stay dirty.
|
|
696
|
+
Because disk Apply does not write base-role variables, a confirmed semantic
|
|
697
|
+
write derived from an unchanged `bg` or `fg` alias also reconciles that alias's
|
|
698
|
+
role-index dependency. Before resetting the dependency, other unwritten
|
|
699
|
+
semantic aliases using the same role are materialized to their resolved
|
|
700
|
+
numeric palette index. Their emitted value and dirty state are preserved for a
|
|
701
|
+
later Apply.
|
|
702
|
+
|
|
612
703
|
---
|
|
613
704
|
|
|
614
705
|
## 4. Color tab contract
|
|
@@ -659,9 +750,11 @@ export interface ColorClusterExtras {
|
|
|
659
750
|
* on init. Set to `false` to disable scheme-to-`data-theme` binding; this
|
|
660
751
|
* does not disable per-mode literal editing or emitted `light-dark(...)`
|
|
661
752
|
* values.
|
|
662
|
-
|
|
753
|
+
*/
|
|
663
754
|
colorMode: false | { defaultMode: 'light' | 'dark'; lightScheme: string; darkScheme: string };
|
|
664
755
|
};
|
|
756
|
+
/** Optional semantic-item-id → SemanticValue defaults override map. */
|
|
757
|
+
semanticDefaults?: Record<string, SemanticValue>;
|
|
665
758
|
}
|
|
666
759
|
```
|
|
667
760
|
|
|
@@ -676,8 +769,8 @@ export interface ColorScheme {
|
|
|
676
769
|
cursor: ColorRef;
|
|
677
770
|
selectionBg: ColorRef;
|
|
678
771
|
selectionFg: ColorRef;
|
|
679
|
-
palette: readonly string[]; //
|
|
680
|
-
shikiTheme
|
|
772
|
+
palette: readonly string[]; // the public type requires exactly 16 entries
|
|
773
|
+
shikiTheme?: string;
|
|
681
774
|
semantic?: Record<string, ColorRef>;
|
|
682
775
|
}
|
|
683
776
|
```
|
|
@@ -744,13 +837,19 @@ The apply pipeline for color tabs:
|
|
|
744
837
|
|
|
745
838
|
- For each palette `TierItem` in the palette tier, write
|
|
746
839
|
`item.cssVar` ← `palette[i]` from the active scheme / user override.
|
|
747
|
-
- For each `(roleKey, cssName)` in `colorExtras.baseRoles`,
|
|
748
|
-
`cssName` ← `palette[state[roleKey]]`.
|
|
840
|
+
- For each `(roleKey, cssName)` in `colorExtras.baseRoles`, the live DOM apply
|
|
841
|
+
path writes `cssName` ← `palette[state[roleKey]]`.
|
|
749
842
|
- For each semantic `TierItem`, resolve
|
|
750
843
|
`state.semanticMappings[key] ?? colorExtras.semanticDefaults[key]`
|
|
751
|
-
through `resolveMapping` and write `
|
|
844
|
+
through `resolveMapping` and write the emitted CSS value: `var(...)` for a
|
|
845
|
+
palette/reference mapping, a literal string for a literal mapping, or
|
|
846
|
+
`light-dark(light, dark)` for a per-mode literal.
|
|
752
847
|
- `clearAppliedStyles()` removes every property the cluster could have set.
|
|
753
848
|
|
|
849
|
+
The disk `buildApplyOverrides` payload intentionally emits palette and
|
|
850
|
+
semantic CSS variables only; base-role values are runtime wiring and are not
|
|
851
|
+
included in source-file rewrites.
|
|
852
|
+
|
|
754
853
|
### 4.6 `applyEndpoint` and `applyRouting`
|
|
755
854
|
|
|
756
855
|
The Apply modal's button is gated on two `PanelConfig` fields:
|
|
@@ -773,6 +872,13 @@ The **bin server** is the reference implementation for the apply contract.
|
|
|
773
872
|
### 5.1 Request & response envelopes
|
|
774
873
|
|
|
775
874
|
The Apply button POSTs to `PanelConfig.applyEndpoint` with a flat JSON diff.
|
|
875
|
+
The client sends only changed tokens. A token is changed exactly when the CSS
|
|
876
|
+
value it would emit differs from the value its baseline would emit. Therefore
|
|
877
|
+
an empty flat override or one equal to its manifest default is omitted;
|
|
878
|
+
semantic role aliases and palette indices compare by their resolved palette
|
|
879
|
+
slot, while literal and ref mappings compare structurally. Palette slots use
|
|
880
|
+
the active color-identity baseline. The Apply payload may also contain a
|
|
881
|
+
secondary color cluster, diffed against that cluster's configured defaults.
|
|
776
882
|
|
|
777
883
|
**Request**
|
|
778
884
|
|
|
@@ -788,6 +894,60 @@ Content-Type: application/json
|
|
|
788
894
|
}
|
|
789
895
|
```
|
|
790
896
|
|
|
897
|
+
The same endpoint accepts two optional coordination fields:
|
|
898
|
+
|
|
899
|
+
- `dryRun: true` computes a preview without creating a temporary file,
|
|
900
|
+
renaming a file, or otherwise mutating disk. A dry run may mix routed and
|
|
901
|
+
unrouted tokens; unrouted entries are diagnostics in the successful preview
|
|
902
|
+
rather than a whole-request error.
|
|
903
|
+
- `expectDigests` maps the repo-relative `file` values from a preceding preview
|
|
904
|
+
to their SHA-256 `digest` values. On a real write, every supplied digest is
|
|
905
|
+
checked after all files have been read and before any file is written.
|
|
906
|
+
|
|
907
|
+
**Response 200 (dry run)**
|
|
908
|
+
|
|
909
|
+
```json
|
|
910
|
+
{
|
|
911
|
+
"ok": true,
|
|
912
|
+
"dryRun": true,
|
|
913
|
+
"files": [
|
|
914
|
+
{
|
|
915
|
+
"file": "src/styles/tokens.css",
|
|
916
|
+
"blockKind": "root",
|
|
917
|
+
"digest": "<64 lowercase SHA-256 hex characters>",
|
|
918
|
+
"changed": ["--myapp-spacing-md"],
|
|
919
|
+
"unchanged": ["--myapp-spacing-lg"],
|
|
920
|
+
"unknown": [],
|
|
921
|
+
"unknownOutsideBlock": [],
|
|
922
|
+
"hunks": [
|
|
923
|
+
{
|
|
924
|
+
"cssVar": "--myapp-spacing-md",
|
|
925
|
+
"line": 12,
|
|
926
|
+
"before": " --myapp-spacing-md: 1rem;",
|
|
927
|
+
"after": " --myapp-spacing-md: 2rem;",
|
|
928
|
+
"context": {
|
|
929
|
+
"before": [" --myapp-spacing-sm: 0.5rem;"],
|
|
930
|
+
"after": [" --myapp-spacing-lg: 3rem;"]
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
]
|
|
934
|
+
}
|
|
935
|
+
],
|
|
936
|
+
"rejected": ["--unrouted-token"],
|
|
937
|
+
"rejectedReasons": ["--unrouted-token: no route configured for prefix family (...)"]
|
|
938
|
+
}
|
|
939
|
+
```
|
|
940
|
+
|
|
941
|
+
`blockKind` identifies the scanned block containing the requested declaration;
|
|
942
|
+
`:root` wins when a request changes declarations in both supported block kinds.
|
|
943
|
+
For an unknown-only file result, the first available kind (`root`, then
|
|
944
|
+
`theme`) is reported. `line` is one-based. `before` and `after` are complete
|
|
945
|
+
declaration lines, while each context array contains the adjacent proposed-file
|
|
946
|
+
line on that side. `hunks` contains exactly one entry per changed cssVar; two
|
|
947
|
+
declarations on one physical line therefore produce two independently-keyed
|
|
948
|
+
hunks with the same line number. Unknown and unchanged tokens do not produce
|
|
949
|
+
hunks.
|
|
950
|
+
|
|
791
951
|
**Response 200 (success)**
|
|
792
952
|
|
|
793
953
|
```json
|
|
@@ -798,11 +958,13 @@ Content-Type: application/json
|
|
|
798
958
|
"file": "src/styles/tokens.css",
|
|
799
959
|
"changed": ["--myapp-spacing-md"],
|
|
800
960
|
"unchanged": ["--myapp-spacing-lg"],
|
|
801
|
-
"unknown": []
|
|
961
|
+
"unknown": [],
|
|
962
|
+
"unknownOutsideBlock": []
|
|
802
963
|
}
|
|
803
964
|
],
|
|
804
965
|
"unknownCssVars": [],
|
|
805
|
-
"unchangedCssVars": ["--myapp-spacing-lg"]
|
|
966
|
+
"unchangedCssVars": ["--myapp-spacing-lg"],
|
|
967
|
+
"unknownOutsideBlockCssVars": []
|
|
806
968
|
}
|
|
807
969
|
```
|
|
808
970
|
|
|
@@ -817,8 +979,10 @@ Content-Type: application/json
|
|
|
817
979
|
```
|
|
818
980
|
|
|
819
981
|
Returned for: malformed JSON, missing `tokens` field, empty tokens map,
|
|
820
|
-
invalid token names (no `--` prefix, spaces, slashes),
|
|
821
|
-
|
|
982
|
+
invalid token names (no `--` prefix, spaces, slashes), or path escape attempts.
|
|
983
|
+
For a real write, an unsupported CSS-var prefix is also a 400 error. A dry run
|
|
984
|
+
keeps unsupported prefixes in its `rejected` / `rejectedReasons` diagnostics
|
|
985
|
+
so the caller can preview the rest of the request.
|
|
822
986
|
|
|
823
987
|
**Response 403 (Forbidden)**
|
|
824
988
|
|
|
@@ -833,9 +997,30 @@ Empty body, `Allow: POST, OPTIONS` header.
|
|
|
833
997
|
**Response 409 (Conflict)**
|
|
834
998
|
|
|
835
999
|
```json
|
|
836
|
-
{ "ok": false, "error": "No top-level :root { ... } block in <file>" }
|
|
1000
|
+
{ "ok": false, "error": "No top-level :root { ... } or @theme { ... } block in <file>" }
|
|
1001
|
+
```
|
|
1002
|
+
|
|
1003
|
+
The handler scans only the first top-level `:root` block and the first
|
|
1004
|
+
top-level `@theme` block (bare or with one modifier). `:root` wins when the
|
|
1005
|
+
same variable is declared in both. Later blocks and nested blocks are not
|
|
1006
|
+
rewritable. A dry run can succeed with only unrouted tokens; those tokens are
|
|
1007
|
+
listed in `rejected` and `rejectedReasons`, while a file with no supported
|
|
1008
|
+
block is a `409`.
|
|
1009
|
+
|
|
1010
|
+
A real write whose current file content does not match a supplied preview
|
|
1011
|
+
digest returns the following envelope before any target is written:
|
|
1012
|
+
|
|
1013
|
+
```json
|
|
1014
|
+
{
|
|
1015
|
+
"ok": false,
|
|
1016
|
+
"reason": "stale-file",
|
|
1017
|
+
"files": ["src/styles/tokens.css"]
|
|
1018
|
+
}
|
|
837
1019
|
```
|
|
838
1020
|
|
|
1021
|
+
The client must request a new dry run and ask the user to review the refreshed
|
|
1022
|
+
hunks. Omitting `expectDigests` preserves the legacy write behaviour.
|
|
1023
|
+
|
|
839
1024
|
**Response 500 (Internal server error)**
|
|
840
1025
|
|
|
841
1026
|
```json
|
|
@@ -863,14 +1048,19 @@ Hosts physically unable to spawn Node.js must:
|
|
|
863
1048
|
the routing map, reject prefixes not in the map.
|
|
864
1049
|
3. Path safety — resolve each target path to an absolute path, verify it sits
|
|
865
1050
|
within `writeRoot`, reject path-escape attempts.
|
|
866
|
-
4. Read & parse — load each CSS file, find the `:root { ... }`
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
1051
|
+
4. Read & parse — load each CSS file, find the first top-level `:root { ... }`
|
|
1052
|
+
or first top-level `@theme { ... }` block (bare or with one modifier; fail
|
|
1053
|
+
409 if neither exists), parse the existing variable values.
|
|
1054
|
+
5. Compute rewrite — compute `changed` / `unchanged` / `unknown` and
|
|
1055
|
+
`unknownOutsideBlock`, build the updated `:root` / `@theme` content, its
|
|
1056
|
+
per-cssVar hunks, and the SHA-256 of the original bytes.
|
|
1057
|
+
6. Preview/stale gate — for `dryRun: true`, return the preview immediately. For
|
|
1058
|
+
a real write with `expectDigests`, compare every supplied digest and return
|
|
1059
|
+
the stale-file 409 before the first mutation when any target differs.
|
|
1060
|
+
7. Atomic write — keep the original file content in memory. Write updated
|
|
871
1061
|
content to a temp file. Atomically rename temp to target. If any write
|
|
872
1062
|
fails, restore every previously-written file.
|
|
873
|
-
|
|
1063
|
+
8. Respond — return the exact JSON envelope shapes pinned in §5.1.
|
|
874
1064
|
|
|
875
1065
|
### 5.4 Routing config — single source of truth
|
|
876
1066
|
|
|
@@ -933,15 +1123,17 @@ if (
|
|
|
933
1123
|
specific version key — an empty `{}` / `[]` / `null` / `''` does NOT trigger
|
|
934
1124
|
it. (zdtp itself never writes such a value: `clearPersistedState()` removes
|
|
935
1125
|
the `-state` keys outright, so this guard only covers envelopes written by
|
|
936
|
-
hand or by another tool.) Overrides MUST be re-applied to
|
|
937
|
-
the panel stays hidden, otherwise
|
|
1126
|
+
hand or by another tool.) Overrides MUST be re-applied to the configured
|
|
1127
|
+
sink (or default `:root`) even when the panel stays hidden, otherwise
|
|
1128
|
+
hard-nav produces a FOUT.
|
|
938
1129
|
- `shouldAutoload()` — reads `${storagePrefix}:autoload` (colon-form, §2).
|
|
939
1130
|
Returns `true` when the flag is `'1'` (explicit, written by `enableAutoload()`)
|
|
940
1131
|
OR `'auto'` (auto-remembered, written by opening the panel — see "Auto-remember
|
|
941
1132
|
on open" below). This is the owner-mode signal: the panel bundle fetches
|
|
942
1133
|
eagerly and mounts CLOSED so the element-path inspector is armed even though
|
|
943
|
-
the panel UI is hidden. General visitors (no flag, or `'0'`) pay
|
|
944
|
-
cost
|
|
1134
|
+
the panel UI is hidden. General visitors (no flag, or `'0'`) pay no
|
|
1135
|
+
panel-bundle cost; the small host adapter/config bootstrap still runs. A
|
|
1136
|
+
downstream host that wants to distinguish the two populations can
|
|
945
1137
|
test `=== '1'` directly — see "Auto-remember on open" for the caveat.
|
|
946
1138
|
- `loadElementPathEnabled()` — reads the element-path inspector's persistence
|
|
947
1139
|
key. Returns `true` when the inspector was left enabled. Ensures the Preact
|
|
@@ -952,9 +1144,11 @@ if (
|
|
|
952
1144
|
enabled. Ensures the Preact shell is mounted and the lazy boundary is
|
|
953
1145
|
imported even when the panel UI is hidden.
|
|
954
1146
|
|
|
955
|
-
When none of the
|
|
1147
|
+
When none of the six signals is present — the common case for first-time
|
|
956
1148
|
visitors and general site visitors on a public site with owner-autoload — the
|
|
957
|
-
panel bundle is NOT fetched
|
|
1149
|
+
panel bundle is NOT fetched, no panel stylesheet is injected, and no panel
|
|
1150
|
+
root is mounted. The small host adapter/config bootstrap still runs to make
|
|
1151
|
+
that decision.
|
|
958
1152
|
|
|
959
1153
|
#### Storage-key table for §6.2 signals
|
|
960
1154
|
|
|
@@ -1006,7 +1200,9 @@ panel bundle is NOT fetched and the page is completely free of panel JS.
|
|
|
1006
1200
|
#### Auto-remember on open
|
|
1007
1201
|
|
|
1008
1202
|
Any action that shows the panel (`showDesignPanel()`, `toggleDesignPanel()`,
|
|
1009
|
-
|
|
1203
|
+
the fixed-name `window.zdtp.show()` / `.toggle()` aliases, an instance
|
|
1204
|
+
handle's `open()` / `toggle()`, the panel header's open action, or an instance
|
|
1205
|
+
toggle event) MUST also write
|
|
1010
1206
|
`${storagePrefix}:autoload = 'auto'` (auto-remembered provenance, distinct
|
|
1011
1207
|
from the `'1'` that `enableAutoload()` writes) — implemented by
|
|
1012
1208
|
`rememberAutoload()`. This ensures that once the owner has opened the panel
|
|
@@ -1034,13 +1230,26 @@ already hold `'1'`, and that provenance was never recorded, so it cannot be
|
|
|
1034
1230
|
reclassified. The `=== '1'` discrimination applies only to opens made from
|
|
1035
1231
|
this version onward.
|
|
1036
1232
|
|
|
1233
|
+
#### Shared Alt+click picker ownership
|
|
1234
|
+
|
|
1235
|
+
Element path, DOM Tweaker, and element inspect share one document-level
|
|
1236
|
+
Alt+click coordinator. Only one owner may be armed at a time; a new request
|
|
1237
|
+
revokes the previous owner's armed state before it starts. Panel-owned surfaces
|
|
1238
|
+
and the host-page specimen are excluded from all three pickers.
|
|
1239
|
+
|
|
1240
|
+
| Feature | Activation | Result |
|
|
1241
|
+
| --- | --- | --- |
|
|
1242
|
+
| Element path | Owner autoload or its panel toggle, then `Alt+click` | Copies an annotated selector/path block. |
|
|
1243
|
+
| DOM Tweaker | Configured feature toggle, then `Alt+click` | Opens the Tailwind class editor and live utility preview. |
|
|
1244
|
+
| Element inspect | Header toggle or `I`, then click; `Alt` also arms the coordinator | Opens the reserved inspect tab with computed and inherited token rows. |
|
|
1245
|
+
|
|
1037
1246
|
### 6.3 Astro view-transition lifecycle
|
|
1038
1247
|
|
|
1039
1248
|
The adapter's existing `astro:before-swap` and `astro:page-load` listeners
|
|
1040
1249
|
stay. They are Astro-specific and only register when `document` is available:
|
|
1041
1250
|
|
|
1042
1251
|
- `astro:before-swap` → unmount the Preact tree, remove the host node, snapshot/restore visibility intent.
|
|
1043
|
-
- `astro:page-load` → re-apply persisted overrides + re-materialise the shell when any of the
|
|
1252
|
+
- `astro:page-load` → re-apply persisted overrides + re-materialise the shell when any of the six gate signals (§6.2) is true.
|
|
1044
1253
|
|
|
1045
1254
|
### 6.4 Console API
|
|
1046
1255
|
|
|
@@ -1104,11 +1313,12 @@ window.zdtp.toggle = () => void | Promise<void>; // toggle the panel
|
|
|
1104
1313
|
always installs first ("first install wins" — see the next point). The
|
|
1105
1314
|
package-root install site is therefore reached only by non-Astro hosts.
|
|
1106
1315
|
- **Never clobbers a host-defined `window.zdtp`.** If `window.zdtp` already
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1316
|
+
exposes callable `show` / `hide` / `toggle` methods, the install is skipped
|
|
1317
|
+
silently — this supports hosts that pre-claim the alias before lazily loading
|
|
1318
|
+
the panel bundle. Other pre-existing values are also left untouched, but
|
|
1319
|
+
produce a `console.warn`. (This includes the edge case of a host that picks
|
|
1320
|
+
`consoleNamespace: 'zdtp'`: the namespace object installed at §6.4 does not
|
|
1321
|
+
expose the fixed-name alias shape, so the second install site warns and skips.)
|
|
1112
1322
|
- **Auto-remember carries over for free.** `zdtp.show()` routes through the
|
|
1113
1323
|
same `showDesignTokenPanel()` / `handle.open()` core as every other open
|
|
1114
1324
|
path, so it arms `${storagePrefix}:autoload = 'auto'` exactly like
|
|
@@ -1121,32 +1331,55 @@ window.zdtp.toggle = () => void | Promise<void>; // toggle the panel
|
|
|
1121
1331
|
|
|
1122
1332
|
### 7.1 Panel-private namespace
|
|
1123
1333
|
|
|
1124
|
-
The panel ships its own bundled CSS.
|
|
1125
|
-
|
|
1334
|
+
The panel ships its own bundled CSS. Panel-private color, font, spacing,
|
|
1335
|
+
typography, and z-index variables use the `--tokentweak-*` prefix; the shared
|
|
1336
|
+
radius token is `--radius-tokentweak`. They are scoped to the panel shell,
|
|
1337
|
+
mini pill, modal class prefix, and the body-level popover/tooltip/inspector
|
|
1338
|
+
surfaces:
|
|
1126
1339
|
|
|
1127
1340
|
```css
|
|
1128
1341
|
:where(.tokenpanel-shell, [data-design-token-panel-modal]) {
|
|
1129
|
-
|
|
1130
|
-
--tokentweak-
|
|
1131
|
-
--tokentweak-color-fg:
|
|
1342
|
+
/* base-0 is the darkest ground; stops ascend toward the foreground. */
|
|
1343
|
+
--tokentweak-palette-base-5: oklch(0.8 0 0);
|
|
1344
|
+
--tokentweak-color-fg: var(--tokentweak-palette-base-5);
|
|
1345
|
+
--tokentweak-color-accent-bar: #efb477;
|
|
1132
1346
|
/* …every panel-chrome value lives here */
|
|
1133
1347
|
}
|
|
1134
1348
|
```
|
|
1135
1349
|
|
|
1136
1350
|
- **No Tailwind dependency.** The package builds and runs without Tailwind in
|
|
1137
1351
|
the consumer.
|
|
1138
|
-
- **
|
|
1139
|
-
|
|
1352
|
+
- **Self-injected by the panel entry.** The panel calls `ensurePanelStyles()`
|
|
1353
|
+
when it first mounts, so a consumer does not need a CSS import. The `./styles`
|
|
1354
|
+
sub-export remains available when a host wants to pull the stylesheet into its
|
|
1355
|
+
own static CSS pipeline; importing it twice is unnecessary.
|
|
1140
1356
|
|
|
1141
1357
|
```ts
|
|
1142
|
-
import '@takazudo/zdtp/styles';
|
|
1358
|
+
import '@takazudo/zdtp/styles'; // optional static-CSS path
|
|
1143
1359
|
```
|
|
1144
1360
|
|
|
1361
|
+
The semantic color layer includes `--tokentweak-color-fg`, `bg`, `muted`,
|
|
1362
|
+
`border`, `surface`, `accent`, `accent-bar`, `accent-hover`, `code-bg`,
|
|
1363
|
+
`code-fg`, `success`, `danger`, and `warning`, backed by the private
|
|
1364
|
+
`--tokentweak-palette-base-*` OKLCH ramp, plus `--tokentweak-font-mono`. Spacing,
|
|
1365
|
+
typography, radius, and stacking values use the same prefix (`pad-*`, `gap-*`,
|
|
1366
|
+
`text-*`, `--radius-tokentweak`, and `z-*`). The chrome does not read host
|
|
1367
|
+
`--color-*` or `--font-mono` variables; hosts that retheme it assign the
|
|
1368
|
+
`--tokentweak-*` names directly on one of the listed scopes.
|
|
1369
|
+
|
|
1370
|
+
Docking is a host-document contract rather than a panel-private token:
|
|
1371
|
+
`--zdtp-dock-inset-right` and `--zdtp-dock-inset-bottom` are published on the
|
|
1372
|
+
host root while the corresponding dock claim is active. The on-page specimen
|
|
1373
|
+
uses `.tokenpanel-on-page-specimen[data-zdtp-specimen]`; it inherits the host
|
|
1374
|
+
font/foreground, is excluded from token scans and page pickers, and is removed
|
|
1375
|
+
when the specimen is disabled, closed, unmounted, or loses its dock claim.
|
|
1376
|
+
|
|
1145
1377
|
### 7.2 Consumer's editable tokens
|
|
1146
1378
|
|
|
1147
1379
|
The tokens the panel writes to (the `cssVar` field on each `TierItem`) are
|
|
1148
|
-
entirely consumer-controlled. The package
|
|
1149
|
-
on `:root
|
|
1380
|
+
entirely consumer-controlled. The package writes them through the configured
|
|
1381
|
+
`applySink`, or through `setProperty` on the default `:root` target when no
|
|
1382
|
+
sink is supplied.
|
|
1150
1383
|
|
|
1151
1384
|
- **Read:** the panel never reads consumer CSS variables (it carries its own
|
|
1152
1385
|
defaults via `TierItem.default`).
|
|
@@ -1162,20 +1395,30 @@ rules on `[data-design-token-panel-modal]`.
|
|
|
1162
1395
|
|
|
1163
1396
|
### 7.4 Self-contained panel chrome palette (no host theme reads)
|
|
1164
1397
|
|
|
1165
|
-
The panel-chrome color tokens are declared in `panel-tokens.css` as
|
|
1166
|
-
|
|
1398
|
+
The panel-chrome color tokens are declared in `panel-tokens.css` as semantic
|
|
1399
|
+
aliases onto a private OKLCH ramp so the panel paints as a neutral dark surface
|
|
1167
1400
|
regardless of what the host's `--color-*` tokens resolve to:
|
|
1168
1401
|
|
|
1169
1402
|
```css
|
|
1170
1403
|
:where(.tokenpanel-shell, [data-design-token-panel-modal]) {
|
|
1171
|
-
|
|
1172
|
-
--tokentweak-
|
|
1173
|
-
--tokentweak-
|
|
1174
|
-
--tokentweak-
|
|
1404
|
+
/* base-0 is the darkest ground; stops ascend toward the foreground. */
|
|
1405
|
+
--tokentweak-palette-base-0: oklch(0.18 0 0);
|
|
1406
|
+
--tokentweak-palette-base-1: oklch(0.25 0 0);
|
|
1407
|
+
--tokentweak-palette-base-2: oklch(0.34 0 0);
|
|
1408
|
+
--tokentweak-palette-base-3: oklch(0.536 0 0);
|
|
1409
|
+
--tokentweak-palette-base-4: oklch(0.66 0 0);
|
|
1410
|
+
--tokentweak-palette-base-5: oklch(0.8 0 0);
|
|
1411
|
+
--tokentweak-palette-base-6: oklch(0.91 0 0);
|
|
1412
|
+
--tokentweak-color-fg: var(--tokentweak-palette-base-5);
|
|
1413
|
+
--tokentweak-color-bg: var(--tokentweak-palette-base-0);
|
|
1414
|
+
--tokentweak-color-muted: var(--tokentweak-palette-base-4);
|
|
1415
|
+
--tokentweak-color-border: var(--tokentweak-palette-base-3);
|
|
1416
|
+
--tokentweak-color-surface: var(--tokentweak-palette-base-1);
|
|
1175
1417
|
--tokentweak-color-accent: #d69a66;
|
|
1418
|
+
--tokentweak-color-accent-bar: #efb477;
|
|
1176
1419
|
--tokentweak-color-accent-hover: #a7c0e3;
|
|
1177
|
-
--tokentweak-color-code-bg:
|
|
1178
|
-
--tokentweak-color-code-fg:
|
|
1420
|
+
--tokentweak-color-code-bg: var(--tokentweak-palette-base-2);
|
|
1421
|
+
--tokentweak-color-code-fg: var(--tokentweak-palette-base-6);
|
|
1179
1422
|
--tokentweak-color-success: #93bb77;
|
|
1180
1423
|
--tokentweak-color-danger: #da6871;
|
|
1181
1424
|
--tokentweak-color-warning: #dfbb77;
|
|
@@ -1192,9 +1435,17 @@ in a demo — MUST NOT bleed into the panel chrome.
|
|
|
1192
1435
|
**Override surface for hosts:** a host that wants to retheme the panel
|
|
1193
1436
|
chrome assigns directly to the `--tokentweak-color-*` /
|
|
1194
1437
|
`--tokentweak-font-mono` names on `.tokenpanel-shell`,
|
|
1195
|
-
`[data-design-token-panel-modal]`,
|
|
1196
|
-
|
|
1197
|
-
|
|
1438
|
+
`.tokenpanel-mini-pill`, `[data-design-token-panel-modal]`, the highlight
|
|
1439
|
+
settings and chain popovers, the color picker, tooltip, element-path label and
|
|
1440
|
+
toast, or an element-inspect surface (or any ancestor). `:where()` keeps
|
|
1441
|
+
specificity at 0. This single name layer is the entire host-override contract
|
|
1442
|
+
for panel chrome — `--color-*` reads are not part of it.
|
|
1443
|
+
|
|
1444
|
+
Hosts may instead override a `--tokentweak-palette-base-*` stop to update all
|
|
1445
|
+
roles that alias it; a direct semantic `--tokentweak-color-*` assignment still
|
|
1446
|
+
wins. The border role is intentionally separate: `--tokentweak-color-muted`
|
|
1447
|
+
now recolors secondary text only. A host that previously used it for both text
|
|
1448
|
+
and 1px dividers must also assign `--tokentweak-color-border`.
|
|
1198
1449
|
|
|
1199
1450
|
**Invariant:** the panel package MUST NOT read `--color-*` or
|
|
1200
1451
|
`--font-mono` anywhere. Both `panel.css` and `panel-tokens.css` are pinned
|
|
@@ -1209,8 +1460,10 @@ grep -n 'var(--font-mono' src/styles/panel-tokens.css # → 0
|
|
|
1209
1460
|
|
|
1210
1461
|
### 7.5 Host-adapter side-effect import (paired-unit obligation)
|
|
1211
1462
|
|
|
1212
|
-
|
|
1213
|
-
|
|
1463
|
+
The consumer MUST own a side-effect import for the host-adapter, paired with
|
|
1464
|
+
`<DesignTokenPanelHost>`. The `./styles` import is optional because the panel
|
|
1465
|
+
entry self-injects its stylesheet; use it only when the host wants a static CSS
|
|
1466
|
+
pipeline:
|
|
1214
1467
|
|
|
1215
1468
|
```astro
|
|
1216
1469
|
<DesignTokenPanelHost config={myPanelConfig} />
|
|
@@ -1224,11 +1477,13 @@ for the host-adapter, paired with `<DesignTokenPanelHost>`:
|
|
|
1224
1477
|
|
|
1225
1478
|
## 8. Storage-key continuity & migration paths
|
|
1226
1479
|
|
|
1227
|
-
### 8.1
|
|
1480
|
+
### 8.1 Minimal fallback before configuration
|
|
1228
1481
|
|
|
1229
|
-
The package ships **zero**
|
|
1230
|
-
|
|
1231
|
-
a
|
|
1482
|
+
The package ships **zero** host-specific identifiers. Before the first explicit
|
|
1483
|
+
`configurePanel` call, `getPanelConfig()` returns a minimal sentinel with empty
|
|
1484
|
+
token manifests and a stub color cluster so imports and adapter boot can remain
|
|
1485
|
+
safe; it is not a useful consumer configuration. Hosts MUST configure the
|
|
1486
|
+
panel explicitly to render their own tabs and token values.
|
|
1232
1487
|
|
|
1233
1488
|
### 8.2 Storage-key derivation is literal
|
|
1234
1489
|
|
|
@@ -1285,7 +1540,7 @@ The historical zdtp-internal map is exported as `ZDTP_LEGACY_TYPOGRAPHY_RENAME_M
|
|
|
1285
1540
|
|
|
1286
1541
|
---
|
|
1287
1542
|
|
|
1288
|
-
## 9. JSON export / import schema (serde
|
|
1543
|
+
## 9. JSON export / import schema (serde)
|
|
1289
1544
|
|
|
1290
1545
|
### 9.1 Schema versioning
|
|
1291
1546
|
|
|
@@ -1293,9 +1548,12 @@ The historical zdtp-internal map is exported as `ZDTP_LEGACY_TYPOGRAPHY_RENAME_M
|
|
|
1293
1548
|
| ----------------------- | ------- | ------------------------------------------------------ |
|
|
1294
1549
|
| `zudo-design-tokens/v1` | Legacy | Flat top-level `color`/`spacing`/`typography`/`size` keys |
|
|
1295
1550
|
| `zudo-design-tokens/v2` | Current | `tabs` wrapper keyed by tab id; cssVar-keyed leaves |
|
|
1551
|
+
| `zudo-design-tokens/v3` | Current | v2 structure with object-valued semantic color mappings |
|
|
1296
1552
|
|
|
1297
|
-
`serialize()`
|
|
1298
|
-
|
|
1553
|
+
`serialize()` emits v2 for states whose semantic mappings are representable by
|
|
1554
|
+
the v2 shape, and upgrades to v3 when an object-valued semantic mapping needs
|
|
1555
|
+
the v3 shape. `deserialize()` accepts v1, v2, and v3 and normalises each to an
|
|
1556
|
+
internal `TweakState`.
|
|
1299
1557
|
|
|
1300
1558
|
### 9.2 v2 format
|
|
1301
1559
|
|
|
@@ -1331,7 +1589,14 @@ Key decisions:
|
|
|
1331
1589
|
|
|
1332
1590
|
`serialize()` only emits tokens the user has changed relative to manifest
|
|
1333
1591
|
defaults. Pass `includeDefaults: true` to dump the full state. A tab key is
|
|
1334
|
-
omitted entirely when nothing in it differs.
|
|
1592
|
+
omitted entirely when nothing in it differs. "Changed" uses the canonical
|
|
1593
|
+
emitted-value definition in §5.1. Export parity covers tokens representable by
|
|
1594
|
+
the current schema: flat tabs and the primary color cluster. The secondary
|
|
1595
|
+
color cluster is Apply-only and is not added to the export schema here.
|
|
1596
|
+
|
|
1597
|
+
A sparse persisted override equal to today's manifest default remains stored
|
|
1598
|
+
but invisible to the UI, diff-only export, and Apply. It can intentionally
|
|
1599
|
+
resurface if a later manifest changes that default.
|
|
1335
1600
|
|
|
1336
1601
|
---
|
|
1337
1602
|
|
|
@@ -1341,10 +1606,12 @@ Items this contract deliberately does NOT pin down:
|
|
|
1341
1606
|
|
|
1342
1607
|
- **Persist envelope internal shape** — frozen at the current shape so
|
|
1343
1608
|
existing user state round-trips without migration.
|
|
1344
|
-
- **Schema id versioning.** `schemaId` is a configure-time
|
|
1345
|
-
it
|
|
1609
|
+
- **Schema id versioning.** `schemaId` is a configure-time display label
|
|
1610
|
+
returned by `getDesignTokenSchema()`; it does not select or version the
|
|
1611
|
+
serializer. The package-owned `SCHEMA_V1` / `SCHEMA_V2` / `SCHEMA_V3`
|
|
1612
|
+
constants govern export and import validation.
|
|
1346
1613
|
- **Shadow-DOM scoping.** The panel writes to `:root` by default; hosts
|
|
1347
|
-
that need scoped writes use `PanelConfig.applySink` (§3.
|
|
1614
|
+
that need scoped writes use `PanelConfig.applySink` (§3.6). The sink
|
|
1348
1615
|
target's lifecycle is owned by the host — not pinned here.
|
|
1349
1616
|
- **Theme-API surface.** The panel does not expose a programmatic API for
|
|
1350
1617
|
reading the current overrides outside the persist envelope.
|
|
@@ -1360,21 +1627,26 @@ Cross-reference table — what each section pins down.
|
|
|
1360
1627
|
| `configurePanel({...})` signature, multi-instance, `PanelInstanceHandle`, per-instance toggle events | §1 |
|
|
1361
1628
|
| Storage-key derivation | §2, §8 |
|
|
1362
1629
|
| Default first-open geometry (coherent size+position, viewport containment, cascade, persisted-position precedence) | §2.1 |
|
|
1630
|
+
| `PanelDockConfig`, dock modes, body-margin reflow, edge claims, and dock storage | §1, §2, §7 |
|
|
1363
1631
|
| `TabConfig` / `TierConfig` / `TierItem` / `TierValueKind` interfaces and apply behaviour | §3 |
|
|
1364
|
-
| `
|
|
1632
|
+
| `TierConfig.preview` / `previewBase` matrix and host-page specimen lifecycle | §3.2 |
|
|
1633
|
+
| `applySink` — optional CSS-var write target (upsert / clear / Reset full set) | §3.6 |
|
|
1365
1634
|
| `ColorClusterExtras` shape and multi-cluster support | §4.1, §4.3 |
|
|
1366
1635
|
| JSON-serializable constraint on color tab config | §4.2 |
|
|
1367
1636
|
| `colorPresets` and `setPanelColorPresets()` lazy attachment | §4.4 |
|
|
1368
1637
|
| Color apply behaviour | §4.5 |
|
|
1369
|
-
| Apply pipeline request / response envelopes
|
|
1638
|
+
| Apply pipeline request / response envelopes, dry-run hunks/digests, stale-write 409 | §5.1 |
|
|
1639
|
+
| Canonical transaction order and in-memory undo/redo history | §3.8 |
|
|
1370
1640
|
| Reference-implementation algorithm + native-implementation guidance | §5.2, §5.3 |
|
|
1371
1641
|
| Routing config single-source | §5.4 |
|
|
1372
|
-
| Astro `<DesignTokenPanelHost>` prop, lazy-load gate (
|
|
1642
|
+
| Astro `<DesignTokenPanelHost>` prop, lazy-load gate (6-signal), owner-autoload, console API | §6 |
|
|
1643
|
+
| Shared Alt+click owner for element path, DOM Tweaker, and element inspect | §6.2 |
|
|
1373
1644
|
| Fixed-name global open API (`window.zdtp.show/hide/toggle`) | §6.5 |
|
|
1374
1645
|
| `--tokentweak-*` namespace and Tailwind-free CSS contract | §7.1 |
|
|
1375
1646
|
| Modal class prefix and `data-design-token-panel-modal` selector contract | §7.3 |
|
|
1376
1647
|
| Self-contained panel chrome palette (no host theme reads) | §7.4 |
|
|
1377
1648
|
| Host-adapter side-effect import (paired-unit obligation) | §7.5 |
|
|
1378
1649
|
| v4 envelope precedence, v1/v2/v3 storage migration, and typography-id rename map | §2, §8.3, §8.4 |
|
|
1379
|
-
| JSON export/import
|
|
1650
|
+
| JSON export/import schemas v1/v2/v3 (serde) | §9 |
|
|
1380
1651
|
| Out-of-scope / deferred concerns | §10 |
|
|
1652
|
+
| Feature walkthrough and shortcut table | [Panel UX tour](/docs/recipes/panel-ux-tour) |
|