@takazudo/zudo-doc 5.5.2 → 5.6.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 (70) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +39 -0
  3. package/dist/chrome/derive.d.ts +46 -0
  4. package/dist/chrome/derive.js +6 -2
  5. package/dist/config-assertions/index.d.ts +31 -0
  6. package/dist/config-assertions/index.js +24 -0
  7. package/dist/config.d.ts +23 -2
  8. package/dist/config.js +3 -0
  9. package/dist/current-path/index.d.ts +27 -0
  10. package/dist/current-path/index.js +11 -0
  11. package/dist/design-token-panel-bootstrap.d.ts +89 -23
  12. package/dist/design-token-panel-bootstrap.js +19 -6
  13. package/dist/doc-page-props/index.d.ts +5 -67
  14. package/dist/doc-route-entries/index.d.ts +10 -95
  15. package/dist/doc-route-entries/index.js +1 -78
  16. package/dist/doc-route-paths/index.d.ts +1 -1
  17. package/dist/head-with-defaults/index.d.ts +3 -1
  18. package/dist/head-with-defaults/index.js +76 -4
  19. package/dist/header/nav-active.d.ts +28 -0
  20. package/dist/header/nav-active.js +2 -1
  21. package/dist/header/nav-overflow-script.js +30 -17
  22. package/dist/header-with-defaults/index.js +11 -2
  23. package/dist/i18n-version/language-switcher.d.ts +6 -0
  24. package/dist/i18n-version/language-switcher.js +3 -1
  25. package/dist/i18n-version/version-switcher.d.ts +6 -0
  26. package/dist/i18n-version/version-switcher.js +3 -1
  27. package/dist/nav-source-docs/index.d.ts +7 -11
  28. package/dist/plugins/route-pages-candidates.d.ts +19 -0
  29. package/dist/plugins/route-pages-candidates.js +17 -0
  30. package/dist/plugins/routes.d.ts +46 -0
  31. package/dist/plugins/routes.js +72 -18
  32. package/dist/preset.d.ts +12 -1
  33. package/dist/preset.js +2 -0
  34. package/dist/route-context/index.js +2 -2
  35. package/dist/routes/_chrome.d.ts +1 -1
  36. package/dist/routes/_chrome.js +4 -0
  37. package/dist/routes/_context.d.ts +3 -3
  38. package/dist/routes/_design-token-panel-bootstrap.d.ts +18 -0
  39. package/dist/routes/_design-token-panel-bootstrap.js +11 -0
  40. package/dist/routes/_docs-helpers.d.ts +1 -36
  41. package/dist/routes/_docs-helpers.js +0 -138
  42. package/dist/safelist.css +1 -1
  43. package/dist/search-widget-script/generated-script.d.ts +8 -0
  44. package/dist/search-widget-script/generated-script.js +465 -0
  45. package/dist/search-widget-script/index.d.ts +1 -18
  46. package/dist/search-widget-script/index.js +1 -443
  47. package/dist/settings.d.ts +82 -1
  48. package/dist/sidebar-tree/category-meta.d.ts +9 -0
  49. package/dist/sidebar-tree/category-meta.js +21 -12
  50. package/dist/sidebar-tree-island/index.d.ts +8 -1
  51. package/dist/sidebar-tree-island/index.js +16 -14
  52. package/dist/site-schema/doc-route-entries.d.ts +89 -0
  53. package/dist/site-schema/doc-route-entries.js +83 -0
  54. package/dist/site-schema/index.d.ts +17 -0
  55. package/dist/site-schema/index.js +46 -0
  56. package/dist/site-schema/nav-tree.d.ts +28 -0
  57. package/dist/site-schema/nav-tree.js +138 -0
  58. package/dist/site-schema/types.d.ts +97 -0
  59. package/dist/site-schema/types.js +0 -0
  60. package/dist/theme/theme-pack-provider.d.ts +34 -3
  61. package/dist/theme/theme-pack-provider.js +30 -2
  62. package/eject/header/nav-active.ts +13 -1
  63. package/eject/header/nav-overflow-script.ts +30 -17
  64. package/eject/sidebar-tree-island/index.tsx +44 -20
  65. package/package.json +22 -12
  66. package/routes-src/_chrome.tsx +21 -9
  67. package/routes-src/_design-token-panel-bootstrap.tsx +63 -0
  68. package/routes-src/_docs-helpers.ts +18 -225
  69. package/routes-src/_virtual.d.ts +5 -2
  70. package/virtual-modules.d.ts +5 -2
@@ -1,37 +1,28 @@
1
- // routes/_docs-helpers — package-side nav-tree helpers for the package-owned
2
- // route entrypoints (epic Package-First Finale #2356, A1 #2361).
1
+ // routes/_docs-helpers — the content bridge for the package-owned route
2
+ // entrypoints (epic Package-First Finale #2356, A1 #2361).
3
3
  //
