@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.
Files changed (113) hide show
  1. package/CHANGELOG.md +143 -0
  2. package/PORTABLE-CONTRACT.md +366 -94
  3. package/README.md +218 -96
  4. package/dist/apply/build-apply-overrides.d.ts +2 -2
  5. package/dist/apply/compute-hunks.d.ts +23 -0
  6. package/dist/apply/last-applied.d.ts +5 -0
  7. package/dist/apply/reconcile-applied.d.ts +19 -0
  8. package/dist/apply-modal.d.ts +2 -48
  9. package/dist/astro/host-adapter.js +3 -3
  10. package/dist/astro/index.js +2 -2
  11. package/dist/{autoload-state-CfL2VUe1.js → autoload-state-7BQYXI7Y.js} +1 -1
  12. package/dist/bin/server.js +52 -50
  13. package/dist/bulk/bulk-actions.d.ts +45 -0
  14. package/dist/bulk/index.d.ts +2 -0
  15. package/dist/chain/index.d.ts +2 -0
  16. package/dist/chain/token-chain-context.d.ts +19 -0
  17. package/dist/chain/token-chain-popover.d.ts +22 -0
  18. package/dist/changed/contribution.d.ts +32 -0
  19. package/dist/changed/footer-content.d.ts +16 -0
  20. package/dist/changed/index.d.ts +4 -0
  21. package/dist/changed/tab-badge.d.ts +8 -0
  22. package/dist/changed/tab-filter.d.ts +8 -0
  23. package/dist/config/panel-config.d.ts +22 -25
  24. package/dist/controls/actions-menu-popover.d.ts +2 -0
  25. package/dist/controls/role-button.d.ts +5 -2
  26. package/dist/controls/tooltip.d.ts +8 -4
  27. package/dist/element-inspect/element-inspect-context.d.ts +22 -0
  28. package/dist/element-inspect/element-inspect-orchestrator.d.ts +17 -0
  29. package/dist/element-inspect/element-inspect-overlay.d.ts +16 -0
  30. package/dist/element-inspect/element-inspect-toggle-button.d.ts +3 -0
  31. package/dist/element-inspect/element-inspect-view.d.ts +6 -0
  32. package/dist/element-inspect/find-tokens-for-element.d.ts +23 -0
  33. package/dist/element-inspect/index.d.ts +8 -0
  34. package/dist/highlight/find-elements.d.ts +14 -3
  35. package/dist/highlight/highlight-orchestrator.d.ts +7 -3
  36. package/dist/highlight/highlight-state.d.ts +3 -2
  37. package/dist/highlight/highlight-toggle-button.d.ts +3 -0
  38. package/dist/highlight/walk-css-rules.d.ts +2 -0
  39. package/dist/history/buttons.d.ts +28 -0
  40. package/dist/history/index.d.ts +3 -0
  41. package/dist/history/rail.d.ts +13 -0
  42. package/dist/history/snapshots.d.ts +57 -0
  43. package/dist/host/host-mutations.d.ts +23 -0
  44. package/dist/index-BOOmFtJh.js +12165 -0
  45. package/dist/{index-BAY1JOUl.js → index-C2DIYD0d.js} +2 -2
  46. package/dist/index.js +14 -14
  47. package/dist/load-routing-BtCE1hGI.js +547 -0
  48. package/dist/{manifest-DCReQE0k.js → manifest-DvuKi7I4.js} +11 -7
  49. package/dist/{panel-config-COHesW2B.js → panel-config-CRf-ONSV.js} +404 -308
  50. package/dist/picker/alt-click-picker.d.ts +10 -2
  51. package/dist/picker/arming-coordinator.d.ts +2 -0
  52. package/dist/picker/index.d.ts +2 -2
  53. package/dist/search/command-palette.d.ts +21 -0
  54. package/dist/search/contribution.d.ts +7 -0
  55. package/dist/search/fuzzy.d.ts +10 -0
  56. package/dist/search/index.d.ts +4 -0
  57. package/dist/search/match-bar.d.ts +14 -0
  58. package/dist/search/search-header.d.ts +7 -0
  59. package/dist/search/token-search.d.ts +36 -0
  60. package/dist/server/create-apply-handler.d.ts +33 -0
  61. package/dist/server/index.d.ts +2 -1
  62. package/dist/server/index.js +1 -1
  63. package/dist/shell/dock-mode-switch.d.ts +6 -0
  64. package/dist/shell/footer.d.ts +1 -0
  65. package/dist/shell/ghost-idle.d.ts +24 -0
  66. package/dist/shell/header.d.ts +5 -0
  67. package/dist/shell/layer-activity.d.ts +6 -0
  68. package/dist/shell/mini-pill.d.ts +21 -0
  69. package/dist/shell/regions.d.ts +26 -0
  70. package/dist/shell/shortcut-dispatcher.d.ts +17 -0
  71. package/dist/shell/tab-bar.d.ts +17 -0
  72. package/dist/shell/tab-overflow-popover.d.ts +13 -0
  73. package/dist/specimen/on-page-specimen.d.ts +19 -0
  74. package/dist/specimen/preview-glyphs.d.ts +2 -0
  75. package/dist/specimen/specimen-state.d.ts +12 -0
  76. package/dist/specimen/specimen-tab-body.d.ts +18 -0
  77. package/dist/specimen/specimen-toolbar.d.ts +10 -0
  78. package/dist/specimen/specimen-values.d.ts +9 -0
  79. package/dist/state/history.d.ts +64 -0
  80. package/dist/state/persist.d.ts +10 -14
  81. package/dist/state/transaction.d.ts +24 -0
  82. package/dist/state/tweak-state.d.ts +16 -0
  83. package/dist/styles/z-index-tokens.d.ts +2 -0
  84. package/dist/tabs/color-tab.d.ts +10 -1
  85. package/dist/tabs/flat/flat-tab.d.ts +27 -0
  86. package/dist/tabs/flat/index.d.ts +8 -0
  87. package/dist/tabs/flat/scroll-to-token-row.d.ts +3 -0
  88. package/dist/tabs/flat/tier-section.d.ts +17 -0
  89. package/dist/tabs/flat/token-controller.d.ts +23 -0
  90. package/dist/tabs/flat/token-row.d.ts +12 -0
  91. package/dist/tabs/flat/types.d.ts +25 -0
  92. package/dist/tabs/font-tab.d.ts +13 -12
  93. package/dist/tabs/generic-tab.d.ts +8 -38
  94. package/dist/tabs/palette/palette-check-view.d.ts +5 -1
  95. package/dist/tabs/palette/palette-edit-view.d.ts +9 -1
  96. package/dist/tabs/palette/palette-tab.d.ts +12 -1
  97. package/dist/tabs/size-tab.d.ts +7 -10
  98. package/dist/tabs/spacing-tab.d.ts +7 -13
  99. package/dist/testing.js +3 -3
  100. package/dist/tokens/tier-model.d.ts +6 -0
  101. package/dist/{tweak-state-BKNxtHzb.js → tweak-state-BGp_7Tfh.js} +473 -423
  102. package/dist/utils/numeric-transform.d.ts +32 -0
  103. package/dist/utils/token-diff.d.ts +25 -0
  104. package/dist/utils/token-graph.d.ts +23 -0
  105. package/dist/utils/token-index.d.ts +30 -0
  106. package/dist/zdtp.css +1 -1
  107. package/package.json +3 -1
  108. package/dist/controls/pill-slider-row.d.ts +0 -36
  109. package/dist/controls/select-row.d.ts +0 -25
  110. package/dist/controls/slider-row.d.ts +0 -29
  111. package/dist/controls/text-row.d.ts +0 -27
  112. package/dist/index-U7Ol7tgA.js +0 -7591
  113. package/dist/load-routing-D4H2VOl5.js +0 -426
