@takazudo/zudo-doc 5.18.1 → 5.19.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,20 @@ All notable changes to `@takazudo/zudo-doc` 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
+ ## [5.19.0] - 2026-09-07
8
+
9
+ ### Bug Fixes
10
+
11
+ - The `gen-z-index` and `gen-component-tokens` bins report a descriptive error instead of a raw Node stack trace. A missing input file now names the path and says which file it is, while `EACCES` / `EISDIR` keep their own message rather than collapsing into a misleading "not found", and a top-level handler prints the message to stderr and exits 1 for any deliberate throw. A non-`Error` throw prints its string form rather than a bare `undefined`. (83a4c6f7a, 134248eba)
12
+
13
+ ## [5.18.2] - 2026-09-06
14
+
15
+ ### Bug Fixes
16
+
17
+ - A site with `designTokenPanel: false` (including the default) now builds without the optional `@takazudo/zdtp` peer installed. `chrome/derive` statically imported the Design Token Panel bootstrap, which imported `@takazudo/zdtp/constants`, so esbuild resolved that edge while bundling — before any runtime check of the setting could make it unreachable. A consumer that honored the published `peerDependenciesMeta` `optional: true` and omitted zdtp failed with `Could not resolve "@takazudo/zdtp/constants"`, and neither marking the package external nor an `addAlias` registration could route around it. The values the bootstrap needed are now vendored in-package, with a conformance test asserting them against the real `@takazudo/zdtp/constants` so the copies cannot drift, and a build-level test that installs a consumer without zdtp and proves the panel-disabled graph no longer reaches it. The affected published range is **5.18.0–5.18.1**; 5.17.2 was the last good release. (29b52ac5b, f6e293352)
18
+ - `gen-z-index` accepts single-quoted `name`, `kind`, and `purpose` values. It previously matched only double-quoted ones, so a single-quoted entry was skipped without comment and silently left out of the generated scale. (64f5a8be4)
19
+ - `gen-z-index` now fails loudly on a `purpose` or `kind` value it cannot read, instead of continuing and emitting a scale that quietly omits the unreadable entry. (0175bb5f6)
20
+
7
21
  ## [5.18.1] - 2026-09-06
8
22
 
9
23
  ### Bug Fixes
@@ -45,6 +45,11 @@ const TOKENS_PATH = resolve(PKG_ROOT, "src/config/component-tokens.ts");
45
45
  const CONTENT_CSS_PATH = resolve(PKG_ROOT, "src/content.css");
46
46
  const FEATURES_CSS_PATH = resolve(PKG_ROOT, "src/features.css");
47
47
 
48
+ // Repo-relative label for TOKENS_PATH, matching the SURFACES table's relPath
49
+ // convention below — used only in the missing-file message so it never
50
+ // embeds this machine's absolute path.
51
+ const TOKENS_REL_PATH = "packages/zudo-doc/src/config/component-tokens.ts";
52
+
48
53
  // Default marker pair = the content-surface block. Kept under the original
49
54
  // names so buildBlock/replaceBlock default to the content block, preserving the
50
55
  // byte-identical content.css output (and the existing unit-test call sites).
@@ -259,10 +264,30 @@ export function replaceBlock(
259
264
  return css.slice(0, lineStart) + block + css.slice(lineEnd);
260
265
  }
261
266
 
