@takazudo/zudo-doc 1.2.0 → 2.0.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 (52) hide show
  1. package/dist/chrome/derive.d.ts +68 -0
  2. package/dist/chrome/derive.js +231 -0
  3. package/dist/chrome/index.d.ts +37 -0
  4. package/dist/chrome/index.js +43 -0
  5. package/dist/content.css +25 -9
  6. package/dist/doc-body-end/index.d.ts +9 -11
  7. package/dist/doc-body-end/index.js +4 -2
  8. package/dist/doc-content-header/index.d.ts +10 -2
  9. package/dist/doc-content-header/index.js +8 -8
  10. package/dist/doc-history-area/index.d.ts +10 -25
  11. package/dist/doc-history-area/index.js +14 -10
  12. package/dist/doc-metainfo-area/index.d.ts +9 -15
  13. package/dist/doc-metainfo-area/index.js +6 -2
  14. package/dist/doc-page-renderer/index.d.ts +11 -2
  15. package/dist/doc-page-renderer/index.js +22 -15
  16. package/dist/doc-page-shell/index.d.ts +11 -3
  17. package/dist/doc-page-shell/index.js +21 -14
  18. package/dist/doc-pager/index.d.ts +6 -7
  19. package/dist/doc-pager/index.js +2 -2
  20. package/dist/doc-route-entries/index.d.ts +22 -46
  21. package/dist/doc-route-entries/index.js +15 -10
  22. package/dist/doc-tags-area/index.d.ts +9 -19
  23. package/dist/doc-tags-area/index.js +12 -2
  24. package/dist/factory-context/index.d.ts +163 -1
  25. package/dist/footer-with-defaults/index.d.ts +12 -13
  26. package/dist/footer-with-defaults/index.js +8 -10
  27. package/dist/head-with-defaults/index.d.ts +12 -16
  28. package/dist/head-with-defaults/index.js +7 -9
  29. package/dist/header-with-defaults/index.d.ts +10 -31
  30. package/dist/header-with-defaults/index.js +15 -18
  31. package/dist/integrations/claude-resources/generate.js +48 -11
  32. package/dist/nav-source-docs/index.d.ts +20 -54
  33. package/dist/nav-source-docs/index.js +9 -10
  34. package/dist/route-context/index.d.ts +24 -0
  35. package/dist/route-context/index.js +147 -0
  36. package/dist/route-enumerators/index.d.ts +25 -74
  37. package/dist/route-enumerators/index.js +17 -18
  38. package/dist/routes/_chrome.d.ts +6 -25
  39. package/dist/routes/_chrome.js +14 -387
  40. package/dist/routes/_context.d.ts +10 -43
  41. package/dist/routes/_context.js +29 -157
  42. package/dist/safelist.css +1 -1
  43. package/dist/sidebar-with-defaults/index.d.ts +8 -15
  44. package/dist/sidebar-with-defaults/index.js +6 -10
  45. package/dist/tag-pages/index.d.ts +12 -3
  46. package/dist/tag-pages/index.js +24 -19
  47. package/dist/versions-page/index.d.ts +10 -3
  48. package/dist/versions-page/index.js +18 -14
  49. package/eject/doc-pager/index.tsx +8 -10
  50. package/package.json +14 -6
  51. package/routes-src/_chrome.tsx +31 -552
  52. package/routes-src/_context.ts +37 -269
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takazudo/zudo-doc",
3
- "version": "1.2.0",
3
+ "version": "2.0.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",
@@ -207,6 +207,14 @@
207
207
  "types": "./dist/mdx-components/index.d.ts",
208
208
  "default": "./dist/mdx-components/index.js"
209
209
  },
210
+ "./route-context": {
211
+ "types": "./dist/route-context/index.d.ts",
212
+ "default": "./dist/route-context/index.js"
213
+ },
214
+ "./chrome": {
215
+ "types": "./dist/chrome/index.d.ts",
216
+ "default": "./dist/chrome/index.js"
217
+ },
210
218
  "./safelist.css": "./dist/safelist.css",
211
219
  "./safelist": "./dist/safelist.css",
212
220
  "./content.css": "./dist/content.css",