4
- // The host's `src/utils/docs.ts` `buildNavTree` / `buildBreadcrumbs` /
5
- // `collectAutoIndexNodes` / `groupSatelliteNodes` / `findNode` /
6
- // `firstRoutedHref` are host-only wrappers around the package primitive
7
- // `buildSidebarTree` (`@takazudo/zudo-doc/sidebar-tree`). The package route
8
- // entrypoints inject these same helpers into the doc-route / nav-source /
9
- // nav-wrapper factories, so this module reproduces them WITHOUT the host `@/`
10
- // alias — the "+ package `docs` helpers" note in the ADR's host-dep table.
4
+ // WHAT IS LEFT HERE: `stableDocs`, and only `stableDocs`. It is the one piece
5
+ // of this module that cannot be browser-safe — it imports `@takazudo/zfb/content`
6
+ // directly (NOT the host `zfb/content` tsconfig alias — Decision 2) to anchor
7
+ // the bridged + draft-filtered array on the build snapshot, so repeat callers
8
+ // within a build get the SAME instance and the nav-tree / doc-route memos
9
+ // short-circuit (the content bridge — Decision 5).
11
10
  //
12
- // Faithful to the host derivation (root-index node synthesis, NavNode shape,
13
- // satellite grouping, breadcrumb walk) but without the host-only LRU /
14
- // identity caches: build-time array-identity stability already comes from the
15
- // snapshot-anchored `stableDocs` (below) + `memoizeDerived` in the factories.
16
- //
17
- // `stableDocs` (the content bridge — Decision 5) imports `@takazudo/zfb/content`
18
- // directly (NOT the host `zfb/content` tsconfig alias — Decision 2), anchoring
19
- // the bridged + draft-filtered array on the snapshot so repeat callers within a
20
- // build get the SAME instance and the nav-tree / doc-route memos short-circuit.
11
+ // WHAT MOVED: every pure nav helper this file used to define — `buildNavTree`,
12
+ // `groupSatelliteNodes`, `findNode`, `firstRoutedHref`, `collectAutoIndexNodes`,
13
+ // `buildBreadcrumbs`, `isNavVisible` — now lives in `../site-schema/nav-tree.js`
14
+ // (#3395); import them from there, not from here. Cutting them loose is what
15
+ // lets `createDocRouteEntries` reach `buildBreadcrumbs` without dragging
16
+ // `@takazudo/zfb/content` into an otherwise browser-safe graph. This module
17
+ // deliberately re-exports NOTHING: a second import path for the nav helpers
18
+ // through this file would put them one hop from the `@takazudo/zfb/content`
19
+ // edge this file exists to carry.
21
20
 
22
21
  import {
23
22
  getCollection,
24
23
  getContentSnapshot,
25
24
  } from "@takazudo/zfb/content";
26
- import {
27
- buildSidebarTree,
28
- type CategoryMeta,
29
- type SidebarNode,
30
- } from "@takazudo/zudo-doc/sidebar-tree";
31
- import { toRouteSlug } from "@takazudo/zudo-doc/slug";
32
- import type { DocNavNode, DocPageEntry, DocPageFrontmatter } from "@takazudo/zudo-doc/doc-page-props";
33
-
34
- export type { CategoryMeta, DocNavNode, DocPageEntry };
25
+ import type { DocPageEntry, DocPageFrontmatter } from "@takazudo/zudo-doc/doc-page-props";
35
26
 
36
27
  // ---------------------------------------------------------------------------
37
28
  // Content bridge — snapshot-anchored stable docs (Decision 5)
@@ -64,201 +55,3 @@ export function stableDocs(collectionName: string): DocPageEntry[] {
64
55
  docsByAnchor.set(anchor, built);
65
56
  return built;
66
57
  }