267
+ /**
268
+ * Reads a package-owned file, translating a missing file into a message that
269
+ * names both which file (`label`) and its repo-relative path (`relPath`) —
270
+ * these paths are absolute constants (see TOKENS_PATH/SURFACES above), so the
271
+ * relative label is what keeps the message free of a machine-specific path.
272
+ * Only ENOENT is translated: EACCES/EISDIR etc. are real, distinct failures
273
+ * (a permissions problem or "that's a directory") that a "not found" message
274
+ * would misreport, so they propagate unchanged with Node's own message.
275
+ */
276
+ function readNamedFile(absPath, relPath, label) {
277
+ try {
278
+ return readFileSync(absPath, "utf8");
279
+ } catch (error) {
280
+ if (error.code === "ENOENT") {
281
+ throw new Error(`${label} file not found at ${relPath}`);
282
+ }
283
+ throw error;
284
+ }
285
+ }
286
+
262
287
  function main() {
263
288
  const check = process.argv.includes("--check");
264
289
 
265
- const tokensSrc = readFileSync(TOKENS_PATH, "utf8");
290
+ const tokensSrc = readNamedFile(TOKENS_PATH, TOKENS_REL_PATH, "tokens");
266
291
  const tokens = parseTokens(tokensSrc);
267
292
  const routes = routeBySurface(tokens);
268
293
 
@@ -277,7 +302,7 @@ function main() {
277
302
  `${target.surface}: ${surfaceTokens.length} token(s), ${selectorCount} selector(s)`,
278
303
  );
279
304
 
280
- const css = readFileSync(target.cssPath, "utf8");
305
+ const css = readNamedFile(target.cssPath, target.relPath, "css");
281
306
  const block = buildBlock(surfaceTokens, target.beginMarker, target.endMarker);
282
307
  const next = replaceBlock(
283
308
  css,
@@ -344,5 +369,21 @@ function isDirectInvocation() {
344
369
  }
345
370
 
346
371
  if (isDirectInvocation()) {
347
- process.exit(main());
372
+ // Turns any Error thrown by main() (the readNamedFile guard, the parser's
373
+ // loud-failure throws, or replaceBlock's missing-markers throw) into a
374
+ // single readable stderr line instead of a raw Node stack trace. This also
375
+ // hides the stack for a genuine *programming* error, not just a user-input
376
+ // one — an accepted CLI tradeoff, not an accident: the process still exits
377
+ // 1 and nothing is swallowed, but a future reader debugging an internal
378
+ // crash needs to call the exported `main()` directly (or temporarily
379
+ // remove this try/catch) to see the stack. Exit codes are unchanged:
380
+ // main()'s own return value (0 or 1) still flows through process.exit on
381
+ // the success path; only an uncaught throw is newly turned into exit(1)
382
+ // with a message.
383
+ try {
384
+ process.exit(main());
385
+ } catch (error) {
386
+ console.error(error instanceof Error ? error.message : String(error));
387
+ process.exit(1);
388
+ }
348
389
  }
@@ -213,62 +213,333 @@ export function validateTiers(tiers, tokensPath = DEFAULT_TOKENS_PATH) {
213
213
  return tiers;
214
214
  }
215
215
 
216
+ const WHITESPACE_RE = /\s/;
217
+ const IDENT_START_RE = /[A-Za-z_$]/;
218
+ const IDENT_PART_RE = /[A-Za-z0-9_$]/;
219
+
220
+ /**
221
+ * Skips whitespace AND comments (line comments to end of line, block comments
222
+ * to their terminator) starting at `i`, returning the offset of the next code
223
+ * character. Shared by the tier scanner and the key/value walk. Comments are
224
+ * trivia here for a load-bearing reason: a commented-out `purpose: "..."`
225
+ * line must NOT count as a real property key, which is exactly why the scan
226
+ * below works at code level instead of regex-matching the raw object body
227
+ * (#4016).
228
+ */
229
+ function skipTrivia(src, i) {
230
+ for (;;) {
231
+ while (i < src.length && WHITESPACE_RE.test(src[i])) i++;
232
+ if (src[i] === "/" && src[i + 1] === "/") {
233
+ const newline = src.indexOf("\n", i);
234
+ i = newline === -1 ? src.length : newline + 1;
235
+ continue;
236
+ }
237
+ if (src[i] === "/" && src[i + 1] === "*") {
238
+ const close = src.indexOf("*/", i + 2);
239
+ i = close === -1 ? src.length : close + 2;
240
+ continue;
241
+ }
242
+ return i;
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Returns the offset one past the `'`/`"` string literal opening at `i`
248
+ * (consuming backslash escapes), or `src.length` when it is unterminated.
249
+ * Escapes are consumed HERE even though an escaped quote is later rejected as
250
+ * an unsupported purpose grammar: the scanner has to agree with JavaScript
251
+ * about where the string ends, or a `name: "a\"b"` would desync every object
252
+ * boundary after it before the rejection ever ran.
253
+ */
254
+ function skipQuoted(src, i) {
255
+ const quote = src[i];
256
+ for (let j = i + 1; j < src.length; j++) {
257
+ if (src[j] === "\\") {
258
+ j++;
259
+ continue;
260
+ }
261
+ if (src[j] === quote) return j + 1;
262
+ }
263
+ return src.length;
264
+ }
265
+
216
266
  /**
217
- * Scans the raw Z_INDEX_TIERS array body for `purpose:` fields and rejects
218
- * any whose quoted value contains a brace or a backslash (which also covers
219
- * escaped quotes) BEFORE the per-object splitter runs. The per-object
220
- * splitter below uses a non-greedy `{...}` match to isolate each tier object,
221
- * which only works when no field value contains a brace — a purpose string
222
- * with a stray `}` would silently truncate the object split and corrupt
223
- * parsing instead of failing loudly. Only a flat, plain double-quoted string
224
- * is supported; a newline between `purpose:` and the opening quote is fine
225
- * (the field-key regexes below all use `\s*`, which matches newlines).
267
+ * Returns the offset one past the template literal opening at `i`, walking
268
+ * `${...}` interpolations (which may nest braces, strings, and further
269
+ * templates). A template literal is never a SUPPORTED tier value — this
270
+ * exists only so a file containing one still yields correct object spans, and
271
+ * therefore reaches the loud per-tier rejection in `parseTiers` naming the
272
+ * offending tier, instead of desyncing the scan into a confusing error.
226
273
  */
227
- function assertSupportedPurposeGrammar(body, tokensPath) {
228
- const purposeKeyRe = /purpose:\s*/g;
229
- let m;
230
- while ((m = purposeKeyRe.exec(body)) !== null) {
231
- const afterKey = m.index + m[0].length;
232
- if (body[afterKey] !== '"') {
233
- // Not immediately followed by a quote — not a value this scan can
234
- // confirm is a real field; let the per-object parser's generic
235
- // "malformed tier object" error handle it if it really is one.
274
+ function skipTemplate(src, i) {
275
+ let j = i + 1;
276
+ while (j < src.length) {
277
+ const ch = src[j];
278
+ if (ch === "\\") {
279
+ j += 2;
280
+ continue;
281
+ }
282
+ if (ch === "`") return j + 1;
283
+ if (ch === "$" && src[j + 1] === "{") {
284
+ let depth = 1;
285
+ j += 2;
286
+ while (j < src.length && depth > 0) {
287
+ const inner = src[j];
288
+ if (inner === '"' || inner === "'") {
289
+ j = skipQuoted(src, j);
290
+ continue;
291
+ }
292
+ if (inner === "`") {
293
+ j = skipTemplate(src, j);
294
+ continue;
295
+ }
296
+ if (inner === "{") depth++;
297
+ else if (inner === "}") depth--;
298
+ j++;
299
+ }
236
300
  continue;
237
301
  }
238
- let i = afterKey + 1;
302
+ j++;
303
+ }
304
+ return src.length;
305
+ }
306
+
307
+ /**
308
+ * Lexes the raw Z_INDEX_TIERS array body at CODE level and returns
309
+ * `{ objects, keys }`:
310
+ *
311
+ * - `objects` — one entry per top-level `{ ... }` tier literal, with its
312
+ * `start`/`end` brace offsets and the property-key sites found inside it.
313
+ * - `keys` — every property-key site in source order, flat. Sites belonging
314
+ * to an object that never closed appear here but in no `objects` entry;
315
+ * that is deliberate, so an unterminated purpose string is still reported
316
+ * as such rather than as an empty tier list.
317
+ *
318
+ * A "site" is `{ key, valueStart }`, where `valueStart` is the first code
319
+ * character after the `:` — the offset every value read anchors at.
320
+ *
321
+ * Working at code level (strings, template literals, and comments skipped
322
+ * wholesale) is what makes the loud-failure invariant safe to add: a
323
+ * `purpose:` inside another field's string value, or on a commented-out line,
324
+ * is not a property key and produces neither a tier field nor an error. A
325
+ * substring or `/purpose\s*:/` test over the object body cannot tell those
326
+ * apart and would turn a silent drop into a spurious hard failure (#4016).
327
+ *
328
+ * Only depth-1 keys are collected: a tier literal is flat, and anything
329
+ * nested is not a tier field.
330
+ */
331
+ function scanTierObjects(body) {
332
+ const objects = [];
333
+ const keys = [];
334
+ let current = null;
335
+ let depth = 0;
336
+ let i = 0;
337
+ while (i < body.length) {
338
+ const ch = body[i];
339
+ if (ch === "/" && (body[i + 1] === "/" || body[i + 1] === "*")) {
340
+ i = skipTrivia(body, i);
341
+ continue;
342
+ }
343
+ if (ch === '"' || ch === "'") {
344
+ i = skipQuoted(body, i);
345
+ continue;
346
+ }
347
+ if (ch === "`") {
348
+ i = skipTemplate(body, i);
349
+ continue;
350
+ }
351
+ if (ch === "{") {
352
+ depth++;
353
+ if (depth === 1) current = { start: i, end: -1, keys: [] };
354
+ i++;
355
+ continue;
356
+ }
357
+ if (ch === "}") {
358
+ if (depth === 1 && current !== null) {
359
+ current.end = i;
360
+ objects.push(current);
361
+ current = null;
362
+ }
363
+ if (depth > 0) depth--;
364
+ i++;
365
+ continue;
366
+ }
367
+ if (depth === 1 && IDENT_START_RE.test(ch)) {
368
+ let end = i + 1;
369
+ while (end < body.length && IDENT_PART_RE.test(body[end])) end++;
370
+ const afterIdent = skipTrivia(body, end);
371
+ if (body[afterIdent] === ":") {
372
+ const site = {
373
+ key: body.slice(i, end),
374
+ valueStart: skipTrivia(body, afterIdent + 1),
375
+ };
376
+ current.keys.push(site);
377
+ keys.push(site);
378
+ }
379
+ i = end;
380
+ continue;
381
+ }
382
+ i++;
383
+ }
384
+ return { objects, keys };
385
+ }
386
+
387
+ /**
388
+ * The LAST site for `key` in a tier object, or null. Last rather than first
389
+ * because a duplicated property key resolves to its final assignment in
390
+ * JavaScript, and the parser's job is to report what the file actually means.
391
+ */
392
+ function lastKeySite(object, key) {
393
+ let found = null;
394
+ for (const site of object.keys) {
395
+ if (site.key === key) found = site;
396
+ }
397
+ return found;
398
+ }
399
+
400
+ /**
401
+ * Reads a flat, plain single- or double-quoted string starting at
402
+ * `valueStart`, returning its raw inner text — or `null` when the value is
403
+ * not a supported quoted literal at all (a template literal, a bare
404
+ * identifier, a concatenation, a ternary: anything this dependency-free
405
+ * parser cannot evaluate). Callers turn that `null` into a loud, tier-naming
406
+ * error rather than a missing field.
407
+ *
408
+ * The delimiter is pinned from the opening character BEFORE the value is
409
+ * scanned, and the scan closes on that same character, so the other quote is
410
+ * ordinary text inside the value: `purpose: "doesn't break"` (exactly what
411
+ * Prettier emits for a value containing an apostrophe) and
412
+ * `purpose: 'a "quoted" phrase'` both read whole. A single
413
+ * `(["'])([^"']*)\1` alternation would truncate both (#4005 / #4014).
414
+ */
415
+ function readQuotedValue(body, valueStart) {
416
+ const quote = body[valueStart];
417
+ if (quote !== '"' && quote !== "'") return null;
418
+ const close = body.indexOf(quote, valueStart + 1);
419
+ if (close === -1) return null;
420
+ // The literal must BE the whole value. Anything other than the property
421
+ // separator after it — `"a" + b`, `cond ? "a" : "b"`, `"a" as const` —
422
+ // is an expression whose first operand would otherwise be read as the
423
+ // field, which is the same silent-data-loss shape as dropping it (#4016).
424
+ const afterLiteral = skipTrivia(body, close + 1);
425
+ if (
426
+ afterLiteral < body.length &&
427
+ body[afterLiteral] !== "," &&
428
+ body[afterLiteral] !== "}"
429
+ ) {
430
+ return null;
431
+ }
432
+ return body.slice(valueStart + 1, close);
433
+ }
434
+
435
+ /**
436
+ * Rejects any REAL `purpose:` property whose quoted value contains a brace or
437
+ * a backslash (which also covers escaped quotes). Backslashes are rejected
438
+ * because this parser never unescapes — a `\n` in the source would reach the
439
+ * generated table as those two literal characters. Braces were originally
440
+ * rejected because the old non-greedy `{...}` object splitter truncated on
441
+ * them; `scanTierObjects` has no such weakness, but the restriction is kept
442
+ * deliberately as a stable contract, so a tokens file that parsed before
443
+ * still parses and one that failed still fails. Only a flat, plain string is
444
+ * supported, single- or double-quoted; a newline between `purpose:` and the
445
+ * opening quote is fine (`skipTrivia` walks it).
446
+ *
447
+ * A value that does not open with a quote at ALL is deliberately not this
448
+ * function's business: that is the unparseable case, reported per tier — with
449
+ * the tier's name — by `parseTiers` below, which cannot be done from here
450
+ * because this pre-pass runs before any tier is identified.
451
+ */
452
+ function assertSupportedPurposeGrammar(body, purposeSites, tokensPath) {
453
+ for (const site of purposeSites) {
454
+ const openingQuote = body[site.valueStart];
455
+ if (openingQuote !== '"' && openingQuote !== "'") continue;
239
456
  let closed = false;
240
- for (; i < body.length; i++) {
457
+ for (let i = site.valueStart + 1; i < body.length; i++) {
241
458
  const ch = body[i];
242
459
  if (ch === "{" || ch === "}" || ch === "\\") {
243
460
  throw new Error(
244
461
  `Unsupported purpose string grammar in ${tokensPath}: purpose values may not ` +
245
- `contain braces, backslashes, or escaped quotes — only flat, plain double-quoted ` +
246
- `strings are supported (the object parser cannot safely handle anything else). ` +
247
- `Offending text near: ${JSON.stringify(body.slice(afterKey, Math.min(afterKey + 40, body.length)))}`,
462
+ `contain braces, backslashes, or escaped quotes — only flat, plain single- or ` +
463
+ `double-quoted strings are supported (the object parser cannot safely handle ` +
464
+ `anything else). ` +
465
+ `Offending text near: ${JSON.stringify(body.slice(site.valueStart, Math.min(site.valueStart + 40, body.length)))}`,
248
466
  );
249
467
  }
250
- if (ch === '"') {
468
+ if (ch === openingQuote) {
251
469
  closed = true;
252
470
  break;
253
471
  }
254
472
  }
255
473
  if (!closed) {
256
474
  throw new Error(
257
- `Unterminated purpose string in ${tokensPath} (no closing double quote found).`,
475
+ `Unterminated purpose string in ${tokensPath} ` +
476
+ `(no closing ${openingQuote === '"' ? "double" : "single"} quote found).`,
258
477
  );
259
478
  }
260
- purposeKeyRe.lastIndex = i + 1;
261
479
  }
262
480
  }
263
481
 
482
+ /**
483
+ * The loud-failure error for a tier field whose key IS present but whose
484
+ * value this parser cannot read (#4016). Names the tier, because "which tier"
485
+ * is the only question the reader has.
486
+ */
487
+ function unreadableFieldError(field, tierName, body, site, tokensPath) {
488
+ return new Error(
489
+ `Unreadable ${field} value for tier "${tierName}" in ${tokensPath}: a ${field} must be a ` +
490
+ `flat, plain single- or double-quoted string literal. A template literal, a bare ` +
491
+ `identifier, a concatenation, or any other expression cannot be read by this ` +
492
+ `dependency-free parser and must not be silently dropped. ` +
493
+ `Offending text near: ${JSON.stringify(body.slice(site.valueStart, Math.min(site.valueStart + 40, body.length)))}`,
494
+ );
495
+ }
496
+
264
497
  /**
265
498
  * Parse the Z_INDEX_TIERS array out of z-index-tokens.ts WITHOUT importing it
266
499
  * (this bin is a dependency-free .mjs and cannot resolve TypeScript). Reads
267
500
  * each `{ name: "...", value: <n>, kind?: "global"|"local", purpose?: "..." }`
268
- * object literal. Throws on a malformed source, an unsupported purpose-string
269
- * grammar, or an unknown `kind` value so drift between the parser and the
270
- * file surfaces loudly. Delegates the structural invariants (non-empty,
271
- * name shape, duplicate names, per-kind value uniqueness) to `validateTiers`.
501
+ * object literal. `name`, `kind`, and `purpose` accept EITHER quote character
502
+ * a project whose Prettier config sets `singleQuote: true` needs no
503
+ * per-file override and the two styles may be mixed freely within a file or
504
+ * within one tier object, since each field's delimiter is resolved
505
+ * independently from its own opening character (see `readQuotedValue`).
506
+ * `value` is unquoted either way. Throws on a malformed source, an
507
+ * unsupported purpose-string grammar, or an unknown `kind` value so drift
508
+ * between the parser and the file surfaces loudly. Delegates the structural
509
+ * invariants (non-empty, name shape, duplicate names, per-kind value
510
+ * uniqueness) to `validateTiers`.
511
+ *
512
+ * ## What the loud-failure invariant covers, and what it does not (#4016)
513
+ *
514
+ * Field values are read anchored at the offsets a code-level scan
515
+ * (`scanTierObjects`) reports for the REAL property keys — never by regex
516
+ * search over the raw object text. Consequences, all deliberate:
517
+ *
518
+ * - COVERED: a `name`/`kind`/`purpose` key that is present but whose value
519
+ * is not exactly one plain quoted string — a template literal, a bare
520
+ * identifier, a concatenation, a ternary — throws and names the tier,
521
+ * instead of leaving the field undefined (or quietly keeping only the
522
+ * leading operand) and rendering `-` with exit 0 (#4005).
523
+ * - COVERED (no false positive): `purpose:` / `kind:` occurring inside
524
+ * another field's string value, or on a commented-out line, is not a
525
+ * property key. It yields neither a field nor an error.
526
+ * - COVERED (no misparse): a value that itself spells another field name,
527
+ * e.g. `purpose: 'see name: "y"'`, can no longer be mistaken for that
528
+ * field, because extraction never searches the object text.
529
+ * - NOT COVERED: values this parser could in principle read but the
530
+ * grammar deliberately excludes — braces, backslashes, escaped quotes in
531
+ * a purpose — still throw as an unsupported grammar, not as a tier field.
532
+ * - NOT COVERED: `value:`. It is read as the integer literal at the start
533
+ * of its value, so a constant reference reports the generic "malformed
534
+ * tier object" error (without a tier name — a tier with no readable
535
+ * name/value has none to report) while an arithmetic expression keeps its
536
+ * leading integer. Left deliberately loose: the acceptance surface here
537
+ * is the string fields, and a `value: 0 as const` hard-failing a
538
+ * previously-valid file would cost more than it buys.
539
+ * - NOT COVERED: any construct the scan's small lexer does not model —
540
+ * quoted property keys (`"purpose": "..."`), computed keys, and spreads
541
+ * are not recognized as keys at all and surface as a malformed object or
542
+ * a missing field.
272
543
  *
273
544
  * `tokensPath` is used purely for error-message context — pass the same path
274
545
  * string (conventional default or an explicit --tokens value) that was used
@@ -288,29 +559,41 @@ export function parseTiers(src, tokensPath = DEFAULT_TOKENS_PATH) {
288
559
  }
289
560
  const body = arrayMatch[1];
290
561
 
291
- assertSupportedPurposeGrammar(body, tokensPath);
562
+ const { objects, keys } = scanTierObjects(body);
563
+
564
+ // Runs across ALL purpose sites before any tier is built, so an
565
+ // unterminated purpose string — which swallows its object's closing brace
566
+ // and leaves that object out of `objects` entirely — is reported as the
567
+ // unterminated string it is.
568
+ assertSupportedPurposeGrammar(
569
+ body,
570
+ keys.filter((site) => site.key === "purpose"),
571
+ tokensPath,
572
+ );
292
573
 
293
574
  const tiers = [];
294
- // Each tier is a `{ ... }` object literal; iterate top-level braces. Safe
295
- // because assertSupportedPurposeGrammar above already ruled out braces
296
- // inside any purpose string.
297
- const objectRe = /\{([\s\S]*?)\}/g;
298
- let m;
299
- while ((m = objectRe.exec(body)) !== null) {
300
- const obj = m[1];
301
- const nameMatch = obj.match(/name:\s*"([^"]+)"/);
302
- const valueMatch = obj.match(/value:\s*(-?\d+)/);
303
- if (!nameMatch || !valueMatch) {
575
+ for (const object of objects) {
576
+ const nameSite = lastKeySite(object, "name");
577
+ const valueSite = lastKeySite(object, "value");
578
+ const name = nameSite === null ? null : readQuotedValue(body, nameSite.valueStart);
579
+ const valueDigits =
580
+ valueSite === null ? null : /^-?\d+/.exec(body.slice(valueSite.valueStart));
581
+ // `!name` rather than `=== null`: a tier name may not be empty either.
582
+ if (!name || valueDigits === null) {
304
583
  throw new Error(
305
- `Malformed tier object in Z_INDEX_TIERS (missing name/value) in ${tokensPath}: ${obj.trim()}`,
584
+ `Malformed tier object in Z_INDEX_TIERS (missing name/value) in ${tokensPath}: ` +
585
+ `${body.slice(object.start + 1, object.end).trim()}`,
306
586
  );
307
587
  }
308
588
 
309
- const tier = { name: nameMatch[1], value: Number(valueMatch[1]) };
589
+ const tier = { name, value: Number(valueDigits[0]) };
310
590
 
311
- const kindMatch = obj.match(/kind:\s*"([^"]*)"/);
312
- if (kindMatch) {
313
- const kindValue = kindMatch[1];
591
+ const kindSite = lastKeySite(object, "kind");
592
+ if (kindSite !== null) {
593
+ const kindValue = readQuotedValue(body, kindSite.valueStart);
594
+ if (kindValue === null) {
595
+ throw unreadableFieldError("kind", tier.name, body, kindSite, tokensPath);
596
+ }
314
597
  if (kindValue !== "global" && kindValue !== "local") {
315
598
  throw new Error(
316
599
  `Invalid kind "${kindValue}" for tier "${tier.name}" in ${tokensPath} ` +
@@ -320,9 +603,13 @@ export function parseTiers(src, tokensPath = DEFAULT_TOKENS_PATH) {
320
603
  tier.kind = kindValue;
321
604
  }
322
605
 
323
- const purposeMatch = obj.match(/purpose:\s*"([^"]*)"/);
324
- if (purposeMatch) {
325
- tier.purpose = purposeMatch[1];
606
+ const purposeSite = lastKeySite(object, "purpose");
607
+ if (purposeSite !== null) {
608
+ const purposeValue = readQuotedValue(body, purposeSite.valueStart);
609
+ if (purposeValue === null) {
610
+ throw unreadableFieldError("purpose", tier.name, body, purposeSite, tokensPath);
611
+ }
612
+ tier.purpose = purposeValue;
326
613
  }
327
614
 
328
615
  tiers.push(tier);
@@ -736,6 +1023,26 @@ export function buildMdTable(tiers, options = {}) {
736
1023
  return lines.join("\n");
737
1024
  }
738
1025
 
1026
+ /**
1027
+ * Reads a user-supplied file, translating a missing file into a message that
1028
+ * names both which file (`label`) and where it looked (`asGivenPath` — the
1029
+ * as-given path, never the resolved absolute one, matching the convention
1030
+ * documented on `main()` below). Only ENOENT is translated: EACCES/EISDIR
1031
+ * etc. are real, distinct failures (a permissions problem or "that's a
1032
+ * directory") that a "not found" message would misreport, so they propagate
1033
+ * unchanged with Node's own message.
1034
+ */
1035
+ function readNamedFile(absPath, asGivenPath, label) {
1036
+ try {
1037
+ return readFileSync(absPath, "utf8");
1038
+ } catch (error) {
1039
+ if (error.code === "ENOENT") {
1040
+ throw new Error(`${label} file not found at ${asGivenPath}`);
1041
+ }
1042
+ throw error;
1043
+ }
1044
+ }
1045
+
739
1046
  /**
740
1047
  * CLI entrypoint. `argv` defaults to the real process argv (minus the node/
741
1048
  * script prefix) so `isDirectInvocation()` below can call `main()` with no
@@ -765,8 +1072,8 @@ export function main(argv = process.argv.slice(2)) {
765
1072
  const tokensAbsPath = resolve(root, tokensPath);
766
1073
  const cssAbsPath = resolve(root, cssPath);
767
1074
 
768
- const tokensSrc = readFileSync(tokensAbsPath, "utf8");
769
- const css = readFileSync(cssAbsPath, "utf8");
1075
+ const tokensSrc = readNamedFile(tokensAbsPath, tokensPath, "tokens");
1076
+ const css = readNamedFile(cssAbsPath, cssPath, "css");
770
1077
 
771
1078
  const tiers = parseTiers(tokensSrc, tokensPath);
772
1079
  const block = buildBlock(tiers, { tokensPath, cssPath, themeWrapper });
@@ -777,7 +1084,7 @@ export function main(argv = process.argv.slice(2)) {
777
1084
  let nextMd;
778
1085
  if (mdTablePath !== undefined) {
779
1086
  mdAbsPath = resolve(root, mdTablePath);
780
- mdSrc = readFileSync(mdAbsPath, "utf8");
1087
+ mdSrc = readNamedFile(mdAbsPath, mdTablePath, "md-table");
781
1088
  const mdBlock = buildMdTable(tiers, { tokensPath });
782
1089
  nextMd = replaceBlock(
783
1090
  mdSrc,
@@ -854,5 +1161,20 @@ function isDirectInvocation() {
854
1161
  }
855
1162
 
856
1163
  if (isDirectInvocation()) {
857
- process.exit(main());
1164
+ // Turns any Error thrown by main() (there are ~17 deliberate `throw new
1165
+ // Error(...)` call sites above, plus the readNamedFile guard) into a single
1166
+ // readable stderr line instead of a raw Node stack trace. This also hides
1167
+ // the stack for a genuine *programming* error, not just a user-input one —
1168
+ // an accepted CLI tradeoff, not an accident: the process still exits 1 and
1169
+ // nothing is swallowed, but a future reader debugging an internal crash
1170
+ // needs to call the exported `main()` directly (or temporarily remove this
1171
+ // try/catch) to see the stack. Exit codes are unchanged: main()'s own
1172
+ // return value (0 or 1) still flows through process.exit on the success
1173
+ // path; only an uncaught throw is newly turned into exit(1) with a message.
1174
+ try {
1175
+ process.exit(main());
1176
+ } catch (error) {
1177
+ console.error(error instanceof Error ? error.message : String(error));
1178
+ process.exit(1);
1179
+ }
858
1180
  }
@@ -3,8 +3,12 @@
3
3
  /**
4
4
  * Design-token panel (zdtp) WIRING MECHANISM + PACKAGE-DEFAULT ISLAND (#2658,
5
5
  * epic Minimal Scaffold #2651). zdtp itself is LAZY-LOADED (#3282, epic
6
- * #3261): this module carries NO top-level value import of `@takazudo/zdtp`
7
- * its side-effect-free `/constants` leaf is the only eager zdtp value import.
6
+ * #3261): this module carries NO top-level value import of `@takazudo/zdtp`
7
+ * whatsoever. It used to eagerly import the side-effect-free `/constants` leaf;
8
+ * since #4018 those constants come from the in-package mirror
9
+ * `./design-token-panel-constants.js`, because that one static edge made an
10
+ * OPTIONAL peer a hard build-time requirement for every chrome consumer
11
+ * (#4009 — see that module's header).
8
12
  * The root package is `import()`ed on the first dispatch on either resolved
9
13
  * toggle channel (the shared `toggle-design-token-panel`, or this instance's own —
10
14
  * see the public 0.5 {@link resolveToggleEventName}), or eagerly when the
@@ -5,7 +5,7 @@ import {
5
5
  EAGER_LOAD_GATE_KEY_SUFFIXES,
6
6
  EAGER_LOAD_GATE_STATE_FAMILY,
7
7
  resolveToggleEventName
8
- } from "@takazudo/zdtp/constants";
8
+ } from "./design-token-panel-constants.js";
9
9
  import {
10
10
  BEFORE_NAVIGATE_EVENT,
11
11
  AFTER_NAVIGATE_EVENT
@@ -0,0 +1,75 @@
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
+ * `as const` is load-bearing, not cosmetic: `hasPersistedPanelState` indexes
24
+ * `config[gate.requiredConfig]`, which only typechecks while `requiredConfig`
25
+ * narrows to `null | "domTweaker"` instead of widening to `string | null`.
26
+ */
27
+ export declare const EAGER_LOAD_GATE_KEY_SUFFIXES: {
28
+ readonly ":visible": {
29
+ readonly acceptedValues: readonly ["1"];
30
+ readonly requiredConfig: null;
31
+ };
32
+ readonly "-open": {
33
+ readonly acceptedValues: readonly ["1"];
34
+ readonly requiredConfig: null;
35
+ };
36
+ readonly ":autoload": {
37
+ readonly acceptedValues: readonly ["1", "auto"];
38
+ readonly requiredConfig: null;
39
+ };
40
+ readonly "-elpath-enabled": {
41
+ readonly acceptedValues: readonly ["1"];
42
+ readonly requiredConfig: null;
43
+ };
44
+ readonly "-domtweaker-enabled": {
45
+ readonly acceptedValues: readonly ["1"];
46
+ readonly requiredConfig: "domTweaker";
47
+ };
48
+ };
49
+ /**
50
+ * The sixth eager-load signal: exact readable state keys, with a content
51
+ * check. Missing keys and raw empty strings are blank;
52
+ * JSON null and empty objects/arrays do not activate. Non-empty collections and
53
+ * all other parsed primitives (even false, 0, or JSON "") activate. Malformed
54
+ * JSON fails open so the panel can migrate or reject the stored payload.
55
+ *
56
+ * matchesKey compares complete strings constructed from the literal prefix, so
57
+ * regex metacharacters are safe and sibling-instance keys are excluded.
58
+ */
59
+ export declare const EAGER_LOAD_GATE_STATE_FAMILY: {
60
+ readonly keySuffixes: {
61
+ readonly v1: "-state";
62
+ readonly v2: "-state-v2";
63
+ readonly v3: "-state-v3";
64
+ readonly v4: "-state-v4";
65
+ };
66
+ readonly matchesKey: (storagePrefix: string, key: string) => boolean;
67
+ readonly valueRules: {
68
+ readonly blank: false;
69
+ readonly jsonNull: false;
70
+ readonly object: "non-empty";
71
+ readonly array: "non-empty";
72
+ readonly primitive: true;
73
+ readonly malformedJson: true;
74
+ };
75
+ };
@@ -0,0 +1,41 @@
1
+ const DEFAULT_STORAGE_PREFIX = "zudo-design-token-panel";
2
+ const DEFAULT_TOGGLE_EVENT = "toggle-design-token-panel";
3
+ function resolveToggleEventName(cfg) {
4
+ return cfg.storagePrefix === void 0 || cfg.storagePrefix === DEFAULT_STORAGE_PREFIX ? DEFAULT_TOGGLE_EVENT : cfg.toggleEvent ?? `toggle-${cfg.storagePrefix}`;
5
+ }
6
+ const EAGER_LOAD_GATE_KEY_SUFFIXES = {
7
+ ":visible": { acceptedValues: ["1"], requiredConfig: null },
8
+ "-open": { acceptedValues: ["1"], requiredConfig: null },
9
+ ":autoload": { acceptedValues: ["1", "auto"], requiredConfig: null },
10
+ "-elpath-enabled": { acceptedValues: ["1"], requiredConfig: null },
11
+ "-domtweaker-enabled": { acceptedValues: ["1"], requiredConfig: "domTweaker" }
12
+ };
13
+ const READABLE_STATE_KEY_SUFFIXES = {
14
+ v1: "-state",
15
+ v2: "-state-v2",
16
+ v3: "-state-v3",
17
+ v4: "-state-v4"
18
+ };
19
+ const EAGER_LOAD_GATE_STATE_FAMILY = {
20
+ keySuffixes: READABLE_STATE_KEY_SUFFIXES,
21
+ matchesKey(storagePrefix, key) {
22
+ return Object.values(READABLE_STATE_KEY_SUFFIXES).some(
23
+ (suffix) => key === storagePrefix + suffix
24
+ );
25
+ },
26
+ valueRules: {
27
+ blank: false,
28
+ jsonNull: false,
29
+ object: "non-empty",
30
+ array: "non-empty",
31
+ primitive: true,
32
+ malformedJson: true
33
+ }
34
+ };
35
+ export {
36
+ DEFAULT_STORAGE_PREFIX,
37
+ DEFAULT_TOGGLE_EVENT,
38
+ EAGER_LOAD_GATE_KEY_SUFFIXES,
39
+ EAGER_LOAD_GATE_STATE_FAMILY,
40
+ resolveToggleEventName
41
+ };
package/dist/safelist.css CHANGED
@@ -1,2 +1,2 @@
1
1
  /* generated by gen-safelist.mjs — do not edit by hand */
2
- @source inline("-left-[calc(var(--spacing-icon-lg)/2)] -link -mb-px -ml-hsp-sm -mt-px -noscript -open -translate-x-full 2xl:w-[24px] [&::-webkit-details-marker]:hidden [&_a]:pointer-events-auto [&_a]:text-accent [&_a]:underline [&_li]:mb-0 [&_nav]:mb-0 [asset-viewer] [data-admonition] [data-kbd-shortcut] [data-switcher-launcher] [doc-history-meta] [doc-history] [doc-layout] [llms-txt] [zudo-doc] a a2 abbr about above absent absolute accent accent- accent:accent- access across activated active actual actually added admonition admonition- admonition-body admonition-title admonition/callout after after-breadcrumb after-content after-navigate after-sidebar after-title against agent agents ai-chat ai-chat-md ai-chat-trigger alert align-top all allow allow-same-origin allow-scripts allowed alone already already-executed already-multiline already-picked also always an anchor and and/or animate-pulse animate-spin announce ansehen antialiased any anywhere anzeigen app appear application/json application/octet-stream application/pdf application/sql application/toml application/x-httpd-php application/xml application/yaml applied applies apply applying approach approval are area arg argument aria-atomic aria-busy aria-controls aria-current aria-disabled aria-expanded aria-haspopup aria-hidden aria-label aria-labelledby aria-live aria-orientation aria-pressed aria-selected aria-valuemax aria-valuemin aria-valuenow arm arms around arrows article as asc ascii aside aspect-[1200/630] aspect-square asset asset- asset-components assets assets/client assistant async at at-rule attach attribute attributes auf authored auto auto-logo-mask autogenerated availability available avc1 avif avis avoid await away b back backdrop:bg-bg/30 backdrop:bg-bg/80 backdrop:bg-overlay/60 backdrop:z-modal-backdrop background background-color backtick backticks baked band banner bar bare base base- base64 base:base- based bash batch be bearbeiten because becomes been before below best best-effort between bg bg-[#fff] bg-accent bg-bg bg-chat-assistant-bg bg-chat-user-bg bg-code-bg bg-fg bg-info/10 bg-info/5 bg-muted bg-overlay/30 bg-surface bg-surface/50 bg-transparent bg-warning/10 bg-warning/5 bi big bigint bin binaries bind binding blank blanks block blockquote blocks blur bodies body body-end-components body-end-scripts bold boolean bootstrap border border-accent border-b border-b-2 border-b-[5px] border-bg/30 border-collapse border-danger border-dashed border-fg border-image border-info/30 border-l border-l-0 border-l-[3px] border-left-width border-muted border-none border-r border-r-0 border-radius border-solid border-t border-t-[2px] border-t-[3px] border-transparent border-warning/30 border-width border-y both bottom-hsp-lg bottom-vsp-xl boundaries box box-border br brackets brand breadcrumb:end breadcrumb:start break-words brief brown browser browser-tab browsers browses btn budget bug build builder built built-in bundler but button buttons by bypassed byte-identical bytes c cache cached calendar-valid call callable called caller calls can cancellation candidate cannot canonical canvas caption captured captures card card-grid cards carry case-insensitive cases cat-nav- catalog catch categories category caught caution center center/contain ch chains change changed changelog changelogs changes characters check checker child children choose chrome chrome-font ci circle cite cjs class class-less class-mode claude claude-agents claude-commands claude-md claude-resources claude-skills cleaned cleanly clear clearing click client client-router client-side clip clobber clobbering close closed closes closing closure code code-block-sr-announce code-group code-group-panel codex codex-agents codex-agents-md codex-config codex-hooks codex-resources codex-rules codex-skills col col-resize col-span-full col-start-1 colgroup collapse collapses collapsible collision color color-scheme color-scheme-changed color-scheme-provider color-tweak colorization colors column comma command commands commas comment commercial commercial-font-denylist commit compare complete component component:github-link component:language-switcher component:search component:theme-toggle component:version-switcher composes composition compute computed concrete conf config configuration configurations configure configured conflicting conflicts confuse connect const construction consumer consumes contain container containers containing contains content content-admonition content-layer content-link content-type content-wrapper:end content-wrapper:start contents context contract control controller controls converts cookie-blocking copied copy copy-url core corners correct correctly corrupt could count covered covers cpp crashes created cross-component crumb- cs csharp css css-presence csv ctx cur current current-path/index.ts current-route currently cursor cursor-not-allowed cursor-pointer custom cycle d danger dark dash data data-active data-admonition data-asset-details-hidden data-auto-logo data-base data-close-search data-current-locale data-default-locale data-doc-date data-doc-description data-doc-metainfo data-doc-pager data-doc-unavailable-versions data-find-active data-find-match data-footer data-group-id data-header data-header-logo data-header-nav data-header-right data-kbd-shortcut data-lang data-language-menu data-language-switcher data-language-toggle data-loading-index data-mermaid-enlarge-ready data-mermaid-rendered data-mermaid-src data-nav-active data-nav-category data-nav-item data-nav-item-dropdown data-nav-more data-nav-more-menu data-nav-more-toggle data-no-results data-note-tray-group data-note-tray-row data-open-search data-pan-active data-processed data-props data-result-count-template data-search-count data-search-count-narrow data-search-dialog data-search-input data-search-placeholder data-search-results data-search-unavailable data-sidebar-hidden data-sidebar-resizer data-site-nav data-switcher-card data-switcher-launcher data-tab-btn data-tab-default data-tab-label data-tab-value data-tabs data-taglist-group data-testid data-theme data-theme-pack data-theme-pack-switcher data-theme/style data-toc-hidden data-trailing-slash data-unavailable-label data-variant data-version-banner data-version-latest data-version-menu data-version-rewire data-version-slug data-version-switcher data-version-toggle data-version-trigger-label data-zd-asset-action data-zd-asset-actions data-zd-asset-details data-zd-asset-details-chevron data-zd-asset-details-list data-zd-asset-details-toggle data-zd-asset-index-action data-zd-asset-index-empty data-zd-asset-index-page data-zd-asset-page data-zd-asset-tree data-zd-copy-url data-zd-html-preview-reservation data-zd-label-collapse data-zd-label-expand data-zd-mobile-sidebar data-zd-mobile-toc data-zd-nav-section data-zd-nosidebar data-zd-pending data-zd-props-preserve data-zd-sidebar-open-key data-zd-theme-pack-css data-zd-theme-pack-css-loading data-zd-theme-pack-loading data-zd-toc data-zd-wide data-zfb-island data-zfb-island-remount data-zfb-reload data-zfb-transition-persist date dated dd decimal decision declaration declare declared declares decoration decoration-muted deepest deepest-match default default-transition-duration defaults deferral deferred del delegated delete deliberately delimiter dependency depends depth der desc description design design-token design-token-panel design-token-trigger desktop desktop-sidebar desktop-sidebar-toggle desktop-sidebar-toggle-island desktop-toc-toggle destroys destructive detach detached details determine deterministic dev dfn diagram diagrams dialog did die dieser diff diff-line-added diff-line-content diff-line-empty diff-line-num diff-line-removed diff-row differ different dir directly directories directory disabled disabled:cursor-default disabled:opacity-50 disabled:pointer-events-none disc display display:none dist distance distinct div dl do doc doc-card- doc-content-band doc-history doc-history-generate doc-history-panel doc-history-trigger doc-page doc-pager doc-prose doc-title docblock docs docs- docs-v- document document-level documentation documented documents does dog dot double-registration download draft drag drawer drift drifts drop dropdown dropdown-parent dropdowns dt duplicate duration duration-150 duration-200 during dynamically e e2e each eager earlier early ease-in-out edge editing einer either eject ejectable ejectables ejected el element elements els else em embedded emit emitting empty empty/undefined en enable enabled end enhanced enhancement enlarged entire entities entries entry entrypoint env equal error escape escaped escapes even event eventually every everything-enabled exactly example exceeds excerpt excludes exclusively existing exists exit expand expected explicit export extends extra f factories failed fall fallback fallbacks falling falls false family fast favicon feature fg field fields fieldset figcaption figure file files fill fills finally find find-match find-match-active fire fires first first-paint first:mt-0 fit fix fixed fixed-width fixtures flag flash flat flex flex-1 flex-col flex-wrap flip flipping flips flow flush-left focus focus-visible:bg-accent/10 focus-visible:border-accent focus-visible:decoration-accent focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2 focus-visible:text-accent focus-visible:underline focus-within:border-accent focus-within:z-local-1 focus:border-accent focus:outline-none focus:text-accent focus:underline folder folders follows font font-bold font-face-parity font-family font-file-missing font-medium font-mono font-sans font-scale font-semibold font-size font-weight font-weight-bold font-weight-medium font-weight-normal font-weight-semibold font/woff2 fonts footer footer- for form format former found four-link fox fragment frame free freeze fresh from frontmatter frontmatter-preview frozen frozen-script fs-extra ftyp full fully function further g gains gap-[0.3em] gap-[clamp(1.5rem,3vw,4rem)] gap-hsp-2xs gap-hsp-lg gap-hsp-md gap-hsp-sm gap-hsp-xl gap-hsp-xs gap-vsp-2xs gap-vsp-3xs gap-vsp-lg gap-vsp-md gap-vsp-xs gap-x-hsp-2xs gap-x-hsp-lg gap-x-hsp-md gap-x-hsp-sm gap-x-hsp-xs gap-y-vsp-2xs gap-y-vsp-3xs gap-y-vsp-lg gap-y-vsp-md gap-y-vsp-xs gaps gate geladen2026 generate generated generation genuine geometry get getting-started gif git github github-dark github-link give go got grab gradient granular graph grid grid-cols-1 grid-cols-2 grid-cols-[auto_1fr] grid-rows-[auto_auto] grid-rows-subgrid group group-focus-visible:decoration-accent group-focus-visible:text-accent group-focus-visible:text-accent-hover group-focus-visible:text-fg group-focus-visible:underline group-focus-within:block group-hover:bg-fg group-hover:block group-hover:decoration-accent group-hover:text-accent group-hover:text-accent-hover group-hover:text-bg group-hover:text-fg group-hover:underline group-open:rotate-90 grouped grouping guard guards gz h h-[0.5rem] h-[0.625rem] h-[0.875rem] h-[1.125rem] h-[1.25rem] h-[1.575rem] h-[10rem] h-[14px] h-[1em] h-[1lh] h-[2.5rem] h-[2rem] h-[3.5rem] h-[3rem] h-[70vh] h-[90vh] h-[calc(100%-3rem)] h-[calc(100vh-3.5rem)] h-dvh h-full h-icon-lg h-icon-md h-icon-sm h-icon-xs h1 h1s h2 h22013h4 h2s h3 h4 h5 h6 half hand-copied hand-editable handle handled handler handlers happens hard-loaded hardcoded has hash-link have head head-links head-scripts header header- header-call:end header-call:start header-right heading heading-h2 heading-h3 heading-h4 heading-rule headings height here hex hi-root hidden hide hierarchical highlight highlighting history home hook hooks hooks-json horizontal host hover:bg-[color-mix(in_srgb,var(--color-surface)_80%,var(--color-fg)_20%)] hover:bg-accent-hover hover:bg-accent/10 hover:bg-danger/10 hover:bg-surface hover:border-accent hover:border-accent-hover hover:border-fg hover:decoration-accent hover:text-accent hover:text-accent-hover hover:text-fg hover:underline hover:z-local-1 hpp hr href hrefs hsp hsp-2xl hsp-2xs hsp-lg hsp-md hsp-sm hsp-xl hsp-xs html i i18n/theme. i2 i3 i4 ico icon icon-lg icon-md icon-sm icon-xs identical idle idx if iframe ignoring image image-enlarge image-overlay-inset image/avif image/gif image/jpeg image/png image/webp image/x-icon img implementation import important important-allowlist imports in inactive includes including incomplete independently index index2026 indirectly info inherit inherited ini initial initialised injected inline inline-block inline-flex inner input input-clear ins inserted-after-color-mode inserted-after-color-scheme inserted-after-site-name inserted-first insertion inset-0 inside inside-only inspect install installation installed instance instanceof instead instructions intended intent intentionally intercept interface internal interpolation into invalid invalidated inverse inversion invocation invoke is is-checker island island-root iso2 iso3 iso4 iso5 iso6 isom ispe issues it italic item item- items items-baseline items-center items-end items-start iteration its itself ja java javascript jpeg jpg js json jsx jumps just justification justify-between justify-center justify-end justify-start katex kbd keep keeping keeps kept key keyboard keyboard-shortcut keydown keys keystroke keyword keywords khroma known-token-names kopieren kotlin kt label landing lands language-menu language-switcher language-toggle larger last:border-b-0 last:pb-0 later latest launch layout lazy leading leading-none leading-normal leading-relaxed leading-snug leading-tight leaf leaf- leak leaves leaving left left-0 left:calc legend legitimate length lets letter-spacing lg lg:block lg:border lg:border-fg lg:border-solid lg:flex lg:flex-col lg:flex-row lg:gap-hsp-xl lg:grid-cols-3 lg:grid-cols-[repeat(auto-fit,minmax(12rem,1fr))] lg:h-[90vh] lg:hidden lg:justify-start lg:m-auto lg:max-h-[90vh] lg:max-w-[52.5rem] lg:ml-[var(--zd-sidebar-w)] lg:pr-hsp-sm lg:pt-vsp-2xl lg:px-hsp-2xl lg:py-vsp-2xl lg:text-left lg:w-[90vw] lg:w-[clamp(16rem,25%,22rem)] li li2 library license lifecycle light light/dark like likely line line-height line/statement lines linger link link- links list list-disc list-none listener lists literal literally literals live lives llms llms-txt load loaded loader loading local local-1 local-2 local-3 locale locales log logo long longer longest-match look loses lostpointercapture lower luminance m m-0 m-auto m10 m14 m16 m21 m6 machinery main major make malformed malformed-markup malicious managed manifest manual manually maps mark markdown marks match matches matching math math-display math-inline max max-h-[85vh] max-h-[90vh] max-h-full max-h-none max-w-[16rem] max-w-[64rem] max-w-[85%] max-w-[85vw] max-w-[90vw] max-w-[calc(100vw-2rem)] max-w-[calc(100vw-var(--spacing-hsp-xl))] max-w-[clamp(50rem,75vw,90rem)] max-w-full max-w-none max-w-sm max-width maximum may mb-0 mb-vsp-2xs mb-vsp-lg mb-vsp-md mb-vsp-sm mb-vsp-xl mb-vsp-xs md mdx means measured measurement measures measuring mechanism menu mermaid message messages meta meta-knob meta-schema metadata migration min-h-0 min-h-[20rem] min-h-[44px] min-h-[60vh] min-h-[calc(100vh-3.5rem)] min-h-screen min-w-0 min-w-[10rem] min-w-[3rem] min-w-[44px] min-w-[8rem] minifier minor mirror mirroring mirrors missing mit mjs ml-[calc(var(--spacing-hsp-xl)+1px)] ml-auto ml-hsp-2xl ml-hsp-lg ml-hsp-md ml-hsp-sm ml-hsp-xl mobile mod modal modal-backdrop mode model modify module moment monospace month more most mount mounted mouseenter mouseleave mov move mp4 mp41 mp42 mr-[calc(var(--spacing-hsp-xl)+1px)] mr-hsp-sm ms mt-0 mt-vsp-2xl mt-vsp-2xs mt-vsp-3xs mt-vsp-lg mt-vsp-md mt-vsp-sm mt-vsp-xl mt-vsp-xs multi-changelog multiple must mutates mutation mutations muted mvhd mx-auto my-vsp-lg my-vsp-md n name named names native natural nav nav-active nav-card- nav/doc navigating navigation navigations near needed needs neither nested neutral never new newly-swapped next nicht no no-color-scheme no-data-theme-selector no-enlarge no-op no-repeat no-underline noch node node:buffer node:fs node:fs/promises node:module node:path node:url node:util nodes nofollow noindex non-draggable non-empty non-index non-light-dark non-literal non-null non-persisted none noopener noreferrer normal noscript not notable note note-tray notes now null number numeric object object-contain observe observer occurred of off offered offsets ofl-required og:description og:image og:image:alt og:image:height og:image:width og:title og:type og:url oklch ol old older omit omitting on once one only onto opacity-60 open open/close option or order original other others otherwise out outgoing outline-none over overflow overflow-auto overflow-hidden overflow-x-auto overflow-y-auto overflow-y:auto overlaps override overrides overscroll-contain overwrite own owned p p-0 p-hsp-2xs p-hsp-lg p-hsp-md p-hsp-sm p-hsp-xl pack pack-scoped package package-default package-injected package-owned packages packs padding page page-loading page-loading-overlay page-loading-spinner page-navigate-end page-title page-wide pages pages/. paint paint-and-read palette pan panel panels paren-balance-aware parent parse parsed parser parses part pass passed passes patch path paths pattern payload payload-budget pb-[50vh] pb-vsp-2xs pb-vsp-lg pb-vsp-md pb-vsp-xl pb-vsp-xs pdf peer peer-focus-visible:border-accent peer-focus-visible:text-accent peer-hover:border-accent peer-hover:text-accent pending per per-block per-link per-package per-release permanently persisted persistence php pi pick picked picks picocolors pins pipelines pl-[1.25rem] pl-hsp-lg pl-hsp-md pl-hsp-sm pl-hsp-xl place place-items-center placeholder placeholder:text-muted plain plural plus png png16 png32 pnpm point pointer pointer-events-none pointercancel pointerdown pointermove pointerup policy polite polygon polyline popover populates port position position:fixed pr-hsp-lg pr-hsp-md pr-hsp-sm pr-hsp-xl pr-hsp-xs pre pre-lowercased preact preact/compat preact/hooks preact/jsx-runtime preconnect preference prefix preload pres present preserving preview preview-swatch-color previews2026 previously primary print prior private produce produced produces producing production profiles project project-owned project-root-relative properties property props prose provided proxy pt-[0.15rem] pt-[2px] pt-vsp-3xs pt-vsp-md pt-vsp-sm pt-vsp-xl pt-vsp-xs ptag- public purely puts px px-hsp-2xl px-hsp-2xs px-hsp-lg px-hsp-md px-hsp-sm px-hsp-xl px-hsp-xs py py-0 py-[2px] py-[4px] py-[calc(var(--spacing-vsp-xs)+0.15rem)] py-hsp-2xs py-hsp-3xs py-hsp-sm py-hsp-xs py-vsp-2xs py-vsp-3xs py-vsp-lg py-vsp-md py-vsp-sm py-vsp-xl py-vsp-xs python q qt query question quick r radius radius-full radius-lg rail ramp range rar rather raw rb re-encode/decode re-exports re-init re-initialized re-querying re-render re-renders re-run re-running re-runs re-selects re-syncs reach reached reaches read reader reader-facing reading readings reads/rewrites real real-value received receives recorded recovers rect redefine redistribution ref- reference referenced references refetch refresh refreshes refusing regardless regenerate regenerates regex registry reinit reinits rejected rel relative release released releases reload relying rem remapped remembered remove remove/rename removed removing rename render rendered renderer renderers renders reorder repaint repair repeated repeating replace replaced replacement replaces repopulate report repository republished requested require required requires reserved resize resize-x resolve resolved resolves responded response restore restores restyle result result-click results results-area retry return returns rev-parse reveal revision revisions rewire rewrite rewrites right right- right-0 right-hsp-lg ring-2 ring-accent risking ro robots role roles root rotate-180 rotate-90 round round-trip rounded rounded-[0.75rem] rounded-bl-[0.25rem] rounded-bl-[1rem] rounded-bl-lg rounded-br-[0.25rem] rounded-br-[1rem] rounded-full rounded-lg rounded-md rounded-t-[1rem] rounds route routed router routes routes-src routes/sitemap.xml row row-span-2 row-start-1 row-start-2 rs ruby rule rules run running runs runtime rust s safe safely safer same same-locale samp sans sans-serif scale scanned scanning scheme scoped scoping score scored script script- script-eval script-evaluation script-injection scripts scroll scrollbar scrolled scrollend scrolling scss seam search search-index section section- see seed segment segments sehen select select-none selection-bg selection-fg selector self self-contained self-hosted self-start self-stretch semantic semibold semver sentinel separator serialised serialize server server-rendered session set sets setting settles setup sh shadow shadow-[0_1px_3px_color-mix(in_srgb,var(--color-fg)_8%,transparent)] shadow-lg shadow-md shadowed shape share shared sharing shell ship shipped ships short shortcut should show shown shrink-0 sidebar sidebar- sidebar-toggle-island sidebar-tree-island sidebar-w sidecar signal silently similarity simple since single single-line single-object-literal singular site site-search site-tree-nav-island sitemap- sites size size-icon-lg skill skills skipped skipping skips slash slot slug slug-dir-parity slugs sm:block sm:border sm:border-muted sm:col-start-2 sm:flex sm:flex-row sm:gap-x-hsp-xl sm:grid sm:grid-cols-2 sm:grid-cols-[minmax(0,1fr)_auto] sm:grid-cols-subgrid sm:h-auto sm:hidden sm:items-center sm:justify-between sm:max-h-[80vh] sm:max-w-[52rem] sm:mr-0 sm:mx-auto sm:my-[10vh] sm:rounded-lg sm:row-span-2 sm:row-start-1 small smol-toml smooth snapping snapshot snapshots so soft soft-nav solid some somehow sort source sources space-y-vsp-2xs space-y-vsp-lg space-y-vsp-sm spacing spacing-0 spacing-px span spans spec specifiers specify spelling splitter spread spurious sql square sr-only src stable stack stale standalone start state state- state:state- statement status stay staying sticky still stock stop stops stored straddles stray strict string strings strip stripe strips stroke-linecap stroke-linejoin stroke-width strong stronger stub-rendered style style-attribute styled styles stylesheet sub subagents subsequent substitute substitution subtracting success successful summary sup supply supported surface surfaces survives svg swap swapped swaps swift switcher switching symlink synchronous synchronously syntactically syntax t tab tab-item tab-panel tabindex table tablist tabpanel tabs tabs-container tabs-content tabs-nav tabular-nums tag tag- tag-item- tagged tags tags:audit take tar tbody td temp-element template temporary temporary-element terminal terms test-results tested text text-accent text-bg text-body text-caption text-center text-chat-assistant-text text-chat-user-text text-code-fg text-danger text-decoration text-display text-fg text-fg/60 text-heading text-info text-left text-micro text-muted text-muted/50 text-right text-scale-2xl text-scale-2xs text-scale-lg text-scale-md text-scale-sm text-scale-xl text-scale-xs text-small text-title text-warning text/css text/csv text/html text/javascript text/jsx text/markdown text/mdx text/plain text/tab-separated-values text/tsx text/typescript text/x-c text/x-csharp text/x-go text/x-java-source text/x-kotlin text/x-python text/x-ruby text/x-rust text/x-scss text/x-shellscript text/x-swift textarea tfoot tgz th than that the thead their them theme theme-color theme-pack theme-pack-changed theme-packs theme-packs/index.json theme-toggle theme/token then there these they this those though three threw through throw throws tighten time timeline tip title tkhd to toast toc toggle toggle-ai-chat toggle-design-token-panel toggles toggling token tokens tolerates toml too toolbar tooltip top top-0 top-[3.5rem] top-full top-hsp-2xs top-level total touches tr tracked tracking-wide tracking-wider trade-off trailing transferred transition transition-[background,color,border-color] transition-[left,color] transition-[right,color] transition-colors transition-transform translate-x-0 translated translations transparent tray treats tree tree-child- tree-item- tree-top- trigger trigger:ai-chat trigger:design-token-panel triggers true truncate truncated try ts tsv tsx turn twitter:card twitter:creator twitter:description twitter:image twitter:site twitter:title two txt type typeface typeof typescript typography u ul umschalten unable unavailable unbalanced unchanged und undefined under underline underlines understand unit-tested unknown unlike unlisted unmaintained unmatchable unobserve unreadable unrelated unreleased unresolvable unresolved unset unsupported unterminated until unusable unwrapped up up-to-date update updated uppercase use used useful user uses using usual utf-8 utf8 utilities utility v v2 val value value-reader values var variable variant verbatim version version- version-menu version-switcher versions vertical via video video/mp4 video/quicktime video/webm viewer viewing viewport viewports virtual:zudo-doc-asset-bodies virtual:zudo-doc-chrome-bindings virtual:zudo-doc-design-token-panel-config virtual:zudo-doc-route-context visibility visible vocabulary void von vsp vsp-2xl vsp-2xs vsp-3xs vsp-lg vsp-md vsp-sm vsp-xl vsp-xs w w-1/2 w-[0.5rem] w-[0.625rem] w-[0.875rem] w-[1.125rem] w-[1.575rem] w-[1.5rem] w-[1.75rem] w-[12rem] w-[14px] w-[16px] w-[16rem] w-[18px] w-[1em] w-[2.5rem] w-[280px] w-[2rem] w-[320px] w-[360px] w-[6.5rem] w-[90vw] w-[calc(100vw-2rem)] w-[var(--zd-sidebar-w)] w-dvw w-full w-icon-lg w-icon-md w-icon-sm w-icon-xs walk walks want warn warning was watching way wbr wbr- we webm webp website weight went were what when where whereas whether which while whitespace-nowrap whitespace-pre whole whose wide wide-gamut wider-than-scrollbar width will window wins wird wired with without word wordmark working works worktrees would wrap wrapped wrapper wrappers wrapping wraps writing written wrong wrote wurde x xl:flex xl:hidden xml y-scrollbar yaml year yet yielded yields yml you your z-dropdown z-local-1 z-modal z-modal-backdrop z-popover z-sidebar z-toolbar zd-asset-code zd-asset-details-rail zd-asset-details-toggle zd-asset-filebar zd-asset-media-grid zd-asset-media-rail zd-asset-page zd-asset-pdf zd-asset-stage zd-content zd-desktop-sidebar-toggle zd-desktop-toc-toggle zd-doc-content-band zd-enlarge-btn zd-enlarge-dialog zd-enlarge-dialog-close zd-enlargeable zd-html-preview-code zd-mermaid-dialog zd-mermaid-enlargeable zd-mermaid-tool-btn zd-mermaid-toolbar zd-mermaid-transform zd-mermaid-viewport zd-sidebar-content-wrapper zd-sidebar-open zd-theme-pack-dialog-title zd-toc-col zdtp zfb zfb:after-swap zfb:before-preparation zfb:before-swap zip zod zoom zudo-design-tokens/v3 zudo-doc zudo-doc-asset-details-visible zudo-doc-code-wrap zudo-doc-design-token-panel-modal zudo-doc-design-tokens zudo-doc-sidebar-visible zudo-doc-sidebar-width zudo-doc-theme zudo-doc-theme-pack zudo-doc-toc-visible zudo-doc-tweak zum");
2
+ @source inline("-domtweaker-enabled -elpath-enabled -left-[calc(var(--spacing-icon-lg)/2)] -link -mb-px -ml-hsp-sm -mt-px -noscript -open -state -state-v2 -state-v3 -state-v4 -translate-x-full 2xl:w-[24px] [&::-webkit-details-marker]:hidden [&_a]:pointer-events-auto [&_a]:text-accent [&_a]:underline [&_li]:mb-0 [&_nav]:mb-0 [asset-viewer] [data-admonition] [data-kbd-shortcut] [data-switcher-launcher] [doc-history-meta] [doc-history] [doc-layout] [llms-txt] [zudo-doc] a a2 abbr about above absent absolute accent accent- accent:accent- access across activated active actual actually added admonition admonition- admonition-body admonition-title admonition/callout after after-breadcrumb after-content after-navigate after-sidebar after-title against agent agents ai-chat ai-chat-md ai-chat-trigger alert align-top all allow allow-same-origin allow-scripts allowed alone already already-executed already-multiline already-picked also always an anchor and and/or animate-pulse animate-spin announce ansehen antialiased any anywhere anzeigen app appear application/json application/octet-stream application/pdf application/sql application/toml application/x-httpd-php application/xml application/yaml applied applies apply applying approach approval are area arg argument aria-atomic aria-busy aria-controls aria-current aria-disabled aria-expanded aria-haspopup aria-hidden aria-label aria-labelledby aria-live aria-orientation aria-pressed aria-selected aria-valuemax aria-valuemin aria-valuenow arm arms around arrows article as asc ascii aside aspect-[1200/630] aspect-square asset asset- asset-components assets assets/client assistant async at at-rule attach attribute attributes auf authored auto auto-logo-mask autogenerated availability available avc1 avif avis avoid await away b back backdrop:bg-bg/30 backdrop:bg-bg/80 backdrop:bg-overlay/60 backdrop:z-modal-backdrop background background-color backtick backticks baked band banner bar bare base base- base64 base:base- based bash batch be bearbeiten because becomes been before below best best-effort between bg bg-[#fff] bg-accent bg-bg bg-chat-assistant-bg bg-chat-user-bg bg-code-bg bg-fg bg-info/10 bg-info/5 bg-muted bg-overlay/30 bg-surface bg-surface/50 bg-transparent bg-warning/10 bg-warning/5 bi big bigint bin binaries bind binding blank blanks block blockquote blocks blur bodies body body-end-components body-end-scripts bold boolean bootstrap border border-accent border-b border-b-2 border-b-[5px] border-bg/30 border-collapse border-danger border-dashed border-fg border-image border-info/30 border-l border-l-0 border-l-[3px] border-left-width border-muted border-none border-r border-r-0 border-radius border-solid border-t border-t-[2px] border-t-[3px] border-transparent border-warning/30 border-width border-y both bottom-hsp-lg bottom-vsp-xl boundaries box box-border br brackets brand breadcrumb:end breadcrumb:start break-words brief brown browser browser-tab browsers browses btn budget bug build builder built built-in bundler but button buttons by bypassed byte-identical bytes c cache cached calendar-valid call callable called caller calls can cancellation candidate cannot canonical canvas caption captured captures card card-grid cards carry case-insensitive cases cat-nav- catalog catch categories category caught caution center center/contain ch chains change changed changelog changelogs changes characters check checker child children choose chrome chrome-font ci circle cite cjs class class-less class-mode claude claude-agents claude-commands claude-md claude-resources claude-skills cleaned cleanly clear clearing click client client-router client-side clip clobber clobbering close closed closes closing closure code code-block-sr-announce code-group code-group-panel codex codex-agents codex-agents-md codex-config codex-hooks codex-resources codex-rules codex-skills col col-resize col-span-full col-start-1 colgroup collapse collapses collapsible collision color color-scheme color-scheme-changed color-scheme-provider color-tweak colorization colors column comma command commands commas comment commercial commercial-font-denylist commit compare complete component component:github-link component:language-switcher component:search component:theme-toggle component:version-switcher composes composition compute computed concrete conf config configuration configurations configure configured conflicting conflicts confuse connect const construction consumer consumes contain container containers containing contains content content-admonition content-layer content-link content-type content-wrapper:end content-wrapper:start contents context contract control controller controls converts cookie-blocking copied copy copy-url core corners correct correctly corrupt could count covered covers cpp crashes created cross-component crumb- cs csharp css css-presence csv ctx cur current current-path/index.ts current-route currently cursor cursor-not-allowed cursor-pointer custom cycle d danger dark dash data data-active data-admonition data-asset-details-hidden data-auto-logo data-base data-close-search data-current-locale data-default-locale data-doc-date data-doc-description data-doc-metainfo data-doc-pager data-doc-unavailable-versions data-find-active data-find-match data-footer data-group-id data-header data-header-logo data-header-nav data-header-right data-kbd-shortcut data-lang data-language-menu data-language-switcher data-language-toggle data-loading-index data-mermaid-enlarge-ready data-mermaid-rendered data-mermaid-src data-nav-active data-nav-category data-nav-item data-nav-item-dropdown data-nav-more data-nav-more-menu data-nav-more-toggle data-no-results data-note-tray-group data-note-tray-row data-open-search data-pan-active data-processed data-props data-result-count-template data-search-count data-search-count-narrow data-search-dialog data-search-input data-search-placeholder data-search-results data-search-unavailable data-sidebar-hidden data-sidebar-resizer data-site-nav data-switcher-card data-switcher-launcher data-tab-btn data-tab-default data-tab-label data-tab-value data-tabs data-taglist-group data-testid data-theme data-theme-pack data-theme-pack-switcher data-theme/style data-toc-hidden data-trailing-slash data-unavailable-label data-variant data-version-banner data-version-latest data-version-menu data-version-rewire data-version-slug data-version-switcher data-version-toggle data-version-trigger-label data-zd-asset-action data-zd-asset-actions data-zd-asset-details data-zd-asset-details-chevron data-zd-asset-details-list data-zd-asset-details-toggle data-zd-asset-index-action data-zd-asset-index-empty data-zd-asset-index-page data-zd-asset-page data-zd-asset-tree data-zd-copy-url data-zd-html-preview-reservation data-zd-label-collapse data-zd-label-expand data-zd-mobile-sidebar data-zd-mobile-toc data-zd-nav-section data-zd-nosidebar data-zd-pending data-zd-props-preserve data-zd-sidebar-open-key data-zd-theme-pack-css data-zd-theme-pack-css-loading data-zd-theme-pack-loading data-zd-toc data-zd-wide data-zfb-island data-zfb-island-remount data-zfb-reload data-zfb-transition-persist date dated dd decimal decision declaration declare declared declares decoration decoration-muted deepest deepest-match default default-transition-duration defaults deferral deferred del delegated delete deliberately delimiter dependency depends depth der desc description design design-token design-token-panel design-token-trigger desktop desktop-sidebar desktop-sidebar-toggle desktop-sidebar-toggle-island desktop-toc-toggle destroys destructive detach detached details determine deterministic dev dfn diagram diagrams dialog did die dieser diff diff-line-added diff-line-content diff-line-empty diff-line-num diff-line-removed diff-row differ different dir directly directories directory disabled disabled:cursor-default disabled:opacity-50 disabled:pointer-events-none disc display display:none dist distance distinct div dl do doc doc-card- doc-content-band doc-history doc-history-generate doc-history-panel doc-history-trigger doc-page doc-pager doc-prose doc-title docblock docs docs- docs-v- document document-level documentation documented documents does dog dot double-registration download draft drag drawer drift drifts drop dropdown dropdown-parent dropdowns dt duplicate duration duration-150 duration-200 during dynamically e e2e each eager earlier early ease-in-out edge editing einer either eject ejectable ejectables ejected el element elements els else em embedded emit emitting empty empty/undefined en enable enabled end enhanced enhancement enlarged entire entities entries entry entrypoint env equal error escape escaped escapes even event eventually every everything-enabled exactly example exceeds excerpt excludes exclusively existing exists exit expand expected explicit export extends extra f factories failed fall fallback fallbacks falling falls false family fast favicon feature fg field fields fieldset figcaption figure file files fill fills finally find find-match find-match-active fire fires first first-paint first:mt-0 fit fix fixed fixed-width fixtures flag flash flat flex flex-1 flex-col flex-wrap flip flipping flips flow flush-left focus focus-visible:bg-accent/10 focus-visible:border-accent focus-visible:decoration-accent focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2 focus-visible:text-accent focus-visible:underline focus-within:border-accent focus-within:z-local-1 focus:border-accent focus:outline-none focus:text-accent focus:underline folder folders follows font font-bold font-face-parity font-family font-file-missing font-medium font-mono font-sans font-scale font-semibold font-size font-weight font-weight-bold font-weight-medium font-weight-normal font-weight-semibold font/woff2 fonts footer footer- for form format former found four-link fox fragment frame free freeze fresh from frontmatter frontmatter-preview frozen frozen-script fs-extra ftyp full fully function further g gains gap-[0.3em] gap-[clamp(1.5rem,3vw,4rem)] gap-hsp-2xs gap-hsp-lg gap-hsp-md gap-hsp-sm gap-hsp-xl gap-hsp-xs gap-vsp-2xs gap-vsp-3xs gap-vsp-lg gap-vsp-md gap-vsp-xs gap-x-hsp-2xs gap-x-hsp-lg gap-x-hsp-md gap-x-hsp-sm gap-x-hsp-xs gap-y-vsp-2xs gap-y-vsp-3xs gap-y-vsp-lg gap-y-vsp-md gap-y-vsp-xs gaps gate geladen2026 generate generated generation genuine geometry get getting-started gif git github github-dark github-link give go got grab gradient granular graph grid grid-cols-1 grid-cols-2 grid-cols-[auto_1fr] grid-rows-[auto_auto] grid-rows-subgrid group group-focus-visible:decoration-accent group-focus-visible:text-accent group-focus-visible:text-accent-hover group-focus-visible:text-fg group-focus-visible:underline group-focus-within:block group-hover:bg-fg group-hover:block group-hover:decoration-accent group-hover:text-accent group-hover:text-accent-hover group-hover:text-bg group-hover:text-fg group-hover:underline group-open:rotate-90 grouped grouping guard guards gz h h-[0.5rem] h-[0.625rem] h-[0.875rem] h-[1.125rem] h-[1.25rem] h-[1.575rem] h-[10rem] h-[14px] h-[1em] h-[1lh] h-[2.5rem] h-[2rem] h-[3.5rem] h-[3rem] h-[70vh] h-[90vh] h-[calc(100%-3rem)] h-[calc(100vh-3.5rem)] h-dvh h-full h-icon-lg h-icon-md h-icon-sm h-icon-xs h1 h1s h2 h22013h4 h2s h3 h4 h5 h6 half hand-copied hand-editable handle handled handler handlers happens hard-loaded hardcoded has hash-link have head head-links head-scripts header header- header-call:end header-call:start header-right heading heading-h2 heading-h3 heading-h4 heading-rule headings height here hex hi-root hidden hide hierarchical highlight highlighting history home hook hooks hooks-json horizontal host hover:bg-[color-mix(in_srgb,var(--color-surface)_80%,var(--color-fg)_20%)] hover:bg-accent-hover hover:bg-accent/10 hover:bg-danger/10 hover:bg-surface hover:border-accent hover:border-accent-hover hover:border-fg hover:decoration-accent hover:text-accent hover:text-accent-hover hover:text-fg hover:underline hover:z-local-1 hpp hr href hrefs hsp hsp-2xl hsp-2xs hsp-lg hsp-md hsp-sm hsp-xl hsp-xs html i i18n/theme. i2 i3 i4 ico icon icon-lg icon-md icon-sm icon-xs identical idle idx if iframe ignoring image image-enlarge image-overlay-inset image/avif image/gif image/jpeg image/png image/webp image/x-icon img implementation import important important-allowlist imports in inactive includes including incomplete independently index index2026 indirectly info inherit inherited ini initial initialised injected inline inline-block inline-flex inner input input-clear ins inserted-after-color-mode inserted-after-color-scheme inserted-after-site-name inserted-first insertion inset-0 inside inside-only inspect install installation installed instance instanceof instead instructions intended intent intentionally intercept interface internal interpolation into invalid invalidated inverse inversion invocation invoke is is-checker island island-root iso2 iso3 iso4 iso5 iso6 isom ispe issues it italic item item- items items-baseline items-center items-end items-start iteration its itself ja java javascript jpeg jpg js json jsx jumps just justification justify-between justify-center justify-end justify-start katex kbd keep keeping keeps kept key keyboard keyboard-shortcut keydown keys keystroke keyword keywords khroma known-token-names kopieren kotlin kt label landing lands language-menu language-switcher language-toggle larger last:border-b-0 last:pb-0 later latest launch layout lazy leading leading-none leading-normal leading-relaxed leading-snug leading-tight leaf leaf- leak leaves leaving left left-0 left:calc legend legitimate length lets letter-spacing lg lg:block lg:border lg:border-fg lg:border-solid lg:flex lg:flex-col lg:flex-row lg:gap-hsp-xl lg:grid-cols-3 lg:grid-cols-[repeat(auto-fit,minmax(12rem,1fr))] lg:h-[90vh] lg:hidden lg:justify-start lg:m-auto lg:max-h-[90vh] lg:max-w-[52.5rem] lg:ml-[var(--zd-sidebar-w)] lg:pr-hsp-sm lg:pt-vsp-2xl lg:px-hsp-2xl lg:py-vsp-2xl lg:text-left lg:w-[90vw] lg:w-[clamp(16rem,25%,22rem)] li li2 library license lifecycle light light/dark like likely line line-height line/statement lines linger link link- links list list-disc list-none listener lists literal literally literals live lives llms llms-txt load loaded loader loading local local-1 local-2 local-3 locale locales log logo long longer longest-match look loses lostpointercapture lower luminance m m-0 m-auto m10 m14 m16 m21 m6 machinery main major make malformed malformed-markup malicious managed manifest manual manually maps mark markdown marks match matches matching math math-display math-inline max max-h-[85vh] max-h-[90vh] max-h-full max-h-none max-w-[16rem] max-w-[64rem] max-w-[85%] max-w-[85vw] max-w-[90vw] max-w-[calc(100vw-2rem)] max-w-[calc(100vw-var(--spacing-hsp-xl))] max-w-[clamp(50rem,75vw,90rem)] max-w-full max-w-none max-w-sm max-width maximum may mb-0 mb-vsp-2xs mb-vsp-lg mb-vsp-md mb-vsp-sm mb-vsp-xl mb-vsp-xs md mdx means measured measurement measures measuring mechanism menu mermaid message messages meta meta-knob meta-schema metadata migration min-h-0 min-h-[20rem] min-h-[44px] min-h-[60vh] min-h-[calc(100vh-3.5rem)] min-h-screen min-w-0 min-w-[10rem] min-w-[3rem] min-w-[44px] min-w-[8rem] minifier minor mirror mirroring mirrors missing mit mjs ml-[calc(var(--spacing-hsp-xl)+1px)] ml-auto ml-hsp-2xl ml-hsp-lg ml-hsp-md ml-hsp-sm ml-hsp-xl mobile mod modal modal-backdrop mode model modify module moment monospace month more most mount mounted mouseenter mouseleave mov move mp4 mp41 mp42 mr-[calc(var(--spacing-hsp-xl)+1px)] mr-hsp-sm ms mt-0 mt-vsp-2xl mt-vsp-2xs mt-vsp-3xs mt-vsp-lg mt-vsp-md mt-vsp-sm mt-vsp-xl mt-vsp-xs multi-changelog multiple must mutates mutation mutations muted mvhd mx-auto my-vsp-lg my-vsp-md n name named names native natural nav nav-active nav-card- nav/doc navigating navigation navigations near needed needs neither nested neutral never new newly-swapped next nicht no no-color-scheme no-data-theme-selector no-enlarge no-op no-repeat no-underline noch node node:buffer node:fs node:fs/promises node:module node:path node:url node:util nodes nofollow noindex non-draggable non-empty non-index non-light-dark non-literal non-null non-persisted none noopener noreferrer normal noscript not notable note note-tray notes now null number numeric object object-contain observe observer occurred of off offered offsets ofl-required og:description og:image og:image:alt og:image:height og:image:width og:title og:type og:url oklch ol old older omit omitting on once one only onto opacity-60 open open/close option or order original other others otherwise out outgoing outline-none over overflow overflow-auto overflow-hidden overflow-x-auto overflow-y-auto overflow-y:auto overlaps override overrides overscroll-contain overwrite own owned p p-0 p-hsp-2xs p-hsp-lg p-hsp-md p-hsp-sm p-hsp-xl pack pack-scoped package package-default package-injected package-owned packages packs padding page page-loading page-loading-overlay page-loading-spinner page-navigate-end page-title page-wide pages pages/. paint paint-and-read palette pan panel panels paren-balance-aware parent parse parsed parser parses part pass passed passes patch path paths pattern payload payload-budget pb-[50vh] pb-vsp-2xs pb-vsp-lg pb-vsp-md pb-vsp-xl pb-vsp-xs pdf peer peer-focus-visible:border-accent peer-focus-visible:text-accent peer-hover:border-accent peer-hover:text-accent pending per per-block per-link per-package per-release permanently persisted persistence php pi pick picked picks picocolors pins pipelines pl-[1.25rem] pl-hsp-lg pl-hsp-md pl-hsp-sm pl-hsp-xl place place-items-center placeholder placeholder:text-muted plain plural plus png png16 png32 pnpm point pointer pointer-events-none pointercancel pointerdown pointermove pointerup policy polite polygon polyline popover populates port position position:fixed pr-hsp-lg pr-hsp-md pr-hsp-sm pr-hsp-xl pr-hsp-xs pre pre-lowercased preact preact/compat preact/hooks preact/jsx-runtime preconnect preference prefix preload pres present preserving preview preview-swatch-color previews2026 previously primary print prior private produce produced produces producing production profiles project project-owned project-root-relative properties property props prose provided proxy pt-[0.15rem] pt-[2px] pt-vsp-3xs pt-vsp-md pt-vsp-sm pt-vsp-xl pt-vsp-xs ptag- public purely puts px px-hsp-2xl px-hsp-2xs px-hsp-lg px-hsp-md px-hsp-sm px-hsp-xl px-hsp-xs py py-0 py-[2px] py-[4px] py-[calc(var(--spacing-vsp-xs)+0.15rem)] py-hsp-2xs py-hsp-3xs py-hsp-sm py-hsp-xs py-vsp-2xs py-vsp-3xs py-vsp-lg py-vsp-md py-vsp-sm py-vsp-xl py-vsp-xs python q qt query question quick r radius radius-full radius-lg rail ramp range rar rather raw rb re-encode/decode re-exports re-init re-initialized re-querying re-render re-renders re-run re-running re-runs re-selects re-syncs reach reached reaches read reader reader-facing reading readings reads/rewrites real real-value received receives recorded recovers rect redefine redistribution ref- reference referenced references refetch refresh refreshes refusing regardless regenerate regenerates regex registry reinit reinits rejected rel relative release released releases reload relying rem remapped remembered remove remove/rename removed removing rename render rendered renderer renderers renders reorder repaint repair repeated repeating replace replaced replacement replaces repopulate report repository republished requested require required requires reserved resize resize-x resolve resolved resolves responded response restore restores restyle result result-click results results-area retry return returns rev-parse reveal revision revisions rewire rewrite rewrites right right- right-0 right-hsp-lg ring-2 ring-accent risking ro robots role roles root rotate-180 rotate-90 round round-trip rounded rounded-[0.75rem] rounded-bl-[0.25rem] rounded-bl-[1rem] rounded-bl-lg rounded-br-[0.25rem] rounded-br-[1rem] rounded-full rounded-lg rounded-md rounded-t-[1rem] rounds route routed router routes routes-src routes/sitemap.xml row row-span-2 row-start-1 row-start-2 rs ruby rule rules run running runs runtime rust s safe safely safer same same-locale samp sans sans-serif scale scanned scanning scheme scoped scoping score scored script script- script-eval script-evaluation script-injection scripts scroll scrollbar scrolled scrollend scrolling scss seam search search-index section section- see seed segment segments sehen select select-none selection-bg selection-fg selector self self-contained self-hosted self-start self-stretch semantic semibold semver sentinel separator serialised serialize server server-rendered session set sets setting settles setup sh shadow shadow-[0_1px_3px_color-mix(in_srgb,var(--color-fg)_8%,transparent)] shadow-lg shadow-md shadowed shape share shared sharing shell ship shipped ships short shortcut should show shown shrink-0 sidebar sidebar- sidebar-toggle-island sidebar-tree-island sidebar-w sidecar signal silently similarity simple since single single-line single-object-literal singular site site-search site-tree-nav-island sitemap- sites size size-icon-lg skill skills skipped skipping skips slash slot slug slug-dir-parity slugs sm:block sm:border sm:border-muted sm:col-start-2 sm:flex sm:flex-row sm:gap-x-hsp-xl sm:grid sm:grid-cols-2 sm:grid-cols-[minmax(0,1fr)_auto] sm:grid-cols-subgrid sm:h-auto sm:hidden sm:items-center sm:justify-between sm:max-h-[80vh] sm:max-w-[52rem] sm:mr-0 sm:mx-auto sm:my-[10vh] sm:rounded-lg sm:row-span-2 sm:row-start-1 small smol-toml smooth snapping snapshot snapshots so soft soft-nav solid some somehow sort source sources space-y-vsp-2xs space-y-vsp-lg space-y-vsp-sm spacing spacing-0 spacing-px span spans spec specifiers specify spelling splitter spread spurious sql square sr-only src stable stack stale standalone start state state- state:state- statement status stay staying sticky still stock stop stops stored straddles stray strict string strings strip stripe strips stroke-linecap stroke-linejoin stroke-width strong stronger stub-rendered style style-attribute styled styles stylesheet sub subagents subsequent substitute substitution subtracting success successful summary sup supply supported surface surfaces survives svg swap swapped swaps swift switcher switching symlink synchronous synchronously syntactically syntax t tab tab-item tab-panel tabindex table tablist tabpanel tabs tabs-container tabs-content tabs-nav tabular-nums tag tag- tag-item- tagged tags tags:audit take tar tbody td temp-element template temporary temporary-element terminal terms test-results tested text text-accent text-bg text-body text-caption text-center text-chat-assistant-text text-chat-user-text text-code-fg text-danger text-decoration text-display text-fg text-fg/60 text-heading text-info text-left text-micro text-muted text-muted/50 text-right text-scale-2xl text-scale-2xs text-scale-lg text-scale-md text-scale-sm text-scale-xl text-scale-xs text-small text-title text-warning text/css text/csv text/html text/javascript text/jsx text/markdown text/mdx text/plain text/tab-separated-values text/tsx text/typescript text/x-c text/x-csharp text/x-go text/x-java-source text/x-kotlin text/x-python text/x-ruby text/x-rust text/x-scss text/x-shellscript text/x-swift textarea tfoot tgz th than that the thead their them theme theme-color theme-pack theme-pack-changed theme-packs theme-packs/index.json theme-toggle theme/token then there these they this those though three threw through throw throws tighten time timeline tip title tkhd to toast toc toggle toggle- toggle-ai-chat toggle-design-token-panel toggles toggling token tokens tolerates toml too toolbar tooltip top top-0 top-[3.5rem] top-full top-hsp-2xs top-level total touches tr tracked tracking-wide tracking-wider trade-off trailing transferred transition transition-[background,color,border-color] transition-[left,color] transition-[right,color] transition-colors transition-transform translate-x-0 translated translations transparent tray treats tree tree-child- tree-item- tree-top- trigger trigger:ai-chat trigger:design-token-panel triggers true truncate truncated try ts tsv tsx turn twitter:card twitter:creator twitter:description twitter:image twitter:site twitter:title two txt type typeface typeof typescript typography u ul umschalten unable unavailable unbalanced unchanged und undefined under underline underlines understand unit-tested unknown unlike unlisted unmaintained unmatchable unobserve unreadable unrelated unreleased unresolvable unresolved unset unsupported unterminated until unusable unwrapped up up-to-date update updated uppercase use used useful user uses using usual utf-8 utf8 utilities utility v v2 val value value-reader values var variable variant verbatim version version- version-menu version-switcher versions vertical via video video/mp4 video/quicktime video/webm viewer viewing viewport viewports virtual:zudo-doc-asset-bodies virtual:zudo-doc-chrome-bindings virtual:zudo-doc-design-token-panel-config virtual:zudo-doc-route-context visibility visible vocabulary void von vsp vsp-2xl vsp-2xs vsp-3xs vsp-lg vsp-md vsp-sm vsp-xl vsp-xs w w-1/2 w-[0.5rem] w-[0.625rem] w-[0.875rem] w-[1.125rem] w-[1.575rem] w-[1.5rem] w-[1.75rem] w-[12rem] w-[14px] w-[16px] w-[16rem] w-[18px] w-[1em] w-[2.5rem] w-[280px] w-[2rem] w-[320px] w-[360px] w-[6.5rem] w-[90vw] w-[calc(100vw-2rem)] w-[var(--zd-sidebar-w)] w-dvw w-full w-icon-lg w-icon-md w-icon-sm w-icon-xs walk walks want warn warning was watching way wbr wbr- we webm webp website weight went were what when where whereas whether which while whitespace-nowrap whitespace-pre whole whose wide wide-gamut wider-than-scrollbar width will window wins wird wired with without word wordmark working works worktrees would wrap wrapped wrapper wrappers wrapping wraps writing written wrong wrote wurde x xl:flex xl:hidden xml y-scrollbar yaml year yet yielded yields yml you your z-dropdown z-local-1 z-modal z-modal-backdrop z-popover z-sidebar z-toolbar zd-asset-code zd-asset-details-rail zd-asset-details-toggle zd-asset-filebar zd-asset-media-grid zd-asset-media-rail zd-asset-page zd-asset-pdf zd-asset-stage zd-content zd-desktop-sidebar-toggle zd-desktop-toc-toggle zd-doc-content-band zd-enlarge-btn zd-enlarge-dialog zd-enlarge-dialog-close zd-enlargeable zd-html-preview-code zd-mermaid-dialog zd-mermaid-enlargeable zd-mermaid-tool-btn zd-mermaid-toolbar zd-mermaid-transform zd-mermaid-viewport zd-sidebar-content-wrapper zd-sidebar-open zd-theme-pack-dialog-title zd-toc-col zdtp zfb zfb:after-swap zfb:before-preparation zfb:before-swap zip zod zoom zudo-design-token-panel zudo-design-tokens/v3 zudo-doc zudo-doc-asset-details-visible zudo-doc-code-wrap zudo-doc-design-token-panel-modal zudo-doc-design-tokens zudo-doc-sidebar-visible zudo-doc-sidebar-width zudo-doc-theme zudo-doc-theme-pack zudo-doc-toc-visible zudo-doc-tweak zum");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takazudo/zudo-doc",
3
- "version": "5.18.1",
3
+ "version": "5.19.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",
@@ -720,7 +720,7 @@
720
720
  "typescript": "^5.0.0",
721
721
  "vitest": "^4.1.0",
722
722
  "zod": "^4.3.6",
723
- "@takazudo/zudo-doc-history-server": "5.18.1"
723
+ "@takazudo/zudo-doc-history-server": "5.19.0"
724
724
  },
725
725
  "scripts": {
726
726
  "gen:search-widget-script": "node scripts/gen-search-widget-script.mjs",