create-zudo-doc 2.5.1 → 3.1.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.
@@ -1,17 +1,61 @@
1
1
  /**
2
2
  * zdtp (zudo-design-token-panel) PanelConfig for this project.
3
3
  *
4
- * This config object is the single source of truth passed to
5
- * `configurePanel(designTokenPanelConfig)` in the bootstrap module.
4
+ * Single source of truth passed to `bootstrapDesignTokenPanel(...)` in
5
+ * `src/lib/design-token-panel-bootstrap.ts`.
6
6
  *
7
- * Type notes:
8
- * - zdtp's `ColorScheme` requires a `shikiTheme: string` field that is not
9
- * present in this project's local `ColorScheme` type or data (zdtp uses it
10
- * only for the panel's client-side code-block preview). Rather than an unsafe
11
- * `as unknown as Record<string, ZdtpColorScheme>` double-cast, every local
12
- * scheme map is run through `toZdtpColorSchemes()` below, which supplies
13
- * `DEFAULT_SHIKI_THEME` as the fallback so the result satisfies zdtp's
14
- * required-field shape with an ordinary type-checked assignment.
7
+ * Ramp-native model (mirrors zudo-doc's Color Ramp Restructure —
8
+ * zudolab/zudo-doc#2584 / #2592; mode-scoped Color tab #2606 / #2610)
9
+ * -------------------------------------------------------------------------
10
+ * The color model is ramp-native (`ColorScheme = { ramps, map }`, see
11
+ * `src/config/color-schemes.ts`). The panel surfaces it through two tabs:
12
+ *
13
+ * - **Palette tab** (reserved id `palette`): three `kind:'color'` OKLCH tiers —
14
+ * `base` (5 stops `--palette-base-0..4`), `accent` (3 stops →
15
+ * `--palette-accent-0..2`), and `state` (4 roles → `--palette-state-{role}`).
16
+ * zdtp's native L/C/H curve editor renders these. Per zdtp's palette-tab
17
+ * contract, a tab carrying MULTIPLE `kind:'color'` tiers MUST omit
18
+ * `colorExtras` (otherwise `resolveColorClusterFromTab` cannot pick a single
19
+ * palette tier). The ramps are shared across light/dark, so token defaults
20
+ * are read from the active scheme's `ramps` and stay in sync with
21
+ * `color-schemes.ts`. The cssVars match the `--palette-*` custom properties
22
+ * the ColorSchemeProvider emits (`schemeToCssPairs`).
23
+ *
24
+ * - **Color tab** (reserved id `color`): a single `semantic` tier holding the
25
+ * 4 base roles (`--zd-bg`/`--zd-fg`/`--zd-selection-{bg,fg}`) + 23 `--zd-*`
26
+ * semantic roles, each rendered as a grouped ramp dropdown. The tier declares
27
+ * `referencesRamps` pointing at the Palette tab's `base`/`accent`/`state`
28
+ * tiers, so each row's `default` is the encoded `tierId:itemId` ramp
29
+ * reference (`buildSemanticTierItems` / `rampRefToPanelDefault`), the picker
30
+ * renders grouped `<optgroup>` dropdowns, and editing emits live
31
+ * `var(--palette-*)`. The tier carries NO `referencesTier` — that resolves
32
+ * intra-tab only; the cross-tab wiring is `referencesRamps` + `semantic:true`.
33
+ *
34
+ * Mode-scoped defaults
35
+ * --------------------
36
+ * The Color tab's semantic defaults are MODE-SCOPED: `buildDesignTokenPanelConfig(mode)`
37
+ * seeds the tier from the active mode's scheme (light map vs dark map). The
38
+ * bootstrap (`@takazudo/zudo-doc/design-token-panel-bootstrap`) destroys +
39
+ * reconfigures the panel on every `color-scheme-changed` toggle so its defaults
40
+ * follow the live light/dark mode.
41
+ *
42
+ * Caveat: a *saved* color OVERRIDE is still mode-AGNOSTIC here — but this is
43
+ * this project's config-shape choice, not a zdtp limitation. zdtp 0.4.5 ships
44
+ * per-scheme/per-mode keyed color persistence (v4 envelope,
45
+ * Takazudo/zudo-design-token-panel#500 / #509): the color slice is keyed by
46
+ * the cluster's resolved scheme identity (`panelSettings.colorScheme` /
47
+ * `colorMode`). This project's color cluster is scheme-less
48
+ * (`colorExtras.colorSchemes = {}`, no `colorMode`) and switches modes
49
+ * externally via the destroy+reconfigure dance above rather than zdtp's own
50
+ * `colorMode` field, so zdtp always resolves the same single (stub) scheme
51
+ * identity and an override repaints both modes until Reset. Only the
52
+ * DEFAULTS are mode-faithful. Do NOT work around this by reaching into zdtp's
53
+ * private storage keys.
54
+ *
55
+ * The color cluster is **scheme-less**: `colorExtras.colorSchemes = {}` (zdtp's
56
+ * documented scheme-less cluster shape) — the ramps ARE the editable source of
57
+ * truth, surfaced by the Palette tab, so a bundled scheme-preset registry no
58
+ * longer applies.
15
59
  */
