@takazudo/zudo-doc 0.2.21 → 0.2.22

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 (275) hide show
  1. package/bin/gen-z-index.mjs +164 -0
  2. package/bin/tags-audit-runner.ts +126 -0
  3. package/bin/tags-audit.mjs +64 -0
  4. package/dist/ai-chat-modal/index.d.ts +8 -0
  5. package/dist/ai-chat-modal/index.js +243 -0
  6. package/dist/body-foot-util/body-foot-util-area.d.ts +4 -8
  7. package/dist/body-foot-util/edit-link.d.ts +4 -8
  8. package/dist/body-foot-util/index.d.ts +4 -3
  9. package/dist/breadcrumb/breadcrumb.d.ts +5 -9
  10. package/dist/breadcrumb/find-path.d.ts +2 -5
  11. package/dist/breadcrumb/index.d.ts +4 -4
  12. package/dist/breadcrumb/types.d.ts +3 -5
  13. package/dist/category-nav/index.d.ts +86 -0
  14. package/dist/category-nav/index.js +44 -0
  15. package/dist/category-tree-nav/index.d.ts +65 -0
  16. package/dist/category-tree-nav/index.js +24 -0
  17. package/dist/code-group/index.d.ts +10 -0
  18. package/dist/code-group/index.js +37 -0
  19. package/dist/code-syntax/code-block-enhancer-script.d.ts +1 -3
  20. package/dist/code-syntax/code-block-enhancer.d.ts +3 -6
  21. package/dist/code-syntax/index.d.ts +9 -8
  22. package/dist/code-syntax/mermaid-init-script.d.ts +3 -5
  23. package/dist/code-syntax/mermaid-init.d.ts +4 -7
  24. package/dist/code-syntax/tabs-init-script.d.ts +1 -3
  25. package/dist/code-syntax/tabs-init.d.ts +3 -6
  26. package/dist/code-syntax/tabs.d.ts +4 -7
  27. package/dist/color-scheme-utils.d.ts +125 -0
  28. package/dist/color-scheme-utils.js +151 -0
  29. package/dist/compose-meta-title/index.d.ts +7 -0
  30. package/dist/compose-meta-title/index.js +10 -0
  31. package/dist/content/component-map.d.ts +13 -17
  32. package/dist/content/content-blockquote.d.ts +3 -6
  33. package/dist/content/content-code.d.ts +3 -6
  34. package/dist/content/content-code.js +1 -1
  35. package/dist/content/content-link.d.ts +3 -6
  36. package/dist/content/content-link.js +1 -1
  37. package/dist/content/content-ol.d.ts +3 -6
  38. package/dist/content/content-paragraph.d.ts +3 -6
  39. package/dist/content/content-strong.d.ts +3 -6
  40. package/dist/content/content-table.d.ts +3 -6
  41. package/dist/content/content-ul.d.ts +3 -6
  42. package/dist/content/heading-h2.d.ts +3 -6
  43. package/dist/content/heading-h3.d.ts +3 -6
  44. package/dist/content/heading-h4.d.ts +3 -6
  45. package/dist/content/index.d.ts +29 -13
  46. package/dist/content-admonition/index.d.ts +15 -0
  47. package/dist/content-admonition/index.js +14 -0
  48. package/dist/design-token-panel-bootstrap.d.ts +38 -0
  49. package/dist/design-token-panel-bootstrap.js +29 -0
  50. package/dist/desktop-sidebar-toggle-island/index.d.ts +5 -0
  51. package/dist/desktop-sidebar-toggle-island/index.js +62 -0
  52. package/dist/details/details.d.ts +3 -7
  53. package/dist/details/index.d.ts +2 -2
  54. package/dist/doc-body-end/index.d.ts +21 -0
  55. package/dist/doc-body-end/index.js +15 -0
  56. package/dist/doc-content-header/index.d.ts +69 -0
  57. package/dist/doc-content-header/index.js +49 -0
  58. package/dist/doc-history/index.d.ts +10 -0
  59. package/dist/doc-history/index.js +407 -0
  60. package/dist/doc-history-area/index.d.ts +84 -0
  61. package/dist/doc-history-area/index.js +76 -0
  62. package/dist/doc-metainfo-area/index.d.ts +46 -0
  63. package/dist/doc-metainfo-area/index.js +41 -0
  64. package/dist/doc-page-props/index.d.ts +93 -0
  65. package/dist/doc-page-props/index.js +0 -0
  66. package/dist/doc-page-renderer/index.d.ts +128 -0
  67. package/dist/doc-page-renderer/index.js +103 -0
  68. package/dist/doc-page-shell/index.d.ts +136 -0
  69. package/dist/doc-page-shell/index.js +127 -0
  70. package/dist/doc-pager/index.d.ts +25 -0
  71. package/dist/doc-pager/index.js +41 -0
  72. package/dist/doc-route-entries/index.d.ts +125 -0
  73. package/dist/doc-route-entries/index.js +76 -0
  74. package/dist/doc-route-paths/index.d.ts +54 -0
  75. package/dist/doc-route-paths/index.js +61 -0
  76. package/dist/doc-tags-area/index.d.ts +38 -0
  77. package/dist/doc-tags-area/index.js +30 -0
  78. package/dist/doclayout/anchors.d.ts +7 -9
  79. package/dist/doclayout/doc-layout-with-defaults.d.ts +16 -12
  80. package/dist/doclayout/doc-layout.d.ts +5 -9
  81. package/dist/doclayout/index.d.ts +6 -6
  82. package/dist/extract-headings/index.d.ts +43 -0
  83. package/dist/extract-headings/index.js +111 -0
  84. package/dist/factory-context/index.d.ts +80 -0
  85. package/dist/factory-context/index.js +0 -0
  86. package/dist/features.css +882 -0
  87. package/dist/footer/footer.d.ts +4 -8
  88. package/dist/footer/index.d.ts +13 -3
  89. package/dist/footer/types.d.ts +4 -6
  90. package/dist/footer-with-defaults/index.d.ts +63 -0
  91. package/dist/footer-with-defaults/index.js +128 -0
  92. package/dist/frontmatter-preview-data/index.d.ts +26 -0
  93. package/dist/frontmatter-preview-data/index.js +23 -0
  94. package/dist/github-helpers/index.d.ts +17 -0
  95. package/dist/github-helpers/index.js +16 -0
  96. package/dist/head/doc-head.d.ts +3 -6
  97. package/dist/head/index.d.ts +9 -5
  98. package/dist/head/og-tags.d.ts +4 -7
  99. package/dist/head/twitter-card.d.ts +3 -6
  100. package/dist/head/types.d.ts +1 -3
  101. package/dist/head-with-defaults/index.d.ts +49 -0
  102. package/dist/head-with-defaults/index.js +62 -0
  103. package/dist/header/header.d.ts +6 -10
  104. package/dist/header/index.d.ts +16 -6
  105. package/dist/header/nav-active.d.ts +5 -7
  106. package/dist/header/nav-overflow-script.d.ts +1 -3
  107. package/dist/header/right-items.d.ts +3 -6
  108. package/dist/header/types.d.ts +10 -12
  109. package/dist/header-with-defaults/index.d.ts +77 -0
  110. package/dist/header-with-defaults/index.js +163 -0
  111. package/dist/html-preview-wrapper/dedent.d.ts +1 -3
  112. package/dist/html-preview-wrapper/highlighted-code.d.ts +3 -7
  113. package/dist/html-preview-wrapper/html-preview-wrapper.d.ts +6 -10
  114. package/dist/html-preview-wrapper/html-preview.d.ts +5 -9
  115. package/dist/html-preview-wrapper/index.d.ts +8 -5
  116. package/dist/html-preview-wrapper/preflight.d.ts +1 -3
  117. package/dist/html-preview-wrapper/preview-base.d.ts +4 -8
  118. package/dist/i18n-version/index.d.ts +7 -5
  119. package/dist/i18n-version/language-switcher.d.ts +5 -8
  120. package/dist/i18n-version/types.d.ts +3 -5
  121. package/dist/i18n-version/version-banner.d.ts +4 -8
  122. package/dist/i18n-version/version-switcher.d.ts +7 -10
  123. package/dist/icons/index.d.ts +9 -13
  124. package/dist/image-enlarge/index.d.ts +13 -0
  125. package/dist/image-enlarge/index.js +176 -0
  126. package/dist/index.d.ts +26 -2
  127. package/dist/inline-version-switcher/index.d.ts +31 -0
  128. package/dist/inline-version-switcher/index.js +44 -0
  129. package/dist/integrations/claude-resources/escape-for-mdx.d.ts +1 -3
  130. package/dist/integrations/claude-resources/generate.d.ts +2 -4
  131. package/dist/integrations/claude-resources/index.d.ts +7 -10
  132. package/dist/integrations/doc-history/index.d.ts +21 -24
  133. package/dist/integrations/doc-history/pre-build.d.ts +7 -9
  134. package/dist/integrations/llms-txt/dev-middleware.d.ts +7 -11
  135. package/dist/integrations/llms-txt/emit.d.ts +2 -7
  136. package/dist/integrations/llms-txt/generate.d.ts +3 -8
  137. package/dist/integrations/llms-txt/index.d.ts +33 -8
  138. package/dist/integrations/llms-txt/load.d.ts +3 -7
  139. package/dist/integrations/llms-txt/strip.d.ts +2 -6
  140. package/dist/integrations/llms-txt/types.d.ts +9 -13
  141. package/dist/integrations/search-index/build-emitter.d.ts +4 -7
  142. package/dist/integrations/search-index/collect.d.ts +2 -5
  143. package/dist/integrations/search-index/dev-middleware.d.ts +5 -8
  144. package/dist/integrations/search-index/index.d.ts +7 -5
  145. package/dist/integrations/search-index/types.d.ts +5 -7
  146. package/dist/island-types/index.d.ts +44 -0
  147. package/dist/island-types/index.js +12 -0
  148. package/dist/locale-merge/index.d.ts +114 -0
  149. package/dist/locale-merge/index.js +27 -0
  150. package/dist/math-block/index.d.ts +18 -0
  151. package/dist/math-block/index.js +29 -0
  152. package/dist/md-utils/index.d.ts +6 -8
  153. package/dist/md-utils/index.js +2 -1
  154. package/dist/mdx-components/index.d.ts +46 -0
  155. package/dist/mdx-components/index.js +161 -0
  156. package/dist/mermaid-enlarge/index.d.ts +11 -0
  157. package/dist/mermaid-enlarge/index.js +290 -0
  158. package/dist/metainfo/doc-metainfo.d.ts +5 -9
  159. package/dist/metainfo/doc-tags.d.ts +7 -11
  160. package/dist/metainfo/frontmatter-preview.d.ts +8 -12
  161. package/dist/metainfo/index.d.ts +6 -4
  162. package/dist/nav-data-prep/index.d.ts +72 -0
  163. package/dist/nav-data-prep/index.js +34 -0
  164. package/dist/nav-indexing/category-nav.d.ts +4 -8
  165. package/dist/nav-indexing/category-tree-nav.d.ts +4 -8
  166. package/dist/nav-indexing/doc-card-grid.d.ts +4 -8
  167. package/dist/nav-indexing/docs-sitemap.d.ts +4 -8
  168. package/dist/nav-indexing/index.d.ts +37 -10
  169. package/dist/nav-indexing/nav-card-grid.d.ts +4 -8
  170. package/dist/nav-indexing/site-tree-nav-demo.d.ts +4 -8
  171. package/dist/nav-indexing/tag-nav.d.ts +6 -10
  172. package/dist/nav-indexing/types.d.ts +6 -8
  173. package/dist/nav-indexing/versions-page-content.d.ts +4 -8
  174. package/dist/nav-scope/index.d.ts +41 -0
  175. package/dist/nav-scope/index.js +41 -0
  176. package/dist/nav-source-cache/index.d.ts +13 -0
  177. package/dist/nav-source-cache/index.js +28 -0
  178. package/dist/nav-source-docs/index.d.ts +169 -0
  179. package/dist/nav-source-docs/index.js +123 -0
  180. package/dist/page-loading/index.d.ts +1 -2
  181. package/dist/page-loading/page-loading-overlay.d.ts +4 -8
  182. package/dist/plugins/claude-resources.d.ts +3 -0
  183. package/dist/plugins/claude-resources.js +27 -0
  184. package/dist/plugins/connect-adapter.d.ts +31 -0
  185. package/dist/plugins/connect-adapter.js +78 -0
  186. package/dist/plugins/doc-history.d.ts +3 -0
  187. package/dist/plugins/doc-history.js +54 -0
  188. package/dist/plugins/llms-txt.d.ts +3 -0
  189. package/dist/plugins/llms-txt.js +48 -0
  190. package/dist/plugins/plugin-utils.d.ts +17 -0
  191. package/dist/plugins/plugin-utils.js +11 -0
  192. package/dist/plugins/search-index.d.ts +3 -0
  193. package/dist/plugins/search-index.js +24 -0
  194. package/dist/preset.d.ts +152 -0
  195. package/dist/preset.js +169 -0
  196. package/dist/render-markdown/index.d.ts +5 -0
  197. package/dist/render-markdown/index.js +115 -0
  198. package/dist/robots.d.ts +36 -0
  199. package/dist/robots.js +17 -0
  200. package/dist/route-enumerators/index.d.ts +204 -0
  201. package/dist/route-enumerators/index.js +156 -0
  202. package/dist/safelist.css +1 -1
  203. package/dist/search-widget/index.d.ts +38 -0
  204. package/dist/search-widget/index.js +169 -0
  205. package/dist/search-widget-script/index.d.ts +18 -0
  206. package/dist/search-widget-script/index.js +465 -0
  207. package/dist/settings.d.ts +255 -0
  208. package/dist/settings.js +0 -0
  209. package/dist/sidebar/index.d.ts +21 -3
  210. package/dist/sidebar/sidebar.d.ts +5 -9
  211. package/dist/sidebar/types.d.ts +4 -6
  212. package/dist/sidebar-prepaint/index.d.ts +21 -0
  213. package/dist/sidebar-prepaint/index.js +23 -0
  214. package/dist/sidebar-resizer/index.d.ts +2 -6
  215. package/dist/sidebar-resizer/sidebar-resizer-init.d.ts +6 -10
  216. package/dist/sidebar-toggle-island/index.d.ts +13 -0
  217. package/dist/sidebar-toggle-island/index.js +122 -0
  218. package/dist/sidebar-tree/build-tree.d.ts +4 -8
  219. package/dist/sidebar-tree/category-meta.d.ts +3 -6
  220. package/dist/sidebar-tree/index.d.ts +18 -3
  221. package/dist/sidebar-tree/types.d.ts +6 -8
  222. package/dist/sidebar-tree-island/index.d.ts +13 -0
  223. package/dist/sidebar-tree-island/index.js +454 -0
  224. package/dist/sidebar-utils/index.d.ts +64 -0
  225. package/dist/sidebar-utils/index.js +88 -0
  226. package/dist/sidebar-with-defaults/index.d.ts +38 -0
  227. package/dist/sidebar-with-defaults/index.js +45 -0
  228. package/dist/site-tree-nav/index.d.ts +71 -0
  229. package/dist/site-tree-nav/index.js +36 -0
  230. package/dist/site-tree-nav-island/index.d.ts +11 -0
  231. package/dist/site-tree-nav-island/index.js +176 -0
  232. package/dist/slug/index.d.ts +4 -0
  233. package/dist/slug/index.js +19 -0
  234. package/dist/smart-break/index.d.ts +55 -0
  235. package/dist/{toc/smart-break.js → smart-break/index.js} +30 -3
  236. package/dist/tab-item/index.d.ts +2 -2
  237. package/dist/tab-item/tab-item.d.ts +6 -7
  238. package/dist/tag-helpers/index.d.ts +40 -0
  239. package/dist/tag-helpers/index.js +54 -0
  240. package/dist/tag-pages/index.d.ts +114 -0
  241. package/dist/tag-pages/index.js +146 -0
  242. package/dist/tags-audit.d.ts +107 -0
  243. package/dist/tags-audit.js +321 -0
  244. package/dist/theme/color-scheme-provider.d.ts +4 -8
  245. package/dist/theme/color-tweak-export-modal.d.ts +4 -7
  246. package/dist/theme/design-token-serde.d.ts +14 -17
  247. package/dist/theme/design-token-types.d.ts +4 -6
  248. package/dist/theme/iframe-bridge.d.ts +12 -14
  249. package/dist/theme/index.d.ts +7 -9
  250. package/dist/theme/theme-toggle.d.ts +3 -8
  251. package/dist/theme-toggle/color-scheme-sync.d.ts +5 -7
  252. package/dist/theme-toggle/index.d.ts +4 -8
  253. package/dist/toc/cx.d.ts +2 -3
  254. package/dist/toc/index.d.ts +8 -6
  255. package/dist/toc/mobile-toc.d.ts +5 -9
  256. package/dist/toc/mobile-toc.js +1 -1
  257. package/dist/toc/toc-title.d.ts +1 -3
  258. package/dist/toc/toc.d.ts +5 -9
  259. package/dist/toc/toc.js +1 -1
  260. package/dist/toc/types.d.ts +1 -3
  261. package/dist/toc/use-active-heading.d.ts +4 -7
  262. package/dist/transitions/index.d.ts +1 -1
  263. package/dist/transitions/page-events.d.ts +4 -6
  264. package/dist/tree-nav-shared/index.d.ts +22 -0
  265. package/dist/tree-nav-shared/index.js +66 -0
  266. package/dist/url-helpers/index.d.ts +37 -0
  267. package/dist/url-helpers/index.js +106 -0
  268. package/dist/url-normalizer/index.d.ts +39 -1
  269. package/dist/url-normalizer/normalize.d.ts +3 -5
  270. package/dist/use-modal-dialog/index.d.ts +70 -0
  271. package/dist/use-modal-dialog/index.js +73 -0
  272. package/dist/versions-page/index.d.ts +55 -0
  273. package/dist/versions-page/index.js +73 -0
  274. package/package.json +290 -10
  275. package/dist/toc/smart-break.d.ts +0 -27
