@takazudo/zudo-doc 8.1.3 → 9.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 (64) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +6 -5
  3. package/dist/ai-chat-modal/index.js +1 -0
  4. package/dist/catalog.js +1 -1
  5. package/dist/chrome/derive.js +2 -2
  6. package/dist/compiled.css +109 -3
  7. package/dist/config.d.ts +13 -7
  8. package/dist/config.js +6 -0
  9. package/dist/design-token-panel-bootstrap-island.d.ts +1 -1
  10. package/dist/features.css +110 -0
  11. package/dist/footer/footer.js +1 -1
  12. package/dist/head-with-defaults/index.js +2 -2
  13. package/dist/html-preview-wrapper/preview-base.js +2 -2
  14. package/dist/icons/index.d.ts +2 -0
  15. package/dist/icons/index.js +36 -0
  16. package/dist/metainfo/doc-tags.js +3 -0
  17. package/dist/nav-indexing/tag-nav.js +7 -1
  18. package/dist/nav-scope/index.d.ts +1 -1
  19. package/dist/nav-scope/index.js +7 -8
  20. package/dist/page-loading/page-loading-overlay.d.ts +5 -1
  21. package/dist/page-loading/page-loading-overlay.js +1 -1
  22. package/dist/page-loading.css +2 -1
  23. package/dist/plugins/zdtp-loader.d.ts +1 -0
  24. package/dist/plugins/zdtp-loader.js +5 -1
  25. package/dist/preset.d.ts +10 -4
  26. package/dist/preset.js +11 -1
  27. package/dist/route-context-payload/index.d.ts +4 -1
  28. package/dist/route-context-payload/index.js +6 -0
  29. package/dist/settings-defaults.js +3 -1
  30. package/dist/settings.d.ts +9 -5
  31. package/dist/sidebar-tree-island/branch-preview.d.ts +19 -0
  32. package/dist/sidebar-tree-island/branch-preview.js +199 -0
  33. package/dist/sidebar-tree-island/index.js +82 -33
  34. package/dist/sidebar-tree-island/scope-state.d.ts +15 -6
  35. package/dist/sidebar-tree-island/scope-state.js +30 -9
  36. package/dist/sidebar-utils/index.js +5 -2
  37. package/dist/theme/theme-pack-provider.d.ts +4 -2
  38. package/dist/theme/theme-pack-provider.js +2 -1
  39. package/dist/theme-cli/config-io.js +26 -3
  40. package/dist/theme-cli/list.js +1 -1
  41. package/dist/theme-packs/default/meta.json +2 -2
  42. package/dist/theme-packs/graphite/meta.json +37 -0
  43. package/dist/theme-packs/graphite/pack.css +401 -0
  44. package/dist/theme-packs/quiet-slate/meta.json +37 -0
  45. package/dist/theme-packs/quiet-slate/pack.css +401 -0
  46. package/dist/theme-packs/warm-mineral/meta.json +37 -0
  47. package/dist/theme-packs/warm-mineral/pack.css +401 -0
  48. package/dist/theme-packs-registry/configured-theme-pack.d.ts +21 -0
  49. package/dist/theme-packs-registry/configured-theme-pack.js +13 -0
  50. package/dist/theme-packs-registry/index.d.ts +1 -0
  51. package/dist/theme-packs-registry/index.js +6 -0
  52. package/dist/theme-packs-registry/resolve-enabled-packs.d.ts +13 -6
  53. package/dist/theme-packs-registry/resolve-enabled-packs.js +15 -5
  54. package/dist/tree-nav-shared/index.d.ts +5 -1
  55. package/dist/tree-nav-shared/index.js +7 -3
  56. package/dist/wind.json +6 -1
  57. package/dist/zdtp-loader.d.ts +1 -1
  58. package/eject/footer/footer.tsx +1 -1
  59. package/eject/header/gen-nav-overflow-script.mjs +2 -2
  60. package/eject/page-loading/page-loading-overlay.tsx +7 -3
  61. package/eject/sidebar-tree-island/branch-preview.ts +247 -0
  62. package/eject/sidebar-tree-island/index.tsx +86 -19
  63. package/eject/sidebar-tree-island/scope-state.ts +40 -10
  64. package/package.json +21 -20
