@takazudo/zudo-doc 5.28.2 → 6.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 (456) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +49 -16
  3. package/bin/gen-z-index.mjs +18 -18
  4. package/dist/agent-docs/identity.d.ts +4 -0
  5. package/dist/agent-docs/identity.js +24 -0
  6. package/dist/agent-docs/index.d.ts +5 -0
  7. package/dist/agent-docs/index.js +5 -0
  8. package/dist/agent-docs/limits.d.ts +11 -0
  9. package/dist/agent-docs/limits.js +24 -0
  10. package/dist/agent-docs/search.d.ts +14 -0
  11. package/dist/agent-docs/search.js +82 -0
  12. package/dist/agent-docs/tokenize.d.ts +2 -0
  13. package/dist/agent-docs/tokenize.js +22 -0
  14. package/dist/agent-docs/types.d.ts +68 -0
  15. package/dist/agent-docs/types.js +0 -0
  16. package/dist/ai-chat-modal/index.d.ts +1 -4
  17. package/dist/ai-chat-modal/index.js +183 -123
  18. package/dist/asset-components/asset-card.d.ts +1 -2
  19. package/dist/asset-components/asset-card.js +12 -12
  20. package/dist/asset-components/asset-code.d.ts +1 -2
  21. package/dist/asset-components/asset-code.js +10 -10
  22. package/dist/asset-components/shared.d.ts +3 -4
  23. package/dist/asset-components/shared.js +4 -4
  24. package/dist/asset-index-page/body.d.ts +5 -6
  25. package/dist/asset-index-page/body.js +6 -6
  26. package/dist/asset-index-page/index.d.ts +1 -2
  27. package/dist/asset-index-page/index.js +1 -1
  28. package/dist/asset-page/body.d.ts +5 -9
  29. package/dist/asset-page/body.js +3 -3
  30. package/dist/asset-page/components.d.ts +16 -17
  31. package/dist/asset-page/components.js +10 -9
  32. package/dist/asset-page/index.d.ts +1 -2
  33. package/dist/asset-page/index.js +1 -1
  34. package/dist/auto-logo/index.d.ts +1 -2
  35. package/dist/auto-logo/index.js +2 -2
  36. package/dist/body-foot-util/body-foot-util-area.d.ts +3 -4
  37. package/dist/body-foot-util/body-foot-util-area.js +1 -2
  38. package/dist/body-foot-util/edit-link.d.ts +2 -3
  39. package/dist/body-foot-util/edit-link.js +1 -2
  40. package/dist/breadcrumb/breadcrumb.d.ts +6 -6
  41. package/dist/breadcrumb/breadcrumb.js +3 -4
  42. package/dist/category-nav/index.d.ts +1 -2
  43. package/dist/category-nav/index.js +11 -5
  44. package/dist/category-tree-nav/index.d.ts +1 -2
  45. package/dist/category-tree-nav/index.js +3 -3
  46. package/dist/chrome/derive.d.ts +18 -27
  47. package/dist/chrome/derive.js +47 -29
  48. package/dist/chrome/index.d.ts +5 -5
  49. package/dist/chrome/index.js +1 -1
  50. package/dist/chrome/island-data.d.ts +4 -0
  51. package/dist/chrome/island-data.js +52 -0
  52. package/dist/chrome/primary-slots.d.ts +2 -3
  53. package/dist/chrome-bindings.d.ts +28 -22
  54. package/dist/code-group/index.d.ts +3 -4
  55. package/dist/code-group/index.js +3 -7
  56. package/dist/code-syntax/code-block-enhancer.d.ts +1 -2
  57. package/dist/code-syntax/code-block-enhancer.js +2 -2
  58. package/dist/code-syntax/mermaid-init.d.ts +1 -2
  59. package/dist/code-syntax/mermaid-init.js +5 -2
  60. package/dist/code-syntax/tabs-init-script.js +1 -1
  61. package/dist/code-syntax/tabs-init.d.ts +1 -2
  62. package/dist/code-syntax/tabs-init.js +2 -2
  63. package/dist/code-syntax/tabs.d.ts +6 -6
  64. package/dist/code-syntax/tabs.js +8 -8
  65. package/dist/compiled.css +2933 -2943
  66. package/dist/config-assertions/index.d.ts +13 -0
  67. package/dist/config-assertions/index.js +14 -0
  68. package/dist/config.d.ts +36 -17
  69. package/dist/config.js +23 -95
  70. package/dist/content/content-blockquote.d.ts +2 -3
  71. package/dist/content/content-blockquote.js +3 -3
  72. package/dist/content/content-code.d.ts +3 -4
  73. package/dist/content/content-code.js +5 -5
  74. package/dist/content/content-link.d.ts +3 -4
  75. package/dist/content/content-link.js +10 -10
  76. package/dist/content/content-ol.d.ts +2 -3
  77. package/dist/content/content-ol.js +5 -4
  78. package/dist/content/content-paragraph.d.ts +2 -3
  79. package/dist/content/content-paragraph.js +1 -1
  80. package/dist/content/content-strong.d.ts +2 -3
  81. package/dist/content/content-strong.js +3 -3
  82. package/dist/content/content-table.d.ts +2 -3
  83. package/dist/content/content-table.js +4 -4
  84. package/dist/content/content-ul.d.ts +2 -3
  85. package/dist/content/content-ul.js +4 -4
  86. package/dist/content/heading-h2.d.ts +2 -3
  87. package/dist/content/heading-h2.js +4 -4
  88. package/dist/content/heading-h3.d.ts +2 -3
  89. package/dist/content/heading-h3.js +4 -4
  90. package/dist/content/heading-h4.d.ts +2 -3
  91. package/dist/content/heading-h4.js +4 -4
  92. package/dist/content-admonition/index.d.ts +3 -4
  93. package/dist/content-admonition/index.js +2 -2
  94. package/dist/content.css +35 -33
  95. package/dist/design-token-panel-bootstrap-controller.d.ts +178 -0
  96. package/dist/design-token-panel-bootstrap-controller.js +359 -0
  97. package/dist/design-token-panel-bootstrap-island.d.ts +5 -0
  98. package/dist/design-token-panel-bootstrap-island.js +19 -0
  99. package/dist/design-token-panel-bootstrap.d.ts +5 -195
  100. package/dist/design-token-panel-bootstrap.js +3 -288
  101. package/dist/desktop-sidebar-toggle-island/index.d.ts +2 -7
  102. package/dist/desktop-sidebar-toggle-island/index.js +2 -58
  103. package/dist/desktop-sidebar-toggle-island/island.d.ts +4 -0
  104. package/dist/desktop-sidebar-toggle-island/island.js +43 -0
  105. package/dist/desktop-sidebar-toggle-island/storage.d.ts +4 -0
  106. package/dist/desktop-sidebar-toggle-island/storage.js +29 -0
  107. package/dist/desktop-toc-toggle-island/index.d.ts +2 -7
  108. package/dist/desktop-toc-toggle-island/index.js +2 -58
  109. package/dist/desktop-toc-toggle-island/island.d.ts +4 -0
  110. package/dist/desktop-toc-toggle-island/island.js +43 -0
  111. package/dist/desktop-toc-toggle-island/storage.d.ts +4 -0
  112. package/dist/desktop-toc-toggle-island/storage.js +29 -0
  113. package/dist/details/details.d.ts +3 -4
  114. package/dist/details/details.js +1 -1
  115. package/dist/doc-body-end/index.d.ts +1 -2
  116. package/dist/doc-body-end/index.js +1 -1
  117. package/dist/doc-body-end-islands/design-token-panel-island.d.ts +2 -2
  118. package/dist/doc-body-end-islands/design-token-panel-island.js +3 -7
  119. package/dist/doc-body-end-islands/index.d.ts +4 -21
  120. package/dist/doc-body-end-islands/index.js +5 -3
  121. package/dist/doc-body-end-islands/theme-pack-switcher-island.d.ts +3 -13
  122. package/dist/doc-body-end-islands/theme-pack-switcher-island.js +11 -13
  123. package/dist/doc-content-header/index.d.ts +1 -2
  124. package/dist/doc-content-header/index.js +1 -1
  125. package/dist/doc-history/index.d.ts +1 -1
  126. package/dist/doc-history/index.js +166 -141
  127. package/dist/doc-history-area/index.d.ts +6 -4
  128. package/dist/doc-history-area/index.js +17 -16
  129. package/dist/doc-metainfo-area/index.d.ts +2 -3
  130. package/dist/doc-metainfo-area/index.js +1 -1
  131. package/dist/doc-page-renderer/index.d.ts +13 -7
  132. package/dist/doc-page-renderer/index.js +10 -1
  133. package/dist/doc-page-shell/index.d.ts +20 -7
  134. package/dist/doc-page-shell/index.js +17 -6
  135. package/dist/doc-pager/index.d.ts +1 -2
  136. package/dist/doc-pager/index.js +3 -3
  137. package/dist/doc-tags-area/index.d.ts +2 -3
  138. package/dist/doc-tags-area/index.js +1 -1
  139. package/dist/doclayout/doc-layout-with-defaults.d.ts +9 -9
  140. package/dist/doclayout/doc-layout-with-defaults.js +5 -15
  141. package/dist/doclayout/doc-layout.d.ts +26 -27
  142. package/dist/doclayout/doc-layout.js +23 -14
  143. package/dist/docs-schema/index.d.ts +4 -0
  144. package/dist/docs-schema/index.js +1 -0
  145. package/dist/extract-headings/index.js +43 -12
  146. package/dist/factory-context/index.d.ts +22 -19
  147. package/dist/features.css +70 -8
  148. package/dist/find-in-page/find-bar.d.ts +4 -2
  149. package/dist/find-in-page/find-bar.js +58 -69
  150. package/dist/find-in-page/index.d.ts +2 -8
  151. package/dist/find-in-page/index.js +33 -30
  152. package/dist/footer/footer.d.ts +3 -4
  153. package/dist/footer/footer.js +3 -3
  154. package/dist/footer-with-defaults/index.d.ts +2 -3
  155. package/dist/footer-with-defaults/index.js +1 -1
  156. package/dist/frontmatter-preview-defaults/index.js +1 -0
  157. package/dist/head/doc-head.d.ts +1 -1
  158. package/dist/head/doc-head.js +24 -32
  159. package/dist/head/og-tags.d.ts +1 -1
  160. package/dist/head/og-tags.js +8 -7
  161. package/dist/head/twitter-card.d.ts +1 -1
  162. package/dist/head/twitter-card.js +1 -1
  163. package/dist/head-with-defaults/index.d.ts +7 -2
  164. package/dist/head-with-defaults/index.js +46 -32
  165. package/dist/header/header.d.ts +8 -8
  166. package/dist/header/header.js +9 -11
  167. package/dist/header/types.d.ts +7 -7
  168. package/dist/header-with-defaults/index.d.ts +1 -2
  169. package/dist/header-with-defaults/index.js +18 -8
  170. package/dist/home-intro/index.d.ts +2 -5
  171. package/dist/home-intro/index.js +7 -5
  172. package/dist/home-intro/prepare.js +4 -3
  173. package/dist/home-page/index.d.ts +3 -3
  174. package/dist/home-page/index.js +19 -17
  175. package/dist/html-preview-wrapper/highlighted-code.d.ts +3 -4
  176. package/dist/html-preview-wrapper/highlighted-code.js +19 -17
  177. package/dist/html-preview-wrapper/html-preview-wrapper.d.ts +4 -25
  178. package/dist/html-preview-wrapper/html-preview-wrapper.js +2 -87
  179. package/dist/html-preview-wrapper/html-preview.d.ts +3 -10
  180. package/dist/html-preview-wrapper/html-preview.js +13 -37
  181. package/dist/html-preview-wrapper/index.d.ts +2 -1
  182. package/dist/html-preview-wrapper/index.js +1 -1
  183. package/dist/html-preview-wrapper/preview-base.d.ts +3 -5
  184. package/dist/html-preview-wrapper/preview-base.js +56 -59
  185. package/dist/html-preview-wrapper/wrapper.d.ts +20 -0
  186. package/dist/html-preview-wrapper/wrapper.js +37 -0
  187. package/dist/hydration-pending.d.ts +3 -5
  188. package/dist/hydration-pending.js +7 -5
  189. package/dist/i18n-version/language-switcher.d.ts +5 -32
  190. package/dist/i18n-version/language-switcher.js +5 -106
  191. package/dist/i18n-version/switcher-generated-scripts.d.ts +2 -0
  192. package/dist/i18n-version/switcher-generated-scripts.js +107 -0
  193. package/dist/i18n-version/switcher-url-state.d.ts +76 -0
  194. package/dist/i18n-version/switcher-url-state.js +103 -0
  195. package/dist/i18n-version/version-banner.d.ts +2 -3
  196. package/dist/i18n-version/version-banner.js +1 -1
  197. package/dist/i18n-version/version-switcher.d.ts +5 -50
  198. package/dist/i18n-version/version-switcher.js +5 -157
  199. package/dist/icons/index.d.ts +18 -19
  200. package/dist/icons/index.js +17 -33
  201. package/dist/image-enlarge/index.d.ts +1 -10
  202. package/dist/image-enlarge/index.js +80 -55
  203. package/dist/image-enlarge/public.d.ts +2 -0
  204. package/dist/image-enlarge/public.js +6 -0
  205. package/dist/image-enlarge/ssr-fallback.d.ts +2 -0
  206. package/dist/image-enlarge/ssr-fallback.js +8 -0
  207. package/dist/index.d.ts +11 -4
  208. package/dist/inline-version-switcher/index.d.ts +1 -2
  209. package/dist/inline-version-switcher/index.js +1 -1
  210. package/dist/island-types/index.d.ts +2 -2
  211. package/dist/island-types/index.js +1 -5
  212. package/dist/math-block/index.d.ts +4 -7
  213. package/dist/math-block/index.js +5 -5
  214. package/dist/mcp/handler.d.ts +8 -0
  215. package/dist/mcp/handler.js +129 -0
  216. package/dist/mcp/index.d.ts +4 -0
  217. package/dist/mcp/index.js +7 -0
  218. package/dist/mcp/loader.d.ts +19 -0
  219. package/dist/mcp/loader.js +202 -0
  220. package/dist/mdx-components/index.js +40 -108
  221. package/dist/mermaid-enlarge/index.d.ts +1 -8
  222. package/dist/mermaid-enlarge/index.js +174 -158
  223. package/dist/mermaid-enlarge/public.d.ts +2 -0
  224. package/dist/mermaid-enlarge/public.js +6 -0
  225. package/dist/mermaid-enlarge/ssr-fallback.d.ts +2 -0
  226. package/dist/mermaid-enlarge/ssr-fallback.js +8 -0
  227. package/dist/metainfo/doc-metainfo.d.ts +2 -3
  228. package/dist/metainfo/doc-metainfo.js +1 -4
  229. package/dist/metainfo/doc-tags.d.ts +2 -3
  230. package/dist/metainfo/doc-tags.js +1 -1
  231. package/dist/metainfo/frontmatter-preview.d.ts +3 -4
  232. package/dist/metainfo/frontmatter-preview.js +1 -1
  233. package/dist/nav-data-prep/index.js +6 -4
  234. package/dist/nav-indexing/category-nav.d.ts +2 -3
  235. package/dist/nav-indexing/category-nav.js +1 -2
  236. package/dist/nav-indexing/category-tree-nav.d.ts +2 -3
  237. package/dist/nav-indexing/category-tree-nav.js +1 -1
  238. package/dist/nav-indexing/doc-card-grid.d.ts +2 -3
  239. package/dist/nav-indexing/doc-card-grid.js +1 -2
  240. package/dist/nav-indexing/docs-sitemap.d.ts +2 -3
  241. package/dist/nav-indexing/docs-sitemap.js +2 -2
  242. package/dist/nav-indexing/index.d.ts +1 -1
  243. package/dist/nav-indexing/nav-card-grid.d.ts +2 -3
  244. package/dist/nav-indexing/nav-card-grid.js +1 -2
  245. package/dist/nav-indexing/note-tray-index-parts/card-list.d.ts +1 -2
  246. package/dist/nav-indexing/note-tray-index-parts/card-list.js +4 -4
  247. package/dist/nav-indexing/note-tray-index-parts/date-line.d.ts +2 -3
  248. package/dist/nav-indexing/note-tray-index-parts/date-line.js +1 -1
  249. package/dist/nav-indexing/note-tray-index-parts/index-list.d.ts +1 -2
  250. package/dist/nav-indexing/note-tray-index-parts/index-list.js +2 -2
  251. package/dist/nav-indexing/note-tray-index-parts/timeline.d.ts +1 -2
  252. package/dist/nav-indexing/note-tray-index-parts/timeline.js +2 -2
  253. package/dist/nav-indexing/note-tray-index.d.ts +1 -2
  254. package/dist/nav-indexing/note-tray-index.js +1 -1
  255. package/dist/nav-indexing/site-tree-nav-demo.d.ts +2 -3
  256. package/dist/nav-indexing/site-tree-nav-demo.js +2 -2
  257. package/dist/nav-indexing/tag-nav.d.ts +1 -2
  258. package/dist/nav-indexing/tag-nav.js +1 -1
  259. package/dist/nav-indexing/types.d.ts +2 -2
  260. package/dist/nav-indexing/versions-page-content.d.ts +2 -3
  261. package/dist/nav-indexing/versions-page-content.js +8 -8
  262. package/dist/note-tray-index/index.d.ts +1 -2
  263. package/dist/note-tray-index/index.js +1 -1
  264. package/dist/page-loading/page-loading-overlay.d.ts +1 -2
  265. package/dist/page-loading/page-loading-overlay.js +3 -5
  266. package/dist/plugins/agent-export.d.ts +3 -0
  267. package/dist/plugins/agent-export.js +34 -0
  268. package/dist/plugins/internal/agent-export/chunk.d.ts +5 -0
  269. package/dist/plugins/internal/agent-export/chunk.js +90 -0
  270. package/dist/plugins/internal/agent-export/index.d.ts +24 -0
  271. package/dist/plugins/internal/agent-export/index.js +123 -0
  272. package/dist/plugins/internal/agent-export/normalize.d.ts +5 -0
  273. package/dist/plugins/internal/agent-export/normalize.js +73 -0
  274. package/dist/plugins/internal/llms-txt/dev-middleware.d.ts +6 -0
  275. package/dist/plugins/internal/llms-txt/dev-middleware.js +8 -3
  276. package/dist/plugins/internal/llms-txt/emit.js +23 -6
  277. package/dist/plugins/internal/llms-txt/generate.d.ts +7 -1
  278. package/dist/plugins/internal/llms-txt/generate.js +9 -2
  279. package/dist/plugins/internal/llms-txt/load.d.ts +2 -0
  280. package/dist/plugins/internal/llms-txt/load.js +20 -4
  281. package/dist/plugins/internal/llms-txt/types.d.ts +10 -0
  282. package/dist/plugins/routes.js +4 -0
  283. package/dist/preset.d.ts +19 -9
  284. package/dist/preset.js +20 -1
  285. package/dist/route-context-payload/index.js +1 -1
  286. package/dist/routes/404.d.ts +2 -3
  287. package/dist/routes/404.js +1 -1
  288. package/dist/routes/_chrome.d.ts +5 -5
  289. package/dist/routes/_chrome.js +7 -2
  290. package/dist/routes/_context.d.ts +4 -4
  291. package/dist/routes/_design-token-panel-bootstrap.d.ts +1 -4
  292. package/dist/routes/_design-token-panel-bootstrap.js +9 -1
  293. package/dist/routes/docs-slug.d.ts +2 -3
  294. package/dist/routes/docs-tags-index.d.ts +2 -3
  295. package/dist/routes/docs-tags-index.js +1 -1
  296. package/dist/routes/docs-tags-tag.d.ts +2 -3
  297. package/dist/routes/docs-tags-tag.js +1 -1
  298. package/dist/routes/docs-versions.d.ts +2 -3
  299. package/dist/routes/docs-versions.js +1 -1
  300. package/dist/routes/files-path.d.ts +2 -3
  301. package/dist/routes/files-path.js +1 -1
  302. package/dist/routes/index.d.ts +2 -3
  303. package/dist/routes/index.js +1 -1
  304. package/dist/routes/locale-docs-slug.d.ts +2 -3
  305. package/dist/routes/locale-docs-tags-index.d.ts +2 -3
  306. package/dist/routes/locale-docs-tags-index.js +1 -1
  307. package/dist/routes/locale-docs-tags-tag.d.ts +2 -3
  308. package/dist/routes/locale-docs-tags-tag.js +1 -1
  309. package/dist/routes/locale-docs-versions.d.ts +2 -3
  310. package/dist/routes/locale-docs-versions.js +1 -1
  311. package/dist/routes/locale-files-path.d.ts +2 -3
  312. package/dist/routes/locale-files-path.js +1 -1
  313. package/dist/routes/locale-index.d.ts +2 -3
  314. package/dist/routes/locale-index.js +1 -1
  315. package/dist/routes/mcp.d.ts +5 -0
  316. package/dist/routes/mcp.js +25 -0
  317. package/dist/routes/v-docs-slug.d.ts +2 -3
  318. package/dist/routes/v-locale-docs-slug.d.ts +2 -3
  319. package/dist/search-widget/index.d.ts +1 -2
  320. package/dist/search-widget/index.js +4 -7
  321. package/dist/search-widget-script/generated-script.js +12 -5
  322. package/dist/settings-defaults.d.ts +2 -0
  323. package/dist/settings-defaults.js +93 -0
  324. package/dist/settings.d.ts +8 -2
  325. package/dist/sidebar/index.d.ts +1 -1
  326. package/dist/sidebar/sidebar.d.ts +12 -44
  327. package/dist/sidebar/sidebar.js +4 -3
  328. package/dist/sidebar/types.d.ts +14 -0
  329. package/dist/sidebar-prepaint/index.d.ts +1 -2
  330. package/dist/sidebar-prepaint/index.js +4 -6
  331. package/dist/sidebar-resizer/sidebar-resizer-init.d.ts +2 -3
  332. package/dist/sidebar-resizer/sidebar-resizer-init.js +3 -3
  333. package/dist/sidebar-toggle-island/index.d.ts +8 -11
  334. package/dist/sidebar-toggle-island/index.js +75 -62
  335. package/dist/sidebar-tree/build-tree.js +5 -6
  336. package/dist/sidebar-tree/types.d.ts +2 -0
  337. package/dist/sidebar-tree-island/index.d.ts +4 -19
  338. package/dist/sidebar-tree-island/index.js +782 -436
  339. package/dist/sidebar-tree-island/scope-state.d.ts +38 -0
  340. package/dist/sidebar-tree-island/scope-state.js +151 -0
  341. package/dist/sidebar-tree-island/sidebar-scroll-preserve.js +6 -2
  342. package/dist/sidebar-utils/index.d.ts +17 -19
  343. package/dist/sidebar-utils/index.js +100 -3
  344. package/dist/sidebar-utils/scope.d.ts +11 -0
  345. package/dist/sidebar-utils/scope.js +67 -0
  346. package/dist/sidebar-with-defaults/index.d.ts +1 -2
  347. package/dist/sidebar-with-defaults/index.js +19 -18
  348. package/dist/site-schema/nav-tree.js +15 -15
  349. package/dist/site-schema/types.d.ts +1 -0
  350. package/dist/site-tree-nav/index.d.ts +2 -3
  351. package/dist/site-tree-nav/index.js +11 -12
  352. package/dist/site-tree-nav/normalize-island-props.d.ts +16 -0
  353. package/dist/site-tree-nav/normalize-island-props.js +122 -0
  354. package/dist/site-tree-nav-island/index.d.ts +3 -3
  355. package/dist/site-tree-nav-island/index.js +243 -144
  356. package/dist/smart-break/index.d.ts +3 -4
  357. package/dist/smart-break/index.js +1 -1
  358. package/dist/tab-item/tab-item.d.ts +3 -4
  359. package/dist/tab-item/tab-item.js +1 -1
  360. package/dist/tag-pages/index.d.ts +3 -3
  361. package/dist/tag-pages/index.js +10 -10
  362. package/dist/theme/color-scheme-provider.d.ts +3 -3
  363. package/dist/theme/color-scheme-provider.js +3 -3
  364. package/dist/theme/theme-pack-provider.d.ts +1 -1
  365. package/dist/theme/theme-pack-provider.js +3 -3
  366. package/dist/theme/theme-toggle.d.ts +2 -3
  367. package/dist/theme/theme-toggle.js +1 -1
  368. package/dist/theme-pack-dialog/index.d.ts +1 -1
  369. package/dist/theme-pack-dialog/index.js +69 -75
  370. package/dist/theme-pack-dialog/theme-pack-card.d.ts +3 -4
  371. package/dist/theme-pack-dialog/theme-pack-card.js +19 -17
  372. package/dist/theme-pack-switcher/index.d.ts +4 -5
  373. package/dist/theme-pack-switcher/index.js +52 -49
  374. package/dist/theme-toggle/index.d.ts +1 -1
  375. package/dist/theme-toggle/index.js +154 -167
  376. package/dist/theme.css +47 -121
  377. package/dist/toc/mobile-toc.d.ts +3 -5
  378. package/dist/toc/mobile-toc.js +29 -27
  379. package/dist/toc/toc.d.ts +3 -4
  380. package/dist/toc/toc.js +18 -18
  381. package/dist/toc/use-active-heading.d.ts +5 -4
  382. package/dist/toc/use-active-heading.js +36 -30
  383. package/dist/toc-prepaint/index.d.ts +1 -2
  384. package/dist/toc-prepaint/index.js +4 -6
  385. package/dist/transitions/nested-island-props-refresh.d.ts +3 -16
  386. package/dist/transitions/nested-island-props-refresh.js +133 -151
  387. package/dist/transitions/page-events.d.ts +8 -13
  388. package/dist/tree-nav-shared/index.d.ts +4 -5
  389. package/dist/tree-nav-shared/index.js +6 -7
  390. package/dist/use-modal-dialog/index.d.ts +9 -63
  391. package/dist/use-modal-dialog/index.js +41 -59
  392. package/dist/versions-page/index.d.ts +3 -3
  393. package/dist/versions-page/index.js +5 -5
  394. package/dist/wind/index.d.ts +5 -0
  395. package/dist/wind/index.js +169 -0
  396. package/dist/wind.json +498 -0
  397. package/dist/z-index-defaults/index.d.ts +4 -4
  398. package/dist/zdtp-loader.d.ts +7 -0
  399. package/dist/zdtp-loader.js +8 -0
  400. package/eject/asset-components/asset-card.tsx +14 -16
  401. package/eject/asset-components/asset-code.tsx +10 -12
  402. package/eject/asset-components/shared.tsx +5 -7
  403. package/eject/breadcrumb/breadcrumb.tsx +15 -16
  404. package/eject/code-group/index.tsx +4 -10
  405. package/eject/content-admonition/index.tsx +5 -6
  406. package/eject/desktop-sidebar-toggle-island/index.ts +4 -0
  407. package/eject/desktop-sidebar-toggle-island/island.tsx +50 -0
  408. package/eject/desktop-sidebar-toggle-island/storage.ts +27 -0
  409. package/eject/details/details.tsx +3 -5
  410. package/eject/doc-history/index.tsx +193 -179
  411. package/eject/doc-pager/index.tsx +3 -4
  412. package/eject/footer/footer.tsx +7 -9
  413. package/eject/header/header.tsx +42 -54
  414. package/eject/header/nav-overflow-script.ts +1 -1
  415. package/eject/header/types.ts +12 -13
  416. package/eject/image-enlarge/index.tsx +84 -69
  417. package/eject/image-enlarge/public.ts +2 -0
  418. package/eject/image-enlarge/ssr-fallback.tsx +7 -0
  419. package/eject/page-loading/page-loading-overlay.tsx +8 -15
  420. package/eject/sidebar/index.ts +1 -0
  421. package/eject/sidebar/sidebar.tsx +16 -97
  422. package/eject/sidebar/types.ts +15 -0
  423. package/eject/sidebar-toggle-island/index.tsx +103 -102
  424. package/eject/sidebar-tree-island/index.tsx +827 -615
  425. package/eject/sidebar-tree-island/scope-state.ts +154 -0
  426. package/eject/sidebar-tree-island/sidebar-scroll-preserve.ts +8 -2
  427. package/eject/site-tree-nav-island/index.tsx +349 -222
  428. package/eject/tab-item/tab-item.tsx +2 -4
  429. package/eject/theme-toggle/hydration-pending.ts +6 -10
  430. package/eject/theme-toggle/index.tsx +133 -173
  431. package/eject/toc/mobile-toc.tsx +27 -31
  432. package/eject/toc/toc.tsx +21 -24
  433. package/eject/toc/use-active-heading.ts +43 -38
  434. package/package.json +40 -22
  435. package/routes-src/404.tsx +2 -3
  436. package/routes-src/_chrome.tsx +7 -2
  437. package/routes-src/_design-token-panel-bootstrap.tsx +1 -63
  438. package/routes-src/docs-slug.tsx +2 -3
  439. package/routes-src/docs-tags-index.tsx +2 -3
  440. package/routes-src/docs-tags-tag.tsx +2 -3
  441. package/routes-src/docs-versions.tsx +2 -3
  442. package/routes-src/files-path.tsx +2 -4
  443. package/routes-src/index.tsx +2 -3
  444. package/routes-src/locale-docs-slug.tsx +2 -3
  445. package/routes-src/locale-docs-tags-index.tsx +2 -3
  446. package/routes-src/locale-docs-tags-tag.tsx +2 -3
  447. package/routes-src/locale-docs-versions.tsx +2 -3
  448. package/routes-src/locale-files-path.tsx +2 -4
  449. package/routes-src/locale-index.tsx +2 -3
  450. package/routes-src/mcp.tsx +25 -0
  451. package/routes-src/v-docs-slug.tsx +2 -3
  452. package/routes-src/v-locale-docs-slug.tsx +2 -3
  453. package/tsconfig.base.json +1 -1
  454. package/dist/safelist.css +0 -2
  455. package/dist/theme-no-reset.css +0 -379
  456. package/eject/desktop-sidebar-toggle-island/index.tsx +0 -110
