@takazudo/zudo-doc 3.3.0 → 4.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 (417) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +2 -2
  3. package/bin/tag-cli-config.ts +126 -0
  4. package/bin/tags-audit-runner.ts +60 -76
  5. package/bin/tags-audit.mjs +17 -36
  6. package/bin/tags-suggest-runner.ts +429 -0
  7. package/bin/tags-suggest.mjs +30 -0
  8. package/bin/zudo-doc.mjs +78 -25
  9. package/dist/breadcrumb/breadcrumb.d.ts +4 -4
  10. package/dist/breadcrumb/find-path.d.ts +2 -2
  11. package/dist/breadcrumb/index.d.ts +1 -1
  12. package/dist/breadcrumb/types.d.ts +0 -5
  13. package/dist/chrome/derive.d.ts +16 -10
  14. package/dist/chrome/derive.js +53 -4
  15. package/dist/chrome/index.d.ts +13 -10
  16. package/dist/chrome/index.js +12 -6
  17. package/dist/chrome/primary-slots.d.ts +21 -0
  18. package/dist/chrome/primary-slots.js +59 -0
  19. package/dist/chrome-bindings.d.ts +68 -0
  20. package/dist/code-syntax/code-block-enhancer-script.d.ts +4 -0
  21. package/dist/code-syntax/code-block-enhancer-script.js +7 -4
  22. package/dist/code-syntax/code-block-enhancer.d.ts +2 -2
  23. package/dist/code-syntax/code-block-enhancer.js +1 -3
  24. package/dist/code-syntax/index.d.ts +5 -5
  25. package/dist/code-syntax/index.js +4 -13
  26. package/dist/code-syntax/mermaid-init-script.d.ts +1 -22
  27. package/dist/code-syntax/mermaid-init-script.js +0 -2
  28. package/dist/code-syntax/mermaid-init.d.ts +0 -1
  29. package/dist/code-syntax/mermaid-init.js +3 -4
  30. package/dist/code-syntax/tabs-init.d.ts +0 -1
  31. package/dist/code-syntax/tabs-init.js +1 -3
  32. package/dist/code-syntax/tabs.d.ts +0 -1
  33. package/dist/code-syntax/tabs.js +1 -3
  34. package/dist/color-scheme-utils.d.ts +71 -3
  35. package/dist/color-scheme-utils.js +137 -0
  36. package/dist/color-schemes-defaults/index.js +13 -0
  37. package/dist/config.d.ts +28 -12
  38. package/dist/config.js +11 -2
  39. package/dist/content/component-map.d.ts +0 -16
  40. package/dist/content/component-map.js +2 -4
  41. package/dist/content/index.d.ts +1 -1
  42. package/dist/content/index.js +2 -3
  43. package/dist/content.css +1 -1
  44. package/dist/design-token-panel-bootstrap.d.ts +45 -40
  45. package/dist/design-token-panel-bootstrap.js +98 -21
  46. package/dist/design-token-panel-config/index.js +1 -4
  47. package/dist/doc-body-end-islands/design-token-panel-island.d.ts +15 -0
  48. package/dist/doc-body-end-islands/design-token-panel-island.js +31 -0
  49. package/dist/doc-body-end-islands/index.d.ts +39 -17
  50. package/dist/doc-body-end-islands/index.js +13 -21
  51. package/dist/doc-body-end-islands/theme-pack-switcher-island.d.ts +37 -0
  52. package/dist/doc-body-end-islands/theme-pack-switcher-island.js +18 -0
  53. package/dist/doc-content-header/index.js +1 -1
  54. package/dist/doc-history-area/index.d.ts +10 -4
  55. package/dist/doc-history-area/index.js +3 -2
  56. package/dist/doc-metainfo-area/index.d.ts +1 -0
  57. package/dist/doc-page-props/index.d.ts +7 -23
  58. package/dist/doc-page-renderer/index.d.ts +1 -0
  59. package/dist/doc-page-renderer/index.js +1 -0
  60. package/dist/doc-page-shell/index.js +19 -12
  61. package/dist/doc-pager/index.js +1 -1
  62. package/dist/doc-route-entries/index.d.ts +2 -2
  63. package/dist/doclayout/doc-layout-with-defaults.js +4 -4
  64. package/dist/doclayout/doc-layout.d.ts +8 -0
  65. package/dist/doclayout/doc-layout.js +10 -1
  66. package/dist/docs-schema/index.js +1 -5
  67. package/dist/eject/index.d.ts +16 -0
  68. package/dist/eject/index.js +122 -28
  69. package/dist/extract-headings/index.d.ts +5 -8
  70. package/dist/extract-headings/index.js +2 -9
  71. package/dist/factory-context/index.d.ts +42 -4
  72. package/dist/features.css +55 -43
  73. package/dist/footer/footer.js +1 -0
  74. package/dist/head-with-defaults/index.d.ts +2 -0
  75. package/dist/head-with-defaults/index.js +16 -0
  76. package/dist/header/header.d.ts +10 -5
  77. package/dist/header/header.js +45 -5
  78. package/dist/header/index.d.ts +1 -1
  79. package/dist/header/types.d.ts +30 -1
  80. package/dist/header-with-defaults/index.js +1 -0
  81. package/dist/home-page/index.d.ts +2 -0
  82. package/dist/home-page/index.js +11 -5
  83. package/dist/home-page/prepare-home-data.js +1 -1
  84. package/dist/locale-merge/index.d.ts +9 -14
  85. package/dist/locale-merge/index.js +6 -4
  86. package/dist/mdx-components/index.js +4 -4
  87. package/dist/plugins/claude-resources.d.ts +1 -0
  88. package/dist/plugins/claude-resources.js +4 -2
  89. package/dist/plugins/doc-history.js +1 -1
  90. package/dist/{integrations → plugins/internal}/claude-resources/index.d.ts +1 -16
  91. package/dist/{integrations → plugins/internal}/claude-resources/index.js +0 -9
  92. package/dist/{integrations → plugins/internal}/doc-history/index.d.ts +0 -17
  93. package/dist/{integrations → plugins/internal}/doc-history/index.js +0 -4
  94. package/dist/{integrations → plugins/internal}/doc-history/pre-build.d.ts +2 -4
  95. package/dist/plugins/internal/llms-txt/index.d.ts +7 -0
  96. package/dist/{integrations → plugins/internal}/llms-txt/load.d.ts +1 -1
  97. package/dist/{integrations → plugins/internal}/llms-txt/load.js +2 -2
  98. package/dist/{integrations → plugins/internal}/llms-txt/strip.d.ts +2 -3
  99. package/dist/{integrations → plugins/internal}/llms-txt/strip.js +1 -1
  100. package/dist/{integrations → plugins/internal}/llms-txt/types.d.ts +13 -22
  101. package/dist/{integrations → plugins/internal}/search-index/collect.js +1 -1
  102. package/dist/plugins/internal/theme-packs/copy.d.ts +32 -0
  103. package/dist/plugins/internal/theme-packs/copy.js +45 -0
  104. package/dist/plugins/internal/theme-packs/dev-middleware.d.ts +22 -0
  105. package/dist/plugins/internal/theme-packs/dev-middleware.js +80 -0
  106. package/dist/plugins/internal/theme-packs/index.d.ts +6 -0
  107. package/dist/plugins/internal/theme-packs/index.js +9 -0
  108. package/dist/plugins/internal/theme-packs/resolve.d.ts +17 -0
  109. package/dist/plugins/internal/theme-packs/resolve.js +17 -0
  110. package/dist/plugins/internal/theme-packs/types.d.ts +22 -0
  111. package/dist/plugins/internal/theme-packs/types.js +0 -0
  112. package/dist/plugins/llms-txt.js +1 -1
  113. package/dist/plugins/routes.js +11 -1
  114. package/dist/plugins/search-index.js +1 -1
  115. package/dist/plugins/theme-packs.d.ts +3 -0
  116. package/dist/plugins/theme-packs.js +40 -0
  117. package/dist/preset.d.ts +19 -14
  118. package/dist/preset.js +24 -9
  119. package/dist/route-context/index.js +4 -6
  120. package/dist/route-enumerators/index.d.ts +6 -18
  121. package/dist/route-enumerators/index.js +8 -6
  122. package/dist/routes/404.js +3 -1
  123. package/dist/routes/_chrome.js +2 -2
  124. package/dist/routes/_context.d.ts +7 -3
  125. package/dist/routes/_context.js +2 -0
  126. package/dist/routes/_docs-helpers.js +9 -21
  127. package/dist/safelist.css +1 -1
  128. package/dist/settings.d.ts +27 -12
  129. package/dist/sidebar-tree/build-tree.d.ts +3 -4
  130. package/dist/sidebar-tree/build-tree.js +4 -3
  131. package/dist/sidebar-tree/index.d.ts +2 -2
  132. package/dist/sidebar-tree/types.d.ts +6 -17
  133. package/dist/site-tree-nav-island/index.d.ts +3 -1
  134. package/dist/site-tree-nav-island/index.js +17 -5
  135. package/dist/site-tree-nav-island/state.d.ts +4 -0
  136. package/dist/site-tree-nav-island/state.js +10 -0
  137. package/dist/tag-helpers/index.d.ts +6 -13
  138. package/dist/tag-helpers/index.js +5 -23
  139. package/dist/tag-pages/index.d.ts +8 -21
  140. package/dist/tag-pages/index.js +14 -10
  141. package/dist/tags-audit.d.ts +16 -44
  142. package/dist/tags-audit.js +9 -172
  143. package/dist/theme/color-scheme-provider.d.ts +2 -3
  144. package/dist/theme/color-scheme-provider.js +2 -10
  145. package/dist/theme/index.d.ts +1 -4
  146. package/dist/theme/index.js +2 -30
  147. package/dist/theme/theme-pack-provider.d.ts +42 -0
  148. package/dist/theme/theme-pack-provider.js +75 -0
  149. package/dist/theme-cli/apply.d.ts +16 -0
  150. package/dist/theme-cli/apply.js +61 -0
  151. package/dist/theme-cli/config-io.d.ts +15 -0
  152. package/dist/theme-cli/config-io.js +51 -0
  153. package/dist/theme-cli/config-rewriter.d.ts +21 -0
  154. package/dist/theme-cli/config-rewriter.js +141 -0
  155. package/dist/theme-cli/config-scanner.d.ts +63 -0
  156. package/dist/theme-cli/config-scanner.js +288 -0
  157. package/dist/theme-cli/index.d.ts +7 -0
  158. package/dist/theme-cli/index.js +38 -0
  159. package/dist/theme-cli/list.d.ts +27 -0
  160. package/dist/theme-cli/list.js +64 -0
  161. package/dist/theme-cli/provenance.d.ts +17 -0
  162. package/dist/theme-cli/provenance.js +35 -0
  163. package/dist/theme-cli/registry.d.ts +14 -0
  164. package/dist/theme-cli/registry.js +13 -0
  165. package/dist/theme-pack-dialog/dialog-state.d.ts +25 -0
  166. package/dist/theme-pack-dialog/dialog-state.js +40 -0
  167. package/dist/theme-pack-dialog/index.d.ts +5 -0
  168. package/dist/theme-pack-dialog/index.js +152 -0
  169. package/dist/theme-pack-dialog/theme-pack-card.d.ts +25 -0
  170. package/dist/theme-pack-dialog/theme-pack-card.js +72 -0
  171. package/dist/theme-pack-switcher/index.d.ts +49 -0
  172. package/dist/theme-pack-switcher/index.js +205 -0
  173. package/dist/theme-pack-switcher/switcher-state.d.ts +56 -0
  174. package/dist/theme-pack-switcher/switcher-state.js +43 -0
  175. package/dist/theme-pack-switcher/theme-pack-sync.d.ts +85 -0
  176. package/dist/theme-pack-switcher/theme-pack-sync.js +121 -0
  177. package/dist/theme-packs/beacon/fonts/AtkinsonHyperlegible-400-latin.woff2 +0 -0
  178. package/dist/theme-packs/beacon/fonts/AtkinsonHyperlegible-700-latin.woff2 +0 -0
  179. package/dist/theme-packs/beacon/fonts/AtkinsonHyperlegible-italic-400-latin.woff2 +0 -0
  180. package/dist/theme-packs/beacon/fonts/AtkinsonHyperlegible-italic-700-latin.woff2 +0 -0
  181. package/dist/theme-packs/beacon/fonts/AtkinsonHyperlegibleMono-italic-latin.woff2 +0 -0
  182. package/dist/theme-packs/beacon/fonts/AtkinsonHyperlegibleMono-latin.woff2 +0 -0
  183. package/dist/theme-packs/beacon/fonts/OFL.txt +94 -0
  184. package/dist/theme-packs/beacon/meta.json +37 -0
  185. package/dist/theme-packs/beacon/pack.css +442 -0
  186. package/dist/theme-packs/broadsheet/fonts/CourierPrime-400-latin.woff2 +0 -0
  187. package/dist/theme-packs/broadsheet/fonts/CourierPrime-700-latin.woff2 +0 -0
  188. package/dist/theme-packs/broadsheet/fonts/OFL.txt +95 -0
  189. package/dist/theme-packs/broadsheet/fonts/PlayfairDisplay-italic-latin.woff2 +0 -0
  190. package/dist/theme-packs/broadsheet/fonts/PlayfairDisplay-latin.woff2 +0 -0
  191. package/dist/theme-packs/broadsheet/fonts/SourceSerif4-italic-latin.woff2 +0 -0
  192. package/dist/theme-packs/broadsheet/fonts/SourceSerif4-latin.woff2 +0 -0
  193. package/dist/theme-packs/broadsheet/meta.json +38 -0
  194. package/dist/theme-packs/broadsheet/pack.css +448 -0
  195. package/dist/theme-packs/brutalist/fonts/ArchivoBlack-latin.woff2 +0 -0
  196. package/dist/theme-packs/brutalist/fonts/IBMPlexMono-400-latin.woff2 +0 -0
  197. package/dist/theme-packs/brutalist/fonts/IBMPlexMono-500-latin.woff2 +0 -0
  198. package/dist/theme-packs/brutalist/fonts/IBMPlexMono-700-latin.woff2 +0 -0
  199. package/dist/theme-packs/brutalist/fonts/OFL.txt +95 -0
  200. package/dist/theme-packs/brutalist/fonts/SpaceGrotesk-latin.woff2 +0 -0
  201. package/dist/theme-packs/brutalist/meta.json +38 -0
  202. package/dist/theme-packs/brutalist/pack.css +546 -0
  203. package/dist/theme-packs/default/meta.json +37 -0
  204. package/dist/theme-packs/drift/fonts/IBMPlexMono-400-latin-ext.woff2 +0 -0
  205. package/dist/theme-packs/drift/fonts/IBMPlexMono-400-latin.woff2 +0 -0
  206. package/dist/theme-packs/drift/fonts/IBMPlexMono-500-latin-ext.woff2 +0 -0
  207. package/dist/theme-packs/drift/fonts/IBMPlexMono-500-latin.woff2 +0 -0
  208. package/dist/theme-packs/drift/fonts/IBMPlexSans-italic-latin.woff2 +0 -0
  209. package/dist/theme-packs/drift/fonts/IBMPlexSans-latin-ext.woff2 +0 -0
  210. package/dist/theme-packs/drift/fonts/IBMPlexSans-latin.woff2 +0 -0
  211. package/dist/theme-packs/drift/fonts/OFL.txt +93 -0
  212. package/dist/theme-packs/drift/meta.json +37 -0
  213. package/dist/theme-packs/drift/pack.css +478 -0
  214. package/dist/theme-packs/fjord/fonts/Inter-latin-ext.woff2 +0 -0
  215. package/dist/theme-packs/fjord/fonts/Inter-latin.woff2 +0 -0
  216. package/dist/theme-packs/fjord/fonts/JetBrainsMono-latin-ext.woff2 +0 -0
  217. package/dist/theme-packs/fjord/fonts/JetBrainsMono-latin.woff2 +0 -0
  218. package/dist/theme-packs/fjord/fonts/OFL.txt +94 -0
  219. package/dist/theme-packs/fjord/meta.json +37 -0
  220. package/dist/theme-packs/fjord/pack.css +375 -0
  221. package/dist/theme-packs/foundry/fonts/Inter-latin-ext.woff2 +0 -0
  222. package/dist/theme-packs/foundry/fonts/Inter-latin.woff2 +0 -0
  223. package/dist/theme-packs/foundry/fonts/OFL.txt +93 -0
  224. package/dist/theme-packs/foundry/meta.json +37 -0
  225. package/dist/theme-packs/foundry/pack.css +202 -0
  226. package/dist/theme-packs/futura-editorial/fonts/Jost-latin.woff2 +0 -0
  227. package/dist/theme-packs/futura-editorial/fonts/NotoSans-italic-latin.woff2 +0 -0
  228. package/dist/theme-packs/futura-editorial/fonts/NotoSans-latin.woff2 +0 -0
  229. package/dist/theme-packs/futura-editorial/fonts/OFL.txt +95 -0
  230. package/dist/theme-packs/futura-editorial/fonts/SpaceMono-400-latin.woff2 +0 -0
  231. package/dist/theme-packs/futura-editorial/fonts/SpaceMono-700-latin.woff2 +0 -0
  232. package/dist/theme-packs/futura-editorial/meta.json +38 -0
  233. package/dist/theme-packs/futura-editorial/pack.css +313 -0
  234. package/dist/theme-packs/hearth/fonts/Fraunces-italic-latin.woff2 +0 -0
  235. package/dist/theme-packs/hearth/fonts/Fraunces-latin.woff2 +0 -0
  236. package/dist/theme-packs/hearth/fonts/Nunito-latin.woff2 +0 -0
  237. package/dist/theme-packs/hearth/fonts/OFL.txt +95 -0
  238. package/dist/theme-packs/hearth/fonts/SplineSansMono-latin.woff2 +0 -0
  239. package/dist/theme-packs/hearth/meta.json +38 -0
  240. package/dist/theme-packs/hearth/pack.css +385 -0
  241. package/dist/theme-packs/hollow/fonts/OFL.txt +94 -0
  242. package/dist/theme-packs/hollow/fonts/SpaceGrotesk-latin.woff2 +0 -0
  243. package/dist/theme-packs/hollow/fonts/SpaceMono-400-italic-latin.woff2 +0 -0
  244. package/dist/theme-packs/hollow/fonts/SpaceMono-400-latin.woff2 +0 -0
  245. package/dist/theme-packs/hollow/fonts/SpaceMono-700-latin.woff2 +0 -0
  246. package/dist/theme-packs/hollow/meta.json +37 -0
  247. package/dist/theme-packs/hollow/pack.css +428 -0
  248. package/dist/theme-packs/ledger/fonts/CrimsonPro-latin-ext-italic.woff2 +0 -0
  249. package/dist/theme-packs/ledger/fonts/CrimsonPro-latin-ext.woff2 +0 -0
  250. package/dist/theme-packs/ledger/fonts/CrimsonPro-latin-italic.woff2 +0 -0
  251. package/dist/theme-packs/ledger/fonts/CrimsonPro-latin.woff2 +0 -0
  252. package/dist/theme-packs/ledger/fonts/IBMPlexMono-400-latin-ext.woff2 +0 -0
  253. package/dist/theme-packs/ledger/fonts/IBMPlexMono-400-latin.woff2 +0 -0
  254. package/dist/theme-packs/ledger/fonts/IBMPlexMono-500-latin-ext.woff2 +0 -0
  255. package/dist/theme-packs/ledger/fonts/IBMPlexMono-500-latin.woff2 +0 -0
  256. package/dist/theme-packs/ledger/fonts/OFL.txt +94 -0
  257. package/dist/theme-packs/ledger/meta.json +37 -0
  258. package/dist/theme-packs/ledger/pack.css +463 -0
  259. package/dist/theme-packs/manuscript/fonts/CourierPrime-400-latin-ext.woff2 +0 -0
  260. package/dist/theme-packs/manuscript/fonts/CourierPrime-400-latin.woff2 +0 -0
  261. package/dist/theme-packs/manuscript/fonts/CourierPrime-700-latin-ext.woff2 +0 -0
  262. package/dist/theme-packs/manuscript/fonts/CourierPrime-700-latin.woff2 +0 -0
  263. package/dist/theme-packs/manuscript/fonts/EBGaramond-latin-italic.woff2 +0 -0
  264. package/dist/theme-packs/manuscript/fonts/EBGaramond-latin.woff2 +0 -0
  265. package/dist/theme-packs/manuscript/fonts/OFL.txt +94 -0
  266. package/dist/theme-packs/manuscript/meta.json +37 -0
  267. package/dist/theme-packs/manuscript/pack.css +376 -0
  268. package/dist/theme-packs/matcha/fonts/MPLUS1Code-latin.woff2 +0 -0
  269. package/dist/theme-packs/matcha/fonts/OFL.txt +95 -0
  270. package/dist/theme-packs/matcha/fonts/ShipporiMincho-500-latin.woff2 +0 -0
  271. package/dist/theme-packs/matcha/fonts/ShipporiMincho-700-latin.woff2 +0 -0
  272. package/dist/theme-packs/matcha/fonts/ZenKakuGothicNew-400-latin.woff2 +0 -0
  273. package/dist/theme-packs/matcha/fonts/ZenKakuGothicNew-500-latin.woff2 +0 -0
  274. package/dist/theme-packs/matcha/meta.json +38 -0
  275. package/dist/theme-packs/matcha/pack.css +409 -0
  276. package/dist/theme-packs/nocturne/fonts/CormorantGaramond-italic-latin.woff2 +0 -0
  277. package/dist/theme-packs/nocturne/fonts/CormorantGaramond-latin.woff2 +0 -0
  278. package/dist/theme-packs/nocturne/fonts/IBMPlexMono-400-latin.woff2 +0 -0
  279. package/dist/theme-packs/nocturne/fonts/IBMPlexMono-500-latin.woff2 +0 -0
  280. package/dist/theme-packs/nocturne/fonts/IBMPlexMono-italic-latin.woff2 +0 -0
  281. package/dist/theme-packs/nocturne/fonts/Manrope-latin.woff2 +0 -0
  282. package/dist/theme-packs/nocturne/fonts/OFL.txt +95 -0
  283. package/dist/theme-packs/nocturne/meta.json +38 -0
  284. package/dist/theme-packs/nocturne/pack.css +502 -0
  285. package/dist/theme-packs/observatory/fonts/JosefinSans-latin.woff2 +0 -0
  286. package/dist/theme-packs/observatory/fonts/Jost-italic-latin.woff2 +0 -0
  287. package/dist/theme-packs/observatory/fonts/Jost-latin.woff2 +0 -0
  288. package/dist/theme-packs/observatory/fonts/OFL.txt +95 -0
  289. package/dist/theme-packs/observatory/fonts/SpaceMono-400-latin.woff2 +0 -0
  290. package/dist/theme-packs/observatory/fonts/SpaceMono-700-latin.woff2 +0 -0
  291. package/dist/theme-packs/observatory/fonts/SpaceMono-italic-latin.woff2 +0 -0
  292. package/dist/theme-packs/observatory/meta.json +38 -0
  293. package/dist/theme-packs/observatory/pack.css +728 -0
  294. package/dist/theme-packs/onyx/fonts/CormorantGaramond-italic-latin.woff2 +0 -0
  295. package/dist/theme-packs/onyx/fonts/CormorantGaramond-latin.woff2 +0 -0
  296. package/dist/theme-packs/onyx/fonts/IBMPlexMono-400-latin-ext.woff2 +0 -0
  297. package/dist/theme-packs/onyx/fonts/IBMPlexMono-400-latin.woff2 +0 -0
  298. package/dist/theme-packs/onyx/fonts/IBMPlexMono-500-latin-ext.woff2 +0 -0
  299. package/dist/theme-packs/onyx/fonts/IBMPlexMono-500-latin.woff2 +0 -0
  300. package/dist/theme-packs/onyx/fonts/Jost-latin.woff2 +0 -0
  301. package/dist/theme-packs/onyx/fonts/OFL.txt +95 -0
  302. package/dist/theme-packs/onyx/meta.json +38 -0
  303. package/dist/theme-packs/onyx/pack.css +497 -0
  304. package/dist/theme-packs/phosphor/fonts/JetBrainsMono-latin-ext.woff2 +0 -0
  305. package/dist/theme-packs/phosphor/fonts/JetBrainsMono-latin.woff2 +0 -0
  306. package/dist/theme-packs/phosphor/fonts/OFL.txt +94 -0
  307. package/dist/theme-packs/phosphor/fonts/VT323-latin-ext.woff2 +0 -0
  308. package/dist/theme-packs/phosphor/fonts/VT323-latin.woff2 +0 -0
  309. package/dist/theme-packs/phosphor/meta.json +38 -0
  310. package/dist/theme-packs/phosphor/pack.css +493 -0
  311. package/dist/theme-packs/solar/fonts/OFL.txt +94 -0
  312. package/dist/theme-packs/solar/fonts/SourceCodePro-italic-latin.woff2 +0 -0
  313. package/dist/theme-packs/solar/fonts/SourceCodePro-latin.woff2 +0 -0
  314. package/dist/theme-packs/solar/fonts/SourceSans3-italic-latin.woff2 +0 -0
  315. package/dist/theme-packs/solar/fonts/SourceSans3-latin.woff2 +0 -0
  316. package/dist/theme-packs/solar/meta.json +37 -0
  317. package/dist/theme-packs/solar/pack.css +380 -0
  318. package/dist/theme-packs/sumi/fonts/IBMPlexMono-400-latin-ext.woff2 +0 -0
  319. package/dist/theme-packs/sumi/fonts/IBMPlexMono-400-latin.woff2 +0 -0
  320. package/dist/theme-packs/sumi/fonts/IBMPlexMono-500-latin-ext.woff2 +0 -0
  321. package/dist/theme-packs/sumi/fonts/IBMPlexMono-500-latin.woff2 +0 -0
  322. package/dist/theme-packs/sumi/fonts/OFL.txt +95 -0
  323. package/dist/theme-packs/sumi/fonts/ShipporiMinchoB1-600-latin.woff2 +0 -0
  324. package/dist/theme-packs/sumi/fonts/ShipporiMinchoB1-700-latin.woff2 +0 -0
  325. package/dist/theme-packs/sumi/fonts/ShipporiMinchoB1-800-latin.woff2 +0 -0
  326. package/dist/theme-packs/sumi/fonts/ZenKakuGothicNew-400-latin.woff2 +0 -0
  327. package/dist/theme-packs/sumi/fonts/ZenKakuGothicNew-500-latin.woff2 +0 -0
  328. package/dist/theme-packs/sumi/meta.json +38 -0
  329. package/dist/theme-packs/sumi/pack.css +502 -0
  330. package/dist/theme-packs/swissgrid/fonts/IBMPlexMono-400-latin-ext.woff2 +0 -0
  331. package/dist/theme-packs/swissgrid/fonts/IBMPlexMono-400-latin.woff2 +0 -0
  332. package/dist/theme-packs/swissgrid/fonts/IBMPlexMono-600-latin.woff2 +0 -0
  333. package/dist/theme-packs/swissgrid/fonts/Inter-latin-ext.woff2 +0 -0
  334. package/dist/theme-packs/swissgrid/fonts/Inter-latin.woff2 +0 -0
  335. package/dist/theme-packs/swissgrid/fonts/InterTight-latin.woff2 +0 -0
  336. package/dist/theme-packs/swissgrid/fonts/OFL.txt +95 -0
  337. package/dist/theme-packs/swissgrid/meta.json +38 -0
  338. package/dist/theme-packs/swissgrid/pack.css +518 -0
  339. package/dist/theme-packs/washi/fonts/MPlus1Code-400-latin.woff2 +0 -0
  340. package/dist/theme-packs/washi/fonts/MPlus1Code-500-latin.woff2 +0 -0
  341. package/dist/theme-packs/washi/fonts/OFL.txt +95 -0
  342. package/dist/theme-packs/washi/fonts/ShipporiMincho-500-latin.woff2 +0 -0
  343. package/dist/theme-packs/washi/fonts/ShipporiMincho-600-latin.woff2 +0 -0
  344. package/dist/theme-packs/washi/fonts/ShipporiMincho-700-latin.woff2 +0 -0
  345. package/dist/theme-packs/washi/fonts/ZenKakuGothicNew-400-latin.woff2 +0 -0
  346. package/dist/theme-packs/washi/fonts/ZenKakuGothicNew-500-latin.woff2 +0 -0
  347. package/dist/theme-packs/washi/fonts/ZenKakuGothicNew-700-latin.woff2 +0 -0
  348. package/dist/theme-packs/washi/meta.json +38 -0
  349. package/dist/theme-packs/washi/pack.css +479 -0
  350. package/dist/theme-packs-registry/index.d.ts +5 -0
  351. package/dist/theme-packs-registry/index.js +30 -0
  352. package/dist/theme-packs-registry/load-registry.d.ts +23 -0
  353. package/dist/theme-packs-registry/load-registry.js +64 -0
  354. package/dist/theme-packs-registry/meta-schema.d.ts +70 -0
  355. package/dist/theme-packs-registry/meta-schema.js +38 -0
  356. package/dist/theme-packs-registry/resolve-enabled-packs.d.ts +25 -0
  357. package/dist/theme-packs-registry/resolve-enabled-packs.js +43 -0
  358. package/dist/theme-packs-registry/token-manifest.d.ts +19 -0
  359. package/dist/theme-packs-registry/token-manifest.js +57 -0
  360. package/dist/theme-packs-registry/validator.d.ts +35 -0
  361. package/dist/theme-packs-registry/validator.js +284 -0
  362. package/dist/theme-toggle/color-scheme-sync.d.ts +2 -4
  363. package/dist/versions-page/index.d.ts +2 -2
  364. package/dist/versions-page/index.js +8 -8
  365. package/eject/breadcrumb/breadcrumb.tsx +4 -4
  366. package/eject/breadcrumb/find-path.ts +2 -2
  367. package/eject/breadcrumb/index.ts +1 -1
  368. package/eject/breadcrumb/types.ts +0 -6
  369. package/eject/code-group/index.tsx +2 -2
  370. package/eject/doc-history/index.tsx +1 -1
  371. package/eject/doc-pager/index.tsx +1 -1
  372. package/eject/footer/footer.tsx +1 -0
  373. package/eject/header/header.tsx +86 -21
  374. package/eject/header/index.ts +3 -0
  375. package/eject/header/types.ts +39 -1
  376. package/eject/site-tree-nav-island/index.tsx +15 -3
  377. package/eject/site-tree-nav-island/state.ts +9 -0
  378. package/eject/theme-toggle/color-scheme-sync.ts +2 -4
  379. package/package.json +35 -29
  380. package/routes-src/404.tsx +4 -1
  381. package/routes-src/_chrome.tsx +6 -5
  382. package/routes-src/_context.ts +4 -0
  383. package/routes-src/_docs-helpers.ts +9 -29
  384. package/routes-src/_virtual.d.ts +4 -0
  385. package/virtual-modules.d.ts +4 -0
  386. package/zfb-config-shim.d.ts +40 -18
  387. package/dist/integrations/llms-txt/index.d.ts +0 -33
  388. package/dist/theme/color-tweak-export-modal.d.ts +0 -16
  389. package/dist/theme/color-tweak-export-modal.js +0 -138
  390. package/dist/theme/design-token-serde.d.ts +0 -183
  391. package/dist/theme/design-token-serde.js +0 -346
  392. package/dist/theme/design-token-types.d.ts +0 -13
  393. package/dist/theme/design-token-types.js +0 -6
  394. package/dist/theme/iframe-bridge.d.ts +0 -42
  395. package/dist/theme/iframe-bridge.js +0 -72
  396. /package/dist/{integrations → plugins/internal}/claude-resources/escape-for-mdx.d.ts +0 -0
  397. /package/dist/{integrations → plugins/internal}/claude-resources/escape-for-mdx.js +0 -0
  398. /package/dist/{integrations → plugins/internal}/claude-resources/generate.d.ts +0 -0
  399. /package/dist/{integrations → plugins/internal}/claude-resources/generate.js +0 -0
  400. /package/dist/{integrations → plugins/internal}/doc-history/pre-build.js +0 -0
  401. /package/dist/{integrations → plugins/internal}/llms-txt/dev-middleware.d.ts +0 -0
  402. /package/dist/{integrations → plugins/internal}/llms-txt/dev-middleware.js +0 -0
  403. /package/dist/{integrations → plugins/internal}/llms-txt/emit.d.ts +0 -0
  404. /package/dist/{integrations → plugins/internal}/llms-txt/emit.js +0 -0
  405. /package/dist/{integrations → plugins/internal}/llms-txt/generate.d.ts +0 -0
  406. /package/dist/{integrations → plugins/internal}/llms-txt/generate.js +0 -0
  407. /package/dist/{integrations → plugins/internal}/llms-txt/index.js +0 -0
  408. /package/dist/{integrations → plugins/internal}/llms-txt/types.js +0 -0
  409. /package/dist/{integrations → plugins/internal}/search-index/build-emitter.d.ts +0 -0
  410. /package/dist/{integrations → plugins/internal}/search-index/build-emitter.js +0 -0
  411. /package/dist/{integrations → plugins/internal}/search-index/collect.d.ts +0 -0
  412. /package/dist/{integrations → plugins/internal}/search-index/dev-middleware.d.ts +0 -0
  413. /package/dist/{integrations → plugins/internal}/search-index/dev-middleware.js +0 -0
  414. /package/dist/{integrations → plugins/internal}/search-index/index.d.ts +0 -0
  415. /package/dist/{integrations → plugins/internal}/search-index/index.js +0 -0
  416. /package/dist/{integrations → plugins/internal}/search-index/types.d.ts +0 -0
  417. /package/dist/{integrations → plugins/internal}/search-index/types.js +0 -0