package/dist/features.css CHANGED
@@ -1350,3 +1350,113 @@ site-search [data-search-results] > :is([data-search-placeholder], p) {
1350
1350
  .zd-theme-pack-active-ring {
1351
1351
  box-shadow: 0 0 0 2px var(--color-accent);
1352
1352
  }
1353
+
1354
+ /* ========================================
1355
+ * Sidebar branch focus preview (frame + branch preview)
1356
+ *
1357
+ * Hovering (mouse/pen) or keyboard-focusing a category's focus frame marks
1358
+ * exactly that branch wrapper `[data-sidebar-preview]` (one per sidebar
1359
+ * instance — see sidebar-tree-island/branch-preview.ts). Every treatment is
1360
+ * paint-only: background, inset box-shadow and border-color. Nothing here may
1361
+ * change box geometry, or the preview would shift rows.
1362
+ *
1363
+ * The wash and leading rule live on the wrapper's own background layer, so the
1364
+ * current-page row's `bg-fg` fill paints over them and stays readable.
1365
+ * ======================================== */
1366
+ [data-sidebar-preview] {
1367
+ background-color: color-mix(in oklch, var(--color-accent) 3%, transparent);
1368
+ box-shadow: inset 2px 0 0 var(--color-accent);
1369
+ }
1370
+
1371
+ [data-sidebar-preview] > [data-sidebar-row]:not([data-sidebar-current]) {
1372
+ background-color: color-mix(in oklch, var(--color-accent) 7%, transparent);
1373
+ }
1374
+
1375
+ [data-sidebar-preview] > [data-sidebar-row]:not([data-sidebar-current]) [data-sidebar-focus] {
1376
+ color: var(--color-accent);
1377
+ background-color: color-mix(in oklch, var(--color-accent) 7%, transparent);
1378
+ }
1379
+
1380
+ /* Only connectors inside the previewed subtree — never the row's own elbow to
1381
+ * its parent, which belongs to the ancestor. */
1382
+ [data-sidebar-preview] > [data-sidebar-children] [data-tree-connector] {
1383
+ border-color: var(--color-accent);
1384
+ }
1385
+
1386
+ /* Scope arrival: a brief wash on the newly focused root row. */
1387
+ [data-sidebar-arrived] > [data-sidebar-row]:not([data-sidebar-current]) {
1388
+ animation: zd-sidebar-arrival 700ms ease-out;
1389
+ }
1390
+
1391
+ @keyframes zd-sidebar-arrival {
1392
+ 0%,
1393
+ 22% {
1394
+ background-color: color-mix(in oklch, var(--color-accent) 12%, transparent);
1395
+ box-shadow: inset 2px 0 0 var(--color-accent);
1396
+ }
1397
+ 100% {
1398
+ background-color: transparent;
1399
+ box-shadow: inset 0 0 0 transparent;
1400
+ }
1401
+ }
1402
+
1403
+ @media (prefers-reduced-motion: reduce) {
1404
+ [data-sidebar-arrived] > [data-sidebar-row]:not([data-sidebar-current]) {
1405
+ animation: none;
1406
+ }
1407
+ }
1408
+
1409
+ /* Touch target: a one-tap focus frame at a comfortable size. */
1410
+ @media (pointer: coarse) {
1411
+ /* Out-specifies the frame's w-/h- utilities, which are emitted after this file. */
1412
+ [data-sidebar-row] [data-sidebar-focus] {
1413
+ width: 2.5rem;
1414
+ height: 2.75rem;
1415
+ }
1416
+ }
1417
+
1418
+ /* Transient tooltip for the focus frame and Restore. Appended to <body> so the
1419
+ * sidebar's scroll viewport and the drawer's transform cannot clip it. */
1420
+ [data-sidebar-tooltip] {
1421
+ position: fixed;
1422
+ z-index: var(--z-index-tooltip);
1423
+ max-width: min(18rem, calc(100vw - 1rem));
1424
+ padding: var(--spacing-vsp-2xs) var(--spacing-hsp-sm);
1425
+ border-radius: var(--radius-DEFAULT);
1426
+ background-color: var(--color-fg);
1427
+ color: var(--color-bg);
1428
+ font-size: var(--text-caption);
1429
+ line-height: 1.4;
1430
+ overflow-wrap: anywhere;
1431
+ box-shadow: 0 4px 12px color-mix(in oklch, var(--color-fg) 20%, transparent);
1432
+ }
1433
+
1434
+ [data-sidebar-tooltip][hidden] {
1435
+ display: none;
1436
+ }
1437
+
1438
+ [data-sidebar-tooltip] > strong {
1439
+ display: block;
1440
+ font-weight: 600;
1441
+ }
1442
+
1443
+ [data-sidebar-tooltip] > span {
1444
+ display: block;
1445
+ font-size: var(--text-micro);
1446
+ opacity: 0.8;
1447
+ }
1448
+
1449
+ @media (forced-colors: active) {
1450
+ [data-sidebar-preview] > [data-sidebar-row] {
1451
+ outline: 2px solid Highlight;
1452
+ outline-offset: -2px;
1453
+ }
1454
+
1455
+ [data-sidebar-preview] > [data-sidebar-children] [data-tree-connector] {
1456
+ border-color: Highlight;
1457
+ }
1458
+
1459
+ [data-sidebar-tooltip] {
1460
+ border: 1px solid CanvasText;
1461
+ }
1462
+ }
@@ -51,7 +51,7 @@ function Footer(props) {
51
51
  children: [
52
52
  "#",
53
53
  tag,
54
- /* @__PURE__ */ jsxs("span", { class: "opacity-60", "aria-hidden": "true", children: [
54
+ /* @__PURE__ */ jsxs("span", { "data-zd-tag-count": true, class: "opacity-60", "aria-hidden": "true", children: [
55
55
  "\xA0(",
56
56
  count,
57
57
  ")"
@@ -6,7 +6,7 @@ import ColorSchemeProvider from "../theme/color-scheme-provider.js";
6
6
  import ThemePackProvider, {
7
7
  themePackVersionMap
8
8
  } from "../theme/theme-pack-provider.js";
9
- import { DEFAULT_THEME_PACK_SLUG } from "../theme-pack-switcher/theme-pack-sync.js";
9
+ import { resolveConfiguredThemePack } from "../theme-packs-registry/configured-theme-pack.js";
10
10
  import { renderAutoLogoIconSvg } from "../auto-logo/icon.js";
11
11
  import { deriveComposeMetaTitle, deriveColorSchemeGenerators } from "../chrome/derive.js";
12
12
  import { assertChromeContext } from "../chrome/assert-chrome-context.js";
@@ -99,7 +99,7 @@ function createHeadWithDefaults(ctx) {
99
99
  const { generateCssCustomProperties, generateLightDarkCssProperties } = deriveColorSchemeGenerators(ctx);
100
100
  const themePackRegistry = ctx.themePackRegistry;
101
101
  const themePackEnabled = themePackRegistry !== null ? themePackVersionMap(themePackRegistry) : null;
102
- const themePackConfigured = settings.themePack ?? DEFAULT_THEME_PACK_SLUG;
102
+ const themePackConfigured = resolveConfiguredThemePack(settings);
103
103
  const themePackBase = withBase("/");
104
104
  const faviconLinks = resolveFaviconLinks(settings.favicon, settings.siteName, withBase);
105
105
  function HeadWithDefaults({
@@ -103,7 +103,7 @@ function PreviewBase({
103
103
  "button",
104
104
  {
105
105
  type: "button",
106
- class: computed(() => `min-h-[44px] min-w-[44px] px-hsp-sm py-hsp-2xs text-caption border rounded-full cursor-pointer transition-[background,color,border-color] duration-150 leading-snug ${i === activeViewport.value ? "bg-accent text-bg border-accent hover:bg-accent-hover hover:border-accent-hover" : "bg-transparent text-muted border-muted hover:bg-[color-mix(in_srgb,var(--color-surface)_80%,var(--color-fg)_20%)]"}`),
106
+ class: computed(() => `min-h-[44px] min-w-[44px] px-hsp-sm py-hsp-2xs text-caption border rounded-full cursor-pointer transition-[background,color,border-color] duration-150 leading-snug ${i === activeViewport.value ? "bg-accent text-bg border-accent hover:bg-accent-hover hover:border-accent-hover" : "bg-transparent text-muted border-muted hover:text-fg hover:bg-[color-mix(in_srgb,var(--color-surface)_80%,var(--color-fg)_20%)]"}`),
107
107
  "aria-pressed": computed(() => i === activeViewport.value),
108
108
  "on:click": () => {
109
109
  activeViewport.value = i;
@@ -137,7 +137,7 @@ function PreviewBase({
137
137
  "button",
138
138
  {
139
139
  type: "button",
140
- class: "flex min-h-[44px] min-w-[44px] items-center w-full px-hsp-md py-hsp-sm text-caption font-medium text-muted bg-surface border-none cursor-pointer gap-hsp-xs hover:bg-[color-mix(in_srgb,var(--color-surface)_80%,var(--color-fg)_20%)]",
140
+ class: "flex min-h-[44px] min-w-[44px] items-center w-full px-hsp-md py-hsp-sm text-caption font-medium text-muted bg-surface border-none cursor-pointer gap-hsp-xs hover:text-fg hover:bg-[color-mix(in_srgb,var(--color-surface)_80%,var(--color-fg)_20%)]",
141
141
  "on:click": () => {
142
142
  codeOpen.value = !codeOpen.value;
143
143
  },
@@ -20,3 +20,5 @@ export declare function FileImage({ class: className }: IconProps): Child;
20
20
  export declare function FileVideo({ class: className }: IconProps): Child;
21
21
  export declare function FilePdf({ class: className }: IconProps): Child;
22
22
  export declare function FileArchive({ class: className }: IconProps): Child;
23
+ export declare function FocusFrame({ class: className }: IconProps): Child;
24
+ export declare function RestoreArrow({ class: className }: IconProps): Child;
@@ -334,6 +334,40 @@ function FileArchive({ class: className }) {
334
334
  }
335
335
  );
336
336
  }
337
+ function FocusFrame({ class: className }) {
338
+ return /* @__PURE__ */ jsx(
339
+ "svg",
340
+ {
341
+ class: className || void 0,
342
+ viewBox: "0 0 24 24",
343
+ fill: "none",
344
+ stroke: "currentColor",
345
+ "stroke-width": "1.65",
346
+ "stroke-linecap": "round",
347
+ "stroke-linejoin": "round",
348
+ "aria-hidden": "true",
349
+ focusable: "false",
350
+ children: /* @__PURE__ */ jsx("path", { d: "M8 3H5a2 2 0 0 0-2 2v3m13-5h3a2 2 0 0 1 2 2v3M3 16v3a2 2 0 0 0 2 2h3m8 0h3a2 2 0 0 0 2-2v-3" })
351
+ }
352
+ );
353
+ }
354
+ function RestoreArrow({ class: className }) {
355
+ return /* @__PURE__ */ jsx(
356
+ "svg",
357
+ {
358
+ class: className || void 0,
359
+ viewBox: "0 0 24 24",
360
+ fill: "none",
361
+ stroke: "currentColor",
362
+ "stroke-width": "1.65",
363
+ "stroke-linecap": "round",
364
+ "stroke-linejoin": "round",
365
+ "aria-hidden": "true",
366
+ focusable: "false",
367
+ children: /* @__PURE__ */ jsx("path", { d: "M3 10a9 9 0 1 1 2.6 8.4M3 4v6h6" })
368
+ }
369
+ );
370
+ }
337
371
  export {
338
372
  ArrowLeft,
339
373
  ChevronLeft,
@@ -346,9 +380,11 @@ export {
346
380
  FilePdf,
347
381
  FileText,
348
382
  FileVideo,
383
+ FocusFrame,
349
384
  Folder,
350
385
  FolderOpen,
351
386
  GitHub,
352
387
  History,
388
+ RestoreArrow,
353
389
  Search
354
390
  };
@@ -20,11 +20,13 @@ function DocTags(props) {
20
20
  {
21
21
  href,
22
22
  "aria-label": `${taggedWithLabel}: ${tag}`,
23
+ "data-zd-tag-chip": true,
23
24
  class: "group relative inline-flex no-underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
24
25
  children: [
25
26
  /* @__PURE__ */ jsx(
26
27
  "span",
27
28
  {
29
+ "data-zd-tag-chip-outline": true,
28
30
  class: "absolute inset-0 bg-muted group-hover:bg-fg",
29
31
  style: "clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 50%, calc(100% - 12px) 100%, 0 100%)"
30
32
  }
@@ -32,6 +34,7 @@ function DocTags(props) {
32
34
  /* @__PURE__ */ jsxs(
33
35
  "span",
34
36
  {
37
+ "data-zd-tag-chip-label": true,
35
38
  class: "relative inline-flex items-center text-caption text-fg bg-bg pl-hsp-sm pr-hsp-lg py-vsp-2xs group-hover:text-bg group-hover:bg-fg",
36
39
  style: "clip-path: polygon(1px 1px, calc(100% - 13px) 1px, calc(100% - 1px) 50%, calc(100% - 13px) calc(100% - 1px), 1px calc(100% - 1px))",
37
40
  children: [
@@ -10,11 +10,13 @@ function AllTagChip({
10
10
  {
11
11
  href,
12
12
  "aria-label": `${labels.taggedWith}: ${tag}`,
13
+ "data-zd-tag-chip": true,
13
14
  class: "group relative inline-flex no-underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
14
15
  children: [
15
16
  /* @__PURE__ */ jsx(
16
17
  "span",
17
18
  {
19
+ "data-zd-tag-chip-outline": true,
18
20
  class: "absolute inset-0 bg-muted group-hover:bg-fg",
19
21
  style: "clip-path: polygon(0 0, calc(100% - 16px) 0, 100% 50%, calc(100% - 16px) 100%, 0 100%)"
20
22
  }
@@ -22,6 +24,7 @@ function AllTagChip({
22
24
  /* @__PURE__ */ jsxs(
23
25
  "span",
24
26
  {
27
+ "data-zd-tag-chip-label": true,
25
28
  class: "relative inline-flex items-center text-small text-fg bg-bg pl-hsp-sm pr-hsp-xl py-vsp-2xs group-hover:text-bg group-hover:bg-fg",
26
29
  style: "clip-path: polygon(1px 1px, calc(100% - 17px) 1px, calc(100% - 1px) 50%, calc(100% - 17px) calc(100% - 1px), 1px calc(100% - 1px))",
27
30
  children: [
@@ -29,7 +32,7 @@ function AllTagChip({
29
32
  "#",
30
33
  tag
31
34
  ] }),
32
- /* @__PURE__ */ jsxs("span", { class: "text-caption opacity-60", children: [
35
+ /* @__PURE__ */ jsxs("span", { "data-zd-tag-count": true, class: "text-caption opacity-60", children: [
33
36
  "\xA0(",
34
37
  count,
35
38
  ")"
@@ -51,11 +54,13 @@ function PageTagChip({
51
54
  {
52
55
  href,
53
56
  "aria-label": `${labels.taggedWith}: ${tag}`,
57
+ "data-zd-tag-chip": true,
54
58
  class: "group relative inline-flex no-underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
55
59
  children: [
56
60
  /* @__PURE__ */ jsx(
57
61
  "span",
58
62
  {
63
+ "data-zd-tag-chip-outline": true,
59
64
  class: "absolute inset-0 bg-muted group-hover:bg-fg",
60
65
  style: "clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 50%, calc(100% - 12px) 100%, 0 100%)"
61
66
  }
@@ -63,6 +68,7 @@ function PageTagChip({
63
68
  /* @__PURE__ */ jsxs(
64
69
  "span",
65
70
  {
71
+ "data-zd-tag-chip-label": true,
66
72
  class: "relative inline-flex items-center text-caption text-fg bg-bg pl-hsp-sm pr-hsp-lg py-vsp-2xs group-hover:text-bg group-hover:bg-fg",
67
73
  style: "clip-path: polygon(1px 1px, calc(100% - 13px) 1px, calc(100% - 1px) 50%, calc(100% - 13px) calc(100% - 1px), 1px calc(100% - 1px))",
68
74
  children: [
@@ -28,7 +28,7 @@ export declare function getNavSectionForSlug(slug: string, headerNav: NavScopeHe
28
28
  /**
29
29
  * Filter top-level NavNodes by a headerNav categoryMatch value.
30
30
  * - `"!"` means everything NOT claimed by explicit matchers
31
- * - `"claude"` means nodes whose slug starts with `"claude"`
31
+ * - `"claude"` means nodes whose slug is `"claude"` or under `"claude/"`
32
32
  * - `undefined` means all nodes
33
33
  *
34
34
  * Parameterized version of the host's `getNavSubtree()` — receives the
@@ -13,26 +13,25 @@ function getCategoryOrder(headerNav) {
13
13
  function getNavSectionForSlug(slug, headerNav) {
14
14
  const topCategory = slug.split("/")[0] ?? "";
15
15
  const all = getCategoryOrder(headerNav);
16
- const explicitMatches = all.filter(
17
- (cm) => cm !== "!" && topCategory.startsWith(cm)
18
- );
19
- if (explicitMatches.length > 0) {
20
- return explicitMatches.sort((a, b) => b.length - a.length)[0];
21
- }
16
+ const explicitMatch = all.find((cm) => cm !== "!" && topCategory === cm);
17
+ if (explicitMatch !== void 0) return explicitMatch;
22
18
  const defaultItem = headerNav.find(
23
19
  (item) => item.categoryMatch === "!"
24
20
  );
25
21
  return defaultItem?.categoryMatch;
26
22
  }
23
+ function matchesCategory(slug, match) {
24
+ return slug === match || slug.startsWith(match + "/");
25
+ }
27
26
  function getNavSubtree(tree, categoryMatch, headerNav) {
28
27
  if (!categoryMatch) return tree;
29
28
  if (categoryMatch === "!") {
30
29
  const explicitPrefixes = getCategoryOrder(headerNav).filter((cm) => cm !== "!");
31
30
  return tree.filter(
32
- (node) => !explicitPrefixes.some((prefix) => node.slug.startsWith(prefix))
31
+ (node) => !explicitPrefixes.some((prefix) => matchesCategory(node.slug, prefix))
33
32
  );
34
33
  }
35
- return tree.filter((node) => node.slug.startsWith(categoryMatch));
34
+ return tree.filter((node) => matchesCategory(node.slug, categoryMatch));
36
35
  }
37
36
  export {
38
37
  getCategoryOrder,
@@ -15,7 +15,11 @@ export interface PageLoadingOverlayProps {
15
15
  */
16
16
  export declare function buildPageLoadingOverlayBootstrap(overlayId: string): string;
17
17
  /**
18
- * Content loading overlay shown while a dynamic navigation is pending.
18
+ * Full-viewport loading overlay shown while a dynamic navigation is pending.
19
+ *
20
+ * Geometry belongs to `page-loading.css` (`position: fixed; inset: 0`); the
21
+ * bootstrap only toggles visibility. Header and sidebar stay stationary through
22
+ * their own named View Transition snapshots, not by clipping the scrim.
19
23
  *
20
24
  * Mount this once per layout (typically inside `DocLayoutWithDefaults`'s
21
25
  * `bodyEnd` slot, alongside the existing body-end providers). It is
@@ -11,7 +11,7 @@ function buildPageLoadingOverlayBootstrap(overlayId) {
11
11
  const after = JSON.stringify(AFTER_NAVIGATE_EVENT);
12
12
  return `(function(){
13
13
  var id=${id};
14
- function show(){var el=document.getElementById(id);if(!el)return;var content=document.querySelector(".zd-sidebar-content-wrapper");var header=document.querySelector("body > header");el.style.left=Math.max(0,content?content.getBoundingClientRect().left:0)+"px";el.style.top=Math.max(0,header?header.getBoundingClientRect().bottom:0)+"px";el.setAttribute("data-visible","");el.setAttribute("aria-hidden","false");}
14
+ function show(){var el=document.getElementById(id);if(!el)return;el.setAttribute("data-visible","");el.setAttribute("aria-hidden","false");}
15
15
  function hide(){var el=document.getElementById(id);if(!el)return;el.removeAttribute("data-visible");el.setAttribute("aria-hidden","true");}
16
16
  function setPending(ev){document.querySelectorAll("[data-zd-nav-pending]").forEach(function(el){el.removeAttribute("data-zd-nav-pending");});var src=ev&&ev.sourceElement;if(src&&src instanceof Element)src.setAttribute("data-zd-nav-pending","");}
17
17
  function clearPending(){document.querySelectorAll("[data-zd-nav-pending]").forEach(function(el){el.removeAttribute("data-zd-nav-pending");});}
@@ -33,7 +33,8 @@
33
33
  position: fixed;
34
34
  view-transition-name: zfb-loading;
35
35
  inset: 0;
36
- /* Pending-content overlay — the bootstrap excludes the layout's chrome.
36
+ /* Full-viewport pending scrim, header and sidebar included. Stationary
37
+ chrome comes from its own named snapshots, not from clipping this box.
37
38
  --z-index-modal fallback (100) ensures the overlay stacks on top even for
38
39
  bare consumers that have not defined the token. */
39
40
  z-index: var(--z-index-modal, 100);
@@ -1,4 +1,5 @@
1
1
  import type { ZfbPlugin } from "@takazudo/zfb/plugins";
2
2
  export declare const ZDTP_LOADER_SPECIFIER = "@takazudo/zudo-doc/zdtp-loader";
3
+ export declare const ZDTP_DISABLED_MESSAGE_PREFIX = "@takazudo/zdtp is not bundled";
3
4
  declare const plugin: ZfbPlugin;
4
5
  export default plugin;
@@ -1,5 +1,8 @@
1
1
  const ZDTP_LOADER_SPECIFIER = "@takazudo/zudo-doc/zdtp-loader";
2
- const DISABLED_LOADER_SOURCE = 'throw new Error("@takazudo/zdtp is not bundled: designTokenPanel is false and bundleZdtp is not set, so this build shadows @takazudo/zudo-doc/zdtp-loader. If you reached this through @takazudo/zudo-doc/design-token-panel-bootstrap to mount your own panel, set bundleZdtp: true and install @takazudo/zdtp.");\nexport {};\n';
2
+ const ZDTP_DISABLED_MESSAGE_PREFIX = "@takazudo/zdtp is not bundled";
3
+ const DISABLED_LOADER_SOURCE = `throw new Error("${ZDTP_DISABLED_MESSAGE_PREFIX}: designTokenPanel is false and bundleZdtp is not set, so this build shadows @takazudo/zudo-doc/zdtp-loader. If you reached this through @takazudo/zudo-doc/design-token-panel-bootstrap to mount your own panel, set bundleZdtp: true and install @takazudo/zdtp.");
4
+ export {};
5
+ `;
3
6
  const plugin = {
4
7
  name: "zdtp-loader",
5
8
  setup(ctx) {
@@ -8,6 +11,7 @@ const plugin = {
8
11
  };
9
12
  var zdtp_loader_default = plugin;
10
13
  export {
14
+ ZDTP_DISABLED_MESSAGE_PREFIX,
11
15
  ZDTP_LOADER_SPECIFIER,
12
16
  zdtp_loader_default as default
13
17
  };
package/dist/preset.d.ts CHANGED
@@ -201,10 +201,16 @@ export interface PresetSettings {
201
201
  * Active theme pack slug (ADR docs/adr/theme-packs.md, Decision 2/7).
202
202
  * Threaded into the `@takazudo/zudo-doc/plugins/theme-packs` descriptor's
203
203
  * options; the plugin's `setup()` validates it against the resolved
204
- * registry and throws loudly on an unknown slug. Omit to use the package
205
- * default (`"default"`).
204
+ * registry and throws loudly on an unknown slug. Omitted is normalized by
205
+ * `resolveConfiguredThemePack`: `"graphite"`, or `"default"` (Classic) when
206
+ * custom `colorSchemes` are passed or `colorMode` is `false`.
206
207
  */
207
- themePack?: string;
208
+ themePack?: string | null;
209
+ /**
210
+ * The resolved `colorMode` setting. Read only to decide the omitted
211
+ * `themePack` (`false` keeps Classic); see {@link themePack}.
212
+ */
213
+ colorMode?: unknown;
208
214
  /**
209
215
  * Enabled pack slugs, in switcher order (ADR Decision 7). `undefined` = all
210
216
  * bundled packs. Threaded into the `@takazudo/zudo-doc/plugins/theme-packs`
@@ -353,5 +359,5 @@ export interface ZudoDocPresetResult {
353
359
  * });
354
360
  * ```
355
361
  */
356
- export declare function zudoDocPreset({ settings, buildDocsSchema, directiveVocabulary, translations, tagVocabulary, colorSchemes, }: ZudoDocPresetArgs): ZudoDocPresetResult;
362
+ export declare function zudoDocPreset({ settings: inputSettings, buildDocsSchema, directiveVocabulary, translations, tagVocabulary, colorSchemes, }: ZudoDocPresetArgs): ZudoDocPresetResult;
357
363
  export declare function buildMarkdownFeatures(settings: Pick<PresetSettings, "mermaid" | "transclude">, directiveVocabulary: DirectiveVocabulary): Record<string, boolean | Record<string, unknown>>;
package/dist/preset.js CHANGED
@@ -10,14 +10,24 @@ import {
10
10
  warnAmbiguousDropdownCategoryMatch
11
11
  } from "./config-assertions/index.js";
12
12
  import { zudoDocWindPreset } from "./wind/index.js";
13
+ import { defaultColorSchemes } from "./color-schemes-defaults/index.js";
14
+ import { resolveConfiguredThemePack } from "./theme-packs-registry/configured-theme-pack.js";
13
15
  function zudoDocPreset({
14
- settings,
16
+ settings: inputSettings,
15
17
  buildDocsSchema,
16
18
  directiveVocabulary,
17
19
  translations,
18
20
  tagVocabulary,
19
21
  colorSchemes
20
22
  }) {
23
+ const settings = {
24
+ ...inputSettings,
25
+ themePack: resolveConfiguredThemePack({
26
+ themePack: inputSettings.themePack,
27
+ colorMode: inputSettings.colorMode,
28
+ customColorSchemes: colorSchemes !== void 0 && colorSchemes !== null && colorSchemes !== defaultColorSchemes
29
+ })
30
+ };
21
31
  assertNoCommaInVersionSlugs(settings.versions);
22
32
  assertNoEmptyStringFaviconOrLogo(settings);
23
33
  assertValidHeaderBrand(settings);
@@ -15,6 +15,9 @@ export type RouteContextTranslations = Record<string, Record<string, string>>;
15
15
  * `siteDescription`, `defaultLocale`, `locales`, `headerNav`, `themePack`).
16
16
  * - `settings` is a shallow, top-level merge over that result and wins last.
17
17
  * Nested settings objects replace wholesale; they are never deep-merged.
18
+ * - A `themePack` still omitted (nullish) after that merge resolves through
19
+ * `resolveConfiguredThemePack`: `"graphite"`, or `"default"` (Classic)
20
+ * when `colorSchemes` data is supplied or `settings.colorMode` is `false`.
18
21
  * - `translations` deep-merges into `defaultTranslations` in two levels:
19
22
  * locales are retained and individual keys within an overridden locale are
20
23
  * retained unless that key is supplied by the caller.
@@ -39,7 +42,7 @@ export interface CreateRouteContextPayloadInput {
39
42
  locales?: Record<string, LocaleConfig>;
40
43
  /** Top-level navigation categories; becomes `settings.headerNav`. */
41
44
  categories?: readonly HeaderNavItem[];
42
- /** Active theme-pack slug; defaults to `DEFAULT_SETTINGS.themePack`. */
45
+ /** Active theme-pack slug; omitted resolves via `resolveConfiguredThemePack`. */
43
46
  themePack?: string;
44
47
  /** Complete browser-facing catalog v2 manifest used to build the registry. */
45
48
  catalog?: ThemePacksCatalogManifest;
@@ -2,6 +2,7 @@ import { DEFAULT_SETTINGS } from "../settings-defaults.js";
2
2
  import { defaultTranslations } from "../i18n-defaults/index.js";
3
3
  import { defaultColorSchemes } from "../color-schemes-defaults/index.js";
4
4
  import { buildThemePackRegistry } from "../theme-packs-registry/build-registry.js";
5
+ import { resolveConfiguredThemePack } from "../theme-packs-registry/configured-theme-pack.js";
5
6
  function mergeTranslations(overrides) {
6
7
  const merged = {};
7
8
  const localeNames = /* @__PURE__ */ new Set([
@@ -27,6 +28,11 @@ function createRouteContextPayload(input) {
27
28
  ...input.themePack !== void 0 ? { themePack: input.themePack } : {},
28
29
  ...input.settings
29
30
  };
31
+ settings.themePack = resolveConfiguredThemePack({
32
+ themePack: settings.themePack,
33
+ colorMode: settings.colorMode,
34
+ customColorSchemes: input.colorSchemes !== void 0 && input.colorSchemes !== null && input.colorSchemes !== defaultColorSchemes
35
+ });
30
36
  const hasRegistryOverride = Object.prototype.hasOwnProperty.call(
31
37
  input,
32
38
  "themePackRegistry"
@@ -86,7 +86,9 @@ const DEFAULT_SETTINGS = {
86
86
  headerNav: [],
87
87
  headerRightItems: [{ type: "component", component: "theme-toggle" }],
88
88
  packageOwnedRoutes: true,
89
- themePack: "default",
89
+ // Omitted on purpose: `resolveConfiguredThemePack` turns an omitted pack into
90
+ // "graphite", or into "default" (Classic) for custom/fixed color schemes.
91
+ themePack: void 0,
90
92
  themePackSwitcher: false,
91
93
  themePacks: void 0
92
94
  };
@@ -621,8 +621,10 @@ export interface Settings {
621
621
  */
622
622
  designTokenPanelConfigModule?: string;
623
623
  /**
624
- * Active theme-pack slug (ADR `docs/adr/theme-packs.md`). `"default"` is
625
- * the stock zudo-doc look — no pack stylesheet is loaded. Must be a member
624
+ * Active theme-pack slug (ADR `docs/adr/theme-packs.md`). Omitted resolves
625
+ * to `"graphite"`, or to `"default"` when the project supplies custom
626
+ * `colorSchemes` or sets `colorMode: false`. `"default"` is Classic, the
627
+ * original zudo-doc look — no pack stylesheet is loaded. Must be a member
626
628
  * of the resolved `themePacks` list; an unknown slug fails the build
627
629
  * loudly at plugin setup (`src/plugins/routes.ts`).
628
630
  */
@@ -634,9 +636,11 @@ export interface Settings {
634
636
  themePackSwitcher?: boolean;
635
637
  /**
636
638
  * Enabled theme-pack slugs, in switcher order. `undefined` = every bundled
637
- * pack, `"default"` first then the rest in canonical (alphabetical-by-slug)
638
- * order. An explicit list is authoritative: may omit `"default"`, reorder
639
- * freely; duplicate or unknown slugs fail the build loudly.
639
+ * pack, `"graphite"` first, `"default"` (Classic) second, then the rest in
640
+ * canonical (alphabetical-by-slug) order. An explicit list is
641
+ * authoritative: may omit any pack, reorder freely; duplicate or unknown
642
+ * slugs fail the build loudly, and so does a list that excludes the
643
+ * effective `themePack`.
640
644
  */
641
645
  themePacks?: string[];
642
646
  }
@@ -0,0 +1,19 @@
1
+ import { type ReadonlySignal, type Ref } from "@takazudo/zfb/zudo-react";
2
+ /** Trigger attribute: the tooltip's title text. */
3
+ export declare const TIP_ATTR = "data-sidebar-tip";
4
+ /** Trigger attribute: optional secondary tooltip line. */
5
+ export declare const TIP_DETAIL_ATTR = "data-sidebar-tip-detail";
6
+ export interface BranchPreview {
7
+ /** Occurrence previewed in this sidebar instance, or null. Never persisted or broadcast. */
8
+ active: ReadonlySignal<string | null>;
9
+ clear: () => void;
10
+ }
11
+ /**
12
+ * Transient branch preview + tooltip for one sidebar island instance.
13
+ * Call `activate()` from the island's `onActivate`; it returns the cleanup.
14
+ * The desktop tree and the mobile drawer are separate instances, so each
15
+ * visible sidebar owns at most one preview and one tooltip.
16
+ */
17
+ export declare function createBranchPreview(navRef: Ref<HTMLElement>): BranchPreview & {
18
+ activate: () => () => void;
19
+ };