@@ -515,9 +523,9 @@
515
523
  ],
516
524
  "peerDependencies": {
517
525
  "preact": "^10.29.1",
518
- "@takazudo/zfb": "^0.1.0-next.69",
519
- "@takazudo/zfb-runtime": "^0.1.0-next.69",
520
- "@takazudo/zudo-doc-history-server": "^1.1.0",
526
+ "@takazudo/zfb": "^0.1.0-next.70",
527
+ "@takazudo/zfb-runtime": "^0.1.0-next.70",
528
+ "@takazudo/zudo-doc-history-server": "^1.2.0",
521
529
  "@takazudo/zdtp": "^0.3.3",
522
530
  "shiki": "^4.0.2",
523
531
  "zod": "^4.3.6",
@@ -559,8 +567,8 @@
559
567
  "typescript": "^5.0.0",
560
568
  "vitest": "^4.1.0",
561
569
  "zod": "^4.3.6",
562
- "@takazudo/zfb": "0.1.0-next.69",
563
- "@takazudo/zfb-runtime": "0.1.0-next.69"
570
+ "@takazudo/zfb": "0.1.0-next.70",
571
+ "@takazudo/zfb-runtime": "0.1.0-next.70"
564
572
  },
565
573
  "scripts": {
566
574
  "build": "tsup && tsc -p tsconfig.build.json",
@@ -1,558 +1,37 @@
1
- /** @jsxRuntime automatic */
2
- /** @jsxImportSource preact */
3
- // routes/_chrome — package-default chrome wiring for the package-owned page
4
- // route entrypoints (epic Package-First Finale #2356, A1 #2361).
1
+ // routes/_chrome thin chrome shim for the package-owned route entrypoints
2
+ // (epic Package-First Finale #2356, A1 #2361).
5
3
  //
6
- // The page routes (index / 404 / docs / versions / tags) render through the
7
- // package's render factories (`doc-page-renderer`, `versions-page`,
8
- // `tag-pages`) + chrome factories (`head/header/footer/sidebar-with-defaults`,
9
- // `doc-page-shell`, …). The HOST stubs (`pages/lib/_*`) wire those factories
10
- // with host singletons AND a handful of host-only bindings the ADR's
11
- // serializable virtual module deliberately does NOT carry:
12
- //
13
- // - the project `colorSchemes` palette map (HeadWithDefaults CSS generation),
14
- // - the `sidebars` config (sidebar section resolution),
15
- // - the `#doc-history-meta` JSON manifest (DocMetainfoArea / DocHistoryArea),
16
- // - the project `frontmatter-preview-renderers`,
17
- // - project island bootstraps wired through `BodyEndIslands`.
18
- //
19
- // Those are host-content / project-config bindings, NOT serializable settings,
20
- // so per the ADR (Decision 1: "components are package defaults"; showcase-only
21
- // slots resolve to a package stub) this module supplies PACKAGE DEFAULTS for
22
- // them: an empty default color scheme, an auto-generated (empty) sidebars
23
- // config, an empty doc-history manifest, empty frontmatter renderers, and a
24
- // package no-op `BodyEndIslands` stub. The seam (data-context + paths()
25
- // enumeration) is fully reconstructed in `_context`; the END-TO-END render
26
- // proof of a stub-less injected route — including re-homing these host-only
27
- // bindings — is A2's job (#2363). With `packageOwnedRoutes` off this module is
28
- // never evaluated; it only needs to typecheck and import.
29
-
30
- import type { JSX, VNode, ComponentChildren } from "preact";
31
- import {
32
- settings,
33
- defaultLocale,
34
- locales,
35
- t,
36
- withBase,
37
- stripBase,
38
- docsUrl,
39
- versionedDocsUrl,
40
- absoluteUrl,
41
- navHref,
42
- buildLocaleLinks,
43
- getNavSectionForSlug,
44
- getCategoryOrder,
45
- toRouteSlug,
46
- resolveNavSource,
47
- loadNavSourceDocs,
48
- buildNavTree,
49
- groupSatelliteNodes,
50
- collectAutoIndexNodes,
51
- findNode,
52
- firstRoutedHref,
53
- collectTags,
54
- stableDocs,
55
- colorSchemes,
56
- } from "./_context.js";
57
- import type { CategoryMeta, DocNavNode } from "./_docs-helpers.js";
58
-
59
- import { createComposeMetaTitle } from "@takazudo/zudo-doc/compose-meta-title";
60
- import {
61
- generateCssCustomProperties,
62
- generateLightDarkCssProperties,
63
- type ColorScheme,
64
- } from "@takazudo/zudo-doc/color-scheme-utils";
65
- import { createHeadWithDefaults } from "@takazudo/zudo-doc/head-with-defaults";
66
- import { createHeaderWithDefaults } from "@takazudo/zudo-doc/header-with-defaults";
67
- import { createFooterWithDefaults } from "@takazudo/zudo-doc/footer-with-defaults";
68
- import { createSidebarWithDefaults } from "@takazudo/zudo-doc/sidebar-with-defaults";
69
- import { createSidebarPrepaint } from "@takazudo/zudo-doc/sidebar-prepaint";
70
- import { createDocBodyEnd } from "@takazudo/zudo-doc/doc-body-end";
71
- import { createBodyEndIslands } from "@takazudo/zudo-doc/doc-body-end-islands";
72
- import { createDocPager } from "@takazudo/zudo-doc/doc-pager";
73
- import { createDocPageShell } from "@takazudo/zudo-doc/doc-page-shell";
74
- import { createDocContentHeader } from "@takazudo/zudo-doc/doc-content-header";
75
- import { createDocMetainfoArea } from "@takazudo/zudo-doc/doc-metainfo-area";
76
- import { createDocTagsArea } from "@takazudo/zudo-doc/doc-tags-area";
77
- import { createDocHistoryArea } from "@takazudo/zudo-doc/doc-history-area";
78
- import { createInlineVersionSwitcher } from "@takazudo/zudo-doc/inline-version-switcher";
79
- import { createRenderDocPage } from "@takazudo/zudo-doc/doc-page-renderer";
80
- import { createVersionsPageView } from "@takazudo/zudo-doc/versions-page";
81
- import { createTagPages } from "@takazudo/zudo-doc/tag-pages";
82
- import { createMdxComponents } from "@takazudo/zudo-doc/mdx-components";
83
- import { createCategoryNavWrapper } from "@takazudo/zudo-doc/category-nav";
84
- import { createCategoryTreeNavWrapper } from "@takazudo/zudo-doc/category-tree-nav";
85
- import { createSiteTreeNavWrapper } from "@takazudo/zudo-doc/site-tree-nav";
86
- import { getTocTitle } from "@takazudo/zudo-doc/toc";
87
- import { SearchWidget } from "@takazudo/zudo-doc/search-widget";
88
- import { buildGitHubRepoUrl, buildGitHubSourceUrl } from "@takazudo/zudo-doc/github-helpers";
89
- import { toHistorySlug } from "@takazudo/zudo-doc/slug";
90
- import {
91
- buildRootMenuItems as buildRootMenuItemsBase,
92
- buildLocaleLinksForNav as buildLocaleLinksForNavBase,
93
- remapVersionedHrefs,
94
- getThemeDefaultMode as getThemeDefaultModeBase,
95
- } from "@takazudo/zudo-doc/nav-data-prep";
96
- import { buildSidebarForSection } from "@takazudo/zudo-doc/sidebar-utils";
97
- import { Details } from "@takazudo/zudo-doc/details";
98
- import {
99
- HtmlPreviewWrapper,
100
- type HtmlPreviewWrapperProps,
101
- } from "@takazudo/zudo-doc/html-preview-wrapper";
102
-
103
- // ---------------------------------------------------------------------------
104
- // Package-default host-only bindings (see module header).
105
- // ---------------------------------------------------------------------------
106
-
107
- /** Package-default color scheme — a neutral 16-step grey ramp. The project's
108
- * real `colorSchemes` palette map is project DATA (not in `settings`), so it
109
- * is not in the serializable virtual module; A2 re-homes it for the render
110
- * proof. Semantic roles fall back to `SEMANTIC_DEFAULTS`. */
111
- const GREY_RAMP: ColorScheme["palette"] = [
112
- "#000000", "#1a1a1a", "#333333", "#4d4d4d", "#666666", "#808080",
113
- "#999999", "#b3b3b3", "#cccccc", "#d9d9d9", "#e6e6e6", "#f2f2f2",
114
- "#ff5555", "#50fa7b", "#f1fa8c", "#8be9fd",
115
- ];
116
- const DEFAULT_SCHEME: ColorScheme = {
117
- background: "#000000",
118
- foreground: "#ffffff",
119
- cursor: "#ffffff",
120
- selectionBg: "#444444",
121
- selectionFg: "#ffffff",
122
- palette: GREY_RAMP,
123
- };
124
-
125
- /** Empty doc-history manifest — the real `#doc-history-meta` virtual JSON is
126
- * host-bound. With the flag off this is never read. */
127
- const docHistoryMeta: Record<string, never> = {};
128
-
129
- /** Empty sidebars config — sidebar sections fall back to the auto-generated
130
- * tree. The project `sidebars` config is host-bound (A2). */
131
- const sidebarsConfig: Record<string, never> = {};
132
-
133
- /** Package-default body-end islands — the package-island subset of the host's
134
- * `BodyEndIslands` (AiChatModal / ImageEnlarge / MermaidEnlarge), reconstructed
135
- * from the serializable virtual-module `settings` flags (#2406 / #2401(c)).
136
- * The host-owned bootstraps (client-router / design-token-panel) cannot live
137
- * in the package, so they are NOT included here — A2/S4 re-homes those. */
138
- const BodyEndIslands = createBodyEndIslands({ settings });
139
-
140
- /** Package no-op DocHistory island stub — renders an empty fragment (the
141
- * `DocHistoryComponent` contract requires a VNode, not null). */
142
- function DocHistoryStub(_props: { slug: string; locale?: string; basePath?: string }): VNode {
143
- return (<></>) as VNode;
144
- }
145
-
146
- /** SearchWidget adapter: the package `SearchWidget` requires a `base` prop, but
147
- * the `HeaderWithDefaults` dep signature omits it (the host stub injects it).
148
- * Inject the base-prefixed search index root here. */
149
- function SearchWidgetBound(props: {
150
- placeholderText: string;
151
- shortcutHint: string;
152
- resultCountTemplate: string;
153
- searchLabel: string;
154
- searchUnavailableText: string;
155
- loadingIndexText: string;
156
- noResultsText: string;
157
- }): JSX.Element {
158
- return SearchWidget({ ...props, base: withBase("/") });
159
- }
160
-
161
- // ---------------------------------------------------------------------------
162
- // composeMetaTitle + Head.
163
- // ---------------------------------------------------------------------------
164
-
165
- export const composeMetaTitle = createComposeMetaTitle(settings.siteName);
166
-
167
- // Scheme-selection: resolve the active color scheme(s) from the host
168
- // `colorSchemes` map supplied via the virtual module. Falls back to
169
- // `DEFAULT_SCHEME` for any missing key or when `colorSchemes` is absent.
170
- // `generateCssCustomProperties` is called in single-scheme mode
171
- // (`settings.colorMode` is false); `generateLightDarkCssProperties` in
172
- // light/dark mode. Both delegate to DEFAULT_SCHEME when `colorSchemes` is null.
173
- function resolveHostScheme(key: string): ColorScheme {
174
- if (!colorSchemes) return DEFAULT_SCHEME;
175
- return colorSchemes[key] ?? DEFAULT_SCHEME;
176
- }
177
-
178
- export const HeadWithDefaults = createHeadWithDefaults({
179
- settings,
180
- composeMetaTitle,
181
- withBase,
182
- absoluteUrl,
183
- // Called only in single-scheme mode (colorMode false): resolve via settings.colorScheme.
184
- generateCssCustomProperties: () =>
185
- generateCssCustomProperties(resolveHostScheme(settings.colorScheme)),
186
- // Called only in light/dark mode (colorMode truthy): resolve the pair.
187
- generateLightDarkCssProperties: () => {
188
- const cm = settings.colorMode;
189
- if (cm) {
190
- return generateLightDarkCssProperties(
191
- resolveHostScheme(cm.lightScheme),
192
- resolveHostScheme(cm.darkScheme),
193
- );
194
- }
195
- // Should not be reached (head-with-defaults only calls this when colorMode
196
- // is truthy), but guard the contract by falling back to DEFAULT_SCHEME.
197
- return generateLightDarkCssProperties(DEFAULT_SCHEME, DEFAULT_SCHEME);
198
- },
199
- });
200
-
201
- // ---------------------------------------------------------------------------
202
- // nav data-prep (bound to settings via _context helpers).
203
- // ---------------------------------------------------------------------------
204
-
205
- function buildRootMenuItems(lang: string, currentVersion: string | undefined) {
206
- return buildRootMenuItemsBase(
207
- lang,
208
- currentVersion,
209
- settings.headerNav,
210
- (key, l) => t(key, l),
211
- (path, l, v) => navHref(path, l, v),
212
- );
213
- }
214
-
215
- function buildLocaleLinksForNav(currentPath: string, lang: string, localeCount: number) {
216
- return buildLocaleLinksForNavBase(currentPath, lang, localeCount, (path, l) =>
217
- buildLocaleLinks(path, l),
218
- );
219
- }
220
-
221
- function buildSidebarNodes(
222
- lang: string,
223
- navSection: string | undefined,
224
- currentVersion: string | undefined,
225
- emptyWhenUnsectioned = true,
226
- ) {
227
- if (navSection === undefined && emptyWhenUnsectioned) return [];
228
- const { navDocs, categoryMeta } = loadNavSourceDocs(lang, currentVersion);
229
- const explicitPrefixes = getCategoryOrder().filter((cm) => cm !== "!");
230
- const rawNodes = buildSidebarForSection(
231
- navDocs,
232
- lang,
233
- navSection,
234
- categoryMeta as unknown as Map<string, CategoryMeta>,
235
- sidebarsConfig,
236
- (d, l, meta) =>
237
- buildNavTree(
238
- d as never[],
239
- l,
240
- meta as Map<string, CategoryMeta> | undefined,
241
- (slug, loc) => docsUrl(slug, loc),
242
- ) as never[],
243
- explicitPrefixes,
244
- );
245
- return currentVersion
246
- ? remapVersionedHrefs(rawNodes, currentVersion, lang, (slug, v, l) =>
247
- versionedDocsUrl(slug, v, l),
248
- )
249
- : rawNodes;
250
- }
251
-
252
- function getThemeDefaultMode() {
253
- return getThemeDefaultModeBase(settings.colorMode);
254
- }
255
-
256
- // ---------------------------------------------------------------------------
257
- // Header / Footer / Sidebar.
258
- // ---------------------------------------------------------------------------
259
-
260
- export const HeaderWithDefaults = createHeaderWithDefaults({
261
- settings,
262
- defaultLocale,
263
- locales,
264
- t,
265
- withBase,
266
- stripBase,
267
- docsUrl,
268
- navHref,
269
- versionedDocsUrl,
270
- buildLocaleLinksForNav,
271
- buildRootMenuItems,
272
- buildSidebarNodes,
273
- getThemeDefaultMode,
274
- buildGitHubRepoUrl: () => buildGitHubRepoUrl(settings.githubUrl),
275
- SearchWidget: SearchWidgetBound,
276
- });
277
-
278
- export const FooterWithDefaults = createFooterWithDefaults({
279
- settings,
280
- defaultLocale,
281
- tagVocabulary: [],
282
- isExternal: (href: string) => /^https?:\/\//.test(href),
283
- resolveHref: (href: string) => (/^https?:\/\//.test(href) ? href : withBase(href)),
284
- withBase,
285
- // The footer taglist is host-bound (project tag aggregation); package default
286
- // renders no tag columns.
287
- loadTagsForLocale: () => [],
288
- });
289
-
290
- export const SidebarWithDefaults = createSidebarWithDefaults({
291
- defaultLocale,
292
- localeCount: locales.length,
293
- buildRootMenuItems,
294
- buildLocaleLinksForNav,
295
- buildSidebarNodes,
296
- getThemeDefaultMode,
297
- t,
298
- });
299
-
300
- const SidebarPrepaint = createSidebarPrepaint({ sidebarToggle: settings.sidebarToggle });
301
- const DocBodyEnd = createDocBodyEnd({ settings, BodyEndIslands });
302
- const DocPager = createDocPager({ t });
303
-
304
- // ---------------------------------------------------------------------------
305
- // Doc content header / metainfo / tags / history.
306
- // ---------------------------------------------------------------------------
307
-
308
- const DocMetainfoArea = createDocMetainfoArea({
309
- settings,
310
- defaultLocale,
311
- docHistoryMeta,
312
- t,
313
- toHistorySlug,
314
- });
315
-
316
- const DocTagsArea = createDocTagsArea({
317
- settings,
318
- defaultLocale,
319
- tagVocabularyEntries: [],
320
- tagHref: (tag: string, locale: string) => {
321
- const encoded = encodeURIComponent(tag);
322
- return withBase(
323
- locale === defaultLocale
324
- ? `/docs/tags/${encoded}`
325
- : `/${locale}/docs/tags/${encoded}`,
326
- );
327
- },
328
- t,
329
- });
330
-
331
- const DocContentHeader = createDocContentHeader({
332
- t,
333
- buildFrontmatterPreviewEntries: () => [],
334
- frontmatterRenderers: {},
335
- DocMetainfoArea,
336
- DocTagsArea,
337
- });
338
-
339
- const DocHistoryArea = createDocHistoryArea({
340
- settings,
341
- defaultLocale,
342
- docHistoryMeta,
343
- t,
344
- toHistorySlug,
345
- buildGitHubSourceUrl: (contentDir: string, entryId: string) =>
346
- buildGitHubSourceUrl(settings.githubUrl, contentDir, entryId),
347
- DocHistory: DocHistoryStub,
348
- });
349
-
350
- const buildInlineVersionSwitcher = createInlineVersionSwitcher({
351
- settings,
352
- defaultLocale,
353
- t,
354
- docsUrl,
355
- versionedDocsUrl,
356
- withBase,
357
- });
358
-
359
- // ---------------------------------------------------------------------------
360
- // MDX components (locale-bound nav wrappers + package defaults).
361
- // ---------------------------------------------------------------------------
362
-
363
- const CategoryNavWrapper = createCategoryNavWrapper({
364
- defaultLocale,
365
- resolveNavSource: resolveNavSource as never,
366
- buildNavTree: ((docs: unknown[], locale: string, categoryMeta: Map<string, unknown>) =>
367
- buildNavTree(
368
- docs as never[],
369
- locale,
370
- categoryMeta as Map<string, CategoryMeta>,
371
- (slug, loc) => docsUrl(slug, loc),
372
- )) as never,
373
- findNode: findNode as never,
374
- firstRoutedHref: firstRoutedHref as never,
375
- });
376
-
377
- const CategoryTreeNavWrapper = createCategoryTreeNavWrapper({
378
- defaultLocale,
379
- resolveNavSource: resolveNavSource as never,
380
- buildNavTree: ((docs: unknown[], locale: string, categoryMeta: Map<string, unknown>) =>
381
- buildNavTree(
382
- docs as never[],
383
- locale,
384
- categoryMeta as Map<string, CategoryMeta>,
385
- (slug, loc) => docsUrl(slug, loc),
386
- )) as never,
387
- groupSatelliteNodes: groupSatelliteNodes as never,
388
- findNode: findNode as never,
389
- });
390
-
391
- const SiteTreeNavWrapper = createSiteTreeNavWrapper({
392
- defaultLocale,
393
- resolveNavSource: resolveNavSource as never,
394
- buildNavTree: ((docs: unknown[], locale: string, categoryMeta: Map<string, unknown>) =>
395
- buildNavTree(
396
- docs as never[],
397
- locale,
398
- categoryMeta as Map<string, CategoryMeta>,
399
- (slug, loc) => docsUrl(slug, loc),
400
- )) as never,
401
- groupSatelliteNodes: groupSatelliteNodes as never,
402
- getCategoryOrder,
403
- });
404
-
405
- /** HtmlPreview MDX binding (package default).
406
- *
407
- * Mirrors the host stub (`pages/_mdx-components.ts`): the global preview
408
- * config is `settings.htmlPreview`, a SERIALIZABLE setting that DOES ride in
409
- * the route-context virtual module, so the package can read it directly (no
410
- * host config needed). `HtmlPreviewWrapper` wraps the bare preview in
411
- * `<Island when="visible">`, which SSR-renders the preview tree — so an
412
- * injected docs page using `<HtmlPreview html="…" />` renders correct HTML.
413
- *
414
- * Hydration caveat: the interactive code-toggle hydrates only if zfb's islands
415
- * scanner reaches the `@takazudo/zfb` <Island> import inside
416
- * `HtmlPreviewWrapper`. The esbuild islands bundler does NOT walk imports of
417
- * modules whose realpath is under `node_modules` (the same gap the routes
418
- * plugin stages around — see `plugins/routes.ts`; upstream report:
419
- * Takazudo/zudo-front-builder, "islands bundler skips addVirtualModule /
420
- * import-walk for node_modules route realpaths"). SSR output is unaffected. */
421
- function HtmlPreviewBound(props: HtmlPreviewWrapperProps): JSX.Element {
422
- return HtmlPreviewWrapper({
423
- globalConfig: settings.htmlPreview ?? null,
424
- ...props,
425
- }) as JSX.Element;
426
- }
427
-
428
- /** Island MDX binding (package default) — an SSR pass-through that renders its
429
- * children, deliberately NOT the real `@takazudo/zfb` <Island>.
430
- *
431
- * Why a pass-through and not `Island → @takazudo/zfb` (the sub-issue's literal
432
- * ask): the MDX corpus never uses `<Island>` as a real render tag (only inside
433
- * changelog prose), and the host stub itself uses this same pass-through. The
434
- * real zfb <Island> emits `data-zfb-island="<firstChildTagName>"` for generic
435
- * MDX children, i.e. a hydration marker pointing at a non-existent manifest
436
- * entry — and the islands scanner can't register it anyway from a package
437
- * (node_modules) import (upstream report above). A pass-through renders the
438
- * server-renderable children correctly with no bogus marker, which is the
439
- * complete and correct behaviour for the corpus. `when` is ignored at SSR
440
- * time (it only matters to the client hydration runtime). */
441
- function IslandPassthrough(props: {
442
- when?: "load" | "idle" | "visible" | "media";
443
- children?: ComponentChildren;
444
- }): ComponentChildren {
445
- return props.children ?? null;
446
- }
447
-
448
- export function createMdxComponentsBound(lang: string = defaultLocale) {
449
- return createMdxComponents({
450
- settings,
451
- locale: lang,
452
- navData: {
453
- CategoryNav: CategoryNavWrapper as never,
454
- CategoryTreeNav: CategoryTreeNavWrapper as never,
455
- SiteTreeNav: SiteTreeNavWrapper as never,
456
- },
457
- // Package-owned content components wired here so an INJECTED docs route
458
- // (packageOwnedRoutes, no host `pages/` stub) renders MDX using these tags
459
- // without the "MDX requires '<X>' to be passed via the 'components' prop"
460
- // error (sub-issue #2390 / supersedes #2377).
461
- // - Details → fully functional (pure <details>, no client JS).
462
- // - HtmlPreview → SSR-renders; see HtmlPreviewBound for the hydration
463
- // caveat tied to the node_modules islands-scanner gap.
464
- // - Island → SSR pass-through; see IslandPassthrough.
465
- // PresetGenerator stays a package stub (render nothing): it is the
466
- // showcase's project-bound interactive island and downstream projects stub
467
- // it. The showcase keeps its host-owned docs catch-all routes (allowlisted)
468
- // so its real PresetGenerator still renders.
469
- extras: {
470
- Details: Details as never,
471
- HtmlPreview: HtmlPreviewBound as never,
472
- Island: IslandPassthrough as never,
473
- PresetGenerator: (_props: unknown) => null,
474
- },
475
- });
476
- }
477
-
478
- // ---------------------------------------------------------------------------
479
- // DocPageShell + renderDocPage.
480
- // ---------------------------------------------------------------------------
481
-
482
- const DocPageShell = createDocPageShell({
483
- settings,
4
+ // The chrome wiring was PROMOTED to the public, shared
5
+ // `createChrome(context, hostBindings)` builder
6
+ // (`@takazudo/zudo-doc/chrome`, CTX #2423). This module is now just the seam
7
+ // that calls it ONCE with the reconstructed route context and NO host bindings
8
+ // so every host-bound slot resolves to its package-default stub and the
9
+ // injected package-routes render is byte-identical to before. The host
10
+ // (HOSTCOLLAPSE wave) will call `createChrome` directly with real bindings.
11
+
12
+ import { routeCtx } from "./_context.js";
13
+ import { createChrome } from "@takazudo/zudo-doc/chrome";
14
+ import type { DocNavNode } from "./_docs-helpers.js";
15
+
16
+ // Empty host bindings → package-default stubs (byte-identical injected path).
17
+ const chrome = createChrome(routeCtx);
18
+
19
+ export const {
484
20
  composeMetaTitle,
485
- getTocTitle,
486
21
  HeadWithDefaults,
487
- SidebarWithDefaults,
488
22
  HeaderWithDefaults,
489
23
  FooterWithDefaults,
490
- SidebarPrepaint,
491
- DocBodyEnd,
492
- DocPager,
493
- });
494
-
495
- export const renderDocPage = createRenderDocPage({
496
- docsUrl,
497
- versionedDocsUrl,
498
- absoluteUrl,
499
- getNavSectionForSlug,
500
- toRouteSlug,
501
- createMdxComponents: createMdxComponentsBound,
502
- t,
503
- buildInlineVersionSwitcher,
504
- DocPageShell,
505
- DocContentHeader,
506
- DocMetainfoArea,
507
- DocHistoryArea,
508
- });
509
-
510
- // ---------------------------------------------------------------------------
511
- // VersionsPageView + TagPages.
512
- // ---------------------------------------------------------------------------
513
-
514
- export const VersionsPageView = createVersionsPageView({
515
- settings,
516
- defaultLocale,
517
- t,
518
- withBase,
519
- composeMetaTitle,
520
- components: {
521
- HeadWithDefaults,
522
- HeaderWithDefaults,
523
- FooterWithDefaults,
524
- BodyEndIslands,
525
- },
526
- });
527
-
528
- const tagPages = createTagPages({
529
- settings,
530
- defaultLocale,
531
- t,
532
- withBase,
533
- docsUrl,
534
- composeMetaTitle,
535
- collectTags: collectTags as never,
536
- stableDocs: stableDocs as never,
537
- isDefaultLocaleOnlyPath: undefined,
538
- components: {
539
- HeadWithDefaults,
540
- HeaderWithDefaults,
541
- FooterWithDefaults,
542
- BodyEndIslands,
543
- DocHistoryArea: DocHistoryArea as never,
544
- },
545
- });
546
-
547
- export const { collectTagMapForLocale, TagDetailPageView, TagsIndexPageView } = tagPages;
548
-
549
- // Re-export the locale-aware site-tree wrapper + the package-default body-end
550
- // islands for the index entrypoints.
551
- export { SiteTreeNavWrapper, BodyEndIslands };
552
-
553
- // Bring the doc-route-entries builder + types into the chrome surface so the
554
- // doc entrypoints import a single module.
555
- export {
556
- buildDocRouteEntries,
557
- } from "./_context.js";
24
+ SidebarWithDefaults,
25
+ renderDocPage,
26
+ VersionsPageView,
27
+ collectTagMapForLocale,
28
+ TagDetailPageView,
29
+ TagsIndexPageView,
30
+ SiteTreeNavWrapper,
31
+ BodyEndIslands,
32
+ } = chrome;
33
+
34
+ // The doc-route-entries builder lives on the route context; the doc entrypoints
35
+ // import it from this chrome module so they reach a single barrel.
36
+ export { buildDocRouteEntries } from "./_context.js";
558
37
  export type { DocNavNode };