@takazudo/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.
Files changed (43) hide show
  1. package/CHANGELOG.md +1038 -0
  2. package/README.md +4 -0
  3. package/dist/chrome/derive.d.ts +4 -1
  4. package/dist/chrome/derive.js +30 -25
  5. package/dist/color-scheme-utils.d.ts +153 -102
  6. package/dist/color-scheme-utils.js +168 -97
  7. package/dist/content.css +5 -5
  8. package/dist/design-token-panel-bootstrap.d.ts +37 -16
  9. package/dist/design-token-panel-bootstrap.js +47 -19
  10. package/dist/doc-page-renderer/index.d.ts +1 -0
  11. package/dist/doc-page-renderer/index.js +2 -0
  12. package/dist/doc-page-shell/index.d.ts +2 -0
  13. package/dist/doc-page-shell/index.js +2 -0
  14. package/dist/doclayout/doc-layout.d.ts +9 -0
  15. package/dist/doclayout/doc-layout.js +2 -0
  16. package/dist/features.css +19 -0
  17. package/dist/home-page/index.d.ts +8 -0
  18. package/dist/home-page/index.js +3 -1
  19. package/dist/integrations/changelog/emit.d.ts +2 -0
  20. package/dist/integrations/changelog/emit.js +24 -0
  21. package/dist/integrations/changelog/generate.d.ts +2 -0
  22. package/dist/integrations/changelog/generate.js +24 -0
  23. package/dist/integrations/changelog/index.d.ts +5 -0
  24. package/dist/integrations/changelog/index.js +11 -0
  25. package/dist/integrations/changelog/load.d.ts +3 -0
  26. package/dist/integrations/changelog/load.js +79 -0
  27. package/dist/integrations/changelog/sanitize.d.ts +10 -0
  28. package/dist/integrations/changelog/sanitize.js +24 -0
  29. package/dist/integrations/changelog/types.d.ts +31 -0
  30. package/dist/integrations/changelog/types.js +0 -0
  31. package/dist/plugins/changelog.d.ts +3 -0
  32. package/dist/plugins/changelog.js +17 -0
  33. package/dist/preset.d.ts +7 -0
  34. package/dist/preset.js +8 -0
  35. package/dist/safelist.css +1 -1
  36. package/dist/settings.d.ts +11 -0
  37. package/dist/theme/design-token-serde.d.ts +74 -33
  38. package/dist/theme/design-token-serde.js +187 -94
  39. package/dist/theme/design-token-types.d.ts +6 -10
  40. package/dist/theme/index.d.ts +1 -1
  41. package/dist/theme-toggle/color-scheme-sync.d.ts +22 -12
  42. package/eject/theme-toggle/color-scheme-sync.ts +22 -12
  43. package/package.json +18 -9
@@ -1,7 +1,16 @@
1
1
  import {
2
2
  emptyOverrides
3
3
  } from "./design-token-types.js";