@@ -0,0 +1,20 @@
1
+ /** @jsxRuntime automatic */
2
+ import type { Child } from "@takazudo/zfb/zudo-react";
3
+ import { type HtmlPreviewWrapperProps } from "./html-preview-wrapper.js";
4
+ /**
5
+ * HTML preview wrapper component — the public MDX-registered binding
6
+ * (`HtmlPreview: HtmlPreviewWrapper`).
7
+ *
8
+ * Eager mode wraps the bare `HtmlPreviewWrapperInner` in
9
+ * `<Island when="visible">`, mirroring the legacy `client:visible` hydration
10
+ * timing while preserving the server-rendered controls and iframe. Visible mode
11
+ * uses zfb's skip-SSR fallback path: static output contains only an inert
12
+ * nonzero reservation, while the real serializable inner props remain on the
13
+ * island marker for native visible scheduling and client mount.
14
+ *
15
+ * The public export name and signature are unchanged from before the
16
+ * zudolab/zudo-doc#1925 fix, so existing consumers that register
17
+ * `HtmlPreview: HtmlPreviewWrapper` keep working (and now hydrate correctly)
18
+ * with no call-site change.
19
+ */
20
+ export declare function HtmlPreviewWrapper(props: HtmlPreviewWrapperProps): Child;
@@ -0,0 +1,37 @@
1
+ import { jsx } from "@takazudo/zfb/zudo-react/jsx-runtime";
2
+ import { Island } from "@takazudo/zfb";
3
+ import { HtmlPreviewWrapperInner } from "./html-preview-wrapper.js";
4
+ function reservationHeight(height) {
5
+ return height != null && height > 0 ? height : 200;
6
+ }
7
+ function HtmlPreviewReservation({
8
+ height
9
+ }) {
10
+ return /* @__PURE__ */ jsx(
11
+ "div",
12
+ {
13
+ "aria-hidden": "true",
14
+ "data-zd-html-preview-reservation": true,
15
+ style: { height: `${reservationHeight(height)}px` }
16
+ }
17
+ );
18
+ }
19
+ function HtmlPreviewWrapper(props) {
20
+ const { loading = "eager", ...innerProps } = props;
21
+ if (loading === "visible") {
22
+ const rendered2 = Island({
23
+ when: "visible",
24
+ ssrFallback: /* @__PURE__ */ jsx(HtmlPreviewReservation, { height: innerProps.height }),
25
+ children: /* @__PURE__ */ jsx(HtmlPreviewWrapperInner, { ...innerProps })
26
+ });
27
+ return rendered2;
28
+ }
29
+ const rendered = Island({
30
+ when: "visible",
31
+ children: /* @__PURE__ */ jsx(HtmlPreviewWrapperInner, { ...innerProps })
32
+ });
33
+ return rendered;
34
+ }
35
+ export {
36
+ HtmlPreviewWrapper
37
+ };
@@ -1,5 +1,3 @@
1
- /**
2
- * Keep an interactive control pending until its first successful client mount.
3
- * Initializing from `enabled` preserves server/client-first-render parity.
4
- */
5
- export declare function useHydrationPending(enabled: boolean): boolean;
1
+ import type { ReadonlySignal, Scope } from "@takazudo/zfb/zudo-react";
2
+ /** Keep SSR and the first client render pending, then release on activation. */
3
+ export declare function hydrationPending(scope: Scope, enabled: boolean): ReadonlySignal<boolean>;
@@ -1,9 +1,11 @@
1
- import { useEffect, useState } from "preact/hooks";
2
- function useHydrationPending(enabled) {
3
- const [pending, setPending] = useState(enabled);
4
- useEffect(() => setPending(false), []);
1
+ import { signal } from "@takazudo/zfb/zudo-react";
2
+ function hydrationPending(scope, enabled) {
3
+ const pending = signal(enabled);
4
+ scope.onActivate(() => {
5
+ pending.value = false;
6
+ });
5
7
  return pending;
6
8
  }
7
9
  export {
8
- useHydrationPending
10
+ hydrationPending
9
11
  };
@@ -1,35 +1,8 @@
1
1
  /** @jsxRuntime automatic */
2
- /** @jsxImportSource preact */
3
- import type { VNode } from "preact";
2
+ import type { Child } from "@takazudo/zfb/zudo-react";
4
3
  import type { LocaleLink } from "./types.js";
5
- /**
6
- * The minimal project config the client re-wire needs to reproduce
7
- * `getPathForLocale`'s output from the live pathname. Emitted as `data-*`
8
- * attributes on the switcher container so {@link LANGUAGE_SWITCHER_INIT_SCRIPT}
9
- * can read it without any serialized props.
10
- */
11
- export interface LanguageSwitcherConfig {
12
- /** Normalized site base with no trailing slash (`""` for a root site). */
13
- base: string;
14
- /** The project's default locale (rendered without a locale prefix). */
15
- defaultLocale: string;
16
- /** Whether the project appends trailing slashes to page URLs. */
17
- trailingSlash: boolean;
18
- }
19
- /**
20
- * Client-side re-computation of a locale-switched href from the *current*
21
- * pathname. This is a self-contained port of `getPathForLocale` (+ its
22
- * `stripBase` / version-prefix split / `withBase` / `applyTrailingSlash`
23
- * dependencies) from `url-helpers`. It MUST stay behaviourally identical to
24
- * that function — pinned by the drift-guard test in
25
- * `__tests__/language-switcher.test.tsx`, which asserts equality against the
26
- * real `buildLocaleLinks` output across a case table.
27
- *
28
- * It is deliberately self-contained (no references to module-scope helpers)
29
- * because {@link LANGUAGE_SWITCHER_INIT_SCRIPT} embeds it verbatim via
30
- * `.toString()`, so it must be valid as a standalone function in the browser.
31
- */
32
- export declare function switchLocaleHref(pathname: string, config: LanguageSwitcherConfig, currentLang: string, targetLang: string): string;
4
+ import type { LanguageSwitcherConfig } from "./switcher-url-state.js";
5
+ export { switchLocaleHref, type LanguageSwitcherConfig } from "./switcher-url-state.js";
33
6
  /**
34
7
  * Inline init script that keeps the switcher's per-page hrefs correct inside a
35
8
  * persisted header. Mounted once wherever a header is rendered (see
@@ -48,7 +21,7 @@ export declare function switchLocaleHref(pathname: string, config: LanguageSwitc
48
21
  * `nav-overflow-script.ts` / `sidebar-tree-island` / `version-switcher.tsx`
49
22
  * use (zudolab/zudo-doc#3398, consolidated by #3408).
50
23
  */
51
- export declare const LANGUAGE_SWITCHER_INIT_SCRIPT: string;
24
+ export { LANGUAGE_SWITCHER_INIT_SCRIPT } from "./switcher-generated-scripts.js";
52
25
  export interface LanguageSwitcherProps {
53
26
  /**
54
27
  * Pre-built locale links, ordered as they should appear in the bar.
@@ -81,5 +54,5 @@ export interface LanguageSwitcherProps {
81
54
  * template's `localeLinks.length > 1 &&` guard so call-sites can mount
82
55
  * the component unconditionally).
83
56
  */
84
- export declare function LanguageSwitcher({ links, config, currentLocale, accessibleLabel, idSuffix, }: LanguageSwitcherProps): VNode | null;
57
+ export declare function LanguageSwitcher({ links, config, currentLocale, accessibleLabel, idSuffix, }: LanguageSwitcherProps): Child;
85
58
  export type { LocaleLink };
@@ -1,106 +1,6 @@
1
- import { jsx, jsxs } from "preact/jsx-runtime";
2
- import { AFTER_NAVIGATE_EVENT } from "../transitions/index.js";
3
- import { CURRENT_PATH_SCRIPT_PRELUDE } from "../current-path/index.js";
4
- function switchLocaleHref(pathname, config, currentLang, targetLang) {
5
- const normalizedBase = config.base;
6
- const defaultLocale = config.defaultLocale;
7
- const trailingSlash = config.trailingSlash;
8
- const stripBase = (path) => {
9
- if (normalizedBase === "") return path;
10
- if (path === normalizedBase) return "/";
11
- return path.indexOf(normalizedBase + "/") === 0 ? path.slice(normalizedBase.length) : path;
12
- };
13
- const applyTrailingSlash = (url) => {
14
- if (!trailingSlash) return url;
15
- if (url.charAt(url.length - 1) === "/") return url;
16
- const suffixIdx = url.search(/[?#]/);
17
- const pathPart = suffixIdx >= 0 ? url.slice(0, suffixIdx) : url;
18
- const suffix = suffixIdx >= 0 ? url.slice(suffixIdx) : "";
19
- if (pathPart.charAt(pathPart.length - 1) === "/") return url;
20
- const segments = pathPart.split("/");
21
- const lastSegment = segments[segments.length - 1] || "";
22
- if (/\.[a-zA-Z]\w*$/.test(lastSegment)) return url;
23
- return pathPart + "/" + suffix;
24
- };
25
- const withBase = (path) => {
26
- const raw = normalizedBase === "" ? path : normalizedBase + (path.charAt(0) === "/" ? path : "/" + path);
27
- return applyTrailingSlash(raw);
28
- };
29
- const stripped = stripBase(pathname);
30
- const versionMatch = stripped.match(/^(\/v\/[^/]+)(\/.*|$)/);
31
- const versionPrefix = versionMatch ? versionMatch[1] || "" : "";
32
- let relativePath = versionMatch ? versionMatch[2] || "/" : stripped;
33
- if (currentLang !== defaultLocale) {
34
- relativePath = relativePath.replace(
35
- new RegExp("^/" + currentLang + "(?:/|$)"),
36
- "/"
37
- );
38
- }
39
- if (targetLang !== defaultLocale) {
40
- relativePath = "/" + targetLang + relativePath;
41
- }
42
- return withBase(versionPrefix + relativePath);
43
- }
44
- const LANGUAGE_SWITCHER_INIT_SCRIPT = `(function(){
45
- var FLAG="__zdLanguageSwitcherInit";
46
- ${CURRENT_PATH_SCRIPT_PRELUDE}
47
- var switchLocaleHref=${switchLocaleHref.toString()};
48
- function close(c,restoreFocus){
49
- var toggle=c.querySelector("[data-language-toggle]");
50
- var menu=c.querySelector("[data-language-menu]");
51
- if(!toggle||!menu)return;
52
- menu.classList.add("hidden");
53
- toggle.setAttribute("aria-expanded","false");
54
- if(restoreFocus)toggle.focus();
55
- }
56
- function refresh(){
57
- var containers=document.querySelectorAll("[data-language-switcher]");
58
- for(var i=0;i<containers.length;i++){
59
- var c=containers[i];
60
- close(c,false);
61
- var menu=c.querySelector("[data-language-menu]");
62
- if(menu){
63
- menu.classList.remove("group-hover:block","group-focus-within:block");
64
- }
65
- if(!c.hasAttribute("data-default-locale"))continue;
66
- var config={base:c.getAttribute("data-base")||"",defaultLocale:c.getAttribute("data-default-locale")||"",trailingSlash:c.getAttribute("data-trailing-slash")==="true"};
67
- var currentLang=c.getAttribute("data-current-locale")||config.defaultLocale;
68
- var anchors=c.querySelectorAll("a[lang]");
69
- for(var j=0;j<anchors.length;j++){
70
- var a=anchors[j];
71
- var target=a.getAttribute("lang");
72
- if(!target)continue;
73
- a.setAttribute("href",switchLocaleHref(readCurrentPath(CURRENT_PATH_DATASET_KEY),config,currentLang,target));
74
- }
75
- }
76
- }
77
- if(window[FLAG]){window[FLAG]();return;}
78
- window[FLAG]=refresh;
79
- document.addEventListener("click",function(e){
80
- var target=e.target;
81
- var toggle=target&&target.closest?target.closest("[data-language-toggle]"):null;
82
- if(toggle){
83
- var switcher=toggle.closest("[data-language-switcher]");
84
- if(switcher){
85
- var menu=switcher.querySelector("[data-language-menu]");
86
- var willOpen=toggle.getAttribute("aria-expanded")!=="true";
87
- document.querySelectorAll("[data-language-switcher]").forEach(function(c){if(c!==switcher)close(c,false);});
88
- if(menu){menu.classList.toggle("hidden",!willOpen);toggle.setAttribute("aria-expanded",String(willOpen));}
89
- }
90
- return;
91
- }
92
- document.querySelectorAll("[data-language-switcher]").forEach(function(c){if(!c.contains(target))close(c,false);});
93
- });
94
- document.addEventListener("keydown",function(e){
95
- if(e.key!=="Escape")return;
96
- document.querySelectorAll('[data-language-toggle][aria-expanded="true"]').forEach(function(toggle){
97
- var switcher=toggle.closest("[data-language-switcher]");
98
- if(switcher)close(switcher,true);
99
- });
100
- });
101
- refresh();
102
- document.addEventListener(${JSON.stringify(AFTER_NAVIGATE_EVENT)},refresh);
103
- })();`;
1
+ import { jsx, jsxs } from "@takazudo/zfb/zudo-react/jsx-runtime";
2
+ import { switchLocaleHref } from "./switcher-url-state.js";
3
+ import { LANGUAGE_SWITCHER_INIT_SCRIPT } from "./switcher-generated-scripts.js";
104
4
  function LanguageSwitcher({
105
5
  links,
106
6
  config,
@@ -130,7 +30,7 @@ function LanguageSwitcher({
130
30
  {
131
31
  type: "button",
132
32
  id: toggleId,
133
- class: "flex max-w-[16rem] cursor-pointer items-center gap-hsp-2xs whitespace-nowrap rounded border border-muted px-hsp-sm py-vsp-3xs text-small text-muted transition-colors hover:border-accent hover:text-accent focus-visible:border-accent focus-visible:text-accent",
33
+ class: "flex max-w-[16rem] cursor-pointer items-center gap-hsp-2xs whitespace-nowrap rounded border border-muted px-hsp-sm py-vsp-3xs text-small text-muted transition-colors duration-0 hover:border-accent hover:text-accent focus-visible:border-accent focus-visible:text-accent",
134
34
  "aria-label": accessibleLabel,
135
35
  "aria-controls": menuId,
136
36
  "aria-expanded": "false",
@@ -146,7 +46,7 @@ function LanguageSwitcher({
146
46
  {
147
47
  id: menuId,
148
48
  "aria-labelledby": toggleId,
149
- class: "absolute right-0 top-full z-dropdown mt-vsp-3xs hidden min-w-[8rem] max-w-[calc(100vw-var(--spacing-hsp-xl))] overflow-x-auto whitespace-nowrap rounded border border-muted bg-surface py-vsp-3xs shadow-lg group-hover:block group-focus-within:block",
49
+ class: "absolute right-0 top-full z-dropdown mt-vsp-3xs hidden min-w-[8rem] max-w-[calc(100vw_-_var(--spacing-hsp-xl))] overflow-x-auto whitespace-nowrap rounded border border-muted bg-surface py-vsp-3xs shadow-lg group-hover:block group-focus-within:block",
150
50
  "data-language-menu": true,
151
51
  children: links.map((link) => /* @__PURE__ */ jsx("li", { children: link.active ? /* @__PURE__ */ jsx(
152
52
  "span",
@@ -175,7 +75,6 @@ function ChevronDownIcon() {
175
75
  return /* @__PURE__ */ jsx(
176
76
  "svg",
177
77
  {
178
- xmlns: "http://www.w3.org/2000/svg",
179
78
  class: "h-icon-xs w-icon-xs shrink-0",
180
79
  fill: "none",
181
80
  viewBox: "0 0 24 24",
@@ -0,0 +1,2 @@
1
+ export declare const LANGUAGE_SWITCHER_INIT_SCRIPT = "(function(){\nvar FLAG=\"__zdLanguageSwitcherInit\";\nvar CURRENT_PATH_DATASET_KEY=\"zdCurrentPath\";var readCurrentPath=function readCurrentPath(datasetKey, explicit) {\n const override = typeof document === \"undefined\" ? void 0 : document.documentElement.dataset[datasetKey];\n return explicit || override || (typeof window === \"undefined\" ? void 0 : window.location.pathname);\n};\nvar switchLocaleHref=function switchLocaleHref(pathname, config, currentLang, targetLang) {\n const normalizedBase = config.base;\n const defaultLocale = config.defaultLocale;\n const trailingSlash = config.trailingSlash;\n const stripBase = (path) => {\n if (normalizedBase === \"\") return path;\n if (path === normalizedBase) return \"/\";\n return path.indexOf(normalizedBase + \"/\") === 0 ? path.slice(normalizedBase.length) : path;\n };\n const applyTrailingSlash = (url) => {\n if (!trailingSlash) return url;\n if (url.charAt(url.length - 1) === \"/\") return url;\n const suffixIdx = url.search(/[?#]/);\n const pathPart = suffixIdx >= 0 ? url.slice(0, suffixIdx) : url;\n const suffix = suffixIdx >= 0 ? url.slice(suffixIdx) : \"\";\n if (pathPart.charAt(pathPart.length - 1) === \"/\") return url;\n const segments = pathPart.split(\"/\");\n const lastSegment = segments[segments.length - 1] || \"\";\n if (/\\.[a-zA-Z]\\w*$/.test(lastSegment)) return url;\n return pathPart + \"/\" + suffix;\n };\n const withBase = (path) => {\n const raw = normalizedBase === \"\" ? path : normalizedBase + (path.charAt(0) === \"/\" ? path : \"/\" + path);\n return applyTrailingSlash(raw);\n };\n const stripped = stripBase(pathname);\n const versionMatch = stripped.match(/^(\\/v\\/[^/]+)(\\/.*|$)/);\n const versionPrefix = versionMatch ? versionMatch[1] || \"\" : \"\";\n let relativePath = versionMatch ? versionMatch[2] || \"/\" : stripped;\n if (currentLang !== defaultLocale) {\n relativePath = relativePath.replace(\n new RegExp(\"^/\" + currentLang + \"(?:/|$)\"),\n \"/\"\n );\n }\n if (targetLang !== defaultLocale) {\n relativePath = \"/\" + targetLang + relativePath;\n }\n return withBase(versionPrefix + relativePath);\n};\nfunction close(c,restoreFocus){\nvar toggle=c.querySelector(\"[data-language-toggle]\");\nvar menu=c.querySelector(\"[data-language-menu]\");\nif(!toggle||!menu)return;\nmenu.classList.add(\"hidden\");\ntoggle.setAttribute(\"aria-expanded\",\"false\");\nif(restoreFocus)toggle.focus();\n}\nfunction refresh(){\nvar containers=document.querySelectorAll(\"[data-language-switcher]\");\nfor(var i=0;i<containers.length;i++){\nvar c=containers[i];\nclose(c,false);\nvar menu=c.querySelector(\"[data-language-menu]\");\nif(menu){\nmenu.classList.remove(\"group-hover:block\",\"group-focus-within:block\");\n}\nif(!c.hasAttribute(\"data-default-locale\"))continue;\nvar config={base:c.getAttribute(\"data-base\")||\"\",defaultLocale:c.getAttribute(\"data-default-locale\")||\"\",trailingSlash:c.getAttribute(\"data-trailing-slash\")===\"true\"};\nvar currentLang=c.getAttribute(\"data-current-locale\")||config.defaultLocale;\nvar anchors=c.querySelectorAll(\"a[lang]\");\nfor(var j=0;j<anchors.length;j++){\nvar a=anchors[j];\nvar target=a.getAttribute(\"lang\");\nif(!target)continue;\na.setAttribute(\"href\",switchLocaleHref(readCurrentPath(CURRENT_PATH_DATASET_KEY),config,currentLang,target));\n}\n}\n}\nif(window[FLAG]){window[FLAG]();return;}\nwindow[FLAG]=refresh;\ndocument.addEventListener(\"click\",function(e){\nvar target=e.target;\nvar toggle=target&&target.closest?target.closest(\"[data-language-toggle]\"):null;\nif(toggle){\nvar switcher=toggle.closest(\"[data-language-switcher]\");\nif(switcher){\nvar menu=switcher.querySelector(\"[data-language-menu]\");\nvar willOpen=toggle.getAttribute(\"aria-expanded\")!==\"true\";\ndocument.querySelectorAll(\"[data-language-switcher]\").forEach(function(c){if(c!==switcher)close(c,false);});\nif(menu){menu.classList.toggle(\"hidden\",!willOpen);toggle.setAttribute(\"aria-expanded\",String(willOpen));}\n}\nreturn;\n}\ndocument.querySelectorAll(\"[data-language-switcher]\").forEach(function(c){if(!c.contains(target))close(c,false);});\n});\ndocument.addEventListener(\"keydown\",function(e){\nif(e.key!==\"Escape\")return;\ndocument.querySelectorAll('[data-language-toggle][aria-expanded=\"true\"]').forEach(function(toggle){\nvar switcher=toggle.closest(\"[data-language-switcher]\");\nif(switcher)close(switcher,true);\n});\n});\nrefresh();\ndocument.addEventListener(\"zfb:after-swap\",refresh);\n})();";
2
+ export declare const VERSION_SWITCHER_REWIRE_SCRIPT = "(function(){\nvar FLAG=\"__zdVersionSwitcherRewire\";\nif(window[FLAG])return;\nwindow[FLAG]=true;\nvar ATTR=\"data-doc-unavailable-versions\";\nvar CURRENT_PATH_DATASET_KEY=\"zdCurrentPath\";var readCurrentPath=function readCurrentPath(datasetKey, explicit) {\n const override = typeof document === \"undefined\" ? void 0 : document.documentElement.dataset[datasetKey];\n return explicit || override || (typeof window === \"undefined\" ? void 0 : window.location.pathname);\n};\nvar computeVersionSwitcherState=function computeVersionSwitcherState(pathname, config, versionSlugs) {\n const normalizedBase = config.base;\n const defaultLocale = config.defaultLocale;\n const currentLocale = config.currentLocale;\n const trailingSlash = config.trailingSlash;\n const stripBase = (path) => {\n if (normalizedBase === \"\") return path;\n if (path === normalizedBase) return \"/\";\n return path.indexOf(normalizedBase + \"/\") === 0 ? path.slice(normalizedBase.length) : path;\n };\n const applyTrailingSlash = (url) => {\n if (!trailingSlash) return url;\n if (url.charAt(url.length - 1) === \"/\") return url;\n const suffixIdx = url.search(/[?#]/);\n const pathPart = suffixIdx >= 0 ? url.slice(0, suffixIdx) : url;\n const suffix = suffixIdx >= 0 ? url.slice(suffixIdx) : \"\";\n if (pathPart.charAt(pathPart.length - 1) === \"/\") return url;\n const segments = pathPart.split(\"/\");\n const lastSegment = segments[segments.length - 1] || \"\";\n if (/\\.[a-zA-Z]\\w*$/.test(lastSegment)) return url;\n return pathPart + \"/\" + suffix;\n };\n const withBase = (path) => {\n const raw = normalizedBase === \"\" ? path : normalizedBase + (path.charAt(0) === \"/\" ? path : \"/\" + path);\n return applyTrailingSlash(raw);\n };\n const versionsPageUrl = withBase(\n currentLocale === defaultLocale ? \"/docs/versions\" : \"/\" + currentLocale + \"/docs/versions\"\n );\n const stripped = stripBase(pathname);\n const versionMatch = stripped.match(/^\\/v\\/([^/]+)(\\/.*|$)/);\n const rest = versionMatch ? versionMatch[2] || \"/\" : stripped;\n let localeStripped = rest;\n if (currentLocale !== defaultLocale) {\n localeStripped = rest.replace(\n new RegExp(\"^/\" + currentLocale + \"(?:/|$)\"),\n \"/\"\n );\n }\n const isVersionsIndex = localeStripped === \"/docs/versions\" || localeStripped === \"/docs/versions/\";\n const isDocPage = /^\\/docs(\\/|$)/.test(localeStripped) && !isVersionsIndex;\n const activeVersion = isDocPage && versionMatch ? versionMatch[1] || null : null;\n const versionHrefs = {};\n let latestHref;\n if (isDocPage) {\n latestHref = withBase(rest);\n for (let i = 0; i < versionSlugs.length; i++) {\n const slug = versionSlugs[i];\n if (slug) versionHrefs[slug] = withBase(\"/v/\" + slug + rest);\n }\n } else {\n latestHref = versionsPageUrl;\n for (let i = 0; i < versionSlugs.length; i++) {\n const slug = versionSlugs[i];\n if (slug) versionHrefs[slug] = versionsPageUrl;\n }\n }\n return { latestHref, versionHrefs, activeVersion };\n};\nfunction setActive(a,active){\na.classList.toggle(\"font-bold\",active);\na.classList.toggle(\"text-accent\",active);\na.classList.toggle(\"text-fg\",!active);\nif(active){a.setAttribute(\"aria-current\",\"page\");}else{a.removeAttribute(\"aria-current\");}\n}\nfunction setDisabled(a,disabled,unavailableLabel){\na.classList.toggle(\"hover:bg-accent/10\",!disabled);\na.classList.toggle(\"hover:underline\",!disabled);\na.classList.toggle(\"focus-visible:underline\",!disabled);\na.classList.toggle(\"text-muted/50\",disabled);\na.classList.toggle(\"cursor-not-allowed\",disabled);\na.classList.toggle(\"pointer-events-none\",disabled);\nif(disabled){\na.setAttribute(\"aria-disabled\",\"true\");\na.setAttribute(\"tabindex\",\"-1\");\na.setAttribute(\"title\",unavailableLabel);\na.classList.remove(\"font-bold\",\"text-accent\",\"text-fg\");\na.removeAttribute(\"aria-current\");\n}else{\na.removeAttribute(\"aria-disabled\");\na.removeAttribute(\"tabindex\");\na.removeAttribute(\"title\");\n}\n}\nfunction rewire(){\nvar articleEl=document.querySelector(\"[\"+ATTR+\"]\");\nvar hasAvailabilityData=articleEl!==null;\nvar unavailableSlugs=hasAvailabilityData?(articleEl.getAttribute(ATTR)||\"\").split(\",\").filter(Boolean):[];\nvar containers=document.querySelectorAll(\"[data-version-rewire]\");\nfor(var i=0;i<containers.length;i++){\nvar c=containers[i];\nvar config={base:c.getAttribute(\"data-base\")||\"\",defaultLocale:c.getAttribute(\"data-default-locale\")||\"\",trailingSlash:c.getAttribute(\"data-trailing-slash\")===\"true\",currentLocale:c.getAttribute(\"data-current-locale\")||\"\"};\nvar unavailableLabel=c.getAttribute(\"data-unavailable-label\")||\"\";\nvar versionAnchors=c.querySelectorAll(\"[data-version-slug]\");\nvar slugs=[];\nfor(var j=0;j<versionAnchors.length;j++){\nvar s=versionAnchors[j].getAttribute(\"data-version-slug\");\nif(s)slugs.push(s);\n}\nvar state=computeVersionSwitcherState(readCurrentPath(CURRENT_PATH_DATASET_KEY),config,slugs);\nvar latest=c.querySelector(\"[data-version-latest]\");\nif(latest){\nlatest.setAttribute(\"href\",state.latestHref);\nsetActive(latest,state.activeVersion===null);\n}\nfor(var k=0;k<versionAnchors.length;k++){\nvar a=versionAnchors[k];\nvar slug=a.getAttribute(\"data-version-slug\");\nif(!slug)continue;\nvar href=state.versionHrefs[slug];\nif(href!=null)a.setAttribute(\"href\",href);\nif(hasAvailabilityData){\nvar disabled=unavailableSlugs.indexOf(slug)!==-1;\nsetDisabled(a,disabled,unavailableLabel);\nif(!disabled)setActive(a,state.activeVersion===slug);\n}else{\nvar alreadyDisabled=a.getAttribute(\"aria-disabled\")===\"true\";\nif(!alreadyDisabled)setActive(a,state.activeVersion===slug);\n}\n}\nvar label=c.querySelector(\"[data-version-trigger-label]\");\nif(label){\nif(state.activeVersion===null){\nif(latest)label.textContent=latest.textContent;\n}else{\nvar activeLabel=null;\nfor(var m=0;m<versionAnchors.length;m++){\nif(versionAnchors[m].getAttribute(\"data-version-slug\")===state.activeVersion){activeLabel=versionAnchors[m].textContent;break;}\n}\nlabel.textContent=activeLabel!=null?activeLabel:state.activeVersion;\n}\n}\n}\n}\n// The initial call is deferred to DOMContentLoaded when the script (inline in\n// <header>, which parses before <article>) would otherwise run before the\n// article element exists. Running early would read a missing ATTR as \"no\n// unavailable slugs\" and clobber the SSR-correct disabled state with\n// everything-enabled \u2014 a first-paint variant of the bug this rewire exists\n// to fix (see the doc comment above; SSR already rendered the right state for\n// this page, so a brief deferral loses nothing).\nif(document.readyState===\"loading\"){document.addEventListener(\"DOMContentLoaded\",rewire);}else{rewire();}\ndocument.addEventListener(\"zfb:after-swap\",rewire);\n})();";
@@ -0,0 +1,107 @@
1
+ const LANGUAGE_SWITCHER_INIT_SCRIPT = `(function(){
2
+ var FLAG="__zdLanguageSwitcherInit";
3
+ var CURRENT_PATH_DATASET_KEY="zdCurrentPath";var readCurrentPath=function readCurrentPath(datasetKey, explicit) {
4
+ const override = typeof document === "undefined" ? void 0 : document.documentElement.dataset[datasetKey];
5
+ return explicit || override || (typeof window === "undefined" ? void 0 : window.location.pathname);
6
+ };
7
+ var switchLocaleHref=function switchLocaleHref(pathname, config, currentLang, targetLang) {
8
+ const normalizedBase = config.base;
9
+ const defaultLocale = config.defaultLocale;
10
+ const trailingSlash = config.trailingSlash;
11
+ const stripBase = (path) => {
12
+ if (normalizedBase === "") return path;
13
+ if (path === normalizedBase) return "/";
14
+ return path.indexOf(normalizedBase + "/") === 0 ? path.slice(normalizedBase.length) : path;
15
+ };
16
+ const applyTrailingSlash = (url) => {
17
+ if (!trailingSlash) return url;
18
+ if (url.charAt(url.length - 1) === "/") return url;
19
+ const suffixIdx = url.search(/[?#]/);
20
+ const pathPart = suffixIdx >= 0 ? url.slice(0, suffixIdx) : url;
21
+ const suffix = suffixIdx >= 0 ? url.slice(suffixIdx) : "";
22
+ if (pathPart.charAt(pathPart.length - 1) === "/") return url;
23
+ const segments = pathPart.split("/");
24
+ const lastSegment = segments[segments.length - 1] || "";
25
+ if (/\\.[a-zA-Z]\\w*$/.test(lastSegment)) return url;
26
+ return pathPart + "/" + suffix;
27
+ };
28
+ const withBase = (path) => {
29
+ const raw = normalizedBase === "" ? path : normalizedBase + (path.charAt(0) === "/" ? path : "/" + path);
30
+ return applyTrailingSlash(raw);
31
+ };
32
+ const stripped = stripBase(pathname);
33
+ const versionMatch = stripped.match(/^(\\/v\\/[^/]+)(\\/.*|$)/);
34
+ const versionPrefix = versionMatch ? versionMatch[1] || "" : "";
35
+ let relativePath = versionMatch ? versionMatch[2] || "/" : stripped;
36
+ if (currentLang !== defaultLocale) {
37
+ relativePath = relativePath.replace(
38
+ new RegExp("^/" + currentLang + "(?:/|$)"),
39
+ "/"
40
+ );
41
+ }
42
+ if (targetLang !== defaultLocale) {
43
+ relativePath = "/" + targetLang + relativePath;
44
+ }
45
+ return withBase(versionPrefix + relativePath);
46
+ };
47
+ function close(c,restoreFocus){
48
+ var toggle=c.querySelector("[data-language-toggle]");
49
+ var menu=c.querySelector("[data-language-menu]");
50
+ if(!toggle||!menu)return;
51
+ menu.classList.add("hidden");
52
+ toggle.setAttribute("aria-expanded","false");
53
+ if(restoreFocus)toggle.focus();
54
+ }
55
+ function refresh(){
56
+ var containers=document.querySelectorAll("[data-language-switcher]");
57
+ for(var i=0;i<containers.length;i++){
58
+ var c=containers[i];
59
+ close(c,false);
60
+ var menu=c.querySelector("[data-language-menu]");
61
+ if(menu){
62
+ menu.classList.remove("group-hover:block","group-focus-within:block");
63
+ }
64
+ if(!c.hasAttribute("data-default-locale"))continue;
65
+ var config={base:c.getAttribute("data-base")||"",defaultLocale:c.getAttribute("data-default-locale")||"",trailingSlash:c.getAttribute("data-trailing-slash")==="true"};
66
+ var currentLang=c.getAttribute("data-current-locale")||config.defaultLocale;
67
+ var anchors=c.querySelectorAll("a[lang]");
68
+ for(var j=0;j<anchors.length;j++){
69
+ var a=anchors[j];
70
+ var target=a.getAttribute("lang");
71
+ if(!target)continue;
72
+ a.setAttribute("href",switchLocaleHref(readCurrentPath(CURRENT_PATH_DATASET_KEY),config,currentLang,target));
73
+ }
74
+ }
75
+ }
76
+ if(window[FLAG]){window[FLAG]();return;}
77
+ window[FLAG]=refresh;
78
+ document.addEventListener("click",function(e){
79
+ var target=e.target;
80
+ var toggle=target&&target.closest?target.closest("[data-language-toggle]"):null;
81
+ if(toggle){
82
+ var switcher=toggle.closest("[data-language-switcher]");
83
+ if(switcher){
84
+ var menu=switcher.querySelector("[data-language-menu]");
85
+ var willOpen=toggle.getAttribute("aria-expanded")!=="true";
86
+ document.querySelectorAll("[data-language-switcher]").forEach(function(c){if(c!==switcher)close(c,false);});
87
+ if(menu){menu.classList.toggle("hidden",!willOpen);toggle.setAttribute("aria-expanded",String(willOpen));}
88
+ }
89
+ return;
90
+ }
91
+ document.querySelectorAll("[data-language-switcher]").forEach(function(c){if(!c.contains(target))close(c,false);});
92
+ });
93
+ document.addEventListener("keydown",function(e){
94
+ if(e.key!=="Escape")return;
95
+ document.querySelectorAll('[data-language-toggle][aria-expanded="true"]').forEach(function(toggle){
96
+ var switcher=toggle.closest("[data-language-switcher]");
97
+ if(switcher)close(switcher,true);
98
+ });
99
+ });
100
+ refresh();
101
+ document.addEventListener("zfb:after-swap",refresh);
102
+ })();`;
103
+ const VERSION_SWITCHER_REWIRE_SCRIPT = '(function(){\nvar FLAG="__zdVersionSwitcherRewire";\nif(window[FLAG])return;\nwindow[FLAG]=true;\nvar ATTR="data-doc-unavailable-versions";\nvar CURRENT_PATH_DATASET_KEY="zdCurrentPath";var readCurrentPath=function readCurrentPath(datasetKey, explicit) {\n const override = typeof document === "undefined" ? void 0 : document.documentElement.dataset[datasetKey];\n return explicit || override || (typeof window === "undefined" ? void 0 : window.location.pathname);\n};\nvar computeVersionSwitcherState=function computeVersionSwitcherState(pathname, config, versionSlugs) {\n const normalizedBase = config.base;\n const defaultLocale = config.defaultLocale;\n const currentLocale = config.currentLocale;\n const trailingSlash = config.trailingSlash;\n const stripBase = (path) => {\n if (normalizedBase === "") return path;\n if (path === normalizedBase) return "/";\n return path.indexOf(normalizedBase + "/") === 0 ? path.slice(normalizedBase.length) : path;\n };\n const applyTrailingSlash = (url) => {\n if (!trailingSlash) return url;\n if (url.charAt(url.length - 1) === "/") return url;\n const suffixIdx = url.search(/[?#]/);\n const pathPart = suffixIdx >= 0 ? url.slice(0, suffixIdx) : url;\n const suffix = suffixIdx >= 0 ? url.slice(suffixIdx) : "";\n if (pathPart.charAt(pathPart.length - 1) === "/") return url;\n const segments = pathPart.split("/");\n const lastSegment = segments[segments.length - 1] || "";\n if (/\\.[a-zA-Z]\\w*$/.test(lastSegment)) return url;\n return pathPart + "/" + suffix;\n };\n const withBase = (path) => {\n const raw = normalizedBase === "" ? path : normalizedBase + (path.charAt(0) === "/" ? path : "/" + path);\n return applyTrailingSlash(raw);\n };\n const versionsPageUrl = withBase(\n currentLocale === defaultLocale ? "/docs/versions" : "/" + currentLocale + "/docs/versions"\n );\n const stripped = stripBase(pathname);\n const versionMatch = stripped.match(/^\\/v\\/([^/]+)(\\/.*|$)/);\n const rest = versionMatch ? versionMatch[2] || "/" : stripped;\n let localeStripped = rest;\n if (currentLocale !== defaultLocale) {\n localeStripped = rest.replace(\n new RegExp("^/" + currentLocale + "(?:/|$)"),\n "/"\n );\n }\n const isVersionsIndex = localeStripped === "/docs/versions" || localeStripped === "/docs/versions/";\n const isDocPage = /^\\/docs(\\/|$)/.test(localeStripped) && !isVersionsIndex;\n const activeVersion = isDocPage && versionMatch ? versionMatch[1] || null : null;\n const versionHrefs = {};\n let latestHref;\n if (isDocPage) {\n latestHref = withBase(rest);\n for (let i = 0; i < versionSlugs.length; i++) {\n const slug = versionSlugs[i];\n if (slug) versionHrefs[slug] = withBase("/v/" + slug + rest);\n }\n } else {\n latestHref = versionsPageUrl;\n for (let i = 0; i < versionSlugs.length; i++) {\n const slug = versionSlugs[i];\n if (slug) versionHrefs[slug] = versionsPageUrl;\n }\n }\n return { latestHref, versionHrefs, activeVersion };\n};\nfunction setActive(a,active){\na.classList.toggle("font-bold",active);\na.classList.toggle("text-accent",active);\na.classList.toggle("text-fg",!active);\nif(active){a.setAttribute("aria-current","page");}else{a.removeAttribute("aria-current");}\n}\nfunction setDisabled(a,disabled,unavailableLabel){\na.classList.toggle("hover:bg-accent/10",!disabled);\na.classList.toggle("hover:underline",!disabled);\na.classList.toggle("focus-visible:underline",!disabled);\na.classList.toggle("text-muted/50",disabled);\na.classList.toggle("cursor-not-allowed",disabled);\na.classList.toggle("pointer-events-none",disabled);\nif(disabled){\na.setAttribute("aria-disabled","true");\na.setAttribute("tabindex","-1");\na.setAttribute("title",unavailableLabel);\na.classList.remove("font-bold","text-accent","text-fg");\na.removeAttribute("aria-current");\n}else{\na.removeAttribute("aria-disabled");\na.removeAttribute("tabindex");\na.removeAttribute("title");\n}\n}\nfunction rewire(){\nvar articleEl=document.querySelector("["+ATTR+"]");\nvar hasAvailabilityData=articleEl!==null;\nvar unavailableSlugs=hasAvailabilityData?(articleEl.getAttribute(ATTR)||"").split(",").filter(Boolean):[];\nvar containers=document.querySelectorAll("[data-version-rewire]");\nfor(var i=0;i<containers.length;i++){\nvar c=containers[i];\nvar config={base:c.getAttribute("data-base")||"",defaultLocale:c.getAttribute("data-default-locale")||"",trailingSlash:c.getAttribute("data-trailing-slash")==="true",currentLocale:c.getAttribute("data-current-locale")||""};\nvar unavailableLabel=c.getAttribute("data-unavailable-label")||"";\nvar versionAnchors=c.querySelectorAll("[data-version-slug]");\nvar slugs=[];\nfor(var j=0;j<versionAnchors.length;j++){\nvar s=versionAnchors[j].getAttribute("data-version-slug");\nif(s)slugs.push(s);\n}\nvar state=computeVersionSwitcherState(readCurrentPath(CURRENT_PATH_DATASET_KEY),config,slugs);\nvar latest=c.querySelector("[data-version-latest]");\nif(latest){\nlatest.setAttribute("href",state.latestHref);\nsetActive(latest,state.activeVersion===null);\n}\nfor(var k=0;k<versionAnchors.length;k++){\nvar a=versionAnchors[k];\nvar slug=a.getAttribute("data-version-slug");\nif(!slug)continue;\nvar href=state.versionHrefs[slug];\nif(href!=null)a.setAttribute("href",href);\nif(hasAvailabilityData){\nvar disabled=unavailableSlugs.indexOf(slug)!==-1;\nsetDisabled(a,disabled,unavailableLabel);\nif(!disabled)setActive(a,state.activeVersion===slug);\n}else{\nvar alreadyDisabled=a.getAttribute("aria-disabled")==="true";\nif(!alreadyDisabled)setActive(a,state.activeVersion===slug);\n}\n}\nvar label=c.querySelector("[data-version-trigger-label]");\nif(label){\nif(state.activeVersion===null){\nif(latest)label.textContent=latest.textContent;\n}else{\nvar activeLabel=null;\nfor(var m=0;m<versionAnchors.length;m++){\nif(versionAnchors[m].getAttribute("data-version-slug")===state.activeVersion){activeLabel=versionAnchors[m].textContent;break;}\n}\nlabel.textContent=activeLabel!=null?activeLabel:state.activeVersion;\n}\n}\n}\n}\n// The initial call is deferred to DOMContentLoaded when the script (inline in\n// <header>, which parses before <article>) would otherwise run before the\n// article element exists. Running early would read a missing ATTR as "no\n// unavailable slugs" and clobber the SSR-correct disabled state with\n// everything-enabled \u2014 a first-paint variant of the bug this rewire exists\n// to fix (see the doc comment above; SSR already rendered the right state for\n// this page, so a brief deferral loses nothing).\nif(document.readyState==="loading"){document.addEventListener("DOMContentLoaded",rewire);}else{rewire();}\ndocument.addEventListener("zfb:after-swap",rewire);\n})();';
104
+ export {
105
+ LANGUAGE_SWITCHER_INIT_SCRIPT,
106
+ VERSION_SWITCHER_REWIRE_SCRIPT
107
+ };
@@ -0,0 +1,76 @@
1
+ /**
2
+ * The minimal project config the client re-wire needs to reproduce
3
+ * `getPathForLocale`'s output from the live pathname. Emitted as `data-*`
4
+ * attributes on the switcher container so {@link LANGUAGE_SWITCHER_INIT_SCRIPT}
5
+ * can read it without any serialized props.
6
+ */
7
+ export interface LanguageSwitcherConfig {
8
+ /** Normalized site base with no trailing slash (`""` for a root site). */
9
+ base: string;
10
+ /** The project's default locale (rendered without a locale prefix). */
11
+ defaultLocale: string;
12
+ /** Whether the project appends trailing slashes to page URLs. */
13
+ trailingSlash: boolean;
14
+ }
15
+ /**
16
+ * Client-side re-computation of a locale-switched href from the *current*
17
+ * pathname. This is a self-contained port of `getPathForLocale` (+ its
18
+ * `stripBase` / version-prefix split / `withBase` / `applyTrailingSlash`
19
+ * dependencies) from `url-helpers`. It MUST stay behaviourally identical to
20
+ * that function — pinned by the drift-guard test in
21
+ * `__tests__/language-switcher.test.tsx`, which asserts equality against the
22
+ * real `buildLocaleLinks` output across a case table.
23
+ *
24
+ * It is deliberately self-contained (no references to module-scope helpers)
25
+ * because {@link LANGUAGE_SWITCHER_INIT_SCRIPT} embeds it verbatim via
26
+ * package-build serialization, so it must be valid as a standalone function
27
+ * in the browser. Downstream builds consume a frozen script string.
28
+ */
29
+ export declare function switchLocaleHref(pathname: string, config: LanguageSwitcherConfig, currentLang: string, targetLang: string): string;
30
+ /**
31
+ * The minimal project config the client re-wire needs to reproduce the header
32
+ * factory's per-page menu URLs from the live pathname. Emitted as `data-*`
33
+ * attributes on the switcher container so {@link VERSION_SWITCHER_REWIRE_SCRIPT}
34
+ * can read it without any serialized props.
35
+ */
36
+ export interface VersionSwitcherRewireConfig {
37
+ /** Normalized site base with no trailing slash (`""` for a root site). */
38
+ base: string;
39
+ /** The project's default locale (rendered without a locale prefix). */
40
+ defaultLocale: string;
41
+ /** Whether the project appends trailing slashes to page URLs. */
42
+ trailingSlash: boolean;
43
+ /**
44
+ * The active locale code — constant within a `header-${lang}` persist window,
45
+ * so it can be read once from the SSR container rather than re-derived.
46
+ */
47
+ currentLocale: string;
48
+ }
49
+ /** The re-computed per-page menu state {@link computeVersionSwitcherState} returns. */
50
+ export interface VersionSwitcherState {
51
+ /** Href for the "Latest" entry, matching the SSR `latestUrl`. */
52
+ latestHref: string;
53
+ /** version slug → href for that version of the current page (SSR `versionUrls`). */
54
+ versionHrefs: Record<string, string>;
55
+ /** Active version slug, or `null` when the current page is on "latest". */
56
+ activeVersion: string | null;
57
+ }
58
+ /**
59
+ * Client-side re-computation of the version-switcher's per-page menu state from
60
+ * the *current* pathname. This is a self-contained port of the header factory's
61
+ * URL logic (`createHeaderWithDefaults`'s `latestUrl` / `versionUrls` block, in
62
+ * turn `docsUrl` / `versionedDocsUrl` / `withBase` from `url-helpers`). It MUST
63
+ * stay behaviourally identical to that SSR path — pinned by the drift-guard test
64
+ * in `__tests__/version-switcher.test.tsx`, which asserts equality against the
65
+ * real `makeUrlHelpers` output across a case table.
66
+ *
67
+ * It is deliberately self-contained (no references to module-scope helpers)
68
+ * because {@link VERSION_SWITCHER_REWIRE_SCRIPT} embeds it verbatim via
69
+ * package-build serialization, so it must be valid as a standalone function
70
+ * in the browser. Downstream builds consume a frozen script string.
71
+ *
72
+ * The `/docs/versions` listing is a standalone package route (`currentSlug`
73
+ * `undefined` on the SSR side), so — like the SSR factory — every menu href
74
+ * there collapses to `versionsPageUrl`; the exact-path check below mirrors that.
75
+ */
76
+ export declare function computeVersionSwitcherState(pathname: string, config: VersionSwitcherRewireConfig, versionSlugs: string[]): VersionSwitcherState;
@@ -0,0 +1,103 @@
1
+ function switchLocaleHref(pathname, config, currentLang, targetLang) {
2
+ const normalizedBase = config.base;
3
+ const defaultLocale = config.defaultLocale;
4
+ const trailingSlash = config.trailingSlash;
5
+ const stripBase = (path) => {
6
+ if (normalizedBase === "") return path;
7
+ if (path === normalizedBase) return "/";
8
+ return path.indexOf(normalizedBase + "/") === 0 ? path.slice(normalizedBase.length) : path;
9
+ };
10
+ const applyTrailingSlash = (url) => {
11
+ if (!trailingSlash) return url;
12
+ if (url.charAt(url.length - 1) === "/") return url;
13
+ const suffixIdx = url.search(/[?#]/);
14
+ const pathPart = suffixIdx >= 0 ? url.slice(0, suffixIdx) : url;
15
+ const suffix = suffixIdx >= 0 ? url.slice(suffixIdx) : "";
16
+ if (pathPart.charAt(pathPart.length - 1) === "/") return url;
17
+ const segments = pathPart.split("/");
18
+ const lastSegment = segments[segments.length - 1] || "";
19
+ if (/\.[a-zA-Z]\w*$/.test(lastSegment)) return url;
20
+ return pathPart + "/" + suffix;
21
+ };
22
+ const withBase = (path) => {
23
+ const raw = normalizedBase === "" ? path : normalizedBase + (path.charAt(0) === "/" ? path : "/" + path);
24
+ return applyTrailingSlash(raw);
25
+ };
26
+ const stripped = stripBase(pathname);
27
+ const versionMatch = stripped.match(/^(\/v\/[^/]+)(\/.*|$)/);
28
+ const versionPrefix = versionMatch ? versionMatch[1] || "" : "";
29
+ let relativePath = versionMatch ? versionMatch[2] || "/" : stripped;
30
+ if (currentLang !== defaultLocale) {
31
+ relativePath = relativePath.replace(
32
+ new RegExp("^/" + currentLang + "(?:/|$)"),
33
+ "/"
34
+ );
35
+ }
36
+ if (targetLang !== defaultLocale) {
37
+ relativePath = "/" + targetLang + relativePath;
38
+ }
39
+ return withBase(versionPrefix + relativePath);
40
+ }
41
+ function computeVersionSwitcherState(pathname, config, versionSlugs) {
42
+ const normalizedBase = config.base;
43
+ const defaultLocale = config.defaultLocale;
44
+ const currentLocale = config.currentLocale;
45
+ const trailingSlash = config.trailingSlash;
46
+ const stripBase = (path) => {
47
+ if (normalizedBase === "") return path;
48
+ if (path === normalizedBase) return "/";
49
+ return path.indexOf(normalizedBase + "/") === 0 ? path.slice(normalizedBase.length) : path;
50
+ };
51
+ const applyTrailingSlash = (url) => {
52
+ if (!trailingSlash) return url;
53
+ if (url.charAt(url.length - 1) === "/") return url;
54
+ const suffixIdx = url.search(/[?#]/);
55
+ const pathPart = suffixIdx >= 0 ? url.slice(0, suffixIdx) : url;
56
+ const suffix = suffixIdx >= 0 ? url.slice(suffixIdx) : "";
57
+ if (pathPart.charAt(pathPart.length - 1) === "/") return url;
58
+ const segments = pathPart.split("/");
59
+ const lastSegment = segments[segments.length - 1] || "";
60
+ if (/\.[a-zA-Z]\w*$/.test(lastSegment)) return url;
61
+ return pathPart + "/" + suffix;
62
+ };
63
+ const withBase = (path) => {
64
+ const raw = normalizedBase === "" ? path : normalizedBase + (path.charAt(0) === "/" ? path : "/" + path);
65
+ return applyTrailingSlash(raw);
66
+ };
67
+ const versionsPageUrl = withBase(
68
+ currentLocale === defaultLocale ? "/docs/versions" : "/" + currentLocale + "/docs/versions"
69
+ );
70
+ const stripped = stripBase(pathname);
71
+ const versionMatch = stripped.match(/^\/v\/([^/]+)(\/.*|$)/);
72
+ const rest = versionMatch ? versionMatch[2] || "/" : stripped;
73
+ let localeStripped = rest;
74
+ if (currentLocale !== defaultLocale) {
75
+ localeStripped = rest.replace(
76
+ new RegExp("^/" + currentLocale + "(?:/|$)"),
77
+ "/"
78
+ );
79
+ }
80
+ const isVersionsIndex = localeStripped === "/docs/versions" || localeStripped === "/docs/versions/";
81
+ const isDocPage = /^\/docs(\/|$)/.test(localeStripped) && !isVersionsIndex;
82
+ const activeVersion = isDocPage && versionMatch ? versionMatch[1] || null : null;
83
+ const versionHrefs = {};
84
+ let latestHref;
85
+ if (isDocPage) {
86
+ latestHref = withBase(rest);
87
+ for (let i = 0; i < versionSlugs.length; i++) {
88
+ const slug = versionSlugs[i];
89
+ if (slug) versionHrefs[slug] = withBase("/v/" + slug + rest);
90
+ }
91
+ } else {
92
+ latestHref = versionsPageUrl;
93
+ for (let i = 0; i < versionSlugs.length; i++) {
94
+ const slug = versionSlugs[i];
95
+ if (slug) versionHrefs[slug] = versionsPageUrl;
96
+ }
97
+ }
98
+ return { latestHref, versionHrefs, activeVersion };
99
+ }
100
+ export {
101
+ computeVersionSwitcherState,
102
+ switchLocaleHref
103
+ };
@@ -1,6 +1,5 @@
1
1
  /** @jsxRuntime automatic */
2
- /** @jsxImportSource preact */
3
- import type { VNode } from "preact";
2
+ import type { Child } from "@takazudo/zfb/zudo-react";
4
3
  export interface VersionBannerLabels {
5
4
  /** Banner body text (e.g. "You are viewing documentation for an older version."). */
6
5
  message: string;
@@ -23,4 +22,4 @@ export interface VersionBannerProps {
23
22
  * The host typically resolves `labels` via `t("version.banner.*", lang)`
24
23
  * and `latestUrl` via the project's URL helpers.
25
24
  */
26
- export declare function VersionBanner(props: VersionBannerProps): VNode;
25
+ export declare function VersionBanner(props: VersionBannerProps): Child;
@@ -1,4 +1,4 @@
1
- import { jsx, jsxs } from "preact/jsx-runtime";
1
+ import { jsx, jsxs } from "@takazudo/zfb/zudo-react/jsx-runtime";
2
2
  function VersionBanner(props) {
3
3
  const { type, latestUrl, labels } = props;
4
4
  return /* @__PURE__ */ jsxs(