@@ -55,8 +55,8 @@
55
55
  * degraded-init paths) can pass `colorDefaults: undefined`; in that case the
56
56
  * whole color block is treated as changed.
57
57
  *
58
- * For non-color tokens, `TokenOverrides` is already a sparse diff (only
59
- * overridden tokens appear in the map) — no baseline comparison is needed.
58
+ * For non-color tokens, the sparse maps may retain empty or default-equal
59
+ * values. Those entries are omitted so Apply matches UI and diff-only export.
60
60
  *
61
61
  * Pure / no IO — safe to import anywhere (browser, Node, tests).
62
62
  */
@@ -0,0 +1,23 @@
1
+ /** A single CSS custom-property change suitable for an apply preview. */
2
+ export interface ApplyHunk {
3
+ cssVar: string;
4
+ /** One-based line number of the declaration in the proposed file. */
5
+ line: number;
6
+ /** Complete declaration line before the rewrite. */
7
+ before: string;
8
+ /** Complete declaration line after the rewrite. */
9
+ after: string;
10
+ /** Neighbouring proposed-file lines, excluding the declaration itself. */
11
+ context: {
12
+ before: string[];
13
+ after: string[];
14
+ };
15
+ }
16
+ /**
17
+ * Compute one preview hunk per changed cssVar.
18
+ *
19
+ * `changedCssVars` is authoritative: unrelated textual differences never
20
+ * become hunks. Input order is retained so the response follows request/apply
21
+ * order, including when multiple declarations share one physical line.
22
+ */
23
+ export declare function computeHunks(beforeSource: string, afterSource: string, changedCssVars: readonly string[], contextLineCount?: number): ApplyHunk[];
@@ -0,0 +1,5 @@
1
+ import type { PanelConfig } from '../config/panel-config';
2
+ export type FlatOverrides = Record<string, string>;
3
+ export declare function loadLastApplied(cfg: PanelConfig): FlatOverrides;
4
+ export declare function saveLastApplied(overrides: FlatOverrides, cfg: PanelConfig): void;
5
+ export declare function unsavedCssVars(current: FlatOverrides, baseline: FlatOverrides): string[];
@@ -0,0 +1,19 @@
1
+ import type { PanelConfig } from '../config/panel-config';
2
+ import type { ColorTweakState, TweakState } from '../state/tweak-state';
3
+ /**
4
+ * Remove only overrides the server confirms it wrote. CSS variables are
5
+ * resolved through the manifest token index so color, secondary-color,
6
+ * reserved, and generic tab state all follow the same address-based path.
7
+ *
8
+ * A same-alias semantic mapping can be emitted because its bg/fg dependency
9
+ * moved even though the mapping itself did not. Since base-role variables are
10
+ * outside disk Apply, reconcile that dependency when its derived semantic var
11
+ * was written. Unwritten aliases are first materialized to their current
12
+ * numeric index so partial writes never discard their emitted value.
13
+ */
14
+ export declare function reconcileApplied(state: TweakState, writtenCssVars: readonly string[], cfg: PanelConfig, colorDefaults: ColorTweakState, secondaryDefaults?: ColorTweakState): TweakState;
15
+ export declare function writtenCssVarsFromResponse(response: {
16
+ updated?: readonly {
17
+ changed?: readonly string[];
18
+ }[];
19
+ }): string[];
@@ -1,58 +1,12 @@
1
- /**
2
- * Apply modal — previews the diff between the current `TweakState` and the
3
- * scheme defaults, then POSTs the diff to the dev-only
4
- * `/api/dev/design-tokens-apply` endpoint so the tweaks are written back
5
- * into the host's design-system CSS files on disk.
6
- *
7
- * Wiring summary
8
- * --------------
9
- * - Diff building is delegated to `./apply/build-apply-overrides`, which
10
- * consumes the new `ColorTweakState` shape (palette + semanticMappings) and
11
- * emits the flat `{ cssVar: value }` map using `SEMANTIC_CSS_NAMES`.
12
- * - Per-file grouping (for the preview and for the success view) uses
13
- * `./apply/route-tokens-to-files` — the exact same routing the dev-API
14
- * handler runs server-side, so the preview matches the server's view of
15
- * the world byte-for-byte.
16
- * - Styling uses bundled BEM classes derived from
17
- * `panelConfig.modalClassPrefix` via `modalClass(...)`. The matching CSS
18
- * lives in `styles/panel.css` keyed on the default modal class prefix;
19
- * consumers that override the prefix opt out of bundled CSS and ship
20
- * their own. No Tailwind classes remain.
21
- *
22
- * Dialog lifecycle (unchanged)
23
- * ----------------------------
24
- * Uses the native `<dialog>` element. Every dismissal path (× / backdrop /
25
- * Escape / programmatic close) routes through `dialog.close()`, which fires
26
- * the native `close` event exactly once; `onClose` then fires exactly once
27
- * per dismissal regardless of the path taken.
28
- */
29
1
  import { type PanelConfig } from './config/panel-config';
