@takazudo/zudo-doc 1.3.0 → 2.0.1

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/doc-body-end/index.d.ts +9 -11
  6. package/dist/doc-body-end/index.js +4 -2
  7. package/dist/doc-content-header/index.d.ts +10 -2
  8. package/dist/doc-content-header/index.js +8 -8
  9. package/dist/doc-history-area/index.d.ts +10 -25
  10. package/dist/doc-history-area/index.js +14 -10
  11. package/dist/doc-metainfo-area/index.d.ts +9 -15
  12. package/dist/doc-metainfo-area/index.js +6 -2
  13. package/dist/doc-page-renderer/index.d.ts +11 -2
  14. package/dist/doc-page-renderer/index.js +22 -15
  15. package/dist/doc-page-shell/index.d.ts +11 -3
  16. package/dist/doc-page-shell/index.js +21 -14
  17. package/dist/doc-pager/index.d.ts +6 -7
  18. package/dist/doc-pager/index.js +2 -2
  19. package/dist/doc-route-entries/index.d.ts +22 -46
  20. package/dist/doc-route-entries/index.js +15 -10
  21. package/dist/doc-tags-area/index.d.ts +9 -19
  22. package/dist/doc-tags-area/index.js +12 -2
  23. package/dist/factory-context/index.d.ts +163 -1
  24. package/dist/footer-with-defaults/index.d.ts +12 -13
  25. package/dist/footer-with-defaults/index.js +8 -10
  26. package/dist/head/types.d.ts +39 -0
  27. package/dist/head-with-defaults/index.d.ts +12 -16
  28. package/dist/head-with-defaults/index.js +93 -10
  29. package/dist/header-with-defaults/index.d.ts +10 -31
  30. package/dist/header-with-defaults/index.js +15 -18
  31. package/dist/nav-source-docs/index.d.ts +20 -54
  32. package/dist/nav-source-docs/index.js +9 -10
  33. package/dist/route-context/index.d.ts +24 -0
  34. package/dist/route-context/index.js +147 -0
  35. package/dist/route-enumerators/index.d.ts +25 -74
  36. package/dist/route-enumerators/index.js +17 -18
  37. package/dist/routes/_chrome.d.ts +6 -25
  38. package/dist/routes/_chrome.js +14 -387
  39. package/dist/routes/_context.d.ts +10 -43
  40. package/dist/routes/_context.js +29 -157
  41. package/dist/safelist.css +1 -1
  42. package/dist/settings.d.ts +54 -0
  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 +13 -5
  51. package/routes-src/_chrome.tsx +31 -552
  52. package/routes-src/_context.ts +37 -269
@@ -1,19 +1,26 @@
1
1
  import { jsx } from "preact/jsx-runtime";
