@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/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,29 @@ 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. |
|
|
295
|
+
|
|
296
|
+
This is the current storage-key inventory, not a release-history table. The
|
|
297
|
+
published 0.4.14 bundle already wrote `${storagePrefix}-position`,
|
|
298
|
+
`${storagePrefix}-size`, `${storagePrefix}-density`, and all three
|
|
299
|
+
`${storagePrefix}-highlight-*` keys. Their appearance in the 0.4.15 contract
|
|
300
|
+
documentation records existing storage continuity; it does not make those keys
|
|
301
|
+
new in 0.4.15.
|
|
276
302
|
|
|
277
303
|
**Constraint — colon, not dash, for `visible` and `autoload`.** Both adapter-
|
|
278
304
|
level flags use a `:` separator; every other derived key uses `-`. The colon
|
|
@@ -290,9 +316,22 @@ myapp-design-token-panel-state-v2
|
|
|
290
316
|
myapp-design-token-panel-state
|
|
291
317
|
myapp-design-token-panel-open
|
|
292
318
|
myapp-design-token-panel-position
|
|
319
|
+
myapp-design-token-panel-size
|
|
320
|
+
myapp-design-token-panel-dock
|
|
321
|
+
myapp-design-token-panel-dock-size
|
|
322
|
+
myapp-design-token-panel-density
|
|
323
|
+
myapp-design-token-panel-ghost
|
|
324
|
+
myapp-design-token-panel-specimen
|
|
325
|
+
myapp-design-token-panel-snapshot-a
|
|
326
|
+
myapp-design-token-panel-snapshot-b
|
|
327
|
+
myapp-design-token-panel-last-applied
|
|
293
328
|
myapp-design-token-panel:visible
|
|
294
329
|
myapp-design-token-panel:autoload
|
|
330
|
+
myapp-design-token-panel-elpath-enabled
|
|
295
331
|
myapp-design-token-panel-domtweaker-enabled
|
|
332
|
+
myapp-design-token-panel-highlight-slots
|
|
333
|
+
myapp-design-token-panel-highlight-outline-width
|
|
334
|
+
myapp-design-token-panel-highlight-active # sessionStorage
|
|
296
335
|
```
|
|
297
336
|
|
|
298
337
|
Unit tests in the package verify these derivations with literal-equality
|
|
@@ -387,14 +426,14 @@ public surface:
|
|
|
387
426
|
```ts
|
|
388
427
|
// Value-kind discriminated union — describes how a tier item is edited.
|
|
389
428
|
export type TierValueKind =
|
|
390
|
-
| { kind: 'length'; step: number; unit: string }
|
|
391
|
-
| { kind: 'number'; step: number }
|
|
429
|
+
| { kind: 'length'; step: number; unit: string; units?: readonly string[] }
|
|
430
|
+
| { kind: 'number'; step: number; unit?: string }
|
|
392
431
|
| { kind: 'select'; options: readonly string[] }
|
|
393
432
|
| { kind: 'text' }
|
|
394
433
|
| { kind: 'cursor' }
|
|
395
434
|
| { kind: 'content' }
|
|
396
435
|
| { kind: 'mask-image' }
|
|
397
|
-
| { kind: 'color' };
|
|
436
|
+
| { kind: 'color'; format?: 'hex' | 'oklch' };
|
|
398
437
|
|
|
399
438
|
export interface PillSpec {
|
|
400
439
|
value: string;
|
|
@@ -414,12 +453,10 @@ export type SemanticValue =
|
|
|
414
453
|
export interface TierItem {
|
|
415
454
|
/** Stable id used as the key in persisted state (e.g. `hsp-2xs`). */
|
|
416
455
|
id: string;
|
|
417
|
-
/** CSS custom property written to
|
|
456
|
+
/** CSS custom property written to the default root or configured apply sink (e.g. `--myapp-spacing-hgap-2xs`). */
|
|
418
457
|
cssVar: string;
|
|
419
458
|
/** Display label shown in the panel row. */
|
|
420
459
|
label: string;
|
|
421
|
-
/** Optional manifest group — tab components use this for section headers. */
|
|
422
|
-
group?: string;
|
|
423
460
|
/** Default value as a CSS string (`0.125rem`, `12px`, etc.). */
|
|
424
461
|
default: string;
|
|
425
462
|
/** Discriminated union describing the control kind and its metadata. */
|
|
@@ -459,6 +496,10 @@ export interface TierConfig {
|
|
|
459
496
|
* this is a multi-source allow-list for individual semantic mappings.
|
|
460
497
|
*/
|
|
461
498
|
referencesRamps?: readonly { tab?: string; tier: string }[];
|
|
499
|
+
/** Optional visual treatment rendered for this tier's values. */
|
|
500
|
+
preview?: 'size' | 'line-height' | 'family' | 'weight' | 'bar' | 'radius' | 'duration';
|
|
501
|
+
/** CSS variable used as the font-size base for a preview, when supplied. */
|
|
502
|
+
previewBase?: string;
|
|
462
503
|
}
|
|
463
504
|
|
|
464
505
|
For the full `SemanticValue` mapping and emission behavior, see the maintained
|
|
@@ -477,38 +518,78 @@ export interface ColorClusterExtras {
|
|
|
477
518
|
defaultShikiTheme: string;
|
|
478
519
|
colorSchemes: Record<string, ColorScheme>;
|
|
479
520
|
panelSettings: ClusterPanelSettings;
|
|
521
|
+
/** Optional semantic-item-id → SemanticValue defaults override map. */
|
|
522
|
+
semanticDefaults?: Record<string, SemanticValue>;
|
|
480
523
|
}
|
|
481
524
|
|
|
482
525
|
/** Top-level tab entry on PanelConfig.tabs. */
|
|
483
526
|
export interface TabConfig {
|
|
484
|
-
/** Stable id.
|
|
527
|
+
/** Stable id. Dedicated panel ids are 'color', 'font', 'spacing', 'size', 'palette', and 'notes'. */
|
|
485
528
|
id: string;
|
|
486
529
|
/** Display label rendered on the tab strip. */
|
|
487
530
|
label: string;
|
|
488
531
|
/** Ordered list of tiers within this tab. */
|
|
489
532
|
tiers: readonly TierConfig[];
|
|
490
|
-
/** Tier ids whose rows are hidden behind an Advanced <details> disclosure. */
|
|
491
|
-
advancedTiers?: readonly string[];
|
|
492
533
|
/**
|
|
493
|
-
* Required on color
|
|
534
|
+
* Required on color entries (id 'color' / 'color-secondary'). Carries the
|
|
494
535
|
* structural metadata (base roles, scheme registry, panel settings) for the
|
|
495
536
|
* color tab's palette picker and semantic table. Absent on non-color tabs.
|
|
496
537
|
*/
|
|
497
538
|
colorExtras?: ColorClusterExtras;
|
|
539
|
+
/** Required on the reserved `notes` tab; forbidden on other tabs. */
|
|
540
|
+
notesExtras?: NotesExtras;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
export interface NotesExtras {
|
|
544
|
+
title: string;
|
|
545
|
+
html: string;
|
|
498
546
|
}
|
|
499
547
|
```
|
|
500
548
|
|
|
501
|
-
### 3.2
|
|
549
|
+
### 3.2 Preview matrix
|
|
550
|
+
|
|
551
|
+
`preview` is opt-in. Omitting it preserves the ordinary flat tier rows, and a
|
|
552
|
+
tier remains one visible heading; previews do not introduce a collapsed or
|
|
553
|
+
progressive-disclosure tier. The current values are:
|
|
554
|
+
|
|
555
|
+
| `preview` | Valid value kind | Runtime treatment |
|
|
556
|
+
| --- | --- | --- |
|
|
557
|
+
| `'size'` | `length`, or a `referencesTier` resolving to `length` | One type-size sample per item, sorted by resolved pixel size. |
|
|
558
|
+
| `'line-height'` | `number` | Paragraph sample with a leading guide; `previewBase` selects a font-size CSS variable when supplied. |
|
|
559
|
+
| `'family'` | `text` | The first item's font-family value supplies the style for every size and line-height sample. |
|
|
560
|
+
| `'weight'` | `select` or `number` | The first item's font-weight value supplies the style for every sample. |
|
|
561
|
+
| `'bar'` | `length` | Compact bar sized from the token value. |
|
|
562
|
+
| `'radius'` | `length` | Compact rounded-corner glyph. |
|
|
563
|
+
| `'duration'` | `length` or `number` with unit `ms` or `s` | Compact timing glyph using the token's duration value. |
|
|
564
|
+
|
|
565
|
+
The font specimen toolbar persists `{ text, preset, overridden, width }` under
|
|
566
|
+
`${storagePrefix}-specimen`; width is clamped to 240–720 pixels. **Render on
|
|
567
|
+
page** mounts a read-only specimen in the host document under
|
|
568
|
+
`.tokenpanel-on-page-specimen[data-zdtp-specimen]`, temporarily forces the
|
|
569
|
+
right dock, and restores the prior mode when the specimen is disabled, closed,
|
|
570
|
+
unmounted, or loses its dock claim. The specimen is excluded from token scans
|
|
571
|
+
and page pickers.
|
|
572
|
+
|
|
573
|
+
### 3.3 Reserved tab ids
|
|
502
574
|
|
|
503
575
|
| Tab id | Meaning |
|
|
504
576
|
| ------------------ | -------------------------------------------------- |
|
|
505
577
|
| `color` | Primary color tab — palette + base roles + semantics + scheme picker. Requires `colorExtras`. |
|
|
506
|
-
| `
|
|
578
|
+
| `font` | Dedicated typography tab with family/weight previews and the host-page specimen option. |
|
|
579
|
+
| `spacing` | Dedicated spacing tab with the numeric bulk editor. |
|
|
580
|
+
| `size` | Dedicated size tab with the numeric bulk editor. |
|
|
581
|
+
| `palette` | Dedicated palette editor for a generic palette tab. |
|
|
582
|
+
| `notes` | Dedicated notes tab; it renders content but carries no token state or apply/export overrides. |
|
|
507
583
|
|
|
508
|
-
|
|
509
|
-
|
|
584
|
+
The panel always prepends a synthetic `Inspect` tab for element inspection; it
|
|
585
|
+
is not supplied in `PanelConfig.tabs`. A configured `color-secondary` entry is
|
|
586
|
+
the companion color-cluster data source consumed by the primary Color tab (and
|
|
587
|
+
requires `colorExtras`); it is not an additional dedicated body dispatcher.
|
|
510
588
|
|
|
511
|
-
|
|
589
|
+
Any other configured id dispatches to `GenericTab`, which renders the tab's
|
|
590
|
+
`tiers` using kind-appropriate editors.
|
|
591
|
+
|
|
592
|
+
### 3.4 Validation rules
|
|
512
593
|
|
|
513
594
|
`assertValidPanelConfig` enforces these structural rules at the host-adapter
|
|
514
595
|
trust boundary:
|
|
@@ -523,7 +604,7 @@ trust boundary:
|
|
|
523
604
|
- `referencesTier` must name an existing tier in the same tab, and the
|
|
524
605
|
referencing tier's kind must match the referenced tier's kind.
|
|
525
606
|
|
|
526
|
-
### 3.
|
|
607
|
+
### 3.5 Apply behaviour for ref-tier items
|
|
527
608
|
|
|
528
609
|
When a `TierConfig` carries `referencesTier`, the apply pipeline treats each
|
|
529
610
|
item's persisted value as the id of an item in the referenced tier. The
|
|
@@ -532,9 +613,9 @@ emitted CSS override is `var(--target-cssvar)` where `target-cssvar` is the
|
|
|
532
613
|
|
|
533
614
|
By default the write target is `:root` (`document.documentElement`). When a
|
|
534
615
|
`PanelConfig.applySink` is configured for the instance, writes are routed
|
|
535
|
-
through the sink instead — see §3.
|
|
616
|
+
through the sink instead — see §3.6.
|
|
536
617
|
|
|
537
|
-
### 3.
|
|
618
|
+
### 3.6 `applySink` — optional CSS-var write target
|
|
538
619
|
|
|
539
620
|
When `PanelConfig.applySink` is set, all CSS-var writes and clears for that
|
|
540
621
|
panel instance route through the sink rather than `document.documentElement`.
|
|
@@ -596,7 +677,7 @@ const handle = configurePanel({
|
|
|
596
677
|
});
|
|
597
678
|
```
|
|
598
679
|
|
|
599
|
-
### 3.
|
|
680
|
+
### 3.7 Helpers (re-exported from the package root)
|
|
600
681
|
|
|
601
682
|
```ts
|
|
602
683
|
export function isLengthKind(v: TierValueKind): boolean;
|
|
@@ -609,6 +690,23 @@ export function isContentKind(v: TierValueKind): boolean;
|
|
|
609
690
|
export function isMaskImageKind(v: TierValueKind): boolean;
|
|
610
691
|
```
|
|
611
692
|
|
|
693
|
+
### 3.8 Canonical state transaction
|
|
694
|
+
|
|
695
|
+
All panel mutations use one transaction path, including ordinary row edits,
|
|
696
|
+
bulk actions, imports, snapshot restore, undo, redo, and reset. A transaction
|
|
697
|
+
applies the new state and CSS-variable writes, saves the persisted envelope,
|
|
698
|
+
updates component state, and then records the history entry in that order.
|
|
699
|
+
History is identity-aware and held in memory only; the persisted A/B snapshots
|
|
700
|
+
and token envelope are separate storage concerns. After a disk apply, the
|
|
701
|
+
implementation resets the last-applied baseline to `{}` and reconciles only
|
|
702
|
+
variables confirmed as written, so retained or unrouted overrides stay dirty.
|
|
703
|
+
Because disk Apply does not write base-role variables, a confirmed semantic
|
|
704
|
+
write derived from an unchanged `bg` or `fg` alias also reconciles that alias's
|
|
705
|
+
role-index dependency. Before resetting the dependency, other unwritten
|
|
706
|
+
semantic aliases using the same role are materialized to their resolved
|
|
707
|
+
numeric palette index. Their emitted value and dirty state are preserved for a
|
|
708
|
+
later Apply.
|
|
709
|
+
|
|
612
710
|
---
|
|
613
711
|
|
|
614
712
|
## 4. Color tab contract
|
|
@@ -659,9 +757,11 @@ export interface ColorClusterExtras {
|
|
|
659
757
|
* on init. Set to `false` to disable scheme-to-`data-theme` binding; this
|
|
660
758
|
* does not disable per-mode literal editing or emitted `light-dark(...)`
|
|
661
759
|
* values.
|
|
662
|
-
|
|
760
|
+
*/
|
|
663
761
|
colorMode: false | { defaultMode: 'light' | 'dark'; lightScheme: string; darkScheme: string };
|
|
664
762
|
};
|
|
763
|
+
/** Optional semantic-item-id → SemanticValue defaults override map. */
|
|
764
|
+
semanticDefaults?: Record<string, SemanticValue>;
|
|
665
765
|
}
|
|
666
766
|
```
|
|
667
767
|
|
|
@@ -676,8 +776,8 @@ export interface ColorScheme {
|
|
|
676
776
|
cursor: ColorRef;
|
|
677
777
|
selectionBg: ColorRef;
|
|
678
778
|
selectionFg: ColorRef;
|
|
679
|
-
palette: readonly string[]; //
|
|
680
|
-
shikiTheme
|
|
779
|
+
palette: readonly string[]; // the public type requires exactly 16 entries
|
|
780
|
+
shikiTheme?: string;
|
|
681
781
|
semantic?: Record<string, ColorRef>;
|
|
682
782
|
}
|
|
683
783
|
```
|
|
@@ -744,13 +844,19 @@ The apply pipeline for color tabs:
|
|
|
744
844
|
|
|
745
845
|
- For each palette `TierItem` in the palette tier, write
|
|
746
846
|
`item.cssVar` ← `palette[i]` from the active scheme / user override.
|
|
747
|
-
- For each `(roleKey, cssName)` in `colorExtras.baseRoles`,
|
|
748
|
-
`cssName` ← `palette[state[roleKey]]`.
|
|
847
|
+
- For each `(roleKey, cssName)` in `colorExtras.baseRoles`, the live DOM apply
|
|
848
|
+
path writes `cssName` ← `palette[state[roleKey]]`.
|
|
749
849
|
- For each semantic `TierItem`, resolve
|
|
750
850
|
`state.semanticMappings[key] ?? colorExtras.semanticDefaults[key]`
|
|
751
|
-
through `resolveMapping` and write `
|
|
851
|
+
through `resolveMapping` and write the emitted CSS value: `var(...)` for a
|
|
852
|
+
palette/reference mapping, a literal string for a literal mapping, or
|
|
853
|
+
`light-dark(light, dark)` for a per-mode literal.
|
|
752
854
|
- `clearAppliedStyles()` removes every property the cluster could have set.
|
|
753
855
|
|
|
856
|
+
The disk `buildApplyOverrides` payload intentionally emits palette and
|
|
857
|
+
semantic CSS variables only; base-role values are runtime wiring and are not
|
|
858
|
+
included in source-file rewrites.
|
|
859
|
+
|
|
754
860
|
### 4.6 `applyEndpoint` and `applyRouting`
|
|
755
861
|
|
|
756
862
|
The Apply modal's button is gated on two `PanelConfig` fields:
|
|
@@ -773,6 +879,13 @@ The **bin server** is the reference implementation for the apply contract.
|
|
|
773
879
|
### 5.1 Request & response envelopes
|
|
774
880
|
|
|
775
881
|
The Apply button POSTs to `PanelConfig.applyEndpoint` with a flat JSON diff.
|
|
882
|
+
The client sends only changed tokens. A token is changed exactly when the CSS
|
|
883
|
+
value it would emit differs from the value its baseline would emit. Therefore
|
|
884
|
+
an empty flat override or one equal to its manifest default is omitted;
|
|
885
|
+
semantic role aliases and palette indices compare by their resolved palette
|
|
886
|
+
slot, while literal and ref mappings compare structurally. Palette slots use
|
|
887
|
+
the active color-identity baseline. The Apply payload may also contain a
|
|
888
|
+
secondary color cluster, diffed against that cluster's configured defaults.
|
|
776
889
|
|
|
777
890
|
**Request**
|
|
778
891
|
|
|
@@ -788,6 +901,60 @@ Content-Type: application/json
|
|
|
788
901
|
}
|
|
789
902
|
```
|
|
790
903
|
|
|
904
|
+
The same endpoint accepts two optional coordination fields:
|
|
905
|
+
|
|
906
|
+
- `dryRun: true` computes a preview without creating a temporary file,
|
|
907
|
+
renaming a file, or otherwise mutating disk. A dry run may mix routed and
|
|
908
|
+
unrouted tokens; unrouted entries are diagnostics in the successful preview
|
|
909
|
+
rather than a whole-request error.
|
|
910
|
+
- `expectDigests` maps the repo-relative `file` values from a preceding preview
|
|
911
|
+
to their SHA-256 `digest` values. On a real write, every supplied digest is
|
|
912
|
+
checked after all files have been read and before any file is written.
|
|
913
|
+
|
|
914
|
+
**Response 200 (dry run)**
|
|
915
|
+
|
|
916
|
+
```json
|
|
917
|
+
{
|
|
918
|
+
"ok": true,
|
|
919
|
+
"dryRun": true,
|
|
920
|
+
"files": [
|
|
921
|
+
{
|
|
922
|
+
"file": "src/styles/tokens.css",
|
|
923
|
+
"blockKind": "root",
|
|
924
|
+
"digest": "<64 lowercase SHA-256 hex characters>",
|
|
925
|
+
"changed": ["--myapp-spacing-md"],
|
|
926
|
+
"unchanged": ["--myapp-spacing-lg"],
|
|
927
|
+
"unknown": [],
|
|
928
|
+
"unknownOutsideBlock": [],
|
|
929
|
+
"hunks": [
|
|
930
|
+
{
|
|
931
|
+
"cssVar": "--myapp-spacing-md",
|
|
932
|
+
"line": 12,
|
|
933
|
+
"before": " --myapp-spacing-md: 1rem;",
|
|
934
|
+
"after": " --myapp-spacing-md: 2rem;",
|
|
935
|
+
"context": {
|
|
936
|
+
"before": [" --myapp-spacing-sm: 0.5rem;"],
|
|
937
|
+
"after": [" --myapp-spacing-lg: 3rem;"]
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
]
|
|
941
|
+
}
|
|
942
|
+
],
|
|
943
|
+
"rejected": ["--unrouted-token"],
|
|
944
|
+
"rejectedReasons": ["--unrouted-token: no route configured for prefix family (...)"]
|
|
945
|
+
}
|
|
946
|
+
```
|
|
947
|
+
|
|
948
|
+
`blockKind` identifies the scanned block containing the requested declaration;
|
|
949
|
+
`:root` wins when a request changes declarations in both supported block kinds.
|
|
950
|
+
For an unknown-only file result, the first available kind (`root`, then
|
|
951
|
+
`theme`) is reported. `line` is one-based. `before` and `after` are complete
|
|
952
|
+
declaration lines, while each context array contains the adjacent proposed-file
|
|
953
|
+
line on that side. `hunks` contains exactly one entry per changed cssVar; two
|
|
954
|
+
declarations on one physical line therefore produce two independently-keyed
|
|
955
|
+
hunks with the same line number. Unknown and unchanged tokens do not produce
|
|
956
|
+
hunks.
|
|
957
|
+
|
|
791
958
|
**Response 200 (success)**
|
|
792
959
|
|
|
793
960
|
```json
|
|
@@ -798,11 +965,13 @@ Content-Type: application/json
|
|
|
798
965
|
"file": "src/styles/tokens.css",
|
|
799
966
|
"changed": ["--myapp-spacing-md"],
|
|
800
967
|
"unchanged": ["--myapp-spacing-lg"],
|
|
801
|
-
"unknown": []
|
|
968
|
+
"unknown": [],
|
|
969
|
+
"unknownOutsideBlock": []
|
|
802
970
|
}
|
|
803
971
|
],
|
|
804
972
|
"unknownCssVars": [],
|
|
805
|
-
"unchangedCssVars": ["--myapp-spacing-lg"]
|
|
973
|
+
"unchangedCssVars": ["--myapp-spacing-lg"],
|
|
974
|
+
"unknownOutsideBlockCssVars": []
|
|
806
975
|
}
|
|
807
976
|
```
|
|
808
977
|
|
|
@@ -817,8 +986,10 @@ Content-Type: application/json
|
|
|
817
986
|
```
|
|
818
987
|
|
|
819
988
|
Returned for: malformed JSON, missing `tokens` field, empty tokens map,
|
|
820
|
-
invalid token names (no `--` prefix, spaces, slashes),
|
|
821
|
-
|
|
989
|
+
invalid token names (no `--` prefix, spaces, slashes), or path escape attempts.
|
|
990
|
+
For a real write, an unsupported CSS-var prefix is also a 400 error. A dry run
|
|
991
|
+
keeps unsupported prefixes in its `rejected` / `rejectedReasons` diagnostics
|
|
992
|
+
so the caller can preview the rest of the request.
|
|
822
993
|
|
|
823
994
|
**Response 403 (Forbidden)**
|
|
824
995
|
|
|
@@ -833,9 +1004,30 @@ Empty body, `Allow: POST, OPTIONS` header.
|
|
|
833
1004
|
**Response 409 (Conflict)**
|
|
834
1005
|
|
|
835
1006
|
```json
|
|
836
|
-
{ "ok": false, "error": "No top-level :root { ... } block in <file>" }
|
|
1007
|
+
{ "ok": false, "error": "No top-level :root { ... } or @theme { ... } block in <file>" }
|
|
837
1008
|
```
|
|
838
1009
|
|
|
1010
|
+
The handler scans only the first top-level `:root` block and the first
|
|
1011
|
+
top-level `@theme` block (bare or with one modifier). `:root` wins when the
|
|
1012
|
+
same variable is declared in both. Later blocks and nested blocks are not
|
|
1013
|
+
rewritable. A dry run can succeed with only unrouted tokens; those tokens are
|
|
1014
|
+
listed in `rejected` and `rejectedReasons`, while a file with no supported
|
|
1015
|
+
block is a `409`.
|
|
1016
|
+
|
|
1017
|
+
A real write whose current file content does not match a supplied preview
|
|
1018
|
+
digest returns the following envelope before any target is written:
|
|
1019
|
+
|
|
1020
|
+
```json
|
|
1021
|
+
{
|
|
1022
|
+
"ok": false,
|
|
1023
|
+
"reason": "stale-file",
|
|
1024
|
+
"files": ["src/styles/tokens.css"]
|
|
1025
|
+
}
|
|
1026
|
+
```
|
|
1027
|
+
|
|
1028
|
+
The client must request a new dry run and ask the user to review the refreshed
|
|
1029
|
+
hunks. Omitting `expectDigests` preserves the legacy write behaviour.
|
|
1030
|
+
|
|
839
1031
|
**Response 500 (Internal server error)**
|
|
840
1032
|
|
|
841
1033
|
```json
|
|
@@ -863,14 +1055,19 @@ Hosts physically unable to spawn Node.js must:
|
|
|
863
1055
|
the routing map, reject prefixes not in the map.
|
|
864
1056
|
3. Path safety — resolve each target path to an absolute path, verify it sits
|
|
865
1057
|
within `writeRoot`, reject path-escape attempts.
|
|
866
|
-
4. Read & parse — load each CSS file, find the `:root { ... }`
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
1058
|
+
4. Read & parse — load each CSS file, find the first top-level `:root { ... }`
|
|
1059
|
+
or first top-level `@theme { ... }` block (bare or with one modifier; fail
|
|
1060
|
+
409 if neither exists), parse the existing variable values.
|
|
1061
|
+
5. Compute rewrite — compute `changed` / `unchanged` / `unknown` and
|
|
1062
|
+
`unknownOutsideBlock`, build the updated `:root` / `@theme` content, its
|
|
1063
|
+
per-cssVar hunks, and the SHA-256 of the original bytes.
|
|
1064
|
+
6. Preview/stale gate — for `dryRun: true`, return the preview immediately. For
|
|
1065
|
+
a real write with `expectDigests`, compare every supplied digest and return
|
|
1066
|
+
the stale-file 409 before the first mutation when any target differs.
|
|
1067
|
+
7. Atomic write — keep the original file content in memory. Write updated
|
|
871
1068
|
content to a temp file. Atomically rename temp to target. If any write
|
|
872
1069
|
fails, restore every previously-written file.
|
|
873
|
-
|
|
1070
|
+
8. Respond — return the exact JSON envelope shapes pinned in §5.1.
|
|
874
1071
|
|
|
875
1072
|
### 5.4 Routing config — single source of truth
|
|
876
1073
|
|
|
@@ -904,8 +1101,17 @@ This is the reason the JSON-serializable constraint in §4.2 is non-negotiable.
|
|
|
904
1101
|
|
|
905
1102
|
### 6.2 Lazy-load gate
|
|
906
1103
|
|
|
907
|
-
The
|
|
908
|
-
|
|
1104
|
+
The machine-readable metadata for these signals is exported from the
|
|
1105
|
+
side-effect-free `@takazudo/zdtp/constants` subpath. Use
|
|
1106
|
+
`EAGER_LOAD_GATE_KEY_SUFFIXES` for the five fixed suffix descriptors
|
|
1107
|
+
(`:visible`, `-open`, `:autoload`, `-elpath-enabled`, and
|
|
1108
|
+
`-domtweaker-enabled`), and `EAGER_LOAD_GATE_STATE_FAMILY` for the versioned
|
|
1109
|
+
`-state` family. These exports are the source of truth for consumers that
|
|
1110
|
+
mirror the gate. Each fixed descriptor supplies `acceptedValues` and
|
|
1111
|
+
`requiredConfig`; presence alone is insufficient, and a named required config
|
|
1112
|
+
property must be defined. The prose below explains the runtime meaning. The host adapter fires one eager
|
|
1113
|
+
`loadPanelModule()` call when any of these signals activates in `localStorage`
|
|
1114
|
+
at page load:
|
|
909
1115
|
|
|
910
1116
|
```ts
|
|
911
1117
|
if (
|
|
@@ -933,15 +1139,25 @@ if (
|
|
|
933
1139
|
specific version key — an empty `{}` / `[]` / `null` / `''` does NOT trigger
|
|
934
1140
|
it. (zdtp itself never writes such a value: `clearPersistedState()` removes
|
|
935
1141
|
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
|
|
1142
|
+
hand or by another tool.) Overrides MUST be re-applied to the configured
|
|
1143
|
+
sink (or default `:root`) even when the panel stays hidden, otherwise
|
|
1144
|
+
hard-nav produces a FOUT.
|
|
1145
|
+
|
|
1146
|
+
`EAGER_LOAD_GATE_STATE_FAMILY.matchesKey(storagePrefix, key)` only recognizes
|
|
1147
|
+
the exact `${storagePrefix}-state` / `${storagePrefix}-state-vN` key shape. It
|
|
1148
|
+
does not read storage or perform the content check. The consumer must apply
|
|
1149
|
+
the accompanying `valueRules`: raw empty strings, JSON `null`, and empty
|
|
1150
|
+
objects/arrays do not activate; non-empty collections, every other parsed
|
|
1151
|
+
primitive (including `false`, `0`, and JSON `""`), and malformed JSON do
|
|
1152
|
+
activate.
|
|
938
1153
|
- `shouldAutoload()` — reads `${storagePrefix}:autoload` (colon-form, §2).
|
|
939
1154
|
Returns `true` when the flag is `'1'` (explicit, written by `enableAutoload()`)
|
|
940
1155
|
OR `'auto'` (auto-remembered, written by opening the panel — see "Auto-remember
|
|
941
1156
|
on open" below). This is the owner-mode signal: the panel bundle fetches
|
|
942
1157
|
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
|
|
1158
|
+
the panel UI is hidden. General visitors (no flag, or `'0'`) pay no
|
|
1159
|
+
panel-bundle cost; the small host adapter/config bootstrap still runs. A
|
|
1160
|
+
downstream host that wants to distinguish the two populations can
|
|
945
1161
|
test `=== '1'` directly — see "Auto-remember on open" for the caveat.
|
|
946
1162
|
- `loadElementPathEnabled()` — reads the element-path inspector's persistence
|
|
947
1163
|
key. Returns `true` when the inspector was left enabled. Ensures the Preact
|
|
@@ -952,9 +1168,11 @@ if (
|
|
|
952
1168
|
enabled. Ensures the Preact shell is mounted and the lazy boundary is
|
|
953
1169
|
imported even when the panel UI is hidden.
|
|
954
1170
|
|
|
955
|
-
When none of the
|
|
1171
|
+
When none of the six signals is present — the common case for first-time
|
|
956
1172
|
visitors and general site visitors on a public site with owner-autoload — the
|
|
957
|
-
panel bundle is NOT fetched
|
|
1173
|
+
panel bundle is NOT fetched, no panel stylesheet is injected, and no panel
|
|
1174
|
+
root is mounted. The small host adapter/config bootstrap still runs to make
|
|
1175
|
+
that decision.
|
|
958
1176
|
|
|
959
1177
|
#### Storage-key table for §6.2 signals
|
|
960
1178
|
|
|
@@ -1006,7 +1224,9 @@ panel bundle is NOT fetched and the page is completely free of panel JS.
|
|
|
1006
1224
|
#### Auto-remember on open
|
|
1007
1225
|
|
|
1008
1226
|
Any action that shows the panel (`showDesignPanel()`, `toggleDesignPanel()`,
|
|
1009
|
-
|
|
1227
|
+
the fixed-name `window.zdtp.show()` / `.toggle()` aliases, an instance
|
|
1228
|
+
handle's `open()` / `toggle()`, the panel header's open action, or an instance
|
|
1229
|
+
toggle event) MUST also write
|
|
1010
1230
|
`${storagePrefix}:autoload = 'auto'` (auto-remembered provenance, distinct
|
|
1011
1231
|
from the `'1'` that `enableAutoload()` writes) — implemented by
|
|
1012
1232
|
`rememberAutoload()`. This ensures that once the owner has opened the panel
|
|
@@ -1034,13 +1254,26 @@ already hold `'1'`, and that provenance was never recorded, so it cannot be
|
|
|
1034
1254
|
reclassified. The `=== '1'` discrimination applies only to opens made from
|
|
1035
1255
|
this version onward.
|
|
1036
1256
|
|
|
1257
|
+
#### Shared Alt+click picker ownership
|
|
1258
|
+
|
|
1259
|
+
Element path, DOM Tweaker, and element inspect share one document-level
|
|
1260
|
+
Alt+click coordinator. Only one owner may be armed at a time; a new request
|
|
1261
|
+
revokes the previous owner's armed state before it starts. Panel-owned surfaces
|
|
1262
|
+
and the host-page specimen are excluded from all three pickers.
|
|
1263
|
+
|
|
1264
|
+
| Feature | Activation | Result |
|
|
1265
|
+
| --- | --- | --- |
|
|
1266
|
+
| Element path | Owner autoload or its panel toggle, then `Alt+click` | Copies an annotated selector/path block. |
|
|
1267
|
+
| DOM Tweaker | Configured feature toggle, then `Alt+click` | Opens the Tailwind class editor and live utility preview. |
|
|
1268
|
+
| Element inspect | Header toggle or `I`, then click; `Alt` also arms the coordinator | Opens the reserved inspect tab with computed and inherited token rows. |
|
|
1269
|
+
|
|
1037
1270
|
### 6.3 Astro view-transition lifecycle
|
|
1038
1271
|
|
|
1039
1272
|
The adapter's existing `astro:before-swap` and `astro:page-load` listeners
|
|
1040
1273
|
stay. They are Astro-specific and only register when `document` is available:
|
|
1041
1274
|
|
|
1042
1275
|
- `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
|
|
1276
|
+
- `astro:page-load` → re-apply persisted overrides + re-materialise the shell when any of the six gate signals (§6.2) is true.
|
|
1044
1277
|
|
|
1045
1278
|
### 6.4 Console API
|
|
1046
1279
|
|
|
@@ -1122,32 +1355,55 @@ window.zdtp.toggle = () => void | Promise<void>; // toggle the panel
|
|
|
1122
1355
|
|
|
1123
1356
|
### 7.1 Panel-private namespace
|
|
1124
1357
|
|
|
1125
|
-
The panel ships its own bundled CSS.
|
|
1126
|
-
|
|
1358
|
+
The panel ships its own bundled CSS. Panel-private color, font, spacing,
|
|
1359
|
+
typography, and z-index variables use the `--tokentweak-*` prefix; the shared
|
|
1360
|
+
radius token is `--radius-tokentweak`. They are scoped to the panel shell,
|
|
1361
|
+
mini pill, modal class prefix, and the body-level popover/tooltip/inspector
|
|
1362
|
+
surfaces:
|
|
1127
1363
|
|
|
1128
1364
|
```css
|
|
1129
1365
|
:where(.tokenpanel-shell, [data-design-token-panel-modal]) {
|
|
1130
|
-
|
|
1131
|
-
--tokentweak-
|
|
1132
|
-
--tokentweak-color-fg:
|
|
1366
|
+
/* base-0 is the darkest ground; stops ascend toward the foreground. */
|
|
1367
|
+
--tokentweak-palette-base-5: oklch(0.8 0 0);
|
|
1368
|
+
--tokentweak-color-fg: var(--tokentweak-palette-base-5);
|
|
1369
|
+
--tokentweak-color-accent-bar: #efb477;
|
|
1133
1370
|
/* …every panel-chrome value lives here */
|
|
1134
1371
|
}
|
|
1135
1372
|
```
|
|
1136
1373
|
|
|
1137
1374
|
- **No Tailwind dependency.** The package builds and runs without Tailwind in
|
|
1138
1375
|
the consumer.
|
|
1139
|
-
- **
|
|
1140
|
-
|
|
1376
|
+
- **Self-injected by the panel entry.** The panel calls `ensurePanelStyles()`
|
|
1377
|
+
when it first mounts, so a consumer does not need a CSS import. The `./styles`
|
|
1378
|
+
sub-export remains available when a host wants to pull the stylesheet into its
|
|
1379
|
+
own static CSS pipeline; importing it twice is unnecessary.
|
|
1141
1380
|
|
|
1142
1381
|
```ts
|
|
1143
|
-
import '@takazudo/zdtp/styles';
|
|
1382
|
+
import '@takazudo/zdtp/styles'; // optional static-CSS path
|
|
1144
1383
|
```
|
|
1145
1384
|
|
|
1385
|
+
The semantic color layer includes `--tokentweak-color-fg`, `bg`, `muted`,
|
|
1386
|
+
`border`, `surface`, `accent`, `accent-bar`, `accent-hover`, `code-bg`,
|
|
1387
|
+
`code-fg`, `success`, `danger`, and `warning`, backed by the private
|
|
1388
|
+
`--tokentweak-palette-base-*` OKLCH ramp, plus `--tokentweak-font-mono`. Spacing,
|
|
1389
|
+
typography, radius, and stacking values use the same prefix (`pad-*`, `gap-*`,
|
|
1390
|
+
`text-*`, `--radius-tokentweak`, and `z-*`). The chrome does not read host
|
|
1391
|
+
`--color-*` or `--font-mono` variables; hosts that retheme it assign the
|
|
1392
|
+
`--tokentweak-*` names directly on one of the listed scopes.
|
|
1393
|
+
|
|
1394
|
+
Docking is a host-document contract rather than a panel-private token:
|
|
1395
|
+
`--zdtp-dock-inset-right` and `--zdtp-dock-inset-bottom` are published on the
|
|
1396
|
+
host root while the corresponding dock claim is active. The on-page specimen
|
|
1397
|
+
uses `.tokenpanel-on-page-specimen[data-zdtp-specimen]`; it inherits the host
|
|
1398
|
+
font/foreground, is excluded from token scans and page pickers, and is removed
|
|
1399
|
+
when the specimen is disabled, closed, unmounted, or loses its dock claim.
|
|
1400
|
+
|
|
1146
1401
|
### 7.2 Consumer's editable tokens
|
|
1147
1402
|
|
|
1148
1403
|
The tokens the panel writes to (the `cssVar` field on each `TierItem`) are
|
|
1149
|
-
entirely consumer-controlled. The package
|
|
1150
|
-
on `:root
|
|
1404
|
+
entirely consumer-controlled. The package writes them through the configured
|
|
1405
|
+
`applySink`, or through `setProperty` on the default `:root` target when no
|
|
1406
|
+
sink is supplied.
|
|
1151
1407
|
|
|
1152
1408
|
- **Read:** the panel never reads consumer CSS variables (it carries its own
|
|
1153
1409
|
defaults via `TierItem.default`).
|
|
@@ -1163,20 +1419,30 @@ rules on `[data-design-token-panel-modal]`.
|
|
|
1163
1419
|
|
|
1164
1420
|
### 7.4 Self-contained panel chrome palette (no host theme reads)
|
|
1165
1421
|
|
|
1166
|
-
The panel-chrome color tokens are declared in `panel-tokens.css` as
|
|
1167
|
-
|
|
1422
|
+
The panel-chrome color tokens are declared in `panel-tokens.css` as semantic
|
|
1423
|
+
aliases onto a private OKLCH ramp so the panel paints as a neutral dark surface
|
|
1168
1424
|
regardless of what the host's `--color-*` tokens resolve to:
|
|
1169
1425
|
|
|
1170
1426
|
```css
|
|
1171
1427
|
:where(.tokenpanel-shell, [data-design-token-panel-modal]) {
|
|
1172
|
-
|
|
1173
|
-
--tokentweak-
|
|
1174
|
-
--tokentweak-
|
|
1175
|
-
--tokentweak-
|
|
1428
|
+
/* base-0 is the darkest ground; stops ascend toward the foreground. */
|
|
1429
|
+
--tokentweak-palette-base-0: oklch(0.18 0 0);
|
|
1430
|
+
--tokentweak-palette-base-1: oklch(0.25 0 0);
|
|
1431
|
+
--tokentweak-palette-base-2: oklch(0.34 0 0);
|
|
1432
|
+
--tokentweak-palette-base-3: oklch(0.536 0 0);
|
|
1433
|
+
--tokentweak-palette-base-4: oklch(0.66 0 0);
|
|
1434
|
+
--tokentweak-palette-base-5: oklch(0.8 0 0);
|
|
1435
|
+
--tokentweak-palette-base-6: oklch(0.91 0 0);
|
|
1436
|
+
--tokentweak-color-fg: var(--tokentweak-palette-base-5);
|
|
1437
|
+
--tokentweak-color-bg: var(--tokentweak-palette-base-0);
|
|
1438
|
+
--tokentweak-color-muted: var(--tokentweak-palette-base-4);
|
|
1439
|
+
--tokentweak-color-border: var(--tokentweak-palette-base-3);
|
|
1440
|
+
--tokentweak-color-surface: var(--tokentweak-palette-base-1);
|
|
1176
1441
|
--tokentweak-color-accent: #d69a66;
|
|
1442
|
+
--tokentweak-color-accent-bar: #efb477;
|
|
1177
1443
|
--tokentweak-color-accent-hover: #a7c0e3;
|
|
1178
|
-
--tokentweak-color-code-bg:
|
|
1179
|
-
--tokentweak-color-code-fg:
|
|
1444
|
+
--tokentweak-color-code-bg: var(--tokentweak-palette-base-2);
|
|
1445
|
+
--tokentweak-color-code-fg: var(--tokentweak-palette-base-6);
|
|
1180
1446
|
--tokentweak-color-success: #93bb77;
|
|
1181
1447
|
--tokentweak-color-danger: #da6871;
|
|
1182
1448
|
--tokentweak-color-warning: #dfbb77;
|
|
@@ -1193,9 +1459,17 @@ in a demo — MUST NOT bleed into the panel chrome.
|
|
|
1193
1459
|
**Override surface for hosts:** a host that wants to retheme the panel
|
|
1194
1460
|
chrome assigns directly to the `--tokentweak-color-*` /
|
|
1195
1461
|
`--tokentweak-font-mono` names on `.tokenpanel-shell`,
|
|
1196
|
-
`[data-design-token-panel-modal]`,
|
|
1197
|
-
|
|
1198
|
-
|
|
1462
|
+
`.tokenpanel-mini-pill`, `[data-design-token-panel-modal]`, the highlight
|
|
1463
|
+
settings and chain popovers, the color picker, tooltip, element-path label and
|
|
1464
|
+
toast, or an element-inspect surface (or any ancestor). `:where()` keeps
|
|
1465
|
+
specificity at 0. This single name layer is the entire host-override contract
|
|
1466
|
+
for panel chrome — `--color-*` reads are not part of it.
|
|
1467
|
+
|
|
1468
|
+
Hosts may instead override a `--tokentweak-palette-base-*` stop to update all
|
|
1469
|
+
roles that alias it; a direct semantic `--tokentweak-color-*` assignment still
|
|
1470
|
+
wins. The border role is intentionally separate: `--tokentweak-color-muted`
|
|
1471
|
+
now recolors secondary text only. A host that previously used it for both text
|
|
1472
|
+
and 1px dividers must also assign `--tokentweak-color-border`.
|
|
1199
1473
|
|
|
1200
1474
|
**Invariant:** the panel package MUST NOT read `--color-*` or
|
|
1201
1475
|
`--font-mono` anywhere. Both `panel.css` and `panel-tokens.css` are pinned
|
|
@@ -1210,8 +1484,10 @@ grep -n 'var(--font-mono' src/styles/panel-tokens.css # → 0
|
|
|
1210
1484
|
|
|
1211
1485
|
### 7.5 Host-adapter side-effect import (paired-unit obligation)
|
|
1212
1486
|
|
|
1213
|
-
|
|
1214
|
-
|
|
1487
|
+
The consumer MUST own a side-effect import for the host-adapter, paired with
|
|
1488
|
+
`<DesignTokenPanelHost>`. The `./styles` import is optional because the panel
|
|
1489
|
+
entry self-injects its stylesheet; use it only when the host wants a static CSS
|
|
1490
|
+
pipeline:
|
|
1215
1491
|
|
|
1216
1492
|
```astro
|
|
1217
1493
|
<DesignTokenPanelHost config={myPanelConfig} />
|
|
@@ -1225,11 +1501,13 @@ for the host-adapter, paired with `<DesignTokenPanelHost>`:
|
|
|
1225
1501
|
|
|
1226
1502
|
## 8. Storage-key continuity & migration paths
|
|
1227
1503
|
|
|
1228
|
-
### 8.1
|
|
1504
|
+
### 8.1 Minimal fallback before configuration
|
|
1229
1505
|
|
|
1230
|
-
The package ships **zero**
|
|
1231
|
-
|
|
1232
|
-
a
|
|
1506
|
+
The package ships **zero** host-specific identifiers. Before the first explicit
|
|
1507
|
+
`configurePanel` call, `getPanelConfig()` returns a minimal sentinel with empty
|
|
1508
|
+
token manifests and a stub color cluster so imports and adapter boot can remain
|
|
1509
|
+
safe; it is not a useful consumer configuration. Hosts MUST configure the
|
|
1510
|
+
panel explicitly to render their own tabs and token values.
|
|
1233
1511
|
|
|
1234
1512
|
### 8.2 Storage-key derivation is literal
|
|
1235
1513
|
|
|
@@ -1286,7 +1564,7 @@ The historical zdtp-internal map is exported as `ZDTP_LEGACY_TYPOGRAPHY_RENAME_M
|
|
|
1286
1564
|
|
|
1287
1565
|
---
|
|
1288
1566
|
|
|
1289
|
-
## 9. JSON export / import schema (serde
|
|
1567
|
+
## 9. JSON export / import schema (serde)
|
|
1290
1568
|
|
|
1291
1569
|
### 9.1 Schema versioning
|
|
1292
1570
|
|
|
@@ -1294,9 +1572,12 @@ The historical zdtp-internal map is exported as `ZDTP_LEGACY_TYPOGRAPHY_RENAME_M
|
|
|
1294
1572
|
| ----------------------- | ------- | ------------------------------------------------------ |
|
|
1295
1573
|
| `zudo-design-tokens/v1` | Legacy | Flat top-level `color`/`spacing`/`typography`/`size` keys |
|
|
1296
1574
|
| `zudo-design-tokens/v2` | Current | `tabs` wrapper keyed by tab id; cssVar-keyed leaves |
|
|
1575
|
+
| `zudo-design-tokens/v3` | Current | v2 structure with object-valued semantic color mappings |
|
|
1297
1576
|
|
|
1298
|
-
`serialize()`
|
|
1299
|
-
|
|
1577
|
+
`serialize()` emits v2 for states whose semantic mappings are representable by
|
|
1578
|
+
the v2 shape, and upgrades to v3 when an object-valued semantic mapping needs
|
|
1579
|
+
the v3 shape. `deserialize()` accepts v1, v2, and v3 and normalises each to an
|
|
1580
|
+
internal `TweakState`.
|
|
1300
1581
|
|
|
1301
1582
|
### 9.2 v2 format
|
|
1302
1583
|
|
|
@@ -1332,7 +1613,14 @@ Key decisions:
|
|
|
1332
1613
|
|
|
1333
1614
|
`serialize()` only emits tokens the user has changed relative to manifest
|
|
1334
1615
|
defaults. Pass `includeDefaults: true` to dump the full state. A tab key is
|
|
1335
|
-
omitted entirely when nothing in it differs.
|
|
1616
|
+
omitted entirely when nothing in it differs. "Changed" uses the canonical
|
|
1617
|
+
emitted-value definition in §5.1. Export parity covers tokens representable by
|
|
1618
|
+
the current schema: flat tabs and the primary color cluster. The secondary
|
|
1619
|
+
color cluster is Apply-only and is not added to the export schema here.
|
|
1620
|
+
|
|
1621
|
+
A sparse persisted override equal to today's manifest default remains stored
|
|
1622
|
+
but invisible to the UI, diff-only export, and Apply. It can intentionally
|
|
1623
|
+
resurface if a later manifest changes that default.
|
|
1336
1624
|
|
|
1337
1625
|
---
|
|
1338
1626
|
|
|
@@ -1342,10 +1630,12 @@ Items this contract deliberately does NOT pin down:
|
|
|
1342
1630
|
|
|
1343
1631
|
- **Persist envelope internal shape** — frozen at the current shape so
|
|
1344
1632
|
existing user state round-trips without migration.
|
|
1345
|
-
- **Schema id versioning.** `schemaId` is a configure-time
|
|
1346
|
-
it
|
|
1633
|
+
- **Schema id versioning.** `schemaId` is a configure-time display label
|
|
1634
|
+
returned by `getDesignTokenSchema()`; it does not select or version the
|
|
1635
|
+
serializer. The package-owned `SCHEMA_V1` / `SCHEMA_V2` / `SCHEMA_V3`
|
|
1636
|
+
constants govern export and import validation.
|
|
1347
1637
|
- **Shadow-DOM scoping.** The panel writes to `:root` by default; hosts
|
|
1348
|
-
that need scoped writes use `PanelConfig.applySink` (§3.
|
|
1638
|
+
that need scoped writes use `PanelConfig.applySink` (§3.6). The sink
|
|
1349
1639
|
target's lifecycle is owned by the host — not pinned here.
|
|
1350
1640
|
- **Theme-API surface.** The panel does not expose a programmatic API for
|
|
1351
1641
|
reading the current overrides outside the persist envelope.
|
|
@@ -1361,21 +1651,26 @@ Cross-reference table — what each section pins down.
|
|
|
1361
1651
|
| `configurePanel({...})` signature, multi-instance, `PanelInstanceHandle`, per-instance toggle events | §1 |
|
|
1362
1652
|
| Storage-key derivation | §2, §8 |
|
|
1363
1653
|
| Default first-open geometry (coherent size+position, viewport containment, cascade, persisted-position precedence) | §2.1 |
|
|
1654
|
+
| `PanelDockConfig`, dock modes, body-margin reflow, edge claims, and dock storage | §1, §2, §7 |
|
|
1364
1655
|
| `TabConfig` / `TierConfig` / `TierItem` / `TierValueKind` interfaces and apply behaviour | §3 |
|
|
1365
|
-
| `
|
|
1656
|
+
| `TierConfig.preview` / `previewBase` matrix and host-page specimen lifecycle | §3.2 |
|
|
1657
|
+
| `applySink` — optional CSS-var write target (upsert / clear / Reset full set) | §3.6 |
|
|
1366
1658
|
| `ColorClusterExtras` shape and multi-cluster support | §4.1, §4.3 |
|
|
1367
1659
|
| JSON-serializable constraint on color tab config | §4.2 |
|
|
1368
1660
|
| `colorPresets` and `setPanelColorPresets()` lazy attachment | §4.4 |
|
|
1369
1661
|
| Color apply behaviour | §4.5 |
|
|
1370
|
-
| Apply pipeline request / response envelopes
|
|
1662
|
+
| Apply pipeline request / response envelopes, dry-run hunks/digests, stale-write 409 | §5.1 |
|
|
1663
|
+
| Canonical transaction order and in-memory undo/redo history | §3.8 |
|
|
1371
1664
|
| Reference-implementation algorithm + native-implementation guidance | §5.2, §5.3 |
|
|
1372
1665
|
| Routing config single-source | §5.4 |
|
|
1373
|
-
| Astro `<DesignTokenPanelHost>` prop, lazy-load gate (
|
|
1666
|
+
| Astro `<DesignTokenPanelHost>` prop, lazy-load gate (6-signal), owner-autoload, console API | §6 |
|
|
1667
|
+
| Shared Alt+click owner for element path, DOM Tweaker, and element inspect | §6.2 |
|
|
1374
1668
|
| Fixed-name global open API (`window.zdtp.show/hide/toggle`) | §6.5 |
|
|
1375
1669
|
| `--tokentweak-*` namespace and Tailwind-free CSS contract | §7.1 |
|
|
1376
1670
|
| Modal class prefix and `data-design-token-panel-modal` selector contract | §7.3 |
|
|
1377
1671
|
| Self-contained panel chrome palette (no host theme reads) | §7.4 |
|
|
1378
1672
|
| Host-adapter side-effect import (paired-unit obligation) | §7.5 |
|
|
1379
1673
|
| v4 envelope precedence, v1/v2/v3 storage migration, and typography-id rename map | §2, §8.3, §8.4 |
|
|
1380
|
-
| JSON export/import
|
|
1674
|
+
| JSON export/import schemas v1/v2/v3 (serde) | §9 |
|
|
1381
1675
|
| Out-of-scope / deferred concerns | §10 |
|
|
1676
|
+
| Feature walkthrough and shortcut table | [Panel UX tour](/docs/recipes/panel-ux-tour) |
|