30
2
  import { type ColorTweakState, type TweakState } from './state/tweak-state';
31
3
  export interface ApplyModalProps {
32
4
  state: TweakState;
33
5
  open: boolean;
34
6
  onClose: () => void;
35
- /**
36
- * Scheme baseline used to diff the current `state.color` against when
37
- * computing the flat cssVar overrides. When absent, the entire color block
38
- * is treated as changed — useful for tests, but real callers (the panel
39
- * itself) always pass the active scheme's initial `ColorTweakState`.
40
- */
41
7
  colorDefaults?: ColorTweakState;
42
- /**
43
- * Fired exactly once after the user confirms a successful apply by clicking
44
- * "Done". The parent is expected to clear the persisted state envelope,
45
- * clear any inline-applied styles, and reset in-memory state to empty.
46
- */
47
- onApplied: () => void;
48
- /**
49
- * The mounted panel instance's config (multi-instance, #357). When supplied,
50
- * the modal resolves its apply routing / endpoint / secondary cluster / modal
51
- * classes from THIS instance rather than the active default instance — so an
52
- * Apply on panel A targets A's endpoint+routing, not whichever instance was
53
- * configured last. Omitted (e.g. a direct test render) → `getPanelConfig()`,
54
- * preserving the single-panel path.
55
- */
8
+ onApplied: (writtenCssVars: string[]) => void;
56
9
  instanceConfig?: PanelConfig;
57
10
  }
11
+ export declare function flattenApplyOverrides(state: TweakState, colorDefaults: ColorTweakState | undefined, cfg: PanelConfig): Record<string, string>;
58
12
  export declare function ApplyModal(props: ApplyModalProps): import("preact").JSX.Element;
@@ -1,6 +1,6 @@
1
- import { c as y, g as m, a as w, b, i as P } from "../panel-config-COHesW2B.js";
2
- import { g, Z as k } from "../tweak-state-BKNxtHzb.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-CfL2VUe1.js";
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";
4
4
  const u = "tokenpanel-config";