2
- function createRenderDocPage(deps) {
3
- const {
4
- docsUrl,
5
- versionedDocsUrl,
6
- absoluteUrl,
7
- getNavSectionForSlug,
8
- toRouteSlug,
9
- createMdxComponents,
10
- t,
11
- buildInlineVersionSwitcher,
12
- DocPageShell,
13
- DocContentHeader,
14
- DocMetainfoArea,
15
- DocHistoryArea
16
- } = deps;
2
+ import { createDocPageShell } from "../doc-page-shell/index.js";
3
+ import { createDocContentHeader } from "../doc-content-header/index.js";
4
+ import { createDocMetainfoArea } from "../doc-metainfo-area/index.js";
5
+ import { createDocHistoryArea } from "../doc-history-area/index.js";
6
+ import { deriveMdxComponents, deriveInlineVersionSwitcher } from "../chrome/derive.js";
7
+ function createRenderDocPage(ctx) {
8
+ const docsUrl = ctx.docsUrl;
9
+ const versionedDocsUrl = ctx.versionedDocsUrl;
10
+ const absoluteUrl = ctx.absoluteUrl;
11
+ const getNavSectionForSlug = ctx.getNavSectionForSlug;
12
+ const toRouteSlug = ctx.toRouteSlug;
13
+ const createMdxComponents = deriveMdxComponents(ctx).createMdxComponentsBound;
14
+ const t = ctx.t;
15
+ const buildInlineVersionSwitcher = deriveInlineVersionSwitcher(
16
+ ctx
17
+ );
18
+ const DocPageShell = createDocPageShell(ctx);
19
+ const DocContentHeader = createDocContentHeader(
20
+ ctx
21
+ );
22
+ const DocMetainfoArea = createDocMetainfoArea(ctx);
23
+ const DocHistoryArea = createDocHistoryArea(ctx);
17
24
  function renderDocPage(props, opts) {
18
25
  const { breadcrumbs, prev, next, headings } = props;
19
26
  const { locale, version, isFallback } = opts;
@@ -2,6 +2,8 @@
2
2
  /** @jsxImportSource preact */
3
3
  import type { ComponentChildren, JSX, VNode } from "preact";
4
4
  import type { VersionBannerLabels } from "../i18n-version/index.js";
5
+ import type { ChromeContext } from "../factory-context/index.js";
6
+ import type { Settings } from "../settings.js";
5
7
  /** A heading item for the TOC. */
6
8
  export interface DocPageHeading {
7
9
  depth: number;
@@ -130,7 +132,13 @@ export interface DocPageShellDeps {
130
132
  }) => JSX.Element;
131
133
  }
132
134
  /**
133
- * Create a `DocPageShell` component bound to the host's settings and
134
- * component dependencies.
135
+ * Create a `DocPageShell` component from the unified {@link ChromeContext}
136
+ * (epic Collapse Wiring Shells #2420, FACTORIES #2424 — breaking signature).
137
+ *
138
+ * Reads `settings` directly, `composeMetaTitle`/`getTocTitle` from the shared
139
+ * derive helper + the package toc helper, and rebuilds the Head / Sidebar /
140
+ * Header / Footer / SidebarPrepaint / DocBodyEnd / DocPager sub-components from
141
+ * the SAME context (so a host-supplied chrome context flows its real bindings
142
+ * straight through, byte-identical to the pre-collapse wiring).
135
143
  */
136
- export declare function createDocPageShell(deps: DocPageShellDeps): (props: DocPageShellProps) => JSX.Element;
144
+ export declare function createDocPageShell<S extends Settings = Settings>(ctx: ChromeContext<S>): (props: DocPageShellProps) => JSX.Element;
@@ -1,22 +1,29 @@
1
1
  import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
2
2
  import { Island } from "@takazudo/zfb";
3
3
  import { DocLayoutWithDefaults } from "../doclayout/index.js";
4
- import { Toc, MobileToc } from "../toc/index.js";
4
+ import { Toc, MobileToc, getTocTitle } from "../toc/index.js";
5
5
  import { Breadcrumb } from "../breadcrumb/index.js";
6
6
  import { NavCardGrid } from "../nav-indexing/index.js";
7
- function createDocPageShell(deps) {
8
- const {
9
- settings,
10
- composeMetaTitle,
11
- getTocTitle,
12
- HeadWithDefaults,
13
- SidebarWithDefaults,
14
- HeaderWithDefaults,
15
- FooterWithDefaults,
16
- SidebarPrepaint,
17
- DocBodyEnd,
18
- DocPager
19
- } = deps;
7
+ import { createSidebarPrepaint } from "../sidebar-prepaint/index.js";
8
+ import { createHeadWithDefaults } from "../head-with-defaults/index.js";
9
+ import { createSidebarWithDefaults } from "../sidebar-with-defaults/index.js";
10
+ import { createHeaderWithDefaults } from "../header-with-defaults/index.js";
11
+ import { createFooterWithDefaults } from "../footer-with-defaults/index.js";
12
+ import { createDocBodyEnd } from "../doc-body-end/index.js";
13
+ import { createDocPager } from "../doc-pager/index.js";
14
+ import { deriveComposeMetaTitle } from "../chrome/derive.js";
15
+ function createDocPageShell(ctx) {
16
+ const settings = ctx.settings;
17
+ const composeMetaTitle = deriveComposeMetaTitle(ctx);
18
+ const HeadWithDefaults = createHeadWithDefaults(ctx);
19
+ const SidebarWithDefaults = createSidebarWithDefaults(ctx);
20
+ const HeaderWithDefaults = createHeaderWithDefaults(ctx);
21
+ const FooterWithDefaults = createFooterWithDefaults(ctx);
22
+ const SidebarPrepaint = createSidebarPrepaint({
23
+ sidebarToggle: Boolean(ctx.settings.sidebarToggle)
24
+ });
25
+ const DocBodyEnd = createDocBodyEnd(ctx);
26
+ const DocPager = createDocPager(ctx);
20
27
  function DocPageShell(props) {
21
28
  const {
22
29
  kind,
@@ -1,6 +1,8 @@
1
1
  /** @jsxRuntime automatic */
2
2
  /** @jsxImportSource preact */
3
3
  import type { JSX } from "preact";
4
+ import type { ChromeContext } from "../factory-context/index.js";
5
+ import type { Settings } from "../settings.js";
4
6
  interface PagerNode {
5
7
  href?: string;
6
8
  label: string;
@@ -13,13 +15,10 @@ export interface DocPagerProps {
13
15
  /** Active locale for translated "Previous" / "Next" labels. */
14
16
  locale: string;
15
17
  }
16
- /** Dependencies injected by the host stub. */
17
- export interface DocPagerDeps {
18
- /** Translate a UI string key for a locale. */
19
- t: (key: string, locale: string) => string;
20
- }
21
18
  /**
22
- * Create a `DocPager` component bound to the host's injected `t` translator.
19
+ * Create a `DocPager` component from the unified {@link ChromeContext}
20
+ * (epic Collapse Wiring Shells #2420, FACTORIES #2424 — breaking signature).
21
+ * Reads only the `t` translator off the context.
23
22
  */
24
- export declare function createDocPager(deps: DocPagerDeps): (props: DocPagerProps) => JSX.Element;
23
+ export declare function createDocPager<S extends Settings = Settings>(ctx: ChromeContext<S>): (props: DocPagerProps) => JSX.Element;
25
24
  export {};
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs } from "preact/jsx-runtime";
2
2
  import { ChevronLeft, ChevronRight } from "../icons/index.js";
3
- function createDocPager(deps) {
4
- const { t } = deps;
3
+ function createDocPager(ctx) {
4
+ const t = ctx.t;
5
5
  function DocPager({ prev, next, locale }) {
6
6
  return /* @__PURE__ */ jsxs("nav", { class: "mt-vsp-2xl grid grid-cols-2 gap-hsp-xl", children: [
7
7
  prev ? /* @__PURE__ */ jsxs(
@@ -2,6 +2,7 @@ import type { DocPageEntry, DocNavNode, AutoIndexNode, DocPageBaseProps } from "
2
2
  import type { NavSourceDocs } from "../nav-source-docs/index.js";
3
3
  import type { BreadcrumbItem } from "../breadcrumb/types.js";
4
4
  import type { HeadingItem } from "../extract-headings/index.js";
5
+ import type { CategoryMeta } from "../sidebar-tree/index.js";
5
6
  export type { DocPageEntry, DocNavNode, AutoIndexNode, DocPageBaseProps, NavSourceDocs };
6
7
  /** One enumerated doc route: a content entry or an auto-generated category
7
8
  * index, with all per-page derived data pre-computed. */
@@ -39,49 +40,33 @@ export interface BuildDocRouteEntriesArgs {
39
40
  }
40
41
  export type { BreadcrumbItem, HeadingItem };
41
42
  /**
42
- * Injected context for `createDocRouteEntries`.
43
+ * Context slice `createDocRouteEntries` derives its bag from (epic Collapse
44
+ * Wiring Shells #2420, FACTORIES #2424 — breaking signature). STRUCTURAL SUBSET
45
+ * of the unified `RouteContext`/`ChromeContext` — the nav-tree builder is
46
+ * reconstructed by binding the context's 4-arg `buildNavTree` to `docsUrl`, and
47
+ * the breadcrumb trail by binding the package `buildBreadcrumbs` to the
48
+ * locale-prefixed `withBase` base, exactly as the pre-collapse wiring did.
43
49
  */
44
50
  export interface DocRouteEntriesContext {
45
- /**
46
- * Build the nav tree for a locale from a flat entry array and category meta.
47
- * Host passes `buildNavTree` from `@/utils/docs`.
48
- */
49
- buildNavTree: (docs: DocPageEntry[], locale: string, categoryMeta: Map<string, unknown>) => DocNavNode[];
50
- /**
51
- * Build breadcrumb trail by walking the nav tree.
52
- * Host passes `buildBreadcrumbs` from `@/utils/docs`.
53
- */
54
- buildBreadcrumbs: (tree: DocNavNode[], slug: string, locale: string, urlFor?: (slug: string) => string) => BreadcrumbItem[];
55
- /**
56
- * Collect all auto-generated index nodes (categories without index.mdx).
57
- * Host passes `collectAutoIndexNodes` from `@/utils/docs`.
58
- */
51
+ /** Default locale code (drives the breadcrumb base-prefix selection). */
52
+ defaultLocale: string;
53
+ /** Build the nav tree for a locale (4-arg form with an explicit href builder). */
54
+ buildNavTree: (docs: DocPageEntry[], locale: string, categoryMeta: Map<string, CategoryMeta> | undefined, buildHref: (slug: string, locale: string) => string) => DocNavNode[];
55
+ /** Build a docs URL for the given slug and locale. */
56
+ docsUrl: (slug: string, locale?: string) => string;
57
+ /** Prefix a path with the configured base directory. */
58
+ withBase: (path: string) => string;
59
+ /** Collect all auto-generated index nodes (categories without index.mdx). */
59
60
  collectAutoIndexNodes: (tree: DocNavNode[]) => AutoIndexNode[];
60
- /**
61
- * Determine the nav section (categoryMatch) for a slug.
62
- * Host passes `getNavSectionForSlug` from `@/utils/nav-scope`.
63
- */
61
+ /** Determine the nav section (categoryMatch) for a slug. */
64
62
  getNavSectionForSlug: (slug: string) => string | undefined;
65
- /**
66
- * Filter top-level nav nodes by a categoryMatch value.
67
- * Host passes `getNavSubtree` from `@/utils/nav-scope`.
68
- */
63
+ /** Filter top-level nav nodes by a categoryMatch value. */
69
64
  getNavSubtree: (tree: DocNavNode[], categoryMatch?: string) => DocNavNode[];
70
- /**
71
- * Convert a content entry slug to a canonical route slug.
72
- * Host passes `toRouteSlug` from `@/utils/slug` (or the package's
73
- * `@takazudo/zudo-doc/slug`).
74
- */
65
+ /** Convert a content entry slug to a canonical route slug. */
75
66
  toRouteSlug: (id: string) => string;
76
- /**
77
- * Convert a canonical route slug to an optional-catchall params array.
78
- * Host passes `toSlugParams` from `@/utils/slug`.
79
- */
67
+ /** Convert a canonical route slug to an optional-catchall params array. */
80
68
  toSlugParams: (slug: string) => string[];
81
- /**
82
- * Extract headings from a raw MDX body.
83
- * Host passes the wrapper from `pages/lib/_extract-headings.ts`.
84
- */
69
+ /** Extract headings from a raw MDX body (bound to settings depth/strategy). */
85
70
  extractHeadings: (body: string) => HeadingItem[];
86
71
  }
87
72
  /**
@@ -109,16 +94,7 @@ export interface DocRouteEntriesAPI {
109
94
  * import { toRouteSlug, toSlugParams } from "@/utils/slug";
110
95
  * import { extractHeadings } from "./_extract-headings";
111
96
  *
112
- * export const { buildDocRouteEntries } = createDocRouteEntries({
113
- * buildNavTree,
114
- * buildBreadcrumbs,
115
- * collectAutoIndexNodes,
116
- * getNavSectionForSlug,
117
- * getNavSubtree,
118
- * toRouteSlug,
119
- * toSlugParams,
120
- * extractHeadings,
121
- * });
97
+ * export const { buildDocRouteEntries } = createDocRouteEntries(routeContext);
122
98
  * export type { DocRouteEntry, BuildDocRouteEntriesArgs };
123
99
  * ```
124
100
  */
@@ -1,4 +1,5 @@
1
1
  import { memoizeDerived } from "../nav-source-cache/index.js";
2
+ import { buildBreadcrumbs as buildBreadcrumbsImpl } from "../routes/_docs-helpers.js";
2
3
  import {
3
4
  resolveDocPrevNext,
4
5
  flattenSubtree,
@@ -6,16 +7,20 @@ import {
6
7
  remapNavChildHrefs
7
8
  } from "../doc-route-paths/index.js";
8
9
  function createDocRouteEntries(ctx) {
9
- const {
10
- buildNavTree,
11
- buildBreadcrumbs,
12
- collectAutoIndexNodes,
13
- getNavSectionForSlug,
14
- getNavSubtree,
15
- toRouteSlug,
16
- toSlugParams,
17
- extractHeadings
18
- } = ctx;
10
+ const defaultLocale = ctx.defaultLocale;
11
+ const buildNavTree = (docs, locale, categoryMeta) => ctx.buildNavTree(docs, locale, categoryMeta, (slug, loc) => ctx.docsUrl(slug, loc));
12
+ const buildBreadcrumbs = (tree, slug, locale, urlFor) => buildBreadcrumbsImpl(
13
+ tree,
14
+ slug,
15
+ locale === defaultLocale ? ctx.withBase("/") : ctx.withBase(`/${locale}/`),
16
+ urlFor
17
+ );
18
+ const collectAutoIndexNodes = ctx.collectAutoIndexNodes;
19
+ const getNavSectionForSlug = ctx.getNavSectionForSlug;
20
+ const getNavSubtree = ctx.getNavSubtree;
21
+ const toRouteSlug = ctx.toRouteSlug;
22
+ const toSlugParams = ctx.toSlugParams;
23
+ const extractHeadings = ctx.extractHeadings;
19
24
  function buildDocRouteEntries(args) {
20
25
  const { source, locale, routeSig, urlFor } = args;
21
26
  return memoizeDerived([source.docs], `docRouteEntries;${routeSig}`, () => {
@@ -1,28 +1,14 @@
1
1
  /** @jsxRuntime automatic */
2
2
  /** @jsxImportSource preact */
3
3
  import type { VNode } from "preact";
4
- import type { TagVocabularyEntry, TagGovernanceMode } from "../settings.js";
4
+ import type { TagVocabularyEntry, TagGovernanceMode, Settings } from "../settings.js";
5
+ import type { ChromeContext } from "../factory-context/index.js";
5
6
  /** Settings subset read by the DocTagsArea factory. */
6
7
  export interface DocTagsAreaSettings {
7
8
  docTags: boolean;
8
9
  tagVocabulary: boolean | readonly TagVocabularyEntry[];
9
10
  tagGovernance: TagGovernanceMode;
10
11
  }
11
- /** Dependencies injected by the host stub. */
12
- export interface DocTagsAreaDeps {
13
- settings: DocTagsAreaSettings;
14
- /** Default locale code (e.g. "en"). */
15
- defaultLocale: string;
16
- /** Tag vocabulary entries (from the host's `@/config/tag-vocabulary`). */
17
- tagVocabularyEntries: readonly TagVocabularyEntry[];
18
- /**
19
- * Build the base-prefixed tag detail page href for the given tag and locale.
20
- * Host passes a pre-bound function using `withBase` and `defaultLocale`.
21
- */
22
- tagHref: (tag: string, locale: string) => string;
23
- /** Translate a UI string key for a locale. */
24
- t: (key: string, locale: string) => string;
25
- }
26
12
  export interface DocTagsAreaProps {
27
13
  /** Page slug, e.g. "guides/sidebar". */
28
14
  slug: string;
@@ -32,7 +18,11 @@ export interface DocTagsAreaProps {
32
18
  tags: readonly string[] | undefined;
33
19
  }
34
20
  /**
35
- * Create a `DocTagsArea` component bound to the host's settings and
36
- * injected dependencies.
21
+ * Create a `DocTagsArea` component from the unified {@link ChromeContext}
22
+ * (epic Collapse Wiring Shells #2420, FACTORIES #2424 — breaking signature).
23
+ *
24
+ * Reads `settings`/`t`/`withBase`/`defaultLocale` off the context; the tag
25
+ * vocabulary is a HOST-bound slot (`ctx.hostBindings.tagVocabulary`, default
26
+ * `[]`); `tagHref` is reconstructed inline (identical to the pre-collapse wiring).
37
27
  */
38
- export declare function createDocTagsArea(deps: DocTagsAreaDeps): (props: DocTagsAreaProps) => VNode | null;
28
+ export declare function createDocTagsArea<S extends Settings = Settings>(ctx: ChromeContext<S>): (props: DocTagsAreaProps) => VNode | null;
@@ -1,8 +1,18 @@
1
1
  import { jsx } from "preact/jsx-runtime";
2
2
  import { DocTags } from "../metainfo/index.js";
3
3
  import { resolvePageTags } from "../tag-helpers/index.js";
4
- function createDocTagsArea(deps) {
5
- const { settings, tagVocabularyEntries, tagHref, t } = deps;
4
+ function createDocTagsArea(ctx) {
5
+ const settings = ctx.settings;
6
+ const defaultLocale = ctx.defaultLocale;
7
+ const withBase = ctx.withBase;
8
+ const tagVocabularyEntries = ctx.hostBindings.tagVocabulary ?? [];
9
+ const tagHref = (tag, locale) => {
10
+ const encoded = encodeURIComponent(tag);
11
+ return withBase(
12
+ locale === defaultLocale ? `/docs/tags/${encoded}` : `/${locale}/docs/tags/${encoded}`
13
+ );
14
+ };
15
+ const t = ctx.t;
6
16
  function DocTagsArea({ locale, tags }) {
7
17
  if (!settings.docTags) return null;
8
18
  const rawTags = tags ?? [];
@@ -1,4 +1,13 @@
1
- import type { Settings } from "../settings.js";
1
+ import type { Settings, TagVocabularyEntry } from "../settings.js";
2
+ import type { ColorScheme } from "../color-scheme-utils.js";
3
+ import type { UrlHelpers } from "../url-helpers/index.js";
4
+ import type { NavSourceDocsAPI } from "../nav-source-docs/index.js";
5
+ import type { DocRouteEntriesAPI } from "../doc-route-entries/index.js";
6
+ import type { RouteEnumeratorsAPI } from "../route-enumerators/index.js";
7
+ import type { ResolvedTag } from "../tag-helpers/index.js";
8
+ import type { DocNavNode, DocPageEntry } from "../doc-page-props/index.js";
9
+ import type { HeadingItem } from "../extract-headings/index.js";
10
+ import type { CategoryMeta } from "../sidebar-tree/index.js";
2
11
  /**
3
12
  * The i18n surface a factory may read. Parameterizes what `base.ts` used to read
4
13
  * off the project's `@/config/i18n` singleton directly, so URL/locale logic moves
@@ -78,3 +87,156 @@ export interface FactoryContext<S = Settings> {
78
87
  /** Opaque per-locale nav-source handle passed to the pure nav builders. */
79
88
  navSource: NavSource;
80
89
  }
90
+ /**
91
+ * The serializable route-context payload carried by the
92
+ * `virtual:zudo-doc-route-context` module (ADR `route-injection-seam.md`,
93
+ * Decision 1) — DATA ONLY, no callables. `createRouteContext` rebuilds the full
94
+ * runtime context from it by calling the importable package factories.
95
+ */
96
+ export interface RouteContextPayload<S = Settings> {
97
+ /** The host's resolved settings object. */
98
+ settings: S;
99
+ /** Per-locale UI-string tables (`translations[locale][key]`). */
100
+ translations: Record<string, Record<string, string>>;
101
+ /** The tag vocabulary (used only when `settings.tagVocabulary` is on). */
102
+ tagVocabulary: readonly TagVocabularyEntry[];
103
+ /** Host color-scheme palette map; `null` when the host passed none (chrome
104
+ * then falls back to a neutral default scheme). */
105
+ colorSchemes: Record<string, ColorScheme> | null;
106
+ }
107
+ /** Aggregated `tag → docs` index entry built by `collectTags`. */
108
+ export interface TagInfo {
109
+ tag: string;
110
+ count: number;
111
+ docs: {
112
+ slug: string;
113
+ title: string;
114
+ description?: string;
115
+ }[];
116
+ }
117
+ /** A docs-href builder: `(slug, locale) => url`. */
118
+ export type RouteHrefBuilder = (slug: string, locale: string) => string;
119
+ /**
120
+ * The reconstructed route context — `settings` + `i18n` + EVERY callable the
121
+ * package routes rebuild from the serializable payload (URL helpers, nav-scope,
122
+ * heading extraction, tag aggregation, nav-source resolution, doc-route-entry
123
+ * + route enumeration, and the pure nav-tree / slug helpers). Produced by
124
+ * `createRouteContext` and consumed by `createChrome`.
125
+ *
126
+ * It composes the already-typed factory API surfaces ({@link UrlHelpers},
127
+ * {@link NavSourceDocsAPI}, {@link DocRouteEntriesAPI},
128
+ * {@link RouteEnumeratorsAPI}) so the callables stay typed by their owning
129
+ * modules rather than re-declared here.
130
+ */
131
+ export interface RouteContext<S = Settings> extends UrlHelpers, NavSourceDocsAPI, DocRouteEntriesAPI, RouteEnumeratorsAPI {
132
+ /** The host's resolved settings object. */
133
+ settings: S;
134
+ /** Host color-scheme palette map (or `null`); threaded to chrome head CSS. */
135
+ colorSchemes: Record<string, ColorScheme> | null;
136
+ /** The reconstructed i18n surface. */
137
+ i18n: FactoryI18n;
138
+ /** Default locale code (un-prefixed `/docs/...`). */
139
+ defaultLocale: string;
140
+ /** All supported locale codes, default first. */
141
+ locales: readonly string[];
142
+ /** Per-locale `{ label, dir }` config lookup. */
143
+ getLocaleConfig(locale: string): {
144
+ label: string;
145
+ dir: string;
146
+ } | undefined;
147
+ /** Display label for a locale. */
148
+ getLocaleLabel(locale: string): string;
149
+ /** Translate a UI string key for a locale (falls back to default then key). */
150
+ t(key: string, locale?: string): string;
151
+ /** The full URL-helper bag (also spread as own members via `extends`). */
152
+ urlHelpers: UrlHelpers;
153
+ /** Ordered category prefixes for the header nav. */
154
+ getCategoryOrder(): string[];
155
+ /** The nav section a slug belongs to (or `undefined`). */
156
+ getNavSectionForSlug(slug: string): string | undefined;
157
+ /** Scope a nav tree to a category. */
158
+ getNavSubtree(tree: DocNavNode[], categoryMatch?: string): DocNavNode[];
159
+ /** Extract TOC headings from a doc body (bound to settings depth/strategy). */
160
+ extractHeadings(body: string): HeadingItem[];
161
+ /** Resolve a raw tag against the bound vocabulary + governance. */
162
+ resolveTagBound(raw: string): ResolvedTag;
163
+ /** Aggregate a `tag → docs` index from a doc collection. */
164
+ collectTags(entries: ReadonlyArray<{
165
+ id: string;
166
+ data: {
167
+ slug?: string;
168
+ title?: string;
169
+ description?: string;
170
+ tags?: string[];
171
+ };
172
+ }>, slugFn: (id: string, data: {
173
+ slug?: string;
174
+ }) => string): Map<string, TagInfo>;
175
+ /** Build a recursive nav tree from a flat doc collection. */
176
+ buildNavTree(docs: DocPageEntry[], locale: string, categoryMeta: Map<string, CategoryMeta> | undefined, buildHref: RouteHrefBuilder, options?: {
177
+ buildHref?: RouteHrefBuilder;
178
+ }): DocNavNode[];
179
+ /** Group slug-prefix satellite nodes under their primary node. */
180
+ groupSatelliteNodes(tree: DocNavNode[], prefixes: string[]): DocNavNode[];
181
+ /** Find a node by slug anywhere in a nav tree. */
182
+ findNode(nodes: DocNavNode[], slug: string): DocNavNode | undefined;
183
+ /** Href of the first routed descendant. */
184
+ firstRoutedHref(node: DocNavNode): string | undefined;
185
+ /** Category nodes that have children but no page of their own. */
186
+ collectAutoIndexNodes(nodes: DocNavNode[]): DocNavNode[];
187
+ /** Visibility predicate for nav inclusion. */
188
+ isNavVisible(doc: DocPageEntry): boolean;
189
+ /** The content-bridge handle: identity-stable, draft-filtered docs loader. */
190
+ stableDocs(collectionName: string): DocPageEntry[];
191
+ /** Canonical route slug for a doc id. */
192
+ toRouteSlug(id: string): string;
193
+ /** Split a route slug into path params. */
194
+ toSlugParams(routeSlug: string): string[];
195
+ }
196
+ /**
197
+ * The genuinely host-bound chrome slots — bindings the serializable
198
+ * route-context payload deliberately does NOT carry (they are host content /
199
+ * project config, not serializable settings). Each is OPTIONAL; `createChrome`
200
+ * fills any omitted slot with the package-default stub that reproduces the
201
+ * pre-host-collapse (injected package-routes) behaviour BYTE-FOR-BYTE. The host
202
+ * (HOSTCOLLAPSE wave) later passes the real bindings.
203
+ */
204
+ export interface ChromeHostBindings {
205
+ /** Header search widget. Default: the package SearchWidget bound to the site base. */
206
+ SearchWidget?: FactoryComponent;
207
+ /** Per-page git-history meta manifest. Default: `{}` (no Created/Updated block). */
208
+ docHistoryMeta?: Record<string, unknown>;
209
+ /** Sidebar section config. Default: `{}` (auto-generated tree only). */
210
+ sidebarsConfig?: Record<string, unknown>;
211
+ /** Frontmatter preview renderers keyed by field. Default: `{}`. */
212
+ frontmatterRenderers?: Record<string, FactoryComponent>;
213
+ /** Frontmatter preview entry builder. Default: `() => []`. */
214
+ buildFrontmatterPreviewEntries?: (...args: unknown[]) => unknown[];
215
+ /** Footer tag-list loader. Default: `() => []`. */
216
+ loadTagsForLocale?: (...args: unknown[]) => unknown[];
217
+ /** Tag vocabulary for footer columns + the tags area. Default: `[]`. */
218
+ tagVocabulary?: readonly unknown[];
219
+ /** Body-end islands (bootstrap islands). Default: the package-island subset
220
+ * derived from `settings` (no host-only client-router / token-panel boots). */
221
+ BodyEndIslands?: FactoryComponent;
222
+ /** DocHistory island. Default: a no-op stub rendering an empty fragment. */
223
+ DocHistory?: FactoryComponent;
224
+ /** MDX content-component overrides (Details / HtmlPreview / Island /
225
+ * PresetGenerator). Default: package SSR impls + a `PresetGenerator` stub. */
226
+ mdxExtras?: Record<string, FactoryComponent>;
227
+ }
228
+ /**
229
+ * The unified chrome context — the superset that fully wires the page chrome:
230
+ * the reconstructed {@link RouteContext} (settings + i18n + every callable) PLUS
231
+ * the host-supplied component allowlist and the host-bound slots. This single
232
+ * shape governs the package-owned routes today and the host collapse later:
233
+ * `createRouteContext` produces the {@link RouteContext} portion and
234
+ * `createChrome` consumes it together with {@link ChromeHostBindings}, supplying
235
+ * package defaults for the `components` allowlist and every omitted host slot.
236
+ */
237
+ export interface ChromeContext<S = Settings> extends RouteContext<S> {
238
+ /** Host-supplied, project-bound component bindings (explicit allowlist). */
239
+ components: FactoryComponents;
240
+ /** Host-bound chrome slots (stub defaults in the injected package path). */
241
+ hostBindings: ChromeHostBindings;
242
+ }
@@ -1,6 +1,8 @@
1
1
  /** @jsxRuntime automatic */
2
2
  /** @jsxImportSource preact */
3
3
  import type { VNode } from "preact";
4
+ import type { ChromeContext } from "../factory-context/index.js";
5
+ import type { Settings } from "../settings.js";
4
6
  /** Tag info returned by the host's `collectTags` (what the factory sees). */
5
7
  export interface FooterTagInfo {
6
8
  tag: string;
@@ -44,20 +46,17 @@ export interface FooterWithDefaultsSettings {
44
46
  tagVocabulary?: unknown;
45
47
  tagGovernance?: string;
46
48
  }
47
- /** Dependencies injected by the host stub. */
48
- export interface FooterWithDefaultsDeps {
49
- settings: FooterWithDefaultsSettings;
50
- defaultLocale: string;
51
- tagVocabulary: readonly FooterVocabularyEntry[];
52
- isExternal: (href: string) => boolean;
53
- resolveHref: (href: string) => string;
54
- withBase: (path: string) => string;
55
- loadTagsForLocale: (lang: string) => FooterTagInfo[];
56
- }
57
49
  /**
58
- * Create a `FooterWithDefaults` component bound to the host's settings
59
- * and data-prep utilities.
50
+ * Create a `FooterWithDefaults` component from the unified {@link ChromeContext}
51
+ * (epic Collapse Wiring Shells #2420, FACTORIES #2424 — breaking signature).
52
+ *
53
+ * Derives its old deps bag from the context: `settings`/`defaultLocale` and the
54
+ * `isExternal`/`resolveHref`/`withBase` URL helpers read directly; the footer
55
+ * tag vocabulary + `loadTagsForLocale` are HOST-bound slots
56
+ * (`ctx.hostBindings.tagVocabulary` / `ctx.hostBindings.loadTagsForLocale`) that
57
+ * default to `[]` / `() => []` — the package stub renders no tag columns,
58
+ * byte-identical to the pre-collapse injected path.
60
59
  */
61
- export declare function createFooterWithDefaults(deps: FooterWithDefaultsDeps): (props: {
60
+ export declare function createFooterWithDefaults<S extends Settings = Settings>(ctx: ChromeContext<S>): (props: {
62
61
  lang?: string;
63
62
  }) => VNode;
@@ -1,15 +1,13 @@
1
1
  import { jsx } from "preact/jsx-runtime";
2
2
  import { Footer } from "../footer/index.js";
3
- function createFooterWithDefaults(deps) {
4
- const {
5
- settings,
6
- defaultLocale,
7
- tagVocabulary,
8
- isExternal,
9
- resolveHref,
10
- withBase,
11
- loadTagsForLocale
12
- } = deps;
3
+ function createFooterWithDefaults(ctx) {
4
+ const settings = ctx.settings;
5
+ const defaultLocale = ctx.defaultLocale;
6
+ const tagVocabulary = ctx.hostBindings.tagVocabulary ?? [];
7
+ const isExternal = ctx.isExternal;
8
+ const resolveHref = ctx.resolveHref;
9
+ const withBase = ctx.withBase;
10
+ const loadTagsForLocale = ctx.hostBindings.loadTagsForLocale ?? (() => []);
13
11
  function localizeHref(href, lang) {
14
12
  if (isExternal(href)) return href;
15
13
  if (lang !== defaultLocale) {
@@ -79,3 +79,42 @@ export interface HeadProps {
79
79
  crossorigin?: "anonymous" | "use-credentials";
80
80
  }>;
81
81
  }
82
+ /** Stylesheet link descriptor for {@link SiteHeadConfig}. */
83
+ export interface HeadStylesheet {
84
+ href: string;
85
+ crossorigin?: "anonymous" | "use-credentials";
86
+ /** CSS media attribute applied to the `<link media>` attribute. */
87
+ media?: string;
88
+ /**
89
+ * When `true`, loads the stylesheet non-render-blocking via the
90
+ * `media="print" + onload="this.media='all'"` pattern, plus a
91
+ * `<noscript><link rel="stylesheet" href>` fallback.
92
+ * Plain (absent or `false`) emits a normal `<link rel="stylesheet">`.
93
+ */
94
+ async?: boolean;
95
+ }
96
+ /** Preconnect hint descriptor for {@link SiteHeadConfig}. */
97
+ export interface HeadPreconnect {
98
+ href: string;
99
+ crossorigin?: "anonymous" | "use-credentials";
100
+ }
101
+ /** Preload hint descriptor for {@link SiteHeadConfig}. */
102
+ export interface HeadPreload {
103
+ href: string;
104
+ as: string;
105
+ type?: string;
106
+ crossorigin?: "anonymous" | "use-credentials";
107
+ }
108
+ /** Meta tag descriptor for {@link SiteHeadConfig}. */
109
+ export interface HeadMeta {
110
+ name?: string;
111
+ property?: string;
112
+ content: string;
113
+ }
114
+ /** Alternate link descriptor for {@link SiteHeadConfig}. */
115
+ export interface HeadAlternateLink {
116
+ rel: string;
117
+ href: string;
118
+ type?: string;
119
+ title?: string;
120
+ }