67
-
68
- // ---------------------------------------------------------------------------
69
- // Nav-tree helpers — ported from src/utils/docs.ts onto buildSidebarTree
70
- // ---------------------------------------------------------------------------
71
-
72
- /** Filter predicate: true when a doc should appear in navigation. */
73
- export function isNavVisible(doc: DocPageEntry): boolean {
74
- return !doc.data.unlisted && !doc.data.standalone;
75
- }
76
-
77
- /** A docs-href builder: `(slug, locale) => url`. */
78
- export type BuildHref = (slug: string, locale: string) => string;
79
-
80
- export interface BuildNavTreeOptions {
81
- buildHref?: BuildHref;
82
- }
83
-
84
- function toNavNode(node: SidebarNode): DocNavNode {
85
- return {
86
- slug: node.id,
87
- label: node.label,
88
- description: node.description,
89
- position: node.sidebar_position ?? 999,
90
- href: node.href,
91
- hasPage: node.hasPage,
92
- children: node.children.map(toNavNode),
93
- sortOrder: node.sortOrder ?? "asc",
94
- };
95
- }
96
-
97
- /** Last entry whose package-derived slug is empty ("") — the entry the shared
98
- * builder skips. Last one wins (mirrors the host builder's overwrite). */
99
- function findRootIndexDoc(docs: DocPageEntry[]): DocPageEntry | undefined {
100
- let found: DocPageEntry | undefined;
101
- for (const d of docs) {
102
- const slug = d.data.slug ?? toRouteSlug(d.slug);
103
- if (slug === "") found = d;
104
- }
105
- return found;
106
- }
107
-
108
- function toRootNavNode(
109
- doc: DocPageEntry,
110
- locale: string,
111
- buildHref: BuildHref,
112
- categoryMeta?: Map<string, CategoryMeta>,
113
- ): DocNavNode {
114
- const meta = categoryMeta?.get("");
115
- const noPage = doc.data.category_no_page ?? meta?.noPage;
116
- const sortOrder =
117
- (doc.data.category_sort_order as "asc" | "desc" | undefined) ?? meta?.sortOrder ?? "asc";
118
- return {
119
- slug: "",
120
- label:
121
- (doc.data.sidebar_label as string | undefined) ??
122
- doc.data.title ??
123
- meta?.label ??
124
- "",
125
- description: doc.data.description ?? meta?.description,
126
- position: (doc.data.sidebar_position as number | undefined) ?? meta?.position ?? 999,
127
- href: noPage ? undefined : buildHref("", locale),
128
- hasPage: noPage !== true,
129
- children: [],
130
- sortOrder,
131
- };
132
- }
133
-
134
- /**
135
- * Build a recursive navigation tree from a flat doc collection. Delegates tree
136
- * construction to the shared `buildSidebarTree`; keeps the host-side concerns
137
- * (DocNavNode shape, root-index node synthesis). `buildHref` parameterizes the
138
- * href space (default: the injected `docsUrl`). Unlike the host copy this drops
139
- * the LRU / identity caches — the snapshot-anchored `stableDocs` already makes
140
- * the input arrays identity-stable so the factory-level `memoizeDerived` short-
141
- * circuits per build.
142
- */
143
- export function buildNavTree(
144
- docs: DocPageEntry[],
145
- locale: string,
146
- categoryMeta: Map<string, CategoryMeta> | undefined,
147
- buildHref: BuildHref,
148
- options?: BuildNavTreeOptions,
149
- ): DocNavNode[] {
150
- const href: BuildHref = options?.buildHref ?? buildHref;
151
- const sidebarTree = buildSidebarTree(
152
- docs,
153
- locale,
154
- {
155
- categoryMeta,
156
- buildHref: (slug, loc) => href(slug, loc),
157
- // Host call sites own visibility; disable the builder's default filter so
158
- // breadcrumb (unfiltered) and nav (pre-filtered) paths are unchanged.
159
- isNavVisible: () => true,
160
- },
161
- );
162
- const result = sidebarTree.map(toNavNode);
163
-
164
- const rootDoc = findRootIndexDoc(docs);
165
- if (rootDoc) {
166
- result.push(toRootNavNode(rootDoc, locale, href, categoryMeta));
167
- result.sort((a, b) => {
168
- const posCompare = a.position - b.position;
169
- if (posCompare !== 0) return posCompare;
170
- return a.slug.localeCompare(b.slug);
171
- });
172
- }
173
- return result;
174
- }
175
-
176
- /** Group "satellite" nodes (slug-prefix siblings) under their primary node. */
177
- export function groupSatelliteNodes(tree: DocNavNode[], prefixes: string[]): DocNavNode[] {
178
- const result = [...tree];
179
- for (const prefix of prefixes) {
180
- const primaryIdx = result.findIndex((n) => n.slug === prefix);
181
- if (primaryIdx < 0) continue;
182
- const primary = result[primaryIdx];
183
- if (!primary) continue;
184
- const satelliteIdxs: number[] = [];
185
- for (let i = 0; i < result.length; i++) {
186
- const node = result[i];
187
- if (node && i !== primaryIdx && node.slug.startsWith(`${prefix}-`)) {
188
- satelliteIdxs.push(i);
189
- }
190
- }
191
- if (satelliteIdxs.length === 0) continue;
192
- const extraChildren: DocNavNode[] = [];
193
- for (const idx of satelliteIdxs) {
194
- const node = result[idx];
195
- if (node) extraChildren.push(node);
196
- }
197
- result[primaryIdx] = { ...primary, children: [...primary.children, ...extraChildren] };
198
- for (const idx of satelliteIdxs.reverse()) result.splice(idx, 1);
199
- }
200
- return result;
201
- }
202
-
203
- /** Find a node by slug anywhere in the tree. */
204
- export function findNode(nodes: DocNavNode[], slug: string): DocNavNode | undefined {
205
- for (const node of nodes) {
206
- if (node.slug === slug) return node;
207
- const found = findNode(node.children, slug);
208
- if (found) return found;
209
- }
210
- return undefined;
211
- }
212
-
213
- /** Href of the first routed descendant, walking children depth-first. */
214
- export function firstRoutedHref(node: DocNavNode): string | undefined {
215
- for (const child of node.children) {
216
- if (child.hasPage && child.href) return child.href;
217
- const nested = firstRoutedHref(child);
218
- if (nested) return nested;
219
- }
220
- return undefined;
221
- }
222
-
223
- /** Collect all category nodes that have children but no page (no index.mdx). */
224
- export function collectAutoIndexNodes(nodes: DocNavNode[]): DocNavNode[] {
225
- const result: DocNavNode[] = [];
226
- for (const node of nodes) {
227
- if (!node.hasPage && node.children.length > 0 && node.href) result.push(node);
228
- result.push(...collectAutoIndexNodes(node.children));
229
- }
230
- return result;
231
- }
232
-
233
- export interface BreadcrumbItem {
234
- label: string;
235
- href?: string;
236
- }
237
-
238
- /** Build breadcrumb trail by walking the nav tree. `homeHref` is the locale
239
- * docs root (injected). `hrefFor` optionally remaps intermediate crumbs into
240
- * a versioned URL space. */
241
- export function buildBreadcrumbs(
242
- tree: DocNavNode[],
243
- slug: string,
244
- homeHref: string,
245
- hrefFor?: (slug: string) => string,
246
- ): BreadcrumbItem[] {
247
- const parts = slug.split("/");
248
- const crumbs: BreadcrumbItem[] = [{ label: "", href: homeHref }];
249
- let nodes = tree;
250
- for (let i = 0; i < parts.length; i++) {
251
- const partialSlug = parts.slice(0, i + 1).join("/");
252
- const node = nodes.find((n) => n.slug === partialSlug);
253
- if (!node) break;
254
- const isLast = i === parts.length - 1;
255
- const href = isLast
256
- ? undefined
257
- : hrefFor && node.href !== undefined
258
- ? hrefFor(node.slug)
259
- : node.href;
260
- crumbs.push({ label: node.label, href });
261
- nodes = node.children;
262
- }
263
- return crumbs;
264
- }
@@ -57,8 +57,11 @@ declare module "virtual:zudo-doc-chrome-bindings" {
57
57
  // …)`, #2658). No on-disk source — materialised at build, either as a
58
58
  // re-export of the host's `settings.designTokenPanelConfigModule` file or as
59
59
  // a re-export of the package default (`@takazudo/zudo-doc/design-token-panel-config`)
60
- // when the setting is absent. See `plugins/routes.ts` and this package's
61
- // `design-token-panel-bootstrap.tsx` for the full contract.
60
+ // when the setting is absent. Since #3396 its SOLE importer is the
61
+ // routes-only wrapper `./_design-token-panel-bootstrap.tsx` — the generic
62
+ // `design-token-panel-bootstrap.tsx` binds the package default directly, so
63
+ // `@takazudo/zudo-doc/chrome` bundles without the routes plugin. See
64
+ // `plugins/routes.ts` and that bootstrap module for the full contract.
62
65
  //
63
66
  // Typed via an inline `import(...)` type (not a top-level import, for the
64
67
  // same ambient-module-declaration reason as `chromeBindings` above) — see
@@ -70,8 +70,11 @@ declare module "virtual:zudo-doc-chrome-bindings" {
70
70
  // …)`, #2658). No on-disk source — materialised at build, either as a
71
71
  // re-export of the host's `settings.designTokenPanelConfigModule` file or as
72
72
  // a re-export of the package default (`@takazudo/zudo-doc/design-token-panel-config`)
73
- // when the setting is absent. See `plugins/routes.ts` and this package's
74
- // `design-token-panel-bootstrap.tsx` for the full contract.
73
+ // when the setting is absent. Since #3396 its SOLE importer is the
74
+ // routes-only wrapper `./_design-token-panel-bootstrap.tsx` — the generic
75
+ // `design-token-panel-bootstrap.tsx` binds the package default directly, so
76
+ // `@takazudo/zudo-doc/chrome` bundles without the routes plugin. See
77
+ // `plugins/routes.ts` and that bootstrap module for the full contract.
75
78
  //
76
79
  // Typed via an inline `import(...)` type (not a top-level import, for the
77
80
  // same ambient-module-declaration reason as `chromeBindings` above) — see