5
5
  function S() {
6
6
  if (typeof document > "u")
@@ -1,6 +1,6 @@
1
- import { s as t } from "../panel-config-COHesW2B.js";
1
+ import { s as t } from "../panel-config-CRf-ONSV.js";
2
2
  import { c as d } from "../color-schemes-CgzOBqGO.js";
3
- import { F as r, G as m, a as g, S as z } from "../manifest-DCReQE0k.js";
3
+ import { F as r, G as m, a as g, S as z } from "../manifest-DvuKi7I4.js";
4
4
  const e = {
5
5
  colorScheme: "Default Dark",
6
6
  colorMode: !1
@@ -1,4 +1,4 @@
1
- import { g as n, j as o } from "./panel-config-COHesW2B.js";
1
+ import { g as n, j as o } from "./panel-config-CRf-ONSV.js";
2
2
  function c() {
3
3
  return typeof document < "u" && document !== null && typeof document.getElementById == "function";
4
4
  }
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { realpathSync as E } from "node:fs";
3
- import { createServer as H } from "node:http";
4
- import { resolve as p } from "node:path";
5
- import { l as $, c as x } from "../load-routing-D4H2VOl5.js";
6
- function g(o, t) {
2
+ import { realpathSync as $ } from "node:fs";
3
+ import { createServer as E } from "node:http";
4
+ import { resolve as h } from "node:path";
5
+ import { l as H, c as L } from "../load-routing-BtCE1hGI.js";
6
+ function w(o, t) {
7
7
  return typeof o != "string" || o.length === 0 || t.length === 0 ? !1 : t.includes(o);
8
8
  }
9
- function w(o) {
9
+ function y(o) {
10
10
  return {
11
11
  "Access-Control-Allow-Origin": o,
12
12
  "Access-Control-Allow-Methods": "POST, OPTIONS",
@@ -14,7 +14,7 @@ function w(o) {
14
14
  "Access-Control-Max-Age": "600"
15
15
  };
16
16
  }
17
- const k = 24681, b = "127.0.0.1", N = `Usage: zdtp-server [options]
17
+ const b = 24681, O = "127.0.0.1", x = `Usage: zdtp-server [options]
18
18
 
19
19
  Run a small Node http server that wraps the design-token apply handler.
20
20
 
@@ -25,8 +25,8 @@ Options:
25
25
  single directory the bin is allowed to write into.
26
26
  --routing <path> REQUIRED. Path to the routing JSON file
27
27
  (prefix -> repo-relative CSS file path).
28
- --port <number> TCP port to bind. Default: ${k}.
29
- --host <addr> Host/interface to bind. Default: ${b}.
28
+ --port <number> TCP port to bind. Default: ${b}.
29
+ --host <addr> Host/interface to bind. Default: ${O}.
30
30
  Use 0.0.0.0 to expose on the LAN (off by default).
31
31
  --allow-origin <origin> Origin allowed to POST to /apply. Repeatable.
32
32
  At least one is required for any browser to apply.
@@ -39,13 +39,13 @@ Examples:
39
39
  --routing ./my.routing.json \\
40
40
  --allow-origin http://localhost:34434
41
41
  `;
42
- function v(o) {
42
+ function N(o) {
43
43
  const t = {
44
44
  root: null,
45
45
  writeRoot: null,
46
46
  routing: null,
47
- port: k,
48
- host: b,
47
+ port: b,
48
+ host: O,
49
49
  allowOrigins: [],
50
50
  quiet: !1,
51
51
  help: !1
@@ -102,9 +102,9 @@ function c(o, t, e) {
102
102
  throw new Error(`${e} requires a value`);
103
103
  return n;
104
104
  }
105
- const y = "/apply", D = "/healthz";
106
- function L(o) {
107
- const t = p(o.root ?? process.cwd()), e = p(t, o.writeRoot), n = p(t, o.routing);
105
+ const k = "/apply", v = "/healthz";
106
+ function D(o) {
107
+ const t = h(o.root ?? process.cwd()), e = h(t, o.writeRoot), n = h(t, o.routing);
108
108
  return {
109
109
  rootDir: t,
110
110
  writeRoot: e,
@@ -119,13 +119,13 @@ function a(o, t, e) {
119
119
  const n = JSON.stringify(e);
120
120
  o.statusCode = t, o.setHeader("Content-Type", "application/json"), o.setHeader("Content-Length", Buffer.byteLength(n).toString()), o.end(n);
121
121
  }
122
- const O = 1048576;
122
+ const A = 1048576;
123
123
  function j(o) {
124
124
  return new Promise((t, e) => {
125
125
  const n = [];
126
126
  let s = 0;
127
127
  o.on("data", (r) => {
128
- if (s += r.byteLength, s > O) {
128
+ if (s += r.byteLength, s > A) {
129
129
  t(413), o.destroy();
130
130
  return;
131
131
  }
@@ -154,13 +154,15 @@ function V(o, t) {
154
154
  if (!o)
155
155
  try {
156
156
  const e = JSON.parse(t);
157
- if (!e.ok || !Array.isArray(e.updated)) return;
158
- const n = e.updated.reduce(
159
- (i, l) => i + (Array.isArray(l.changed) ? l.changed.length : 0),
157
+ if (!e.ok) return;
158
+ const n = e.dryRun === !0 ? e.files : e.updated;
159
+ if (!Array.isArray(n)) return;
160
+ const s = n.reduce(
161
+ (i, f) => i + (Array.isArray(f.changed) ? f.changed.length : 0),
160
162
  0
161
- ), s = e.updated.length, r = e.updated.filter((i) => Array.isArray(i.changed) && i.changed.length > 0).map((i) => i.file);
163
+ ), r = n.length, l = n.filter((i) => Array.isArray(i.changed) && i.changed.length > 0).map((i) => i.file), u = e.dryRun === !0 ? "dry-run" : "applied";
162
164
  console.log(
163
- `[design-token-panel] applied ${n} tokens to ${s} files (changed: ${r.length > 0 ? r.join(", ") : "none"})`
165
+ `[design-token-panel] ${u} ${s} ${s === 1 ? "token" : "tokens"} to ${r} ${r === 1 ? "file" : "files"} (changed: ${l.length > 0 ? l.join(", ") : "none"})`
164
166
  ), Array.isArray(e.unknownCssVars) && e.unknownCssVars.length > 0 && console.log(
165
167
  `[design-token-panel] unknown: ${e.unknownCssVars.length} cssVar(s) not found (${e.unknownCssVars.join(", ")})`
166
168
  ), Array.isArray(e.unknownOutsideBlockCssVars) && e.unknownOutsideBlockCssVars.length > 0 && console.log(
@@ -172,9 +174,9 @@ function V(o, t) {
172
174
  function B(o) {
173
175
  const { applyHandler: t, config: e } = o;
174
176
  return async function(s, r) {
175
- const i = s.url ?? "/", l = (s.method ?? "GET").toUpperCase(), u = typeof s.headers.origin == "string" ? s.headers.origin : null;
177
+ const l = s.url ?? "/", u = (s.method ?? "GET").toUpperCase(), d = typeof s.headers.origin == "string" ? s.headers.origin : null;
176
178
  try {
177
- if (i === D && l === "GET") {
179
+ if (l === v && u === "GET") {
178
180
  a(r, 200, {
179
181
  ok: !0,
180
182
  writeRoot: e.writeRoot,
@@ -183,51 +185,51 @@ function B(o) {
183
185
  });
184
186
  return;
185
187
  }
186
- if (i === y) {
187
- if (l === "OPTIONS") {
188
- if (!g(u, e.allowOrigins)) {
188
+ if (l === k) {
189
+ if (u === "OPTIONS") {
190
+ if (!w(d, e.allowOrigins)) {
189
191
  a(r, 403, { ok: !1, error: "Origin not allowed" });
190
192
  return;
191
193
  }
192
- const S = w(u);
194
+ const S = y(d);
193
195
  for (const [C, P] of Object.entries(S))
194
196
  r.setHeader(C, P);
195
197
  r.statusCode = 204, r.end();
196
198
  return;
197
199
  }
198
- if (l !== "POST") {
200
+ if (u !== "POST") {
199
201
  r.setHeader("Allow", "POST, OPTIONS"), a(r, 405, { ok: !1, error: "Method not allowed" });
200
202
  return;
201
203
  }
202
- const d = s.headers["content-type"];
203
- if (typeof d != "string" || !d.toLowerCase().includes("application/json")) {
204
+ const p = s.headers["content-type"];
205
+ if (typeof p != "string" || !p.toLowerCase().includes("application/json")) {
204
206
  a(r, 415, { ok: !1, error: "Content-Type must be application/json" });
205
207
  return;
206
208
  }
207
- if (!g(u, e.allowOrigins)) {
209
+ if (!w(d, e.allowOrigins)) {
208
210
  a(r, 403, { ok: !1, error: "Origin not allowed" });
209
211
  return;
210
212
  }
211
- const f = await j(s);
212
- if (f === 413) {
213
+ const i = await j(s);
214
+ if (i === 413) {
213
215
  a(r, 413, {
214
216
  ok: !1,
215
217
  error: "Payload Too Large",
216
- limit: O
218
+ limit: A
217
219
  });
218
220
  return;
219
221
  }
220
- const A = f, m = new Request(`http://localhost${y}`, {
222
+ const f = i, m = new Request(`http://localhost${k}`, {
221
223
  method: "POST",
222
224
  headers: U(s),
223
- body: A
224
- }), h = await t(m), R = await h.clone().text(), T = w(u);
225
- await I(r, h, T), V(e.quiet, R);
225
+ body: f
226
+ }), g = await t(m), R = await g.clone().text(), T = y(d);
227
+ await I(r, g, T), V(e.quiet, R);
226
228
  return;
227
229
  }
228
230
  a(r, 404, { ok: !1, error: "Not found" });
229
- } catch (d) {
230
- console.error("[design-token-panel] Unhandled error:", d), r.headersSent ? r.end() : a(r, 500, { ok: !1, error: "Internal server error" });
231
+ } catch (p) {
232
+ console.error("[design-token-panel] Unhandled error:", p), r.headersSent ? r.end() : a(r, 500, { ok: !1, error: "Internal server error" });
231
233
  }
232
234
  };