4
- const DESIGN_TOKEN_SCHEMA = "zudo-doc-design-tokens/v1";
4
+ import {
5
+ SEMANTIC_KEYS,
6
+ SEMANTIC_RAMP_DEFAULTS,
7
+ STATE_ROLES
8
+ } from "../color-scheme-utils.js";
9
+ const DESIGN_TOKEN_SCHEMA = "zudo-doc-design-tokens/v3";
10
+ const LEGACY_SCHEMA_V1 = "zudo-doc-design-tokens/v1";
11
+ const LEGACY_SCHEMA_V2 = "zudo-doc-design-tokens/v2";
12
+ const BASE_RAMP_LENGTH = 5;
13
+ const ACCENT_RAMP_LENGTH = 3;
5
14
  class DesignTokenSchemaError extends Error {
6
15
  reason;
7
16
  actualSchema;
@@ -33,47 +42,12 @@ function serializeColor(color, opts) {
33
42
  const full = opts.includeDefaults === true;
34
43
  const out = {};
35
44
  let changed = false;
36
- const paletteChanged = full || !baseline || baseline.palette.length !== color.palette.length || color.palette.some((c, i) => c !== baseline.palette[i]);
37
- if (paletteChanged) {
38
- out.palette = [...color.palette];
45
+ if (full || !baseline || !deepEqual(color.ramps, baseline.ramps)) {
46
+ out.ramps = cloneRamps(color.ramps);
39
47
  changed = true;
40
48
  }
41
- const base = {};
42
- let baseChanged = false;
43
- const baseEntries = [
44
- ["bg", color.background, baseline?.background],
45
- ["fg", color.foreground, baseline?.foreground],
46
- ["cursor", color.cursor, baseline?.cursor],
47
- ["sel-bg", color.selectionBg, baseline?.selectionBg],
48
- ["sel-fg", color.selectionFg, baseline?.selectionFg]
49
- ];
50
- for (const [key, value, baselineValue] of baseEntries) {
51
- if (full || baseline === void 0 || value !== baselineValue) {
52
- base[key] = value;
53
- baseChanged = true;
54
- }
55
- }
56
- if (baseChanged) {
57
- out.base = base;
58
- changed = true;
59
- }
60
- const semantic = {};
61
- let semanticChanged = false;
62
- const semKeys = /* @__PURE__ */ new Set([
63
- ...Object.keys(color.semanticMappings),
64
- ...baseline ? Object.keys(baseline.semanticMappings) : []
65
- ]);
66
- for (const key of semKeys) {
67
- const cur = color.semanticMappings[key];
68
- if (cur === void 0) continue;
69
- const base2 = baseline?.semanticMappings[key];
70
- if (full || base2 === void 0 || cur !== base2) {
71
- semantic[key] = cur;
72
- semanticChanged = true;
73
- }
74
- }
75
- if (semanticChanged) {
76
- out.semantic = semantic;
49
+ if (full || !baseline || !deepEqual(color.map, baseline.map)) {
50
+ out.map = cloneMap(color.map);
77
51
  changed = true;
78
52
  }
79
53
  return changed ? out : void 0;
@@ -116,7 +90,9 @@ function deserialize(input, opts) {
116
90
  `Missing "$schema" key. Expected "${DESIGN_TOKEN_SCHEMA}".`
117
91
  );
118
92
  }
119
- if (schema !== DESIGN_TOKEN_SCHEMA) {
93
+ const legacyV1 = schema === LEGACY_SCHEMA_V1;
94
+ const legacyV2 = schema === LEGACY_SCHEMA_V2;
95
+ if (schema !== DESIGN_TOKEN_SCHEMA && !legacyV1 && !legacyV2) {
120
96
  throw new DesignTokenSchemaError(
121
97
  "schema-mismatch",
122
98
  `Unsupported "$schema" value: ${JSON.stringify(schema)}. Expected "${DESIGN_TOKEN_SCHEMA}".`,
@@ -126,7 +102,7 @@ function deserialize(input, opts) {
126
102
  const warnings = [];
127
103
  const unknownTokens = [];
128
104
  const baseline = opts.colorDefaults ?? neutralColorDefaults();
129
- const color = deserializeColor(obj.color, baseline, warnings);
105
+ const color = deserializeColor(obj.color, baseline, warnings, legacyV1, legacyV2);
130
106
  const spacing = deserializeOverrides(
131
107
  obj.spacing,
132
108
  opts.manifest.spacing,
@@ -154,55 +130,114 @@ function deserialize(input, opts) {
154
130
  warnings
155
131
  };
156
132
  }
157
- function deserializeColor(raw, baseline, warnings) {
133
+ function isLegacyColorPayload(raw) {
134
+ if (!raw || typeof raw !== "object") return false;
135
+ const c = raw;
136
+ return Array.isArray(c.palette) || c.base !== void 0;
137
+ }
138
+ function deserializeColor(raw, baseline, warnings, legacyV1, legacyV2) {
139
+ if (legacyV1 || isLegacyColorPayload(raw)) {
140
+ const msg = "Legacy v1 design-token color state detected; color was reset to the default scheme (the old 16-slot palette has no faithful ramp mapping).";
141
+ warnings.push(msg);
142
+ console.warn(`[zudo-doc] ${msg}`);
143
+ return cloneScheme(baseline);
144
+ }
145
+ if (legacyV2) {
146
+ const msg = "Legacy v2 design-token color state detected (pre-5/3-minimize ramps); color was reset to the default scheme.";
147
+ warnings.push(msg);
148
+ console.warn(`[zudo-doc] ${msg}`);
149
+ return cloneScheme(baseline);
150
+ }
158
151
  if (!raw || typeof raw !== "object") {
159
- return { ...baseline, palette: [...baseline.palette], semanticMappings: { ...baseline.semanticMappings } };
152
+ return cloneScheme(baseline);
160
153
  }
161
154
  const c = raw;
162
- let palette = [...baseline.palette];
163
- if (Array.isArray(c.palette)) {
164
- const parsed = c.palette.filter((v) => typeof v === "string");
165
- if (parsed.length === 16 && parsed.length === c.palette.length) {
166
- palette = parsed;
167
- } else if (c.palette.length > 0) {
168
- const detail = parsed.length < c.palette.length ? `${c.palette.length - parsed.length} non-string entries dropped, leaving ${parsed.length}` : `${c.palette.length} entries`;
169
- warnings.push(
170
- `color.palette: expected 16 string entries; got ${detail}. Palette ignored.`
171
- );
172
- }
155
+ const ramps = parseRamps(c.ramps, baseline.ramps, warnings);
156
+ const map = parseMap(c.map, baseline.map, warnings);
157
+ return { ramps, map };
158
+ }
159
+ function parseRamps(raw, baseline, warnings) {
160
+ if (raw === void 0) return cloneRamps(baseline);
161
+ if (!raw || typeof raw !== "object") {
162
+ warnings.push("color.ramps is not an object; kept baseline ramps.");
163
+ return cloneRamps(baseline);
173
164
  }
174
- const base = c.base && typeof c.base === "object" ? c.base : {};
175
- const background = numOr(base.bg, baseline.background);
176
- const foreground = numOr(base.fg, baseline.foreground);
177
- const cursor = numOr(base.cursor, baseline.cursor);
178
- const selectionBg = numOr(base["sel-bg"], baseline.selectionBg);
179
- const selectionFg = numOr(base["sel-fg"], baseline.selectionFg);
180
- const semanticMappings = {
181
- ...baseline.semanticMappings
182
- };
183
- if (c.semantic && typeof c.semantic === "object") {
184
- for (const [key, val] of Object.entries(c.semantic)) {
185
- if (typeof val === "number") {
186
- semanticMappings[key] = val;
187
- } else if (val === "bg" || val === "fg") {
188
- semanticMappings[key] = val;
189
- } else {
190
- warnings.push(
191
- `color.semantic.${key} has unsupported value ${JSON.stringify(val)}; kept baseline.`
192
- );
165
+ const r = raw;
166
+ const base = parseOklchArray(r.base, BASE_RAMP_LENGTH, "color.ramps.base", warnings) ?? [...baseline.base];
167
+ const accent = parseOklchArray(r.accent, ACCENT_RAMP_LENGTH, "color.ramps.accent", warnings) ?? [...baseline.accent];
168
+ const state = parseState(r.state, baseline.state, warnings);
169
+ return { base, accent, state };
170
+ }
171
+ function parseOklchArray(raw, expectedLength, label, warnings) {
172
+ if (!Array.isArray(raw)) {
173
+ warnings.push(`${label}: expected an array of ${expectedLength} strings; kept baseline.`);
174
+ return null;
175
+ }
176
+ const strings = raw.filter((v) => typeof v === "string" && v.length > 0);
177
+ if (strings.length !== expectedLength || strings.length !== raw.length) {
178
+ warnings.push(
179
+ `${label}: expected ${expectedLength} non-empty string entries; got ${raw.length} (${strings.length} valid). Kept baseline.`
180
+ );
181
+ return null;
182
+ }
183
+ return strings;
184
+ }
185
+ function parseState(raw, baseline, warnings) {
186
+ const src = raw && typeof raw === "object" ? raw : {};
187
+ const out = {};
188
+ for (const role of STATE_ROLES) {
189
+ const v = src[role];
190
+ if (typeof v === "string" && v.length > 0) {
191
+ out[role] = v;
192
+ } else {
193
+ if (v !== void 0) {
194
+ warnings.push(`color.ramps.state.${role} is not a non-empty string; kept baseline.`);
193
195
  }
196
+ out[role] = baseline[role];
194
197
  }
195
198
  }
199
+ return out;
200
+ }
201
+ function parseMap(raw, baseline, warnings) {
202
+ if (raw === void 0) return cloneMap(baseline);
203
+ if (!raw || typeof raw !== "object") {
204
+ warnings.push("color.map is not an object; kept baseline map.");
205
+ return cloneMap(baseline);
206
+ }
207
+ const m = raw;
208
+ const semRaw = m.semantic && typeof m.semantic === "object" ? m.semantic : {};
209
+ const semantic = {};
210
+ for (const key of SEMANTIC_KEYS) {
211
+ semantic[key] = parseRef(semRaw[key], baseline.semantic[key], `color.map.semantic.${key}`, warnings);
212
+ }
196
213
  return {
197
- palette,
198
- background,
199
- foreground,
200
- cursor,
201
- selectionBg,
202
- selectionFg,
203
- semanticMappings
214
+ bg: parseRef(m.bg, baseline.bg, "color.map.bg", warnings),
215
+ fg: parseRef(m.fg, baseline.fg, "color.map.fg", warnings),
216
+ selectionBg: parseRef(m.selectionBg, baseline.selectionBg, "color.map.selectionBg", warnings),
217
+ selectionFg: parseRef(m.selectionFg, baseline.selectionFg, "color.map.selectionFg", warnings),
218
+ semantic
204
219
  };
205
220
  }
221
+ function parseRef(raw, fallback, label, warnings) {
222
+ if (raw === void 0) return cloneRef(fallback);
223
+ if (isValidRampRef(raw)) return cloneRef(raw);
224
+ warnings.push(`${label} is not a valid RampRef (${JSON.stringify(raw)}); kept baseline.`);
225
+ return cloneRef(fallback);
226
+ }
227
+ function isValidRampRef(v) {
228
+ if (typeof v === "string") return v.length > 0;
229
+ if (!v || typeof v !== "object") return false;
230
+ const o = v;
231
+ if ("base" in o) return isRampIndex(o.base);
232
+ if ("accent" in o) return isRampIndex(o.accent);
233
+ if ("state" in o) {
234
+ return typeof o.state === "string" && STATE_ROLES.includes(o.state);
235
+ }
236
+ return false;
237
+ }
238
+ function isRampIndex(v) {
239
+ return typeof v === "number" && Number.isInteger(v) && v >= 0;
240
+ }
206
241
  function deserializeOverrides(raw, manifest, label, unknownTokens, warnings) {
207
242
  if (!raw || typeof raw !== "object") return emptyOverrides();
208
243
  const byVar = /* @__PURE__ */ new Map();
@@ -227,22 +262,80 @@ function deserializeOverrides(raw, manifest, label, unknownTokens, warnings) {
227
262
  }
228
263
  return out;
229
264
  }
230
- function numOr(v, fallback) {
231
- return typeof v === "number" && Number.isFinite(v) ? v : fallback;
265
+ function cloneRef(ref) {
266
+ return typeof ref === "string" ? ref : { ...ref };
267
+ }
268
+ function cloneRamps(ramps) {
269
+ return {
270
+ base: [...ramps.base],
271
+ accent: [...ramps.accent],
272
+ state: { ...ramps.state }
273
+ };
274
+ }
275
+ function cloneMap(map) {
276
+ const semantic = {};
277
+ for (const key of SEMANTIC_KEYS) {
278
+ semantic[key] = cloneRef(map.semantic[key]);
279
+ }
280
+ return {
281
+ bg: cloneRef(map.bg),
282
+ fg: cloneRef(map.fg),
283
+ selectionBg: cloneRef(map.selectionBg),
284
+ selectionFg: cloneRef(map.selectionFg),
285
+ semantic
286
+ };
287
+ }
288
+ function cloneScheme(scheme) {
289
+ return { ramps: cloneRamps(scheme.ramps), map: cloneMap(scheme.map) };
290
+ }
291
+ function deepEqual(a, b) {
292
+ if (a === b) return true;
293
+ if (typeof a !== typeof b) return false;
294
+ if (Array.isArray(a) || Array.isArray(b)) {
295
+ if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;
296
+ return a.every((v, i) => deepEqual(v, b[i]));
297
+ }
298
+ if (a && b && typeof a === "object" && typeof b === "object") {
299
+ const ao = a;
300
+ const bo = b;
301
+ const aKeys = Object.keys(ao);
302
+ const bKeys = Object.keys(bo);
303
+ if (aKeys.length !== bKeys.length) return false;
304
+ return aKeys.every((k) => Object.prototype.hasOwnProperty.call(bo, k) && deepEqual(ao[k], bo[k]));
305
+ }
306
+ return false;
232
307
  }
233
308
  function neutralColorDefaults() {
234
- const palette = Array.from(
235
- { length: 16 },
236
- (_, i) => i === 0 ? "#000000" : i === 15 ? "#ffffff" : "#808080"
237
- );
309
+ const base = [
310
+ "oklch(0.965 0 0)",
311
+ "oklch(0.705 0 0)",
312
+ "oklch(0.480 0 0)",
313
+ "oklch(0.300 0 0)",
314
+ "oklch(0.185 0 0)"
315
+ ];
316
+ const accent = [
317
+ "oklch(0.755 0 0)",
318
+ "oklch(0.700 0 0)",
319
+ "oklch(0.470 0 0)"
320
+ ];
238
321
  return {
239
- palette,
240
- background: 0,
241
- foreground: 15,
242
- cursor: 6,
243
- selectionBg: 0,
244
- selectionFg: 15,
245
- semanticMappings: {}
322
+ ramps: {
323
+ base,
324
+ accent,
325
+ state: {
326
+ danger: "oklch(0.640 0.170 25)",
327
+ success: "oklch(0.680 0.145 145)",
328
+ warning: "oklch(0.760 0.135 82)",
329
+ info: "oklch(0.680 0.130 245)"
330
+ }
331
+ },
332
+ map: {
333
+ bg: { base: 4 },
334
+ fg: { base: 0 },
335
+ selectionBg: { base: 2 },
336
+ selectionFg: { base: 0 },
337
+ semantic: { ...SEMANTIC_RAMP_DEFAULTS }
338
+ }
246
339
  };
247
340
  }
248
341
  export {
@@ -1,15 +1,11 @@
1
- export interface ColorTweakState {
2
- palette: string[];
3
- background: number;
4
- foreground: number;
5
- cursor: number;
6
- selectionBg: number;
7
- selectionFg: number;
8
- semanticMappings: Record<string, number | "bg" | "fg">;
9
- }
1
+ import type { ColorScheme } from "../color-scheme-utils.js";
2
+ /** The per-scheme color state the design-token panel edits — a ramp-native
3
+ * `ColorScheme`. Retained as a named alias so call sites reading
4
+ * `ColorTweakState` keep compiling after the ramp restructure. */
5
+ export type ColorTweakState = ColorScheme;
10
6
  export type TokenOverrides = Record<string, string>;
11
7
  export interface TweakState {
12
- color: ColorTweakState;
8
+ color: ColorScheme;
13
9
  spacing: TokenOverrides;
14
10
  font: TokenOverrides;
15
11
  size: TokenOverrides;
@@ -2,6 +2,6 @@ export { default as ThemeToggle } from "./theme-toggle.js";
2
2
  export { default as ColorSchemeProvider } from "./color-scheme-provider.js";
3
3
  export type { ColorSchemeProviderProps, ColorSchemeProviderColorMode, } from "./color-scheme-provider.js";
4
4
  export { default as ColorTweakExportModal } from "./color-tweak-export-modal.js";
5
- export { DESIGN_TOKEN_SCHEMA, DesignTokenSchemaError, deserialize, serialize, type DesignTokenJson, type DesignTokenJsonColor, type DesignTokenJsonColorBase, type DesignTokenJsonOverrides, type DesignTokenManifest, type DeserializeOptions, type DeserializeResult, type SerializeOptions, } from "./design-token-serde.js";
5
+ export { DESIGN_TOKEN_SCHEMA, DesignTokenSchemaError, deserialize, serialize, type DesignTokenJson, type DesignTokenJsonColor, type DesignTokenJsonOverrides, type DesignTokenManifest, type DeserializeOptions, type DeserializeResult, type SerializeOptions, } from "./design-token-serde.js";
6
6
  export { emptyOverrides, type ColorTweakState, type TokenOverrides, type TweakState, } from "./design-token-types.js";
7
7
  export { BRIDGE_SOURCE, isBridgeMessage, installIframeReceiver, onIframeReady, sendApplyCssVars, sendClearCssVars, type BridgeMessage, type ApplyCssVarsMessage, type ClearCssVarsMessage, type ReadyMessage, type ErrorMessage, type CssVarPair, } from "./iframe-bridge.js";
@@ -14,19 +14,29 @@ export declare function readColorSchemeFromDom(defaultMode: ColorSchemeMode): Co
14
14
  *
15
15
  * Tweak-state reconciliation is intentionally NOT done here (#2037). The zdtp
16
16
  * panel owns its own storage lifecycle: it persists the unified tweak envelope
17
- * under `zudo-doc-tweak-state-v3` (auto-migrating the legacy
18
- * `zudo-doc-tweak-state-v2` / `zudo-doc-tweak-state` keys into it), and its own
19
- * `color-scheme-changed` listener clears applied inline styles and re-seeds the
20
- * color slice from the newly active scheme. An earlier version of this function
21
- * deleted `zudo-doc-tweak-state` + `-v2` on every toggle, which (a) targeted
22
- * stale keys after zdtp moved to v3 — so it no longer did anything — and
23
- * (b) when it did fire, wiped the whole envelope including scheme-independent
24
- * spacing/typography/size tweaks, contradicting the documented carry-over
25
- * guarantee. So the host no longer touches zdtp's private storage keys.
17
+ * under `zudo-doc-tweak-state-v4` (auto-migrating the legacy
18
+ * `zudo-doc-tweak-state-v3` / `-v2` / `zudo-doc-tweak-state` (v1) keys into
19
+ * it), and its own `color-scheme-changed` listener clears applied inline
20
+ * styles and re-seeds the color slice from the newly active scheme. An
21
+ * earlier version of this function deleted `zudo-doc-tweak-state` + `-v2` on
22
+ * every toggle, which (a) targeted stale keys after zdtp moved to v3 — so it
23
+ * no longer did anything — and (b) when it did fire, wiped the whole envelope
24
+ * including scheme-independent spacing/typography/size tweaks, contradicting
25
+ * the documented carry-over guarantee. So the host no longer touches zdtp's
26
+ * private storage keys.
26
27
  *
27
- * Whether palette tweaks should instead persist per-scheme (so a light/dark
28
- * round-trip keeps them) is a zdtp design question tracked upstream at
29
- * Takazudo/zudo-design-token-panel#343. See zudo-doc#2037.
28
+ * The design-token-panel bootstrap ALSO listens for this event and, on toggle,
29
+ * destroys + reconfigures the panel with the new mode's mode-scoped semantic
30
+ * DEFAULTS (see `design-token-panel-bootstrap.ts` + the host's
31
+ * `buildDesignTokenPanelConfig`, #2610). That keeps the panel's per-mode
32
+ * defaults faithful. A *saved* color OVERRIDE is still mode-agnostic here,
33
+ * though — not because zdtp can't key it per scheme (zdtp 0.4.5 ships
34
+ * per-scheme/per-mode keyed color persistence, v4 envelope,
35
+ * Takazudo/zudo-design-token-panel#500 / #509) but because THIS host's color
36
+ * cluster is scheme-less and switches modes externally (destroy + reconfigure
37
+ * above, not zdtp's own `colorMode` field), so zdtp always resolves the same
38
+ * single scheme identity and an override repaints both modes until Reset.
39
+ * See zudo-doc#2037 / #2610.
30
40
  */
31
41
  export declare function applyColorScheme(next: ColorSchemeMode): void;
32
42
  /**
@@ -42,19 +42,29 @@ export function readColorSchemeFromDom(
42
42
  *
43
43
  * Tweak-state reconciliation is intentionally NOT done here (#2037). The zdtp
44
44
  * panel owns its own storage lifecycle: it persists the unified tweak envelope
45
- * under `zudo-doc-tweak-state-v3` (auto-migrating the legacy
46
- * `zudo-doc-tweak-state-v2` / `zudo-doc-tweak-state` keys into it), and its own
47
- * `color-scheme-changed` listener clears applied inline styles and re-seeds the
48
- * color slice from the newly active scheme. An earlier version of this function
49
- * deleted `zudo-doc-tweak-state` + `-v2` on every toggle, which (a) targeted
50
- * stale keys after zdtp moved to v3 — so it no longer did anything — and
51
- * (b) when it did fire, wiped the whole envelope including scheme-independent
52
- * spacing/typography/size tweaks, contradicting the documented carry-over
53
- * guarantee. So the host no longer touches zdtp's private storage keys.
45
+ * under `zudo-doc-tweak-state-v4` (auto-migrating the legacy
46
+ * `zudo-doc-tweak-state-v3` / `-v2` / `zudo-doc-tweak-state` (v1) keys into
47
+ * it), and its own `color-scheme-changed` listener clears applied inline
48
+ * styles and re-seeds the color slice from the newly active scheme. An
49
+ * earlier version of this function deleted `zudo-doc-tweak-state` + `-v2` on
50
+ * every toggle, which (a) targeted stale keys after zdtp moved to v3 — so it
51
+ * no longer did anything — and (b) when it did fire, wiped the whole envelope
52
+ * including scheme-independent spacing/typography/size tweaks, contradicting
53
+ * the documented carry-over guarantee. So the host no longer touches zdtp's
54
+ * private storage keys.
54
55
  *
55
- * Whether palette tweaks should instead persist per-scheme (so a light/dark
56
- * round-trip keeps them) is a zdtp design question tracked upstream at
57
- * Takazudo/zudo-design-token-panel#343. See zudo-doc#2037.
56
+ * The design-token-panel bootstrap ALSO listens for this event and, on toggle,
57
+ * destroys + reconfigures the panel with the new mode's mode-scoped semantic
58
+ * DEFAULTS (see `design-token-panel-bootstrap.ts` + the host's
59
+ * `buildDesignTokenPanelConfig`, #2610). That keeps the panel's per-mode
60
+ * defaults faithful. A *saved* color OVERRIDE is still mode-agnostic here,
61
+ * though — not because zdtp can't key it per scheme (zdtp 0.4.5 ships
62
+ * per-scheme/per-mode keyed color persistence, v4 envelope,
63
+ * Takazudo/zudo-design-token-panel#500 / #509) but because THIS host's color
64
+ * cluster is scheme-less and switches modes externally (destroy + reconfigure
65
+ * above, not zdtp's own `colorMode` field), so zdtp always resolves the same
66
+ * single scheme identity and an override repaints both modes until Reset.
67
+ * See zudo-doc#2037 / #2610.
58
68
  */
59
69
  export function applyColorScheme(next: ColorSchemeMode): void {
60
70
  document.documentElement.setAttribute("data-theme", next);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takazudo/zudo-doc",
3
- "version": "2.5.1",
3
+ "version": "3.1.0",
4
4
  "type": "module",
5
5
  "description": "zudo-doc framework primitives layer that sits on top of zfb's engine — sidebar, theme, TOC, breadcrumb, layouts, head injection, View Transitions, SSR-skip wrappers (per ADR-003).",
6
6
  "license": "MIT",
@@ -115,6 +115,10 @@
115
115
  "types": "./dist/integrations/llms-txt/index.d.ts",
116
116
  "default": "./dist/integrations/llms-txt/index.js"
117
117
  },
118
+ "./integrations/changelog": {
119
+ "types": "./dist/integrations/changelog/index.d.ts",
120
+ "default": "./dist/integrations/changelog/index.js"
121
+ },
118
122
  "./integrations/search-index": {
119
123
  "types": "./dist/integrations/search-index/index.d.ts",
120
124
  "default": "./dist/integrations/search-index/index.js"
@@ -175,6 +179,10 @@
175
179
  "types": "./dist/plugins/llms-txt.d.ts",
176
180
  "default": "./dist/plugins/llms-txt.js"
177
181
  },
182
+ "./plugins/changelog": {
183
+ "types": "./dist/plugins/changelog.d.ts",
184
+ "default": "./dist/plugins/changelog.js"
185
+ },
178
186
  "./plugins/search-index": {
179
187
  "types": "./dist/plugins/search-index.d.ts",
180
188
  "default": "./dist/plugins/search-index.js"
@@ -536,14 +544,15 @@
536
544
  "bin",
537
545
  "eject",
538
546
  "routes-src",
539
- "README.md"
547
+ "README.md",
548
+ "CHANGELOG.md"
540
549
  ],
541
550
  "peerDependencies": {
542
551
  "preact": "^10.29.1",
543
- "@takazudo/zfb": "^0.1.0-next.76",
544
- "@takazudo/zfb-runtime": "^0.1.0-next.76",
545
- "@takazudo/zudo-doc-history-server": "^2.2.1",
546
- "@takazudo/zdtp": "^0.4.2",
552
+ "@takazudo/zfb": "^0.1.0-next.77",
553
+ "@takazudo/zfb-runtime": "^0.1.0-next.77",
554
+ "@takazudo/zudo-doc-history-server": "^3.0.0",
555
+ "@takazudo/zdtp": "^0.4.5",
547
556
  "shiki": "^4.0.2",
548
557
  "zod": "^4.3.6",
549
558
  "katex": "^0.16.0",
@@ -584,9 +593,9 @@
584
593
  "typescript": "^5.0.0",
585
594
  "vitest": "^4.1.0",
586
595
  "zod": "^4.3.6",
587
- "@takazudo/zfb": "0.1.0-next.76",
588
- "@takazudo/zfb-runtime": "0.1.0-next.76",
589
- "@takazudo/zudo-doc-history-server": "2.5.1"
596
+ "@takazudo/zfb": "0.1.0-next.77",
597
+ "@takazudo/zfb-runtime": "0.1.0-next.77",
598
+ "@takazudo/zudo-doc-history-server": "3.1.0"
590
599
  },
591
600
  "scripts": {
592
601
  "build": "tsup && tsc -p tsconfig.build.json",