@takazudo/zdtp 0.4.15 → 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 CHANGED
@@ -4,6 +4,37 @@ All notable changes to `@takazudo/zdtp` are documented in this file.
4
4
 
5
5
  The format is based on Keep a Changelog, and release notes are generated from the changelog MDX pages.
6
6
 
7
+ ## [0.5.0] - 2026-09-06
8
+
9
+ `@takazudo/zdtp/constants` now exposes `DEFAULT_STORAGE_PREFIX`, `DEFAULT_TOGGLE_EVENT`, `resolveToggleEventName`, `EAGER_LOAD_GATE_KEY_SUFFIXES`, and `EAGER_LOAD_GATE_STATE_FAMILY` without importing the panel. Lazy hosts can share toggle-event rules and eager-load metadata; state-family matching still requires the documented content checks. The storage-key documentation is also corrected: position, size, density, and all three highlight keys already existed in published 0.4.14.
10
+
11
+ ### Features
12
+
13
+ - feat(zdtp): publish isolated constants entry (11ff48b)
14
+ - feat: describe eager-load gate signals with behavioral drift guard (0a2b610)
15
+
16
+ ### Fixed
17
+
18
+ - fix: keep dock controls visible and reconcile menu with rendered CSS (dae7dcc)
19
+ - fix(zdtp): preserve readable labels in changed token rows (97ede7f)
20
+
21
+ ### Other Changes
22
+
23
+ - Merge pull request [#769](https://github.com/Takazudo/zudo-design-token-panel/pull/769) from Takazudo/base/sweep-260906 (c4c6230)
24
+ - Merge pull request [#778](https://github.com/Takazudo/zudo-design-token-panel/pull/778) from Takazudo/base/sweep-260906-gate-constants (cc29811)
25
+ - Merge branch 'topic/765-constants-docs' into base/sweep-260906-gate-constants (a82dc82)
26
+ - docs: document constants subpath and storage key continuity (17426e0)
27
+ - Merge branch 'topic/764-constants-package' into base/sweep-260906-gate-constants (572d11c)
28
+ - Merge branch 'topic/763-gate-signals' into base/sweep-260906-gate-constants (c09f456)
29
+ - Merge branch 'topic/762-constants-leaf' into base/sweep-260906-gate-constants (f038f71)
30
+ - refactor(zdtp): extract panel constants leaf (369e495)
31
+ - Merge pull request [#773](https://github.com/Takazudo/zudo-design-token-panel/pull/773) from Takazudo/base/sweep-260906-dock-escape (08678c2)
32
+ - Merge branch 'topic/759-dock-fix' into base/sweep-260906-dock-escape (a44f2a4)
33
+ - Merge branch 'topic/758-dock-decision' into base/sweep-260906-dock-escape (3d1ee55)
34
+ - docs: define visible dock controls and CSS-driven menu contract (0da81f3)
35
+ - Merge pull request [#768](https://github.com/Takazudo/zudo-design-token-panel/pull/768) from Takazudo/base/sweep-260906-changed-row-label (323b9b0)
36
+ - Merge branch 'topic/754-changed-row-label' into base/sweep-260906-changed-row-label (69846f2)
37
+
7
38
  ## [0.4.15] - 2026-09-05
8
39
 
9
40
  ### Features
@@ -293,6 +293,13 @@ derives the keys at runtime from this single base.
293
293
  | `highlight-outline-width` | `${storagePrefix}-highlight-outline-width` | highlight-state | Global highlight outline width in local storage, clamped to 1–20. |
294
294
  | `highlight-active` | `${storagePrefix}-highlight-active` | highlight-state | Active CSS-variable-to-slot map in session storage. |
295
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.
302
+
296
303
  **Constraint — colon, not dash, for `visible` and `autoload`.** Both adapter-
297
304
  level flags use a `:` separator; every other derived key uses `-`. The colon
298
305
  form is a historical artifact for `visible`, preserved for storage-key
@@ -1094,8 +1101,17 @@ This is the reason the JSON-serializable constraint in §4.2 is non-negotiable.
1094
1101
 
1095
1102
  ### 6.2 Lazy-load gate
1096
1103
 
1097
- The host adapter fires one eager `loadPanelModule()` call when any of the
1098
- following signals is present in `localStorage` at page load:
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:
1099
1115
 
1100
1116
  ```ts
1101
1117
  if (
@@ -1126,6 +1142,14 @@ if (
1126
1142
  hand or by another tool.) Overrides MUST be re-applied to the configured
1127
1143
  sink (or default `:root`) even when the panel stays hidden, otherwise
1128
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.
1129
1153
  - `shouldAutoload()` — reads `${storagePrefix}:autoload` (colon-form, §2).
1130
1154
  Returns `true` when the flag is `'1'` (explicit, written by `enableAutoload()`)
1131
1155
  OR `'auto'` (auto-remembered, written by opening the panel — see "Auto-remember
package/README.md CHANGED
@@ -414,6 +414,57 @@ Copy an example's structure when porting the panel into a new host.
414
414
 
415
415
  If you are building a **Rust SSG** or other non-Node host, the bin still runs as a sidecar Node.js subprocess (started by your host's build orchestration). The same routing JSON and host-adapter setup applies — the only difference is your host ships its own config format (not TypeScript) and you invoke the bin via your build system's subprocess spawner rather than npm scripts.
416
416
 
417
+ #### Pre-import activation from a custom host
418
+
419
+ The side-effect-free `@takazudo/zdtp/constants` subpath exposes
420
+ `DEFAULT_STORAGE_PREFIX`, `DEFAULT_TOGGLE_EVENT`, and
421
+ `resolveToggleEventName` without importing the panel. It also exports the
422
+ machine-readable eager-load metadata (`EAGER_LOAD_GATE_KEY_SUFFIXES` and
423
+ `EAGER_LOAD_GATE_STATE_FAMILY`); the exact gate contract lives in
424
+ [`PORTABLE-CONTRACT.md`](./PORTABLE-CONTRACT.md) §6.2.
425
+
426
+ A custom host can use those constants to register its toggle listener in the
427
+ initial bundle and fetch the panel only when activated. Keep the stylesheet
428
+ setup from §4.2 (or import `@takazudo/zdtp/styles` in your host stylesheet
429
+ pipeline):
430
+
431
+ ```ts
432
+ import type { PanelConfig } from '@takazudo/zdtp';
433
+ import { resolveToggleEventName } from '@takazudo/zdtp/constants';
434
+
435
+ // Call once with your complete config (for example myPanelConfig in §4.1.1).
436
+ export function installLazyPanel(config: PanelConfig): void {
437
+ const toggleEvent = resolveToggleEventName(config);
438
+ let loading: Promise<void> | undefined;
439
+
440
+ function loadOnToggle(): void {
441
+ if (loading) return;
442
+ loading = import('@takazudo/zdtp')
443
+ .then(({ configurePanel }) => {
444
+ configurePanel(config);
445
+ window.removeEventListener(toggleEvent, loadOnToggle);
446
+ window.dispatchEvent(new CustomEvent(toggleEvent));
447
+ })
448
+ .catch((error: unknown) => {
449
+ loading = undefined;
450
+ console.error('Failed to load @takazudo/zdtp', error);
451
+ });
452
+ }
453
+
454
+ window.addEventListener(toggleEvent, loadOnToggle);
455
+ }
456
+ ```
457
+
458
+ The default `DEFAULT_STORAGE_PREFIX` is
459
+ `'zudo-design-token-panel'`, and its `DEFAULT_TOGGLE_EVENT` is
460
+ `'toggle-design-token-panel'`. `resolveToggleEventName` preserves that
461
+ historical event even when a default-prefix config supplies `toggleEvent`; a
462
+ non-default prefix uses its supplied `toggleEvent`, or derives
463
+ `toggle-${storagePrefix}` when the override is omitted. The same config
464
+ resolves the listener event and configures the loaded panel. This activation-only
465
+ example does not implement the saved-state eager-load gate; see §6.2 of the
466
+ contract when building a complete host adapter.
467
+
417
468
  ### 4.3 Recipe — Rust SSG (zfb)
418
469
 
419
470
  Worked example for the case where the host is a Rust dev server (e.g. [zfb / zudo-front-builder](https://github.com/Takazudo/zudo-front-builder)) rather than a Node-based runner. The bin itself is unchanged — it remains a Node.js subprocess invoked as `node path/to/dist/bin/server.js ...`. The Rust host's only job is to spawn that Node process, forward shutdown signals to it, and configure `--allow-origin` so the browser POST from the panel UI is accepted.
@@ -1,6 +1,6 @@
1
- import { c as y, g as m, a as w, b, i as P } from "../panel-config-CRf-ONSV.js";
2
- import { g, Z as k } from "../tweak-state-BGp_7Tfh.js";
3
- import { s as A, l as D, a as E, i as c, r as f, c as _, b as I, d } from "../autoload-state-7BQYXI7Y.js";
1
+ import { c as y, g as m, a as w, b, i as P } from "../panel-config-BSu6TUht.js";
2
+ import { g, Z as k } from "../tweak-state-B7ok3Ob3.js";
3
+ import { s as A, l as D, a as E, i as c, r as f, c as _, b as I, d } from "../autoload-state-DmTY6tRy.js";
4
4
  const u = "tokenpanel-config";
5
5
  function S() {
6
6
  if (typeof document > "u")
@@ -1,4 +1,4 @@
1
- import { s as t } from "../panel-config-CRf-ONSV.js";
1
+ import { s as t } from "../panel-config-BSu6TUht.js";
2
2
  import { c as d } from "../color-schemes-CgzOBqGO.js";
3
3
  import { F as r, G as m, a as g, S as z } from "../manifest-DvuKi7I4.js";
4
4
  const e = {
@@ -1,4 +1,4 @@
1
- import { g as n, j as o } from "./panel-config-CRf-ONSV.js";
1
+ import { g as n, j as o } from "./panel-config-BSu6TUht.js";
2
2
  function c() {
3
3
  return typeof document < "u" && document !== null && typeof document.getElementById == "function";
4
4
  }
@@ -47,6 +47,7 @@
47
47
  */
48
48
  import type { ColorScheme } from './color-schemes';
49
49
  import type { TabConfig } from '../tokens/tier-model';
50
+ export { DEFAULT_STORAGE_PREFIX, DEFAULT_TOGGLE_EVENT } from '../constants';
50
51
  /**
51
52
  * Apply-routing map.
52
53
  *
@@ -510,13 +511,6 @@ export declare function storageKey_visible(cfg: PanelConfig): string;
510
511
  export declare function storageKey_autoload(cfg: PanelConfig): string;
511
512
  /** DOM id of the root element the Preact panel tree mounts into. */
512
513
  export declare function panelRootId(cfg: PanelConfig): string;
513
- /**
514
- * Historical public toggle-event name. Hosts have shipped `window.dispatchEvent(
515
- * new CustomEvent('toggle-design-token-panel'))` since the single-panel era, so
516
- * the default instance MUST keep emitting/listening on this name regardless of
517
- * its derived `toggle-${storagePrefix}` form.
518
- */
519
- export declare const DEFAULT_TOGGLE_EVENT = "toggle-design-token-panel";
520
514
  /**
521
515
  * Window-event name that toggles this instance's panel.
522
516
  *
@@ -0,0 +1,66 @@
1
+ /** Default storage-key prefix used by the single-panel configuration. */
2
+ export declare const DEFAULT_STORAGE_PREFIX = "zudo-design-token-panel";
3
+ /** Historical public window-event name for the default panel instance. */
4
+ export declare const DEFAULT_TOGGLE_EVENT = "toggle-design-token-panel";
5
+ /**
6
+ * Resolve the window-event name that toggles a panel instance.
7
+ *
8
+ * The default prefix keeps the historical event name, even when a host
9
+ * supplies a `toggleEvent`. Other prefixes honor an explicit event name and
10
+ * otherwise derive one from the prefix.
11
+ */
12
+ export declare function resolveToggleEventName(cfg: {
13
+ storagePrefix?: string;
14
+ toggleEvent?: string;
15
+ }): string;
16
+ /**
17
+ * The five fixed eager-load signals, keyed by suffix relative to storagePrefix.
18
+ * Only acceptedValues activate a flag; presence alone is insufficient.
19
+ * requiredConfig means that property must be !== undefined in the panel config.
20
+ * This excludes preference keys and is NOT the whole gate: also inspect
21
+ * EAGER_LOAD_GATE_STATE_FAMILY, whose keys require a content check.
22
+ */
23
+ export declare const EAGER_LOAD_GATE_KEY_SUFFIXES: {
24
+ readonly ':visible': {
25
+ readonly acceptedValues: readonly ["1"];
26
+ readonly requiredConfig: null;
27
+ };
28
+ readonly '-open': {
29
+ readonly acceptedValues: readonly ["1"];
30
+ readonly requiredConfig: null;
31
+ };
32
+ readonly ':autoload': {
33
+ readonly acceptedValues: readonly ["1", "auto"];
34
+ readonly requiredConfig: null;
35
+ };
36
+ readonly '-elpath-enabled': {
37
+ readonly acceptedValues: readonly ["1"];
38
+ readonly requiredConfig: null;
39
+ };
40
+ readonly '-domtweaker-enabled': {
41
+ readonly acceptedValues: readonly ["1"];
42
+ readonly requiredConfig: "domTweaker";
43
+ };
44
+ };
45
+ /**
46
+ * The sixth eager-load signal: exact -state / -state-vN keys, for every numeric
47
+ * version, with a content check. Missing keys and raw empty strings are blank;
48
+ * JSON null and empty objects/arrays do not activate. Non-empty collections and
49
+ * all other parsed primitives (even false, 0, or JSON "") activate. Malformed
50
+ * JSON fails open so the panel can migrate or reject the stored payload.
51
+ *
52
+ * matchesKey compares the prefix literally before matching the suffix, so regex
53
+ * metacharacters in a prefix are safe and sibling-instance keys are excluded.
54
+ * These are storage signal descriptions, not a storage reader or panel bootstrap.
55
+ */
56
+ export declare const EAGER_LOAD_GATE_STATE_FAMILY: {
57
+ readonly matchesKey: (storagePrefix: string, key: string) => boolean;
58
+ readonly valueRules: {
59
+ readonly blank: false;
60
+ readonly jsonNull: false;
61
+ readonly object: "non-empty";
62
+ readonly array: "non-empty";
63
+ readonly primitive: true;
64
+ readonly malformedJson: true;
65
+ };
66
+ };
@@ -0,0 +1,30 @@
1
+ const n = "zudo-design-token-panel", l = "toggle-design-token-panel";
2
+ function o(e) {
3
+ return e.storagePrefix === void 0 || e.storagePrefix === n ? l : e.toggleEvent ?? `toggle-${e.storagePrefix}`;
4
+ }
5
+ const a = {
6
+ ":visible": { acceptedValues: ["1"], requiredConfig: null },
7
+ "-open": { acceptedValues: ["1"], requiredConfig: null },
8
+ ":autoload": { acceptedValues: ["1", "auto"], requiredConfig: null },
9
+ "-elpath-enabled": { acceptedValues: ["1"], requiredConfig: null },
10
+ "-domtweaker-enabled": { acceptedValues: ["1"], requiredConfig: "domTweaker" }
11
+ }, r = {
12
+ matchesKey(e, t) {
13
+ return t.startsWith(e) && /^-state(-v\d+)?$/.test(t.slice(e.length));
14
+ },
15
+ valueRules: {
16
+ blank: !1,
17
+ jsonNull: !1,
18
+ object: "non-empty",
19
+ array: "non-empty",
20
+ primitive: !0,
21
+ malformedJson: !0
22
+ }
23
+ };
24
+ export {
25
+ n as DEFAULT_STORAGE_PREFIX,
26
+ l as DEFAULT_TOGGLE_EVENT,
27
+ a as EAGER_LOAD_GATE_KEY_SUFFIXES,
28
+ r as EAGER_LOAD_GATE_STATE_FAMILY,
29
+ o as resolveToggleEventName
30
+ };
@@ -1,7 +1,7 @@
1
1
  import { jsx as y, jsxs as K, Fragment as kt } from "preact/jsx-runtime";
2
2
  import { useEffect as P, useState as Y, useRef as O, useMemo as J, useCallback as X } from "preact/hooks";
3
- import { b as ft, p as wt, u as ht, a as Ne, A as bt, Z as gt } from "./index-BOOmFtJh.js";
4
- import { g as vt, m as j } from "./panel-config-CRf-ONSV.js";
3
+ import { b as ft, p as wt, u as ht, a as Ne, A as bt, Z as gt } from "./index-CHzTi0y5.js";
4
+ import { g as vt, m as j } from "./panel-config-BSu6TUht.js";
5
5
  const xt = (e, o) => {
6
6
  const t = new Array(e.length + o.length);
7
7
  for (let r = 0; r < e.length; r++)