233
235
  }
@@ -247,28 +249,28 @@ function q(o, t) {
247
249
  function F() {
248
250
  let o;
249
251
  try {
250
- o = v(process.argv.slice(2));
252
+ o = N(process.argv.slice(2));
251
253
  } catch (r) {
252
254
  console.error(`[design-token-panel] ${r.message}`), console.error(""), console.error("Run --help for usage."), process.exit(1);
253
255
  }
254
- o.help && (process.stdout.write(N), process.exit(0));
255
- const t = L(o);
256
+ o.help && (process.stdout.write(x), process.exit(0));
257
+ const t = D(o);
256
258
  let e;
257
259
  try {
258
- e = $(t.routingPath);
260
+ e = H(t.routingPath);
259
261
  } catch (r) {
260
262
  console.error(`[design-token-panel] Failed to load routing: ${r.message}`), process.exit(1);
261
263
  }
262
- const n = x({
264
+ const n = L({
263
265
  rootDir: t.rootDir,
264
266
  writeRoot: t.writeRoot,
265
267
  routing: e
266
- }), s = H(B({ applyHandler: n, config: t }));
268
+ }), s = E(B({ applyHandler: n, config: t }));
267
269
  q(s, t.port), s.listen(t.port, t.host, () => {
268
270
  if (!t.quiet) {
269
- const r = s.address(), i = typeof r == "object" && r ? r.port : t.port;
271
+ const r = s.address(), l = typeof r == "object" && r ? r.port : t.port;
270
272
  console.log(
271
- `[design-token-panel] listening on http://${t.host}:${i} (writeRoot: ${t.writeRoot})`
273
+ `[design-token-panel] listening on http://${t.host}:${l} (writeRoot: ${t.writeRoot})`
272
274
  ), t.allowOrigins.length === 0 && console.log(
273
275
  "[design-token-panel] WARNING: no --allow-origin set; browser POST /apply will be rejected."
274
276
  );
@@ -278,7 +280,7 @@ function F() {
278
280
  const _ = (() => {
279
281
  if (typeof process.argv[1] != "string") return !1;
280
282
  try {
281
- const o = E(process.argv[1]), t = new URL(`file://${p(o)}`).href, e = import.meta.url;
283
+ const o = $(process.argv[1]), t = new URL(`file://${h(o)}`).href, e = import.meta.url;
282
284
  return t === e;
283
285
  } catch {
284
286
  return !1;
@@ -0,0 +1,45 @@
1
+ import type { ComponentChildren } from 'preact';
2
+ import type { TierConfig } from '../tokens/tier-model';
3
+ import { type NumericValue } from '../utils/numeric-transform';
4
+ import type { FlatTabEntry, RowContribution, TokenAddress } from '../tabs/flat/types';
5
+ export interface BulkOperations {
6
+ multiply: string;
7
+ add: string;
8
+ roundToStep: string;
9
+ setTo: string;
10
+ }
11
+ export declare const DEFAULT_BULK_OPERATIONS: BulkOperations;
12
+ export interface BulkPatchEntry {
13
+ address: TokenAddress;
14
+ value: string;
15
+ }
16
+ export interface BulkContributionOptions {
17
+ entriesByTier: ReadonlyMap<string, readonly FlatTabEntry[]>;
18
+ selectedKeys: ReadonlySet<string>;
19
+ operations: BulkOperations;
20
+ onToggle: (entry: FlatTabEntry, checked: boolean) => void;
21
+ onSelectTier: (tier: TierConfig, checked: boolean) => void;
22
+ onQuick: (tier: TierConfig, factor: number) => void;
23
+ }
24
+ /** Return the declared unit for a numeric token kind. */
25
+ export declare function numericEntryUnit(entry: FlatTabEntry): string;
26
+ /**
27
+ * Bulk selection is deliberately narrower than numeric row rendering. A row
28
+ * must be a writable literal length/number with a parseable current value.
29
+ * Reference tiers, readonly rows, and active pill sentinels cannot safely
30
+ * participate in a numeric transform.
31
+ */
32
+ export declare function isBulkSelectable(entry: FlatTabEntry): boolean;
33
+ export declare const isSelectable: typeof isBulkSelectable;
34
+ export declare function numericValueForEntry(entry: FlatTabEntry): NumericValue | null;
35
+ /** Compute one preview value from the action-bar operation fields. */
36
+ export declare function transformBulkEntry(entry: FlatTabEntry, operations: BulkOperations): string | null;
37
+ export declare function createBulkContribution(options: BulkContributionOptions): RowContribution;
38
+ export interface BulkActionBarProps {
39
+ entries: readonly FlatTabEntry[];
40
+ operations: BulkOperations;
41
+ onOperationsChange: (operations: BulkOperations) => void;
42
+ onClear: () => void;
43
+ onApply: (patch: readonly BulkPatchEntry[]) => void;
44
+ }
45
+ export declare function BulkActionBar({ entries, operations, onOperationsChange, onClear, onApply, }: BulkActionBarProps): ComponentChildren;
@@ -0,0 +1,2 @@
1
+ export { BulkActionBar, DEFAULT_BULK_OPERATIONS, createBulkContribution, isBulkSelectable, isSelectable, numericEntryUnit, numericValueForEntry, transformBulkEntry, } from './bulk-actions';
2
+ export type { BulkActionBarProps, BulkContributionOptions, BulkOperations, BulkPatchEntry, } from './bulk-actions';
@@ -0,0 +1,2 @@
1
+ export { ChainButton, ChainPopover, TOKEN_CHAIN_CONTRIBUTION, TokenChainButton, TokenChainPopover, type TokenChainButtonProps, type TokenChainPopoverProps, } from './token-chain-popover';
2
+ export { TokenChainProvider, useTokenChainContext, type TokenChainContextValue, type TokenChainProviderProps, } from './token-chain-context';
@@ -0,0 +1,19 @@
1
+ import type { ComponentChildren } from 'preact';
2
+ import type { PanelConfig } from '../config/panel-config';
3
+ import type { TweakState } from '../state/tweak-state';
4
+ import { type TokenGraph } from '../utils/token-graph';
5
+ export interface TokenChainContextValue {
6
+ graph: TokenGraph;
7
+ }
8
+ export interface TokenChainProviderProps {
9
+ instanceConfig: PanelConfig;
10
+ state: TweakState | null;
11
+ children?: ComponentChildren;
12
+ }
13
+ /**
14
+ * Keeps the dependency graph tied to the mounted panel instance and its live
15
+ * tweak state. A chain control rendered outside this provider simply degrades
16
+ * to no chain affordance, which keeps the row primitives useful in isolation.
17
+ */
18
+ export declare function TokenChainProvider({ instanceConfig, state, children, }: TokenChainProviderProps): import("preact").JSX.Element;
19
+ export declare function useTokenChainContext(): TokenChainContextValue | null;
@@ -0,0 +1,22 @@
1
+ import type { JSX } from 'preact';
2
+ import { type TokenAddress } from '../utils/token-index';
3
+ import type { RowContribution } from '../tabs/flat/types';
4
+ export interface TokenChainPopoverProps {
5
+ address: TokenAddress;
6
+ anchorRef: React.RefObject<HTMLElement | null>;
7
+ onClose: () => void;
8
+ }
9
+ /**
10
+ * Body of the per-token chain surface. It is mounted only while its trigger
11
+ * is open, so the first page probe is deferred until the user asks for it.
12
+ */
13
+ export declare function TokenChainPopover({ address, anchorRef, onClose, }: TokenChainPopoverProps): JSX.Element | null;
14
+ export interface TokenChainButtonProps {
15
+ address: TokenAddress;
16
+ }
17
+ /** Chain trigger used by flat rows and Color-tab custom rows. */
18
+ export declare function TokenChainButton({ address }: TokenChainButtonProps): JSX.Element | null;
19
+ /** Shared FlatTab contribution for every non-Color row. */
20
+ export declare const TOKEN_CHAIN_CONTRIBUTION: RowContribution;
21
+ export declare const ChainPopover: typeof TokenChainPopover;
22
+ export declare const ChainButton: typeof TokenChainButton;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Changed-state row contribution.
3
+ *
4
+ * The S2 token evaluator is deliberately the only source of truth here. A
5
+ * row's visual state, Changed-only filtering, ghost value, and revert affordance
6
+ * all consult the same `isChanged` result for the row's stable token address.
7
+ */
8
+ import type { PanelConfig } from '../config/panel-config';
9
+ import type { TweakState } from '../state/tweak-state';
10
+ import { revertEntry, type ColorBaseline } from '../utils/token-diff';
11
+ import type { TokenIndex, TokenAddress } from '../utils/token-index';
12
+ import type { RowContribution } from '../tabs/flat/types';
13
+ export interface ChangedContributionOptions {
14
+ index: TokenIndex;
15
+ state: TweakState;
16
+ baseline: ColorBaseline;
17
+ cfg: PanelConfig;
18
+ /** True while the active tab's transient Changed-only filter is enabled. */
19
+ changedOnly?: boolean;
20
+ /** Reverts one stable token address through the shell transaction. */
21
+ onRevert: (address: TokenAddress) => void;
22
+ }
23
+ /**
24
+ * Build the contribution used by FlatTab-based token lists. `revertEntry`
25
+ * remains in the shell callback rather than here so this presentation seam
26
+ * never mutates state directly.
27
+ */
28
+ export declare function changedContribution(options: ChangedContributionOptions): RowContribution;
29
+ /** Explicit factory alias for feature callers and downstream consumers. */
30
+ export declare const createChangedContribution: typeof changedContribution;
31
+ export declare const changedStateContribution: typeof changedContribution;
32
+ export { revertEntry };
@@ -0,0 +1,16 @@
1
+ import type { JSX } from 'preact';
2
+ import type { PanelConfig } from '../config/panel-config';
3
+ import type { ColorBaseline } from '../utils/token-diff';
4
+ import type { TweakState } from '../state/tweak-state';
5
+ import type { TokenIndex } from '../utils/token-index';
6
+ export declare const COPY_REVERT_MS = 2000;
7
+ export interface ChangedFooterContentProps {
8
+ index: TokenIndex;
9
+ state: TweakState;
10
+ baseline: ColorBaseline;
11
+ cfg: PanelConfig;
12
+ onRevertAll: () => void;
13
+ }
14
+ /** Footer summary + evaluator-backed Copy diff / Revert all actions. */
15
+ export declare function ChangedFooterContent({ index, state, baseline, cfg, onRevertAll, }: ChangedFooterContentProps): JSX.Element;
16
+ export declare const ChangedFooter: typeof ChangedFooterContent;
@@ -0,0 +1,4 @@
1
+ export { changedContribution, changedStateContribution, createChangedContribution, revertEntry, } from './contribution';
2
+ export { ChangedFooter, ChangedFooterContent, COPY_REVERT_MS } from './footer-content';
3
+ export { ChangedOnlyToggle } from './tab-filter';
4
+ export { ChangedTabBadge, TabChangedBadge } from './tab-badge';
@@ -0,0 +1,8 @@
1
+ import type { JSX } from 'preact';
2
+ export interface ChangedTabBadgeProps {
3
+ tabId: string;
4
+ count: number;
5
+ }
6
+ /** Count badge rendered inside a tab button without affecting tab overflow. */
7
+ export declare function ChangedTabBadge({ tabId, count }: ChangedTabBadgeProps): JSX.Element | null;
8
+ export declare const TabChangedBadge: typeof ChangedTabBadge;
@@ -0,0 +1,8 @@
1
+ import type { JSX } from 'preact';
2
+ export interface ChangedOnlyToggleProps {
3
+ enabled: boolean;
4
+ count: number;
5
+ onChange: (enabled: boolean) => void;
6
+ }
7
+ /** Transient active-tab Changed-only filter (never persisted). */
8
+ export declare function ChangedOnlyToggle({ enabled, count, onChange, }: ChangedOnlyToggleProps): JSX.Element;
@@ -72,6 +72,10 @@ export type ApplyRoutingMap = Record<string, string>;
72
72
  export interface DomTweakerConfig {
73
73
  themeCss?: string;
74
74
  }
75
+ export interface PanelDockConfig {
76
+ /** Whether docked panels reserve space in the host document. Defaults to body-margin. */
77
+ reflow?: 'body-margin' | 'none';
78
+ }
75
79
  /**
76
80
  * Apply sink interface — allows routing CSS-var writes somewhere other than
77
81
  * the host `:root` (e.g. a shadow root, an iframe document, or a spy in
@@ -150,6 +154,8 @@ export interface PanelConfig {
150
154
  * panel config.
151
155
  */
152
156
  domTweaker?: DomTweakerConfig;
157
+ /** Docked-panel integration. Omitted values use body-margin host reflow. */
158
+ dock?: PanelDockConfig;
153
159
  /**
154
160
  * Host-supplied tab configuration for the data-driven tab strip.
155
161
  *
@@ -470,8 +476,22 @@ export declare function storageKey_open(cfg: PanelConfig): string;
470
476
  export declare function storageKey_position(cfg: PanelConfig): string;
471
477
  /** User-resized panel size `{ width, height }` (pixels). Lives alongside position. */
472
478
  export declare function storageKey_size(cfg: PanelConfig): string;
479
+ /** Persisted shell dock mode. */
480
+ export declare function storageKey_dock(cfg: PanelConfig): string;
481
+ /** Per-axis docked dimensions (`right` width and `bottom` height). */
482
+ export declare function storageKey_dockSize(cfg: PanelConfig): string;
473
483
  /** Tab-grid density preference (one of `0` / `1` / `2`). Lives alongside size/position. */
474
484
  export declare function storageKey_density(cfg: PanelConfig): string;
485
+ /** Font specimen toolbar state (`{ text, preset, overridden, width }`). */
486
+ export declare function storageKey_specimen(cfg: PanelConfig): string;
487
+ /** Persisted A/B snapshot slot. `slot` is lower-case for storage continuity. */
488
+ export declare function storageKey_snapshot(cfg: PanelConfig, slot: 'a' | 'b'): string;
489
+ /** Persisted snapshot A slot. */
490
+ export declare function storageKey_snapshotA(cfg: PanelConfig): string;
491
+ /** Persisted snapshot B slot. */
492
+ export declare function storageKey_snapshotB(cfg: PanelConfig): string;
493
+ /** Last flattened override set known to match the apply baseline. */
494
+ export declare function storageKey_lastApplied(cfg: PanelConfig): string;
475
495
  /**
476
496
  * Adapter-level visibility-intent flag.
477
497
  *
@@ -532,31 +552,6 @@ export interface ZdtpGlobalApi {
532
552
  hide: () => void | Promise<void>;
533
553
  toggle: () => void | Promise<void>;
534
554
  }
535
- /**
536
- * Install `window.zdtp = { show, hide, toggle }`, the fixed-name console
537
- * sugar for the common single-panel case (issue #523).
538
- *
539
- * Guard rules:
540
- * - A pre-existing `window.zdtp` WITHOUT this package's marker is assumed to
541
- * be host-defined — never overwritten. Logs a `console.warn` so the host
542
- * can see why `zdtp.show()` did not appear.
543
- * - A pre-existing `window.zdtp` WITH the marker means this package already
544
- * installed the alias (from the other call site, or an earlier run of this
545
- * same one). First install wins — the call is a silent no-op. In the Astro
546
- * flow this manifests as "the adapter wins": its bootstrap script always
547
- * runs (and installs the alias) before the panel module's lazy dynamic
548
- * import can resolve and reach the package-root install site.
549
- *
550
- * `show` / `hide` / `toggle` are caller-supplied closures, so which instance
551
- * they target is up to the caller — the package-root install site (below,
552
- * `index.tsx`) wraps `showDesignTokenPanel()` etc., which re-resolve
553
- * `getPanelConfig()` (the CURRENT default instance) on every call; the Astro
554
- * host-adapter install site instead binds to the specific `PanelInstanceHandle`
555
- * captured at its own install time, which does NOT track a later change of
556
- * default (see PORTABLE-CONTRACT.md §6.5 for the full nuance). Either way,
557
- * for a multi-instance page use `configurePanel(cfg).open()` etc. on the
558
- * specific instance's own handle instead of relying on this alias.
559
- */
560
555
  export declare function installZdtpGlobalAlias(api: ZdtpGlobalApi): void;
561
556
  /**
562
557
  * Runtime validation at the host-adapter trust boundary. The Astro inline
@@ -575,6 +570,8 @@ export declare function assertValidPanelConfig(value: unknown): asserts value is
575
570
  * has not configured one — callers MUST treat empty as "apply disabled".
576
571
  */
577
572
  export declare function resolveApplyRouting(cfg?: PanelConfig): ApplyRoutingMap;
573
+ /** Whether the host has supplied both pieces required for disk-rewrite Apply. */
574
+ export declare function isApplyConfigured(cfg?: PanelConfig): boolean;
578
575
  /**
579
576
  * Lazily attach a host-supplied color-preset map AFTER `configurePanel(...)`.
580
577
  *