@@ -0,0 +1,106 @@
1
+ function makeUrlHelpers(settings, i18n) {
2
+ const { defaultLocale, locales, getLocaleLabel } = i18n;
3
+ const normalizedBase = settings.base.replace(/\/+$/, "");
4
+ function applyTrailingSlash(url) {
5
+ if (!settings.trailingSlash) return url;
6
+ if (url.endsWith("/")) return url;
7
+ const suffixIdx = url.search(/[?#]/);
8
+ const pathPart = suffixIdx >= 0 ? url.slice(0, suffixIdx) : url;
9
+ const suffix = suffixIdx >= 0 ? url.slice(suffixIdx) : "";
10
+ if (pathPart.endsWith("/")) return url;
11
+ const lastSegment = pathPart.split("/").pop() ?? "";
12
+ if (/\.[a-zA-Z]\w*$/.test(lastSegment)) return url;
13
+ return pathPart + "/" + suffix;
14
+ }
15
+ function withBase(path) {
16
+ const raw = normalizedBase === "" ? path : `${normalizedBase}${path.startsWith("/") ? path : `/${path}`}`;
17
+ return applyTrailingSlash(raw);
18
+ }
19
+ function stripBase(path) {
20
+ if (normalizedBase === "") return path;
21
+ if (path === normalizedBase) return "/";
22
+ return path.startsWith(`${normalizedBase}/`) ? path.slice(normalizedBase.length) : path;
23
+ }
24
+ function absoluteUrl(pageUrl) {
25
+ return settings.siteUrl ? settings.siteUrl.replace(/\/$/, "") + pageUrl : void 0;
26
+ }
27
+ function docsUrl(slug, lang = defaultLocale) {
28
+ const path = lang === defaultLocale ? `/docs/${slug}` : `/${lang}/docs/${slug}`;
29
+ return withBase(path);
30
+ }
31
+ function isExternal(href) {
32
+ return href.startsWith("http://") || href.startsWith("https://");
33
+ }
34
+ function resolveHref(href) {
35
+ return isExternal(href) ? href : withBase(href);
36
+ }
37
+ function navHref(path, lang, currentVersion) {
38
+ const isNonDefaultLocale = lang != null && lang !== defaultLocale;
39
+ const versionPrefix = currentVersion ? `/v/${currentVersion}` : "";
40
+ return withBase(
41
+ isNonDefaultLocale ? `${versionPrefix}/${lang}${path}` : `${versionPrefix}${path}`
42
+ );
43
+ }
44
+ function splitVersionPrefix(path) {
45
+ const m = path.match(/^(\/v\/[^/]+)(\/.*|$)/);
46
+ return m ? { versionPrefix: m[1] ?? "", rest: m[2] ?? "/" } : { versionPrefix: "", rest: path };
47
+ }
48
+ function getPathForLocale(path, currentLang, targetLang) {
49
+ const { versionPrefix, rest } = splitVersionPrefix(stripBase(path));
50
+ let relativePath = rest;
51
+ if (currentLang !== defaultLocale) {
52
+ relativePath = relativePath.replace(new RegExp(`^/${currentLang}(?:/|$)`), "/");
53
+ }
54
+ if (targetLang !== defaultLocale) {
55
+ relativePath = `/${targetLang}${relativePath}`;
56
+ }
57
+ return withBase(`${versionPrefix}${relativePath}`);
58
+ }
59
+ function isDefaultLocaleOnlyPath(path) {
60
+ const stripped = stripBase(path);
61
+ const normalized = stripped.endsWith("/") ? stripped : `${stripped}/`;
62
+ return settings.defaultLocaleOnlyPrefixes.some((prefix) => normalized.startsWith(prefix));
63
+ }
64
+ function buildLocaleLinks(currentPath, currentLang) {
65
+ let defaultLocalePath = splitVersionPrefix(stripBase(currentPath)).rest;
66
+ if (currentLang !== defaultLocale) {
67
+ defaultLocalePath = defaultLocalePath.replace(new RegExp(`^/${currentLang}(?:/|$)`), "/");
68
+ }
69
+ if (isDefaultLocaleOnlyPath(defaultLocalePath)) {
70
+ return [{
71
+ code: currentLang,
72
+ label: getLocaleLabel(currentLang),
73
+ href: getPathForLocale(currentPath, currentLang, currentLang),
74
+ active: true
75
+ }];
76
+ }
77
+ return locales.map((code) => ({
78
+ code,
79
+ label: getLocaleLabel(code),
80
+ href: getPathForLocale(currentPath, currentLang, code),
81
+ active: code === currentLang
82
+ }));
83
+ }
84
+ function versionedDocsUrl(slug, versionSlug, lang = defaultLocale) {
85
+ const path = lang === defaultLocale ? `/v/${versionSlug}/docs/${slug}` : `/v/${versionSlug}/${lang}/docs/${slug}`;
86
+ return withBase(path);
87
+ }
88
+ return {
89
+ normalizedBase,
90
+ applyTrailingSlash,
91
+ withBase,
92
+ stripBase,
93
+ absoluteUrl,
94
+ docsUrl,
95
+ isExternal,
96
+ resolveHref,
97
+ navHref,
98
+ getPathForLocale,
99
+ buildLocaleLinks,
100
+ isDefaultLocaleOnlyPath,
101
+ versionedDocsUrl
102
+ };
103
+ }
104
+ export {
105
+ makeUrlHelpers
106
+ };
@@ -1 +1,39 @@
1
- export { buildUrl, normalizePathname, shouldSkipNormalization } from './normalize.js';
1
+ /**
2
+ * Public entry for `@takazudo/zudo-doc/url-normalizer`.
3
+ *
4
+ * Build-time URL normalizer that ensures every emitted route URL ends with
5
+ * a trailing slash, matching the `trailingSlash: "always"` policy of the
6
+ * legacy Astro build.
7
+ *
8
+ * ## Why build-time only?
9
+ *
10
+ * zfb is a purely static site builder — there is no server or dev middleware.
11
+ * The Astro `src/middleware-handler.ts` ran at request time; the equivalent
12
+ * guarantee is now split:
13
+ *
14
+ * - **Build time** (this module): `buildUrl()` constructs URLs that always
15
+ * end with `/`, and `normalizePathname()` corrects any bare pathname passed
16
+ * in from external data.
17
+ * - **Runtime**: the deployment host (e.g. Cloudflare Pages `_redirects`) is
18
+ * responsible for redirecting requests that arrive without a trailing slash.
19
+ *
20
+ * See the "Trailing-Slash Policy" concept doc in the showcase docs for the
21
+ * full design rationale and an example `_redirects` rule.
22
+ *
23
+ * ## Usage
24
+ *
25
+ * ```ts
26
+ * import {
27
+ * buildUrl,
28
+ * normalizePathname,
29
+ * shouldSkipNormalization,
30
+ * } from "@takazudo/zudo-doc/url-normalizer";
31
+ *
32
+ * // In a paths() implementation:
33
+ * const url = buildUrl("docs", slug); // "/docs/my-slug/"
34
+ *
35
+ * // In an integration that receives raw pathnames:
36
+ * const canonical = normalizePathname(rawPathname);
37
+ * ```
38
+ */
39
+ export { buildUrl, normalizePathname, shouldSkipNormalization } from "./normalize.js";
@@ -58,7 +58,7 @@
58
58
  * buildUrl() // "/"
59
59
  * buildUrl("", "docs", "") // "/docs/"
60
60
  */
61
- declare function buildUrl(...segments: string[]): string;
61
+ export declare function buildUrl(...segments: string[]): string;
62
62
  /**
63
63
  * Return `true` when `pathname` should NOT receive a trailing slash.
64
64
  *
@@ -78,7 +78,7 @@ declare function buildUrl(...segments: string[]): string;
78
78
  * shouldSkipNormalization("/docs/guide") // false (needs trailing slash)
79
79
  * shouldSkipNormalization("/docs/v2.0") // false (number after dot → not an extension)
80
80
  */
81
- declare function shouldSkipNormalization(pathname: string): boolean;
81
+ export declare function shouldSkipNormalization(pathname: string): boolean;
82
82
  /**
83
83
  * Return `pathname` with a trailing slash appended if needed.
84
84
  *
@@ -99,6 +99,4 @@ declare function shouldSkipNormalization(pathname: string): boolean;
99
99
  * normalizePathname("/docs/guide/") // "/docs/guide/" (no-op)
100
100
  * normalizePathname("/assets/app.js") // "/assets/app.js" (skipped)
101
101
  */
102
- declare function normalizePathname(pathname: string): string;
103
-
104
- export { buildUrl, normalizePathname, shouldSkipNormalization };
102
+ export declare function normalizePathname(pathname: string): string;
@@ -0,0 +1,70 @@
1
+ interface UseModalDialogOptions {
2
+ /** True when the dialog should be open. */
3
+ isOpen: boolean;
4
+ /** Called when the dialog is closed for any reason (Escape, backdrop, navigation). */
5
+ onClose: () => void;
6
+ /**
7
+ * DOM event name that triggers a close-and-reset. Pass the host's SPA
8
+ * after-navigate event name (e.g. `AFTER_NAVIGATE_EVENT`); pass `undefined`
9
+ * to skip navigation-close wiring entirely.
10
+ */
11
+ navigateEvent?: string;
12
+ /**
13
+ * When `true`, enable backdrop-click-to-close. The caller must forward the
14
+ * click handler returned by this hook to the `<dialog>` element's `onClick`.
15
+ * Defaults to `false` so opt-in only.
16
+ */
17
+ backdropClickClose?: boolean;
18
+ /**
19
+ * When `true`, enable focus management:
20
+ * - On open: capture `document.activeElement` as the return target (unless
21
+ * `returnFocusRef` is provided), then move focus to the first focusable
22
+ * element inside the dialog (or the dialog itself as a fallback).
23
+ * - On close: restore focus to the captured element.
24
+ *
25
+ * When a caller already manages focus internally (e.g. ai-chat-modal focuses
26
+ * its input in its own effect), pass `restoreFocusOnly: true` instead to get
27
+ * trigger-capture + restore without the "move into dialog" step.
28
+ */
29
+ manageFocus?: boolean;
30
+ /**
31
+ * Like `manageFocus` but skips the "focus first element in dialog" step —
32
+ * use when the caller has its own focus-on-open logic and only needs
33
+ * trigger-capture + focus restore on close.
34
+ */
35
+ restoreFocusOnly?: boolean;
36
+ /**
37
+ * Optional ref holding the element to return focus to on close. When
38
+ * provided and non-null, this takes precedence over the internally captured
39
+ * `document.activeElement`. Useful when the trigger element is conditionally
40
+ * rendered and therefore removed from the DOM before the open effect fires
41
+ * (e.g. the doc-history trigger button, which is unmounted when `isOpen`
42
+ * is true). The caller should set `returnFocusRef.current` to the trigger
43
+ * element in its click handler, before calling `setState`.
44
+ */
45
+ returnFocusRef?: React.RefObject<HTMLElement | null>;
46
+ }
47
+ interface UseModalDialogResult {
48
+ dialogRef: React.RefObject<HTMLDialogElement>;
49
+ /**
50
+ * Pass this to `<dialog onClick={handleBackdropClick}>`.
51
+ * Only wired when `backdropClickClose` is true; otherwise a no-op.
52
+ */
53
+ handleBackdropClick: (e: React.MouseEvent<HTMLDialogElement>) => void;
54
+ }
55
+ /**
56
+ * Shared hook for `<dialog>`-based modal components.
57
+ *
58
+ * Usage:
59
+ * ```tsx
60
+ * const { dialogRef, handleBackdropClick } = useModalDialog({
61
+ * isOpen,
62
+ * onClose: handleClose,
63
+ * navigateEvent: AFTER_NAVIGATE_EVENT,
64
+ * backdropClickClose: true,
65
+ * });
66
+ * return <dialog ref={dialogRef} onClick={handleBackdropClick} ... />;
67
+ * ```
68
+ */
69
+ export declare function useModalDialog({ isOpen, onClose, navigateEvent, backdropClickClose, manageFocus, restoreFocusOnly, returnFocusRef, }: UseModalDialogOptions): UseModalDialogResult;
70
+ export {};
@@ -0,0 +1,73 @@
1
+ "use client";
2
+ import { useEffect, useRef } from "preact/compat";
3
+ function useModalDialog({
4
+ isOpen,
5
+ onClose,
6
+ navigateEvent,
7
+ backdropClickClose = false,
8
+ manageFocus = false,
9
+ restoreFocusOnly = false,
10
+ returnFocusRef
11
+ }) {
12
+ const dialogRef = useRef(null);
13
+ const internalTriggerRef = useRef(null);
14
+ useEffect(() => {
15
+ const dialog = dialogRef.current;
16
+ if (!dialog) return;
17
+ if (isOpen && !dialog.open) {
18
+ if ((manageFocus || restoreFocusOnly) && !returnFocusRef) {
19
+ internalTriggerRef.current = document.activeElement;
20
+ }
21
+ dialog.showModal();
22
+ if (manageFocus && !restoreFocusOnly) {
23
+ const FOCUSABLE = 'button:not([disabled]),a[href],[tabindex]:not([tabindex="-1"]),input:not([disabled]),select:not([disabled]),textarea:not([disabled])';
24
+ const first = dialog.querySelector(FOCUSABLE);
25
+ if (first) {
26
+ first.focus();
27
+ } else {
28
+ dialog.focus();
29
+ }
30
+ }
31
+ } else if (!isOpen && dialog.open) {
32
+ dialog.close();
33
+ }
34
+ }, [isOpen, manageFocus, restoreFocusOnly, returnFocusRef]);
35
+ useEffect(() => {
36
+ const dialog = dialogRef.current;
37
+ if (!dialog) return;
38
+ function onDialogClose() {
39
+ if (manageFocus || restoreFocusOnly) {
40
+ const trigger = returnFocusRef ? returnFocusRef.current : internalTriggerRef.current;
41
+ if (trigger instanceof HTMLElement) {
42
+ trigger.focus();
43
+ }
44
+ internalTriggerRef.current = null;
45
+ }
46
+ if (isOpen) onClose();
47
+ }
48
+ dialog.addEventListener("close", onDialogClose);
49
+ return () => dialog.removeEventListener("close", onDialogClose);
50
+ }, [isOpen, onClose, manageFocus, restoreFocusOnly, returnFocusRef]);
51
+ useEffect(() => {
52
+ if (!navigateEvent) return;
53
+ function handleNavigation() {
54
+ const dialog = dialogRef.current;
55
+ if (dialog?.open) {
56
+ dialog.close();
57
+ onClose();
58
+ }
59
+ }
60
+ document.addEventListener(navigateEvent, handleNavigation);
61
+ return () => document.removeEventListener(navigateEvent, handleNavigation);
62
+ }, [navigateEvent, onClose]);
63
+ function handleBackdropClick(e) {
64
+ if (!backdropClickClose) return;
65
+ const dialog = dialogRef.current;
66
+ if (!dialog) return;
67
+ if (e.target === dialog) dialog.close();
68
+ }
69
+ return { dialogRef, handleBackdropClick };
70
+ }
71
+ export {
72
+ useModalDialog
73
+ };
@@ -0,0 +1,55 @@
1
+ /** @jsxRuntime automatic */
2
+ /** @jsxImportSource preact */
3
+ import type { ComponentChildren, JSX } from "preact";
4
+ /** Minimal version config entry needed by the versions page. */
5
+ export interface VersionsPageVersionEntry {
6
+ slug: string;
7
+ label?: string;
8
+ banner?: "unmaintained" | "unreleased" | false;
9
+ }
10
+ /** Settings subset read by the versions page factory. */
11
+ export interface VersionsPageSettings {
12
+ noindex?: boolean;
13
+ dynamicPageTransition?: boolean;
14
+ versions: VersionsPageVersionEntry[] | false;
15
+ base: string;
16
+ }
17
+ /** Host-supplied component bindings injected into the versions page factory. */
18
+ export interface VersionsPageComponents {
19
+ HeadWithDefaults: (props: {
20
+ title: string;
21
+ }) => JSX.Element;
22
+ HeaderWithDefaults: (props: {
23
+ lang?: string;
24
+ currentPath?: string;
25
+ }) => JSX.Element;
26
+ FooterWithDefaults: (props: {
27
+ lang?: string;
28
+ }) => JSX.Element;
29
+ BodyEndIslands: (props: {
30
+ basePath: string;
31
+ }) => JSX.Element;
32
+ }
33
+ /** Injected dependencies for {@link createVersionsPageView}. */
34
+ export interface VersionsPageDeps {
35
+ settings: VersionsPageSettings;
36
+ /** Default locale code (e.g. `"en"`). */
37
+ defaultLocale: string;
38
+ /** Translate a UI string key for a locale. */
39
+ t: (key: string, locale: string) => string;
40
+ /** Prefix a path with the configured base directory. */
41
+ withBase: (path: string) => string;
42
+ /** Compose the meta `<title>` value. */
43
+ composeMetaTitle: (title: string) => string;
44
+ components: VersionsPageComponents;
45
+ }
46
+ /** Props for the VersionsPageView component. */
47
+ export interface VersionsPageViewProps {
48
+ locale: string;
49
+ children?: ComponentChildren;
50
+ }
51
+ /**
52
+ * Create a `VersionsPageView` component bound to the host's settings and
53
+ * component dependencies.
54
+ */
55
+ export declare function createVersionsPageView(deps: VersionsPageDeps): (props: VersionsPageViewProps) => JSX.Element;
@@ -0,0 +1,73 @@
1
+ import { Fragment, jsx } from "preact/jsx-runtime";
2
+ import { DocLayoutWithDefaults } from "../doclayout/index.js";
3
+ import { VersionsPageContent } from "../nav-indexing/index.js";
4
+ function createVersionsPageView(deps) {
5
+ const {
6
+ settings,
7
+ defaultLocale,
8
+ t,
9
+ withBase,
10
+ composeMetaTitle,
11
+ components: {
12
+ HeadWithDefaults,
13
+ HeaderWithDefaults,
14
+ FooterWithDefaults,
15
+ BodyEndIslands
16
+ }
17
+ } = deps;
18
+ function VersionsPageView({ locale }) {
19
+ const isDefault = locale === defaultLocale;
20
+ const prefix = isDefault ? "" : `/${locale}`;
21
+ const pageTitle = t("version.page.title", locale);
22
+ const labels = {
23
+ pageTitle,
24
+ latestTitle: t("version.page.latest.title", locale),
25
+ latestDescription: t("version.page.latest.description", locale),
26
+ latestLink: t("version.page.latest.link", locale),
27
+ pastTitle: t("version.page.past.title", locale),
28
+ pastDescription: t("version.page.past.description", locale),
29
+ unmaintained: t("version.page.unmaintained", locale),
30
+ unreleased: t("version.page.unreleased", locale),
31
+ versionCol: t("version.switcher.label", locale),
32
+ statusCol: t("version.page.status", locale),
33
+ docsCol: t("version.page.docs", locale)
34
+ };
35
+ const latestHref = withBase(`${prefix}/docs/getting-started`);
36
+ const versions = settings.versions ? settings.versions.map((v) => ({
37
+ slug: v.slug,
38
+ label: v.label ?? v.slug,
39
+ // Version prefix comes BEFORE the locale — the only routed shape is
40
+ // pages/v/[version]/{locale}/docs/...; /{locale}/v/... has no route.
41
+ docsHref: withBase(`/v/${v.slug}${prefix}/docs/getting-started/`),
42
+ banner: v.banner
43
+ })) : [];
44
+ return /* @__PURE__ */ jsx(
45
+ DocLayoutWithDefaults,
46
+ {
47
+ title: composeMetaTitle(pageTitle),
48
+ head: /* @__PURE__ */ jsx(HeadWithDefaults, { title: pageTitle }),
49
+ lang: locale,
50
+ noindex: settings.noindex,
51
+ hideSidebar: true,
52
+ hideToc: true,
53
+ sidebarOverride: /* @__PURE__ */ jsx(Fragment, {}),
54
+ headerOverride: /* @__PURE__ */ jsx(HeaderWithDefaults, { lang: locale, currentPath: withBase(`${prefix}/docs/versions`) }),
55
+ footerOverride: /* @__PURE__ */ jsx(FooterWithDefaults, { lang: locale }),
56
+ bodyEndComponents: /* @__PURE__ */ jsx(BodyEndIslands, { basePath: settings.base ?? "/" }),
57
+ enableClientRouter: settings.dynamicPageTransition,
58
+ children: /* @__PURE__ */ jsx(
59
+ VersionsPageContent,
60
+ {
61
+ latestHref,
62
+ versions,
63
+ labels
64
+ }
65
+ )
66
+ }
67
+ );
68
+ }
69
+ return VersionsPageView;
70
+ }
71
+ export {
72
+ createVersionsPageView
73
+ };