16
60
 
17
61
  import type {
@@ -20,7 +64,6 @@ import type {
20
64
  TierConfig,
21
65
  TierItem,
22
66
  ColorClusterExtras,
23
- ColorScheme as ZdtpColorScheme,
24
67
  TokenDef,
25
68
  } from "@takazudo/zdtp";
26
69
  import {
@@ -28,66 +71,23 @@ import {
28
71
  FONT_TOKENS,
29
72
  SIZE_TOKENS,
30
73
  } from "./design-tokens-manifest";
74
+ import {
75
+ getActiveScheme,
76
+ STATE_ROLES,
77
+ type ColorScheme,
78
+ } from "./color-scheme-utils";
79
+ import { buildSemanticTierItems } from "@takazudo/zudo-doc/color-scheme-utils";
31
80
  import { colorSchemes } from "./color-schemes";
32
- import type { ColorScheme as LocalColorScheme } from "./color-schemes";
33
- import { SEMANTIC_DEFAULTS, SEMANTIC_CSS_NAMES } from "./color-scheme-utils";
34
81
  import { settings } from "./settings";
35
- import { DESIGN_TOKEN_SCHEMA } from "@takazudo/zudo-doc/theme";
36
82
 
37
83
  /**
38
- * Base-role fallback indices. Background defaults to palette index 0,
39
- * foreground to 15, cursor to 6, selection to 0/15.
40
- */
41
- const BASE_DEFAULTS = {
42
- background: 0,
43
- foreground: 15,
44
- cursor: 6,
45
- selectionBg: 0,
46
- selectionFg: 15,
47
- } as const;
48
-
49
- /**
50
- * Fallback Shiki theme used when a color scheme's `shikiTheme` field is absent.
84
+ * Inert fallback for the still-REQUIRED `ColorClusterExtras.defaultShikiTheme`.
85
+ * zdtp's Shiki integration is a no-op stub, so this value has no visible
86
+ * effect if you highlight code some other way — but the field is typed
87
+ * `string`, so a value is required.
51
88
  */
52
89
  const DEFAULT_SHIKI_THEME = "github-dark";
53
90
 
54
- /**
55
- * Normalize this project's local `ColorScheme` records into zdtp's
56
- * `ColorScheme` shape. zdtp's type requires `shikiTheme: string`; the local
57
- * scheme type makes it optional. This helper fills `DEFAULT_SHIKI_THEME` only
58
- * when a scheme doesn't declare its own, so the result is assignable to
59
- * `Record<string, ZdtpColorScheme>` via an ordinary type-checked assignment —
60
- * replacing the previous `as unknown as` double-cast that bypassed every field
61
- * check. Tracked upstream at Takazudo/zudo-design-token-panel#342 (shikiTheme
62
- * should be optional in zdtp's `ColorScheme` type); drop this helper once that
63
- * lands.
64
- */
65
- function toZdtpColorSchemes(
66
- schemes: Record<string, LocalColorScheme>,
67
- ): Record<string, ZdtpColorScheme> {
68
- const normalized: Record<string, ZdtpColorScheme> = {};
69
- for (const [name, scheme] of Object.entries(schemes)) {
70
- normalized[name] = {
71
- ...scheme,
72
- shikiTheme: scheme.shikiTheme ?? DEFAULT_SHIKI_THEME,
73
- };
74
- }
75
- return normalized;
76
- }
77
-
78
- /**
79
- * Initial palette taken from the configured active scheme.
80
- */
81
- function getInitialPalette(): readonly string[] {
82
- const scheme = colorSchemes[settings.colorScheme];
83
- if (!scheme) {
84
- throw new Error(
85
- `Unknown color scheme: "${settings.colorScheme}". Available: ${Object.keys(colorSchemes).join(", ")}`,
86
- );
87
- }
88
- return scheme.palette;
89
- }
90
-
91
91
  // ---------------------------------------------------------------------------
92
92
  // Helpers — partition flat manifest arrays into TabConfig.tiers by group.
93
93
  // ---------------------------------------------------------------------------
@@ -129,6 +129,9 @@ function toTierItem(t: TokenDef): TierItem {
129
129
 
130
130
  /**
131
131
  * Build a tier from the subset of `tokens` whose `group` matches `groupId`.
132
+ * The tier's items share the same kind by construction (all items in a
133
+ * group share the same slider/select/text shape in this project's manifest).
134
+ * zdtp's `assertValidTabs` validator requires this.
132
135
  */
133
136
  function tierFromGroup(
134
137
  tokens: readonly TokenDef[],
@@ -145,100 +148,203 @@ function tierFromGroup(
145
148
  }
146
149
 
147
150
  // ---------------------------------------------------------------------------
148
- // Color tab — palette and semantic tiers + colorExtras for cluster metadata.
151
+ // Palette tab — three ramp tiers (base / accent / state), OKLCH curve editor.
149
152
  // ---------------------------------------------------------------------------
150
153
 
151
- const PALETTE_TIER_ID = "palette";
154
+ /**
155
+ * Build the three ramp tiers from the active scheme's shared `ramps`. Light
156
+ * and dark schemes share the same Tier-1 ramps, so the active scheme's ramps
157
+ * are the single source of truth — read from here rather than hardcoding a
158
+ * second copy of the values.
159
+ */
160
+ function buildRampTiers(): TierConfig[] {
161
+ const { ramps } = getActiveScheme();
152
162
 
153
- function buildPaletteTier(): TierConfig {
154
- const initial = getInitialPalette();
155
- const items: TierItem[] = [];
156
- for (let i = 0; i < 16; i++) {
157
- items.push({
158
- id: `p${i}`,
159
- cssVar: `--zd-${i}`,
160
- label: `p${i}`,
161
- default: initial[i] ?? "#808080",
162
- type: { kind: "color" },
163
- });
164
- }
165
- return {
166
- id: PALETTE_TIER_ID,
167
- label: "Palette",
168
- items,
163
+ const baseTier: TierConfig = {
164
+ id: "base",
165
+ label: "Base",
166
+ items: ramps.base.map((color, i): TierItem => ({
167
+ id: `base-${i}`,
168
+ cssVar: `--palette-base-${i}`,
169
+ label: String(i),
170
+ default: color,
171
+ type: { kind: "color", format: "oklch" },
172
+ })),
173
+ };
174
+
175
+ const accentTier: TierConfig = {
176
+ id: "accent",
177
+ label: "Accent",
178
+ items: ramps.accent.map((color, i): TierItem => ({
179
+ id: `accent-${i}`,
180
+ cssVar: `--palette-accent-${i}`,
181
+ label: String(i),
182
+ default: color,
183
+ type: { kind: "color", format: "oklch" },
184
+ })),
185
+ };
186
+
187
+ const stateTier: TierConfig = {
188
+ id: "state",
189
+ label: "State",
190
+ items: STATE_ROLES.map((role): TierItem => ({
191
+ id: `state-${role}`,
192
+ cssVar: `--palette-state-${role}`,
193
+ label: role,
194
+ default: ramps.state[role],
195
+ type: { kind: "color", format: "oklch" },
196
+ })),
169
197
  };
198
+
199
+ return [baseTier, accentTier, stateTier];
170
200
  }
171
201
 
172
- function buildSemanticTier(): TierConfig {
173
- const items: TierItem[] = [];
174
- for (const [key, cssVar] of Object.entries(SEMANTIC_CSS_NAMES)) {
175
- const idx = SEMANTIC_DEFAULTS[key];
176
- if (idx === undefined) continue;
177
- items.push({
178
- id: key,
179
- cssVar,
180
- label: key,
181
- default: `p${idx}`,
182
- type: { kind: "color" },
183
- });
184
- }
202
+ const PALETTE_TAB: TabConfig = {
203
+ id: "palette",
204
+ label: "Palette",
205
+ tiers: buildRampTiers(),
206
+ // No colorExtras: a tab with multiple kind:'color' tiers MUST omit it so
207
+ // resolveColorClusterFromTab is not invoked and zdtp renders the ramps with
208
+ // its native curve editor (zdtp palette-tab contract).
209
+ };
210
+
211
+ // ---------------------------------------------------------------------------
212
+ // Color tab mode-scoped semantic tier (4 base roles + 23 --zd-* roles) as
213
+ // grouped ramp dropdowns referencing the Palette tab.
214
+ // ---------------------------------------------------------------------------
215
+
216
+ type PanelMode = "light" | "dark";
217
+
218
+ /**
219
+ * Resolve the `ColorScheme` whose `map` seeds the semantic tier for `mode`.
220
+ * With a light/dark pair configured, picks `colorMode.{light,dark}Scheme`; on
221
+ * the single-scheme path (`settings.colorMode === false`) there is no pair, so
222
+ * the active `settings.colorScheme` is used for both modes (no toggle wiring).
223
+ */
224
+ function schemeForMode(mode: PanelMode): ColorScheme {
225
+ const cm = settings.colorMode;
226
+ if (!cm) return getActiveScheme();
227
+ const name = mode === "dark" ? cm.darkScheme : cm.lightScheme;
228
+ return colorSchemes[name] ?? getActiveScheme();
229
+ }
230
+
231
+ /**
232
+ * Semantic tier — 4 base roles + 23 `--zd-*` roles, each a grouped ramp
233
+ * dropdown. `referencesRamps` names the Palette tab's ramp tiers this tier's
234
+ * `{ref}` mappings resolve against (cross-tab, resolved at mount by
235
+ * `resolveColorClusterFromTab`); `semantic: true` marks it so zdtp never
236
+ * mistakes it for the palette tier. Items come from `buildSemanticTierItems`:
237
+ * every `default` is an encoded `tierId:itemId` ramp reference, so a scheme
238
+ * with no override round-trips to the exact ramp stop (no snapping to a
239
+ * resolved color). Seeded from `schemeForMode(mode)` — this is the only
240
+ * mode-varying tier.
241
+ */
242
+ function buildSemanticTier(mode: PanelMode): TierConfig {
185
243
  return {
186
244
  id: "semantic",
187
245
  label: "Semantic",
188
- items,
189
- referencesTier: PALETTE_TIER_ID,
246
+ semantic: true,
247
+ referencesRamps: [
248
+ { tab: "palette", tier: "base" },
249
+ { tab: "palette", tier: "accent" },
250
+ { tab: "palette", tier: "state" },
251
+ ],
252
+ items: buildSemanticTierItems(schemeForMode(mode)),
190
253
  };
191
254
  }
192
255
 
193
- const COLOR_EXTRAS: ColorClusterExtras = {
194
- // Customize these values to match your project name to avoid localStorage
195
- // collisions when multiple zudo-doc projects run in the same browser.
196
- id: "my-doc",
197
- label: "My Doc",
198
- baseRoles: {
199
- background: "--zd-bg",
200
- foreground: "--zd-fg",
201
- cursor: "--zd-cursor",
202
- selectionBg: "--zd-sel-bg",
203
- selectionFg: "--zd-sel-fg",
204
- },
205
- baseDefaults: BASE_DEFAULTS,
206
- defaultShikiTheme: DEFAULT_SHIKI_THEME,
207
- // toZdtpColorSchemes fills the fallback only for schemes without their own
208
- // shikiTheme, so this is a type-checked assignment rather than an unsafe cast.
209
- colorSchemes: toZdtpColorSchemes(colorSchemes),
210
- panelSettings: {
211
- colorScheme: settings.colorScheme,
212
- // colorMode: strip off respectPrefersColorScheme (not in zdtp's shape).
213
- colorMode: settings.colorMode
214
- ? {
215
- defaultMode: settings.colorMode.defaultMode,
216
- lightScheme: settings.colorMode.lightScheme,
217
- darkScheme: settings.colorMode.darkScheme,
218
- }
219
- : false,
220
- },
221
- };
256
+ /**
257
+ * Color cluster extras. Scheme-less (`colorSchemes: {}`) with no base-role
258
+ * editors (`baseRoles`/`baseDefaults` empty) the Palette tab owns the ramps
259
+ * and the semantic tier owns the roles.
260
+ *
261
+ * `panelSettings.colorMode` is an OBJECT (not `false`) with `defaultMode = mode`.
262
+ * On this scheme-less cluster its only live effect is `getClusterDefaultMode()`,
263
+ * which drives the per-mode literal collapse/preview side — pinning it to the
264
+ * ACTIVE mode keeps that side following the live toggle (a bare `false` would
265
+ * pin it to `light` and mis-collapse per-mode literals for a dark-mode user).
266
+ * `colorScheme`/`lightScheme`/`darkScheme` only need to be non-empty strings
267
+ * (the validator requires that even with `colorSchemes: {}`; the names are not
268
+ * checked against the empty registry).
269
+ */
270
+ function buildColorExtras(mode: PanelMode): ColorClusterExtras {
271
+ const cm = settings.colorMode;
272
+ const lightScheme = cm ? cm.lightScheme : settings.colorScheme;
273
+ const darkScheme = cm ? cm.darkScheme : settings.colorScheme;
274
+ return {
275
+ // Customize id/label to match your project name to avoid localStorage
276
+ // collisions when multiple zudo-doc-based projects run in the same browser.
277
+ id: "my-doc",
278
+ label: "My Doc",
279
+ baseRoles: {},
280
+ baseDefaults: {},
281
+ defaultShikiTheme: DEFAULT_SHIKI_THEME,
282
+ colorSchemes: {},
283
+ panelSettings: {
284
+ colorScheme: settings.colorScheme,
285
+ colorMode: { defaultMode: mode, lightScheme, darkScheme },
286
+ },
287
+ };
288
+ }
222
289
 
223
- const COLOR_TAB: TabConfig = {
224
- id: "color",
225
- label: "Color",
226
- tiers: [buildPaletteTier(), buildSemanticTier()],
227
- colorExtras: COLOR_EXTRAS,
228
- };
290
+ function buildColorTab(mode: PanelMode): TabConfig {
291
+ return {
292
+ id: "color",
293
+ label: "Color",
294
+ tiers: [buildSemanticTier(mode)],
295
+ colorExtras: buildColorExtras(mode),
296
+ };
297
+ }
229
298
 
230
299
  // ---------------------------------------------------------------------------
231
- // Font tab
300
+ // Font tab — five tiers grouped by the manifest's `group` field.
232
301
  // ---------------------------------------------------------------------------
233
302
 
234
303
  const FONT_SCALE_TIER_ID = "font-scale";
235
304
 
305
+ /**
306
+ * Tier 2 semantic role → Tier 1 abstract scale item id. Mirrors the `var(--…)`
307
+ * wiring in `global.css` (`--text-body: var(--text-scale-md)` etc.). The role
308
+ * tier is a *reference* tier: each item's stored value is the id of a
309
+ * `font-scale` item, exactly like the Color tab's semantic→palette tier. zdtp
310
+ * renders these as dropdowns and emits `var(--text-scale-*)`, so editing a
311
+ * scale step propagates to every role live.
312
+ */
313
+ const FONT_ROLE_TO_SCALE: Readonly<Record<string, string>> = {
314
+ "text-micro": "text-scale-2xs",
315
+ "text-caption": "text-scale-xs",
316
+ "text-small": "text-scale-sm",
317
+ "text-body": "text-scale-md",
318
+ "text-title": "text-scale-lg",
319
+ "text-heading": "text-scale-xl",
320
+ "text-display": "text-scale-2xl",
321
+ };
322
+
323
+ /**
324
+ * Build the semantic font-size tier as a reference tier pointing at the
325
+ * `font-scale` tier. Defaults are overridden to the referenced scale id (the
326
+ * manifest still records resolved rem values for serde / the flat-manifest
327
+ * generator template, so the override happens here rather than in the
328
+ * manifest to keep both consumers correct).
329
+ */
330
+ function buildFontRoleTier(): TierConfig {
331
+ const base = tierFromGroup(FONT_TOKENS, "font-size", "Font size");
332
+ return {
333
+ ...base,
334
+ items: base.items.map((item) => {
335
+ const scaleId = FONT_ROLE_TO_SCALE[item.id];
336
+ return scaleId ? { ...item, default: scaleId } : item;
337
+ }),
338
+ referencesTier: FONT_SCALE_TIER_ID,
339
+ };
340
+ }
341
+
236
342
  const FONT_TAB: TabConfig = {
237
343
  id: "font",
238
344
  label: "Font",
239
345
  tiers: [
240
346
  tierFromGroup(FONT_TOKENS, FONT_SCALE_TIER_ID, "Scale"),
241
- tierFromGroup(FONT_TOKENS, "font-size", "Font size"),
347
+ buildFontRoleTier(),
242
348
  tierFromGroup(FONT_TOKENS, "line-height", "Line height"),
243
349
  tierFromGroup(FONT_TOKENS, "font-weight", "Font weight"),
244
350
  tierFromGroup(FONT_TOKENS, "font-family", "Font family"),
@@ -246,7 +352,7 @@ const FONT_TAB: TabConfig = {
246
352
  };
247
353
 
248
354
  // ---------------------------------------------------------------------------
249
- // Spacing tab
355
+ // Spacing tab — four tiers grouped by the manifest's `group` field.
250
356
  // ---------------------------------------------------------------------------
251
357
 
252
358
  const SPACING_TAB: TabConfig = {
@@ -261,7 +367,7 @@ const SPACING_TAB: TabConfig = {
261
367
  };
262
368
 
263
369
  // ---------------------------------------------------------------------------
264
- // Size tab
370
+ // Size tab — two tiers grouped by the manifest's `group` field.
265
371
  // ---------------------------------------------------------------------------
266
372
 
267
373
  const SIZE_TAB: TabConfig = {
@@ -273,16 +379,57 @@ const SIZE_TAB: TabConfig = {
273
379
  ],
274
380
  };
275
381
 
276
- export const designTokenPanelConfig: PanelConfig = {
277
- // Customize these values to match your project name to avoid localStorage
278
- // collisions when multiple zudo-doc projects run in the same browser.
279
- storagePrefix: "my-doc-tweak",
280
- consoleNamespace: "myDoc",
281
- modalClassPrefix: "my-doc-design-token-panel-modal",
282
- // Must match DESIGN_TOKEN_SCHEMA in @takazudo/zudo-doc/theme so that
283
- // exported JSON files remain importable across panel versions.
284
- schemaId: DESIGN_TOKEN_SCHEMA,
285
- exportFilenameBase: "my-doc-design-tokens",
286
- tabs: [COLOR_TAB, FONT_TAB, SPACING_TAB, SIZE_TAB],
287
- colorPresets: {},
288
- };
382
+ /**
383
+ * Detect the initial color-scheme mode for the first `configurePanel` call. In
384
+ * the browser, read `<html data-theme>` (set pre-paint by the
385
+ * ColorSchemeProvider bootstrap); otherwise fall back to
386
+ * `settings.colorMode.defaultMode` (or `light` on the single-scheme path).
387
+ * SSR-safe: guards `document`.
388
+ */
389
+ function detectInitialMode(): PanelMode {
390
+ if (typeof document !== "undefined") {
391
+ const attr = document.documentElement.getAttribute("data-theme");
392
+ if (attr === "light" || attr === "dark") return attr;
393
+ }
394
+ const cm = settings.colorMode;
395
+ return cm ? cm.defaultMode : "light";
396
+ }
397
+
398
+ /**
399
+ * Build the full PanelConfig for a given color-scheme `mode`. Only the Color
400
+ * tab's semantic tier and `panelSettings.colorMode.defaultMode` vary by mode;
401
+ * the Palette/Font/Spacing/Size tabs are mode-independent. The bootstrap calls
402
+ * this per mode on every `color-scheme-changed` toggle (destroy + reconfigure).
403
+ */
404
+ export function buildDesignTokenPanelConfig(mode: PanelMode): PanelConfig {
405
+ return {
406
+ // Customize these values to match your project name to avoid localStorage
407
+ // collisions when multiple zudo-doc-based projects run in the same browser.
408
+ storagePrefix: "my-doc-tweak",
409
+ consoleNamespace: "myDoc",
410
+ modalClassPrefix: "my-doc-design-token-panel-modal",
411
+ // DISPLAY-ONLY in zdtp 0.4.5: the panel's export hard-codes
412
+ // `zudo-design-tokens/v2` and auto-upgrades to `.../v3` when object leaves
413
+ // ({ref}/{literal}/per-mode) are present — which the semantic tier's ramp
414
+ // refs always are, so real exports carry v3. `schemaId` does NOT gate
415
+ // import; it only labels the Import-modal hint. zdtp DOES export its own
416
+ // `SCHEMA_V1`/`SCHEMA_V2`/`SCHEMA_V3` constants (#498/#505), but those are
417
+ // zdtp's fixed internal schema strings, unrelated to this field. Set to v3
418
+ // (a literal, not one of those constants) so the hint matches what exports
419
+ // actually carry.
420
+ schemaId: "zudo-design-tokens/v3",
421
+ exportFilenameBase: "my-doc-design-tokens",
422
+ tabs: [PALETTE_TAB, buildColorTab(mode), FONT_TAB, SPACING_TAB, SIZE_TAB],
423
+ };
424
+ }
425
+
426
+ /**
427
+ * Back-compat / initial-call export: the config for the mode detected at module
428
+ * load. Pass the `buildDesignTokenPanelConfig` BUILDER (not this plain object)
429
+ * to the bootstrap for live mode-scoped rebuilds on light/dark toggle — see
430
+ * `src/lib/design-token-panel-bootstrap.ts`. This plain-config export remains
431
+ * for callers that only need a static config.
432
+ */
433
+ export const designTokenPanelConfig: PanelConfig = buildDesignTokenPanelConfig(
434
+ detectInitialMode(),
435
+ );
@@ -5,9 +5,16 @@
5
5
  * settings.designTokenPanel is truthy. The dynamic import is gated there so
6
6
  * this module is only bundled when the feature is enabled.
7
7
  *
8
- * The wiring MECHANISM (configurePanel + setLifecycleAdapter) now lives in the
9
- * package at `@takazudo/zudo-doc/design-token-panel-bootstrap`. This file
10
- * passes the project's PanelConfig DATA to that mechanism.
8
+ * The wiring MECHANISM (configurePanel + setLifecycleAdapter + the mode-scoped
9
+ * reconfigure) lives in the package at
10
+ * `@takazudo/zudo-doc/design-token-panel-bootstrap`. This file passes the
11
+ * project's PanelConfig DATA to that mechanism.
12
+ *
13
+ * We pass the `buildDesignTokenPanelConfig` BUILDER (not the plain
14
+ * `designTokenPanelConfig` object) so the bootstrap rebuilds the panel per
15
+ * light/dark mode on every `color-scheme-changed` toggle — keeping the Color
16
+ * tab's semantic defaults mode-faithful. A plain-config caller also works (see
17
+ * `bootstrapDesignTokenPanel`'s JSDoc) but gets no toggle listener.
11
18
  *
12
19
  * S9a package-first migration — zudolab/zudo-doc#2333.
13
20
  *
@@ -18,6 +25,6 @@
18
25
  */
19
26
 
20
27
  import { bootstrapDesignTokenPanel } from "@takazudo/zudo-doc/design-token-panel-bootstrap";
21
- import { designTokenPanelConfig } from "@/config/design-token-panel-config";
28
+ import { buildDesignTokenPanelConfig } from "@/config/design-token-panel-config";
22
29
 
23
- bootstrapDesignTokenPanel(designTokenPanelConfig);
30
+ bootstrapDesignTokenPanel(buildDesignTokenPanelConfig);