@@ -87,6 +87,7 @@ export function Footer(props: FooterProps): VNode {
87
87
  return (
88
88
  <footer
89
89
  class="border-t border-muted bg-surface"
90
+ data-footer
90
91
  // Strategy B: locale-keyed persist (zudolab/zudo-doc#1546).
91
92
  // The footer's locale-aware bits (link labels, copyright) are SSR'd
92
93
  // per locale; a locale-keyed persist key (`footer-en`, `footer-ja`)
@@ -49,6 +49,8 @@ import { LANGUAGE_SWITCHER_INIT_SCRIPT } from "../i18n-version/language-switcher
49
49
  import { VERSION_SWITCHER_REWIRE_SCRIPT } from "../i18n-version/version-switcher.js";
50
50
  import type {
51
51
  HeaderNavItem,
52
+ HeaderRightComponentProps,
53
+ HeaderRightComponentRegistry,
52
54
  HeaderRightItem,
53
55
  Locale,
54
56
  } from "./types.js";
@@ -137,10 +139,9 @@ export interface HeaderProps {
137
139
  search?: ComponentChildren;
138
140
 
139
141
  /**
140
- * When provided, emits `data-zfb-transition-persist={persistKey}` on the
142
+ * Emits `data-zfb-transition-persist={persistKey}` on the
141
143
  * `<header>` element so zfb's client-router preserves DOM-node identity
142
- * across same-locale View Transition swaps. Omit to disable persist
143
- * (back-compat default — the header is re-rendered on every swap).
144
+ * across same-locale View Transition swaps.
144
145
  *
145
146
  * **Locale keying**: callers MUST key by locale (e.g. `"header-en"`,
146
147
  * `"header-ja"`). Cross-locale swaps must NOT share the same key; a
@@ -156,7 +157,7 @@ export interface HeaderProps {
156
157
  * for consistency, matching the Astro reference implementation
157
158
  * (zudolab/zudo-doc#1546).
158
159
  */
159
- persistKey?: string;
160
+ persistKey: string;
160
161
 
161
162
  /** Site-name string shown in the logo anchor (host `settings.siteName`). */
162
163
  siteName: string;
@@ -175,6 +176,13 @@ export interface HeaderProps {
175
176
  */
176
177
  headerRightItems: HeaderRightItem[];
177
178
 
179
+ /**
180
+ * Host-callable renderers for project-owned component names. The registry is
181
+ * carried through `chromeBindingsModule`; it is never part of the serialized
182
+ * settings payload. Package built-in names are reserved.
183
+ */
184
+ headerRightComponents?: HeaderRightComponentRegistry;
185
+
178
186
  /**
179
187
  * Whether the host has a `colorMode` config. Required because the
180
188
  * `theme-toggle` right-item is two-gated: the filter drops it when
@@ -253,6 +261,7 @@ export function Header(props: HeaderProps): JSX.Element {
253
261
  siteName,
254
262
  headerNav,
255
263
  headerRightItems,
264
+ headerRightComponents,
256
265
  colorModeEnabled,
257
266
  hasLocales,
258
267
  hasVersions,
@@ -267,14 +276,15 @@ export function Header(props: HeaderProps): JSX.Element {
267
276
  const matchPath = pathForMatch(pathWithoutBase, lang, i18n.defaultLocale);
268
277
 
269
278
  const activeNavPath = computeActiveNavPath(headerNav, matchPath);
279
+ const rightItemDispatch = createRightItemDispatch(headerRightComponents);
270
280
 
271
281
  return (
272
282
  <header
273
283
  class="sticky top-0 z-toolbar flex h-[3.5rem] items-center border-b border-muted bg-surface px-hsp-lg"
274
284
  data-header
275
285
  // Strategy B persist (zudolab/zudo-doc#1546): the header now carries
276
- // data-zfb-transition-persist when a locale-keyed persistKey is
277
- // supplied (e.g. "header-en" / "header-ja"). Cross-locale swaps use
286
+ // data-zfb-transition-persist with a locale-keyed persistKey
287
+ // (e.g. "header-en" / "header-ja"). Cross-locale swaps use
278
288
  // different keys, so the router replaces the header element entirely,
279
289
  // re-rendering the locale toggle anchors and all locale-specific SSR
280
290
  // content with fresh markup. Same-locale swaps share the key and
@@ -303,7 +313,6 @@ export function Header(props: HeaderProps): JSX.Element {
303
313
  // LANGUAGE_SWITCHER_INIT_SCRIPT recomputes each anchor's href from
304
314
  // window.location on AFTER_NAVIGATE_EVENT, same as the controls above
305
315
  // (zudolab/zudo-doc#2551).
306
- // Omit persistKey to fall back to the old repaint-on-every-swap path.
307
316
  data-zfb-transition-persist={persistKey}
308
317
  >
309
318
  {sidebarToggle ?? (
@@ -371,6 +380,7 @@ export function Header(props: HeaderProps): JSX.Element {
371
380
  colorModeEnabled,
372
381
  hasLocales,
373
382
  },
383
+ rightItemDispatch,
374
384
  ))}
375
385
  </div>
376
386
 
@@ -513,17 +523,7 @@ function renderNavItem(
513
523
  );
514
524
  }
515
525
 
516
- interface RightItemContext {
517
- lang: Locale | undefined;
518
- githubRepoUrl: string | null;
519
- githubLabel: string;
520
- themeToggle: ComponentChildren;
521
- languageSwitcher: ComponentChildren;
522
- versionSwitcher: ComponentChildren;
523
- search: ComponentChildren;
524
- colorModeEnabled: boolean;
525
- hasLocales: boolean;
526
- }
526
+ type RightItemContext = Omit<HeaderRightComponentProps, "item" | "index">;
527
527
 
528
528
  /**
529
529
  * Shared trigger-button shell for header-right items that dispatch a
@@ -591,7 +591,15 @@ type RightItemHandler = (
591
591
 
592
592
  // Dispatch table keyed by `${type}:${trigger|component}`, or just `type`
593
593
  // for link/html items that carry no sub-type discriminant.
594
- const RIGHT_ITEM_DISPATCH: Record<string, RightItemHandler> = {
594
+ const BUILTIN_COMPONENT_NAMES = [
595
+ "theme-toggle",
596
+ "language-switcher",
597
+ "version-switcher",
598
+ "github-link",
599
+ "search",
600
+ ] as const;
601
+
602
+ const BASE_RIGHT_ITEM_DISPATCH: Readonly<Record<string, RightItemHandler>> = {
595
603
  "trigger:design-token-panel": (_item, index) => (
596
604
  <TriggerButton
597
605
  index={index}
@@ -737,10 +745,55 @@ const RIGHT_ITEM_DISPATCH: Record<string, RightItemHandler> = {
737
745
  },
738
746
  };
739
747
 
748
+ /**
749
+ * Compose the immutable package dispatch table with host-callable component
750
+ * entries. Built-ins are reserved: a host collision is almost certainly a
751
+ * typo or an attempted override, so reject it rather than silently changing
752
+ * package markup. Runtime callable checks keep JavaScript/untyped consumers on
753
+ * the same contract as TypeScript callers.
754
+ */
755
+ function createRightItemDispatch(
756
+ hostRegistry: HeaderRightComponentRegistry | undefined,
757
+ ): ReadonlyMap<string, RightItemHandler> {
758
+ const dispatch = new Map<string, RightItemHandler>(
759
+ Object.entries(BASE_RIGHT_ITEM_DISPATCH),
760
+ );
761
+ if (hostRegistry === undefined) return dispatch;
762
+
763
+ for (const [name, component] of Object.entries(hostRegistry)) {
764
+ if (BUILTIN_COMPONENT_NAMES.includes(name as typeof BUILTIN_COMPONENT_NAMES[number])) {
765
+ throw new Error(
766
+ `[zudo-doc] Duplicate header-right component name "${name}" at ` +
767
+ `chromeBindings.headerRightComponents[${JSON.stringify(name)}]: built-in names are reserved and ` +
768
+ `cannot be shadowed. Remove this registry entry or choose a project-owned name.`,
769
+ );
770
+ }
771
+ if (typeof component !== "function") {
772
+ throw new TypeError(
773
+ `[zudo-doc] Invalid header-right component "${name}" at ` +
774
+ `chromeBindings.headerRightComponents[${JSON.stringify(name)}]: expected a callable renderer.`,
775
+ );
776
+ }
777
+
778
+ dispatch.set(`component:${name}`, (item, index, ctx) => {
779
+ if (item.type !== "component") return null;
780
+ const CustomComponent = component;
781
+ return (
782
+ <SlotWrapper index={index}>
783
+ <CustomComponent item={item} index={index} {...ctx} />
784
+ </SlotWrapper>
785
+ );
786
+ });
787
+ }
788
+
789
+ return dispatch;
790
+ }
791
+
740
792
  function renderRightItem(
741
793
  item: HeaderRightItem,
742
794
  index: number,
743
795
  ctx: RightItemContext,
796
+ dispatch: ReadonlyMap<string, RightItemHandler>,
744
797
  ): VNode | null {
745
798
  const key =
746
799
  item.type === "trigger"
@@ -748,6 +801,18 @@ function renderRightItem(
748
801
  : item.type === "component"
749
802
  ? `component:${item.component}`
750
803
  : item.type;
751
- const handler = RIGHT_ITEM_DISPATCH[key];
752
- return handler ? handler(item, index, ctx) : null;
804
+ const handler = dispatch.get(key);
805
+ if (handler) return handler(item, index, ctx);
806
+
807
+ if (item.type === "component") {
808
+ throw new Error(
809
+ `[zudo-doc] Unknown header-right component "${item.component}" at ` +
810
+ `Header.headerRightItems[${index}].component. Register a callable renderer as ` +
811
+ `chromeBindings.headerRightComponents["${item.component}"] through ` +
812
+ `settings.chromeBindingsModule, or use a built-in name: ` +
813
+ `${BUILTIN_COMPONENT_NAMES.join(", ")}.`,
814
+ );
815
+ }
816
+
817
+ return null;
753
818
  }
@@ -14,8 +14,11 @@ export type {
14
14
  Locale,
15
15
  HeaderNavChildItem,
16
16
  HeaderNavItem,
17
+ HeaderRightBuiltinComponentName,
17
18
  HeaderRightComponentItem,
18
19
  HeaderRightComponentName,
20
+ HeaderRightComponentProps,
21
+ HeaderRightComponentRegistry,
19
22
  HeaderRightHtmlItem,
20
23
  HeaderRightItem,
21
24
  HeaderRightLinkItem,
@@ -11,6 +11,8 @@
11
11
  // downstream consumers may continue to use the v2 types until the v2
12
12
  // package itself widens them. Changes here are v2 breaking changes.
13
13
 
14
+ import type { ComponentChildren } from "preact";
15
+
14
16
  /**
15
17
  * Locale code as seen by the header. Widened from the host's literal
16
18
  * union (`"en" | "ja" | …`) to plain `string` at the v2 boundary so the
@@ -30,13 +32,22 @@ export interface HeaderNavItem extends HeaderNavChildItem {
30
32
  children?: HeaderNavChildItem[];
31
33
  }
32
34
 
33
- export type HeaderRightComponentName =
35
+ export type HeaderRightBuiltinComponentName =
34
36
  | "theme-toggle"
35
37
  | "language-switcher"
36
38
  | "version-switcher"
37
39
  | "github-link"
38
40
  | "search";
39
41
 
42
+ /**
43
+ * A serializable name resolved against the package built-ins plus the host's
44
+ * `headerRightComponents` chrome-binding registry. The intersection preserves
45
+ * built-in autocomplete while allowing project-owned names.
46
+ */
47
+ export type HeaderRightComponentName =
48
+ | HeaderRightBuiltinComponentName
49
+ | (string & {});
50
+
40
51
  export type HeaderRightTriggerName = "design-token-panel" | "ai-chat";
41
52
 
42
53
  export interface HeaderRightComponentItem {
@@ -44,6 +55,33 @@ export interface HeaderRightComponentItem {
44
55
  component: HeaderRightComponentName;
45
56
  }
46
57
 
58
+ /**
59
+ * Exact props passed to a host `headerRightComponents` renderer. They mirror
60
+ * the existing header-right dispatch context; no callable enters the
61
+ * serialized {@link HeaderRightComponentItem}.
62
+ */
63
+ export interface HeaderRightComponentProps {
64
+ /** The serialized item that selected this renderer. */
65
+ item: HeaderRightComponentItem;
66
+ /** Zero-based position in the rendered `headerRightItems` array. */
67
+ index: number;
68
+ lang: Locale | undefined;
69
+ githubRepoUrl: string | null;
70
+ githubLabel: string;
71
+ themeToggle: ComponentChildren;
72
+ languageSwitcher: ComponentChildren;
73
+ versionSwitcher: ComponentChildren;
74
+ search: ComponentChildren;
75
+ colorModeEnabled: boolean;
76
+ hasLocales: boolean;
77
+ }
78
+
79
+ /** A callable-only host registry keyed by serialized component name. */
80
+ export type HeaderRightComponentRegistry = Record<
81
+ string,
82
+ (props: HeaderRightComponentProps) => ComponentChildren
83
+ >;
84
+
47
85
  export interface HeaderRightTriggerItem {
48
86
  type: "trigger";
49
87
  trigger: HeaderRightTriggerName;
@@ -8,6 +8,7 @@ import { useState } from "preact/hooks";
8
8
  import type { SidebarNavNode } from "../sidebar/types.js";
9
9
  import { INDENT, connectorLeft, ConnectorLines, CategoryLinkIcon } from "../tree-nav-shared/index.js";
10
10
  import { ChevronRight } from "../icons/index.js";
11
+ import { initialCategoryOpenState, toggleCategoryOpenState } from "./state.js";
11
12
 
12
13
  // site-tree-nav uses wider padding than the narrow sidebar
13
14
  const SITE_BASE_PAD = "clamp(0.5rem, 0.8vw, 1rem)";
@@ -39,6 +40,8 @@ export interface SiteTreeNavProps {
39
40
  ariaLabel?: string;
40
41
  categoryOrder?: string[];
41
42
  categoryIgnore?: string[];
43
+ /** Root-category slugs that should start collapsed. */
44
+ initiallyCollapsedCategorySlugs?: string[];
42
45
  }
43
46
 
44
47
  export function SiteTreeNav({
@@ -46,6 +49,7 @@ export function SiteTreeNav({
46
49
  ariaLabel = "Site index",
47
50
  categoryOrder,
48
51
  categoryIgnore,
52
+ initiallyCollapsedCategorySlugs,
49
53
  }: SiteTreeNavProps) {
50
54
  let processedTree = tree;
51
55
  if (categoryIgnore) {
@@ -55,6 +59,7 @@ export function SiteTreeNav({
55
59
  if (categoryOrder) {
56
60
  processedTree = reorderTree(processedTree, categoryOrder);
57
61
  }
62
+ const initiallyCollapsed = new Set(initiallyCollapsedCategorySlugs);
58
63
  return (
59
64
  <nav
60
65
  aria-label={ariaLabel}
@@ -67,7 +72,12 @@ export function SiteTreeNav({
67
72
  {processedTree.map((node) => (
68
73
  <div key={node.slug} className="min-w-0 border border-muted pl-hsp-sm py-vsp-2xs">
69
74
  {node.children.length > 0 ? (
70
- <CategoryNode node={node} depth={0} isLast={true} />
75
+ <CategoryNode
76
+ node={node}
77
+ depth={0}
78
+ isLast={true}
79
+ initiallyCollapsed={initiallyCollapsed.has(node.slug)}
80
+ />
71
81
  ) : (
72
82
  <LeafNode node={node} depth={0} isLast={true} />
73
83
  )}
@@ -107,13 +117,15 @@ function CategoryNode({
107
117
  node,
108
118
  depth,
109
119
  isLast,
120
+ initiallyCollapsed = false,
110
121
  }: {
111
122
  node: SidebarNavNode;
112
123
  depth: number;
113
124
  isLast: boolean;
125
+ initiallyCollapsed?: boolean;
114
126
  }) {
115
- const [open, setOpen] = useState(true);
116
- const toggle = () => setOpen((prev) => !prev);
127
+ const [open, setOpen] = useState(() => initialCategoryOpenState(initiallyCollapsed));
128
+ const toggle = () => setOpen(toggleCategoryOpenState);
117
129
  const paddingLeft = padLeft(depth);
118
130
 
119
131
  return (
@@ -0,0 +1,9 @@
1
+ /** Derive the one-time open state used when a category mounts. */
2
+ export function initialCategoryOpenState(initiallyCollapsed: boolean): boolean {
3
+ return !initiallyCollapsed;
4
+ }
5
+
6
+ /** Toggle a mounted category without coupling later state to its initial input. */
7
+ export function toggleCategoryOpenState(open: boolean): boolean {
8
+ return !open;
9
+ }
@@ -41,10 +41,8 @@ export function readColorSchemeFromDom(
41
41
  * `color-scheme-changed` window event.
42
42
  *
43
43
  * Tweak-state reconciliation is intentionally NOT done here (#2037). The zdtp
44
- * panel owns its own storage lifecycle: it persists the unified tweak envelope
45
- * under `zudo-doc-tweak-state-v4` (auto-migrating the legacy
46
- * `zudo-doc-tweak-state-v3` / `-v2` / `zudo-doc-tweak-state` (v1) keys into
47
- * it), and its own `color-scheme-changed` listener clears applied inline
44
+ * panel owns its own storage lifecycle and current persisted-state contract;
45
+ * its own `color-scheme-changed` listener clears applied inline
48
46
  * styles and re-seeds the color slice from the newly active scheme. An
49
47
  * earlier version of this function deleted `zudo-doc-tweak-state` + `-v2` on
50
48
  * every toggle, which (a) targeted stale keys after zdtp moved to v3 — so it
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takazudo/zudo-doc",
3
- "version": "3.3.0",
3
+ "version": "4.0.0",
4
4
  "type": "module",
5
5
  "description": "zudo-doc framework primitives layer that sits on top of zfb's engine — sidebar, theme, TOC, breadcrumb, layouts, head injection, View Transitions, SSR-skip wrappers (per ADR-003).",
6
6
  "license": "MIT",
@@ -107,26 +107,10 @@
107
107
  "types": "./dist/transitions/index.d.ts",
108
108
  "default": "./dist/transitions/index.js"
109
109
  },
110
- "./integrations/doc-history": {
111
- "types": "./dist/integrations/doc-history/index.d.ts",
112
- "default": "./dist/integrations/doc-history/index.js"
113
- },
114
- "./integrations/llms-txt": {
115
- "types": "./dist/integrations/llms-txt/index.d.ts",
116
- "default": "./dist/integrations/llms-txt/index.js"
117
- },
118
110
  "./integrations/changelog": {
119
111
  "types": "./dist/integrations/changelog/index.d.ts",
120
112
  "default": "./dist/integrations/changelog/index.js"
121
113
  },
122
- "./integrations/search-index": {
123
- "types": "./dist/integrations/search-index/index.d.ts",
124
- "default": "./dist/integrations/search-index/index.js"
125
- },
126
- "./integrations/claude-resources": {
127
- "types": "./dist/integrations/claude-resources/index.d.ts",
128
- "default": "./dist/integrations/claude-resources/index.js"
129
- },
130
114
  "./content": {
131
115
  "types": "./dist/content/index.d.ts",
132
116
  "default": "./dist/content/index.js"
@@ -195,6 +179,10 @@
195
179
  "types": "./dist/plugins/routes.d.ts",
196
180
  "default": "./dist/plugins/routes.js"
197
181
  },
182
+ "./plugins/theme-packs": {
183
+ "types": "./dist/plugins/theme-packs.d.ts",
184
+ "default": "./dist/plugins/theme-packs.js"
185
+ },
198
186
  "./content-admonition": {
199
187
  "types": "./dist/content-admonition/index.d.ts",
200
188
  "default": "./dist/content-admonition/index.js"
@@ -237,10 +225,10 @@
237
225
  },
238
226
  "./theme.css": "./dist/theme.css",
239
227
  "./safelist.css": "./dist/safelist.css",
240
- "./safelist": "./dist/safelist.css",
241
228
  "./content.css": "./dist/content.css",
242
229
  "./page-loading.css": "./dist/page-loading.css",
243
230
  "./features.css": "./dist/features.css",
231
+ "./theme-packs/*": "./dist/theme-packs/*",
244
232
  "./tsconfig.base.json": "./tsconfig.base.json",
245
233
  "./zfb-config-shim.d.ts": "./zfb-config-shim.d.ts",
246
234
  "./virtual-modules.d.ts": "./virtual-modules.d.ts",
@@ -575,12 +563,17 @@
575
563
  "./config": {
576
564
  "types": "./dist/config.d.ts",
577
565
  "default": "./dist/config.js"
566
+ },
567
+ "./theme-cli": {
568
+ "types": "./dist/theme-cli/index.d.ts",
569
+ "default": "./dist/theme-cli/index.js"
578
570
  }
579
571
  },
580
572
  "bin": {
581
573
  "gen-component-tokens": "./bin/gen-component-tokens.mjs",
582
574
  "gen-z-index": "./bin/gen-z-index.mjs",
583
575
  "tags-audit": "./bin/tags-audit.mjs",
576
+ "tags-suggest": "./bin/tags-suggest.mjs",
584
577
  "zudo-doc": "./bin/zudo-doc.mjs"
585
578
  },
586
579
  "files": [
@@ -595,15 +588,16 @@
595
588
  "CHANGELOG.md"
596
589
  ],
597
590
  "peerDependencies": {
591
+ "@takazudo/zdtp": "^0.4.9",
592
+ "@takazudo/zfb": "^0.1.0-next.87",
593
+ "@takazudo/zfb-md-wasm": "^0.1.0-next.87",
594
+ "@takazudo/zfb-runtime": "^0.1.0-next.87",
595
+ "@takazudo/zudo-doc-history-server": "^4.0.0",
596
+ "diff": "^8.0.0",
597
+ "katex": "^0.16.0",
598
598
  "preact": "^10.29.1",
599
- "@takazudo/zfb": "^0.1.0-next.78",
600
- "@takazudo/zfb-runtime": "^0.1.0-next.78",
601
- "@takazudo/zudo-doc-history-server": "^3.1.0",
602
- "@takazudo/zdtp": "^0.4.6",
603
599
  "shiki": "^4.0.2",
604
- "zod": "^4.3.6",
605
- "katex": "^0.16.0",
606
- "diff": "^8.0.0"
600
+ "zod": "^4.3.6"
607
601
  },
608
602
  "peerDependenciesMeta": {
609
603
  "@takazudo/zudo-doc-history-server": {
@@ -612,6 +606,9 @@
612
606
  "@takazudo/zdtp": {
613
607
  "optional": true
614
608
  },
609
+ "@takazudo/zfb-md-wasm": {
610
+ "optional": true
611
+ },
615
612
  "shiki": {
616
613
  "optional": true
617
614
  },
@@ -623,16 +620,26 @@
623
620
  }
624
621
  },
625
622
  "dependencies": {
623
+ "@inquirer/prompts": "^8.4.2",
626
624
  "fs-extra": "^11.3.0",
627
625
  "gray-matter": "^4.0.3",
628
626
  "minimist": "^1.2.8",
629
- "picocolors": "^1.1.1"
627
+ "picocolors": "^1.1.1",
628
+ "pluralize": "^8.0.0",
629
+ "string-similarity": "^4.0.4",
630
+ "tsx": "^4.21.0"
630
631
  },
631
632
  "devDependencies": {
633
+ "@takazudo/zfb": "0.1.0-next.87",
634
+ "@takazudo/zfb-md-wasm": "0.1.0-next.87",
635
+ "@takazudo/zfb-runtime": "0.1.0-next.87",
632
636
  "@types/fs-extra": "^11.0.4",
633
637
  "@types/minimist": "^1.2.5",
634
638
  "@types/node": "^25.3.5",
639
+ "@types/pluralize": "^0.0.33",
640
+ "@types/string-similarity": "^4.0.2",
635
641
  "cross-env": "^7.0.3",
642
+ "happy-dom": "^20.10.6",
636
643
  "preact": "^10.29.1",
637
644
  "preact-render-to-string": "^6.6.6",
638
645
  "shiki": "^4.0.2",
@@ -640,13 +647,12 @@
640
647
  "typescript": "^5.0.0",
641
648
  "vitest": "^4.1.0",
642
649
  "zod": "^4.3.6",
643
- "@takazudo/zfb": "0.1.0-next.78",
644
- "@takazudo/zfb-runtime": "0.1.0-next.78",
645
- "@takazudo/zudo-doc-history-server": "3.3.0"
650
+ "@takazudo/zudo-doc-history-server": "4.0.0"
646
651
  },
647
652
  "scripts": {
648
653
  "build": "tsup && tsc -p tsconfig.build.json",
649
654
  "dev": "tsup --watch",
655
+ "test:plugin-resolution": "node scripts/check-plugin-resolution.mjs",
650
656
  "test": "vitest run --config vitest.config.ts",
651
657
  "test:slow": "vitest run --config vitest.slow.config.ts",
652
658
  "typecheck": "tsc --noEmit"
@@ -5,7 +5,8 @@
5
5
 
6
6
  import type { JSX } from "preact";
7
7
  import { DocLayoutWithDefaults } from "@takazudo/zudo-doc/doclayout";
8
- import { settings, defaultLocale, withBase } from "./_context.js";
8
+ import { resolveThemePackSsrSlug } from "@takazudo/zudo-doc/theme";
9
+ import { settings, defaultLocale, withBase, themePackRegistry } from "./_context.js";
9
10
  import {
10
11
  HeadWithDefaults,
11
12
  HeaderWithDefaults,
@@ -25,6 +26,8 @@ export default function NotFoundPage(): JSX.Element {
25
26
  title={composeMetaTitle(title)}
26
27
  head={<HeadWithDefaults title={title} />}
27
28
  lang={locale}
29
+ // SSR `data-theme-pack` html attribute (ADR theme-packs.md D3, #2822).
30
+ dataThemePack={resolveThemePackSsrSlug(themePackRegistry, settings)}
28
31
  noindex={true}
29
32
  hideSidebar={true}
30
33
  hideToc={true}
@@ -44,10 +44,11 @@ import { chromeBindings } from "virtual:zudo-doc-chrome-bindings";
44
44
  // prop contract before performing the widening, restoring the #2674
45
45
  // drift-detection check a bare cast would erase.)
46
46
  //
47
- // `...chromeBindings` is spread AFTER the `defineChromeBindings({ DocHistory })`
48
- // result so a host that configured `chromeBindingsModule` can override ANY
49
- // slot — including DocHistory itself — while a host that didn't still gets
50
- // the #2480 fix for free. `chromeBindings` (the virtual re-export) is already
47
+ // The statically imported DocHistory is spread AFTER `...chromeBindings` so
48
+ // scanner-safe hydration wins consistently with generated self-contained
49
+ // routes. Hosts can override every other slot; DocHistory customization uses
50
+ // the package island's supported owner path rather than a virtual callable
51
+ // that the scanner cannot register. `chromeBindings` (the virtual re-export) is already
51
52
  // erased to the structural `ChromeHostBindings` at its own source, so it is
52
53
  // spread as-is rather than run back through `defineChromeBindings` (which
53
54
  // cannot recover types `defineChromeBindings` never checked in the first
@@ -65,8 +66,8 @@ import { chromeBindings } from "virtual:zudo-doc-chrome-bindings";
65
66
  // static chain route → this shim → `createChrome` → `chrome/derive` →
66
67
  // `design-token-panel-bootstrap`.
67
68
  const chrome = createChrome(routeCtx, {
68
- ...defineChromeBindings({ DocHistory }),
69
69
  ...chromeBindings,
70
+ ...defineChromeBindings({ DocHistory }),
70
71
  });
71
72
 
72
73
  export const {
@@ -22,6 +22,7 @@ import { routeContext } from "virtual:zudo-doc-route-context";
22
22
 
23
23
  import type { Settings } from "@takazudo/zudo-doc/settings";
24
24
  import type { ColorScheme } from "@takazudo/zudo-doc/color-scheme-utils";
25
+ import type { ThemePackRegistry } from "@takazudo/zudo-doc/theme-packs-registry";
25
26
  import {
26
27
  createRouteContext,
27
28
  type RouteContextPayload,
@@ -42,6 +43,9 @@ export const settings: Settings = routeCtx.settings;
42
43
  /** Host color-scheme palette map. `null` when not supplied — `_chrome.tsx`
43
44
  * falls back to `DEFAULT_SCHEME` in that case. */
44
45
  export const colorSchemes: Record<string, ColorScheme> | null = routeCtx.colorSchemes;
46
+ /** Resolved, enabled, ordered theme-pack registry. `null` when the routes
47
+ * plugin did not thread one (ADR `docs/adr/theme-packs.md`, Decision 2). */
48
+ export const themePackRegistry: ThemePackRegistry | null = routeCtx.themePackRegistry;
45
49
 
46
50
  export const {
47
51
  i18n,
@@ -22,7 +22,6 @@
22
22
  import {
23
23
  getCollection,
24
24
  getContentSnapshot,
25
- type CollectionEntry,
26
25
  } from "@takazudo/zfb/content";
27
26
  import {
28
27
  buildSidebarTree,
@@ -44,29 +43,10 @@ function snapshotAnchor(name: string): readonly unknown[] | undefined {
44
43
  return getContentSnapshot()?.collections[name];
45
44
  }
46
45
 
47
- const bridgedByAnchor = new WeakMap<object, DocPageEntry[]>();
46
+ const docsByAnchor = new WeakMap<object, DocPageEntry[]>();
48
47
 
49
- /** Bridge a raw zfb collection entry onto the `DocPageEntry` shape the factories
50
- * expect (Astro-compat `id`/`collection`, with `index` suffix stripped via the
51
- * canonical root-slug rule). */
52
- function bridgeEntry(
53
- e: CollectionEntry<DocPageFrontmatter>,
54
- collectionName: string,
55
- ): DocPageEntry {
56
- return {
57
- slug: e.slug,
58
- id: toRouteSlug(e.slug),
59
- collection: collectionName,
60
- data: e.data,
61
- body: e.body,
62
- module_specifier: e.module_specifier,
63
- Content: e.Content,
64
- };
65
- }
66
-
67
- function buildBridged(collectionName: string): DocPageEntry[] {
68
- const raw = getCollection<DocPageFrontmatter>(collectionName);
69
- return raw.map((e) => bridgeEntry(e, collectionName)).filter((d) => !d.data.draft);
48
+ function buildDocs(collectionName: string): DocPageEntry[] {
49
+ return getCollection<DocPageFrontmatter>(collectionName).filter((entry) => !entry.data.draft);
70
50
  }
71
51
 
72
52
  /**
@@ -77,11 +57,11 @@ function buildBridged(collectionName: string): DocPageEntry[] {
77
57
  */
78
58
  export function stableDocs(collectionName: string): DocPageEntry[] {
79
59
  const anchor = snapshotAnchor(collectionName);
80
- if (anchor === undefined) return buildBridged(collectionName);
81
- const cached = bridgedByAnchor.get(anchor);
60
+ if (anchor === undefined) return buildDocs(collectionName);
61
+ const cached = docsByAnchor.get(anchor);
82
62
  if (cached) return cached;
83
- const built = buildBridged(collectionName);
84
- bridgedByAnchor.set(anchor, built);
63
+ const built = buildDocs(collectionName);
64
+ docsByAnchor.set(anchor, built);
85
65
  return built;
86
66
  }
87
67
 
@@ -119,7 +99,7 @@ function toNavNode(node: SidebarNode): DocNavNode {
119
99
  function findRootIndexDoc(docs: DocPageEntry[]): DocPageEntry | undefined {
120
100
  let found: DocPageEntry | undefined;
121
101
  for (const d of docs) {
122
- const slug = d.data.slug ?? d.id.replace(/\/index$/, "");
102
+ const slug = d.data.slug ?? toRouteSlug(d.slug);
123
103
  if (slug === "") found = d;
124
104
  }
125
105
  return found;
@@ -169,7 +149,7 @@ export function buildNavTree(
169
149
  ): DocNavNode[] {
170
150
  const href: BuildHref = options?.buildHref ?? buildHref;
171
151
  const sidebarTree = buildSidebarTree(
172
- docs.map((d) => ({ id: d.id, data: d.data })),
152
+ docs,
173
153
  locale,
174
154
  {
175
155
  categoryMeta,