@takazudo/zudo-doc 3.2.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 (439) hide show
  1. package/CHANGELOG.md +61 -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 -4
  14. package/dist/chrome/derive.js +64 -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 +227 -0
  20. package/dist/chrome-bindings.js +6 -0
  21. package/dist/code-syntax/code-block-enhancer-script.d.ts +4 -0
  22. package/dist/code-syntax/code-block-enhancer-script.js +7 -4
  23. package/dist/code-syntax/code-block-enhancer.d.ts +2 -2
  24. package/dist/code-syntax/code-block-enhancer.js +1 -3
  25. package/dist/code-syntax/index.d.ts +5 -5
  26. package/dist/code-syntax/index.js +4 -13
  27. package/dist/code-syntax/mermaid-init-script.d.ts +1 -22
  28. package/dist/code-syntax/mermaid-init-script.js +0 -2
  29. package/dist/code-syntax/mermaid-init.d.ts +0 -1
  30. package/dist/code-syntax/mermaid-init.js +3 -4
  31. package/dist/code-syntax/tabs-init.d.ts +0 -1
  32. package/dist/code-syntax/tabs-init.js +1 -3
  33. package/dist/code-syntax/tabs.d.ts +0 -1
  34. package/dist/code-syntax/tabs.js +1 -3
  35. package/dist/color-scheme-utils.d.ts +72 -4
  36. package/dist/color-scheme-utils.js +137 -0
  37. package/dist/color-schemes-defaults/index.d.ts +23 -0
  38. package/dist/color-schemes-defaults/index.js +134 -0
  39. package/dist/config.d.ts +459 -0
  40. package/dist/config.js +125 -0
  41. package/dist/content/component-map.d.ts +0 -16
  42. package/dist/content/component-map.js +2 -4
  43. package/dist/content/index.d.ts +1 -1
  44. package/dist/content/index.js +2 -3
  45. package/dist/content.css +1 -1
  46. package/dist/design-token-panel-bootstrap.d.ts +82 -27
  47. package/dist/design-token-panel-bootstrap.js +110 -21
  48. package/dist/design-token-panel-config/index.d.ts +49 -0
  49. package/dist/design-token-panel-config/index.js +211 -0
  50. package/dist/design-token-panel-config/manifest.d.ts +46 -0
  51. package/dist/design-token-panel-config/manifest.js +105 -0
  52. package/dist/directive-vocabulary-defaults/index.d.ts +16 -0
  53. package/dist/directive-vocabulary-defaults/index.js +12 -0
  54. package/dist/doc-body-end-islands/design-token-panel-island.d.ts +15 -0
  55. package/dist/doc-body-end-islands/design-token-panel-island.js +31 -0
  56. package/dist/doc-body-end-islands/index.d.ts +52 -7
  57. package/dist/doc-body-end-islands/index.js +19 -0
  58. package/dist/doc-body-end-islands/theme-pack-switcher-island.d.ts +37 -0
  59. package/dist/doc-body-end-islands/theme-pack-switcher-island.js +18 -0
  60. package/dist/doc-content-header/index.js +1 -1
  61. package/dist/doc-history-area/index.d.ts +10 -4
  62. package/dist/doc-history-area/index.js +3 -2
  63. package/dist/doc-metainfo-area/index.d.ts +1 -0
  64. package/dist/doc-page-props/index.d.ts +7 -23
  65. package/dist/doc-page-renderer/index.d.ts +1 -0
  66. package/dist/doc-page-renderer/index.js +1 -0
  67. package/dist/doc-page-shell/index.js +19 -12
  68. package/dist/doc-pager/index.js +1 -1
  69. package/dist/doc-route-entries/index.d.ts +2 -2
  70. package/dist/doclayout/doc-layout-with-defaults.js +4 -4
  71. package/dist/doclayout/doc-layout.d.ts +8 -0
  72. package/dist/doclayout/doc-layout.js +10 -1
  73. package/dist/docs-schema/index.d.ts +67 -0
  74. package/dist/docs-schema/index.js +43 -0
  75. package/dist/eject/index.d.ts +16 -0
  76. package/dist/eject/index.js +122 -28
  77. package/dist/extract-headings/index.d.ts +5 -8
  78. package/dist/extract-headings/index.js +2 -9
  79. package/dist/factory-context/index.d.ts +56 -4
  80. package/dist/features.css +65 -43
  81. package/dist/find-in-page/find-bar.d.ts +9 -0
  82. package/dist/find-in-page/find-bar.js +114 -0
  83. package/dist/find-in-page/find-in-page.d.ts +17 -0
  84. package/dist/find-in-page/find-in-page.js +131 -0
  85. package/dist/find-in-page/index.d.ts +11 -0
  86. package/dist/find-in-page/index.js +49 -0
  87. package/dist/footer/footer.js +1 -0
  88. package/dist/frontmatter-preview-defaults/index.d.ts +16 -0
  89. package/dist/frontmatter-preview-defaults/index.js +25 -0
  90. package/dist/head-with-defaults/index.d.ts +2 -0
  91. package/dist/head-with-defaults/index.js +16 -0
  92. package/dist/header/header.d.ts +10 -5
  93. package/dist/header/header.js +45 -5
  94. package/dist/header/index.d.ts +1 -1
  95. package/dist/header/types.d.ts +30 -1
  96. package/dist/header-with-defaults/index.js +1 -0
  97. package/dist/home-page/index.d.ts +2 -0
  98. package/dist/home-page/index.js +11 -5
  99. package/dist/home-page/prepare-home-data.js +1 -1
  100. package/dist/i18n-defaults/index.d.ts +22 -0
  101. package/dist/i18n-defaults/index.js +167 -0
  102. package/dist/locale-merge/index.d.ts +9 -14
  103. package/dist/locale-merge/index.js +6 -4
  104. package/dist/mdx-components/index.js +4 -4
  105. package/dist/plugins/claude-resources.d.ts +1 -0
  106. package/dist/plugins/claude-resources.js +4 -2
  107. package/dist/plugins/doc-history.js +1 -1
  108. package/dist/{integrations → plugins/internal}/claude-resources/index.d.ts +1 -16
  109. package/dist/{integrations → plugins/internal}/claude-resources/index.js +0 -9
  110. package/dist/{integrations → plugins/internal}/doc-history/index.d.ts +0 -17
  111. package/dist/{integrations → plugins/internal}/doc-history/index.js +0 -4
  112. package/dist/{integrations → plugins/internal}/doc-history/pre-build.d.ts +2 -4
  113. package/dist/plugins/internal/llms-txt/index.d.ts +7 -0
  114. package/dist/{integrations → plugins/internal}/llms-txt/load.d.ts +1 -1
  115. package/dist/{integrations → plugins/internal}/llms-txt/load.js +2 -2
  116. package/dist/{integrations → plugins/internal}/llms-txt/strip.d.ts +2 -3
  117. package/dist/{integrations → plugins/internal}/llms-txt/strip.js +1 -1
  118. package/dist/{integrations → plugins/internal}/llms-txt/types.d.ts +13 -22
  119. package/dist/{integrations → plugins/internal}/search-index/collect.js +1 -1
  120. package/dist/plugins/internal/theme-packs/copy.d.ts +32 -0
  121. package/dist/plugins/internal/theme-packs/copy.js +45 -0
  122. package/dist/plugins/internal/theme-packs/dev-middleware.d.ts +22 -0
  123. package/dist/plugins/internal/theme-packs/dev-middleware.js +80 -0
  124. package/dist/plugins/internal/theme-packs/index.d.ts +6 -0
  125. package/dist/plugins/internal/theme-packs/index.js +9 -0
  126. package/dist/plugins/internal/theme-packs/resolve.d.ts +17 -0
  127. package/dist/plugins/internal/theme-packs/resolve.js +17 -0
  128. package/dist/plugins/internal/theme-packs/types.d.ts +22 -0
  129. package/dist/plugins/internal/theme-packs/types.js +0 -0
  130. package/dist/plugins/llms-txt.js +1 -1
  131. package/dist/plugins/routes.js +55 -21
  132. package/dist/plugins/search-index.js +1 -1
  133. package/dist/plugins/theme-packs.d.ts +3 -0
  134. package/dist/plugins/theme-packs.js +40 -0
  135. package/dist/preset.d.ts +28 -14
  136. package/dist/preset.js +24 -9
  137. package/dist/route-context/index.js +4 -6
  138. package/dist/route-enumerators/index.d.ts +6 -18
  139. package/dist/route-enumerators/index.js +8 -6
  140. package/dist/routes/404.js +3 -1
  141. package/dist/routes/_chrome.js +3 -2
  142. package/dist/routes/_context.d.ts +7 -3
  143. package/dist/routes/_context.js +2 -0
  144. package/dist/routes/_docs-helpers.js +9 -21
  145. package/dist/safelist.css +1 -1
  146. package/dist/settings.d.ts +64 -12
  147. package/dist/sidebar-tree/build-tree.d.ts +3 -4
  148. package/dist/sidebar-tree/build-tree.js +4 -3
  149. package/dist/sidebar-tree/index.d.ts +2 -2
  150. package/dist/sidebar-tree/types.d.ts +6 -17
  151. package/dist/site-tree-nav-island/index.d.ts +3 -1
  152. package/dist/site-tree-nav-island/index.js +17 -5
  153. package/dist/site-tree-nav-island/state.d.ts +4 -0
  154. package/dist/site-tree-nav-island/state.js +10 -0
  155. package/dist/tag-helpers/index.d.ts +6 -13
  156. package/dist/tag-helpers/index.js +5 -23
  157. package/dist/tag-pages/index.d.ts +8 -21
  158. package/dist/tag-pages/index.js +14 -10
  159. package/dist/tags-audit.d.ts +16 -44
  160. package/dist/tags-audit.js +9 -172
  161. package/dist/theme/color-scheme-provider.d.ts +2 -3
  162. package/dist/theme/color-scheme-provider.js +2 -10
  163. package/dist/theme/index.d.ts +1 -4
  164. package/dist/theme/index.js +2 -30
  165. package/dist/theme/theme-pack-provider.d.ts +42 -0
  166. package/dist/theme/theme-pack-provider.js +75 -0
  167. package/dist/theme-cli/apply.d.ts +16 -0
  168. package/dist/theme-cli/apply.js +61 -0
  169. package/dist/theme-cli/config-io.d.ts +15 -0
  170. package/dist/theme-cli/config-io.js +51 -0
  171. package/dist/theme-cli/config-rewriter.d.ts +21 -0
  172. package/dist/theme-cli/config-rewriter.js +141 -0
  173. package/dist/theme-cli/config-scanner.d.ts +63 -0
  174. package/dist/theme-cli/config-scanner.js +288 -0
  175. package/dist/theme-cli/index.d.ts +7 -0
  176. package/dist/theme-cli/index.js +38 -0
  177. package/dist/theme-cli/list.d.ts +27 -0
  178. package/dist/theme-cli/list.js +64 -0
  179. package/dist/theme-cli/provenance.d.ts +17 -0
  180. package/dist/theme-cli/provenance.js +35 -0
  181. package/dist/theme-cli/registry.d.ts +14 -0
  182. package/dist/theme-cli/registry.js +13 -0
  183. package/dist/theme-pack-dialog/dialog-state.d.ts +25 -0
  184. package/dist/theme-pack-dialog/dialog-state.js +40 -0
  185. package/dist/theme-pack-dialog/index.d.ts +5 -0
  186. package/dist/theme-pack-dialog/index.js +152 -0
  187. package/dist/theme-pack-dialog/theme-pack-card.d.ts +25 -0
  188. package/dist/theme-pack-dialog/theme-pack-card.js +72 -0
  189. package/dist/theme-pack-switcher/index.d.ts +49 -0
  190. package/dist/theme-pack-switcher/index.js +205 -0
  191. package/dist/theme-pack-switcher/switcher-state.d.ts +56 -0
  192. package/dist/theme-pack-switcher/switcher-state.js +43 -0
  193. package/dist/theme-pack-switcher/theme-pack-sync.d.ts +85 -0
  194. package/dist/theme-pack-switcher/theme-pack-sync.js +121 -0
  195. package/dist/theme-packs/beacon/fonts/AtkinsonHyperlegible-400-latin.woff2 +0 -0
  196. package/dist/theme-packs/beacon/fonts/AtkinsonHyperlegible-700-latin.woff2 +0 -0
  197. package/dist/theme-packs/beacon/fonts/AtkinsonHyperlegible-italic-400-latin.woff2 +0 -0
  198. package/dist/theme-packs/beacon/fonts/AtkinsonHyperlegible-italic-700-latin.woff2 +0 -0
  199. package/dist/theme-packs/beacon/fonts/AtkinsonHyperlegibleMono-italic-latin.woff2 +0 -0
  200. package/dist/theme-packs/beacon/fonts/AtkinsonHyperlegibleMono-latin.woff2 +0 -0
  201. package/dist/theme-packs/beacon/fonts/OFL.txt +94 -0
  202. package/dist/theme-packs/beacon/meta.json +37 -0
  203. package/dist/theme-packs/beacon/pack.css +442 -0
  204. package/dist/theme-packs/broadsheet/fonts/CourierPrime-400-latin.woff2 +0 -0
  205. package/dist/theme-packs/broadsheet/fonts/CourierPrime-700-latin.woff2 +0 -0
  206. package/dist/theme-packs/broadsheet/fonts/OFL.txt +95 -0
  207. package/dist/theme-packs/broadsheet/fonts/PlayfairDisplay-italic-latin.woff2 +0 -0
  208. package/dist/theme-packs/broadsheet/fonts/PlayfairDisplay-latin.woff2 +0 -0
  209. package/dist/theme-packs/broadsheet/fonts/SourceSerif4-italic-latin.woff2 +0 -0
  210. package/dist/theme-packs/broadsheet/fonts/SourceSerif4-latin.woff2 +0 -0
  211. package/dist/theme-packs/broadsheet/meta.json +38 -0
  212. package/dist/theme-packs/broadsheet/pack.css +448 -0
  213. package/dist/theme-packs/brutalist/fonts/ArchivoBlack-latin.woff2 +0 -0
  214. package/dist/theme-packs/brutalist/fonts/IBMPlexMono-400-latin.woff2 +0 -0
  215. package/dist/theme-packs/brutalist/fonts/IBMPlexMono-500-latin.woff2 +0 -0
  216. package/dist/theme-packs/brutalist/fonts/IBMPlexMono-700-latin.woff2 +0 -0
  217. package/dist/theme-packs/brutalist/fonts/OFL.txt +95 -0
  218. package/dist/theme-packs/brutalist/fonts/SpaceGrotesk-latin.woff2 +0 -0
  219. package/dist/theme-packs/brutalist/meta.json +38 -0
  220. package/dist/theme-packs/brutalist/pack.css +546 -0
  221. package/dist/theme-packs/default/meta.json +37 -0
  222. package/dist/theme-packs/drift/fonts/IBMPlexMono-400-latin-ext.woff2 +0 -0
  223. package/dist/theme-packs/drift/fonts/IBMPlexMono-400-latin.woff2 +0 -0
  224. package/dist/theme-packs/drift/fonts/IBMPlexMono-500-latin-ext.woff2 +0 -0
  225. package/dist/theme-packs/drift/fonts/IBMPlexMono-500-latin.woff2 +0 -0
  226. package/dist/theme-packs/drift/fonts/IBMPlexSans-italic-latin.woff2 +0 -0
  227. package/dist/theme-packs/drift/fonts/IBMPlexSans-latin-ext.woff2 +0 -0
  228. package/dist/theme-packs/drift/fonts/IBMPlexSans-latin.woff2 +0 -0
  229. package/dist/theme-packs/drift/fonts/OFL.txt +93 -0
  230. package/dist/theme-packs/drift/meta.json +37 -0
  231. package/dist/theme-packs/drift/pack.css +478 -0
  232. package/dist/theme-packs/fjord/fonts/Inter-latin-ext.woff2 +0 -0
  233. package/dist/theme-packs/fjord/fonts/Inter-latin.woff2 +0 -0
  234. package/dist/theme-packs/fjord/fonts/JetBrainsMono-latin-ext.woff2 +0 -0
  235. package/dist/theme-packs/fjord/fonts/JetBrainsMono-latin.woff2 +0 -0
  236. package/dist/theme-packs/fjord/fonts/OFL.txt +94 -0
  237. package/dist/theme-packs/fjord/meta.json +37 -0
  238. package/dist/theme-packs/fjord/pack.css +375 -0
  239. package/dist/theme-packs/foundry/fonts/Inter-latin-ext.woff2 +0 -0
  240. package/dist/theme-packs/foundry/fonts/Inter-latin.woff2 +0 -0
  241. package/dist/theme-packs/foundry/fonts/OFL.txt +93 -0
  242. package/dist/theme-packs/foundry/meta.json +37 -0
  243. package/dist/theme-packs/foundry/pack.css +202 -0
  244. package/dist/theme-packs/futura-editorial/fonts/Jost-latin.woff2 +0 -0
  245. package/dist/theme-packs/futura-editorial/fonts/NotoSans-italic-latin.woff2 +0 -0
  246. package/dist/theme-packs/futura-editorial/fonts/NotoSans-latin.woff2 +0 -0
  247. package/dist/theme-packs/futura-editorial/fonts/OFL.txt +95 -0
  248. package/dist/theme-packs/futura-editorial/fonts/SpaceMono-400-latin.woff2 +0 -0
  249. package/dist/theme-packs/futura-editorial/fonts/SpaceMono-700-latin.woff2 +0 -0
  250. package/dist/theme-packs/futura-editorial/meta.json +38 -0
  251. package/dist/theme-packs/futura-editorial/pack.css +313 -0
  252. package/dist/theme-packs/hearth/fonts/Fraunces-italic-latin.woff2 +0 -0
  253. package/dist/theme-packs/hearth/fonts/Fraunces-latin.woff2 +0 -0
  254. package/dist/theme-packs/hearth/fonts/Nunito-latin.woff2 +0 -0
  255. package/dist/theme-packs/hearth/fonts/OFL.txt +95 -0
  256. package/dist/theme-packs/hearth/fonts/SplineSansMono-latin.woff2 +0 -0
  257. package/dist/theme-packs/hearth/meta.json +38 -0
  258. package/dist/theme-packs/hearth/pack.css +385 -0
  259. package/dist/theme-packs/hollow/fonts/OFL.txt +94 -0
  260. package/dist/theme-packs/hollow/fonts/SpaceGrotesk-latin.woff2 +0 -0
  261. package/dist/theme-packs/hollow/fonts/SpaceMono-400-italic-latin.woff2 +0 -0
  262. package/dist/theme-packs/hollow/fonts/SpaceMono-400-latin.woff2 +0 -0
  263. package/dist/theme-packs/hollow/fonts/SpaceMono-700-latin.woff2 +0 -0
  264. package/dist/theme-packs/hollow/meta.json +37 -0
  265. package/dist/theme-packs/hollow/pack.css +428 -0
  266. package/dist/theme-packs/ledger/fonts/CrimsonPro-latin-ext-italic.woff2 +0 -0
  267. package/dist/theme-packs/ledger/fonts/CrimsonPro-latin-ext.woff2 +0 -0
  268. package/dist/theme-packs/ledger/fonts/CrimsonPro-latin-italic.woff2 +0 -0
  269. package/dist/theme-packs/ledger/fonts/CrimsonPro-latin.woff2 +0 -0
  270. package/dist/theme-packs/ledger/fonts/IBMPlexMono-400-latin-ext.woff2 +0 -0
  271. package/dist/theme-packs/ledger/fonts/IBMPlexMono-400-latin.woff2 +0 -0
  272. package/dist/theme-packs/ledger/fonts/IBMPlexMono-500-latin-ext.woff2 +0 -0
  273. package/dist/theme-packs/ledger/fonts/IBMPlexMono-500-latin.woff2 +0 -0
  274. package/dist/theme-packs/ledger/fonts/OFL.txt +94 -0
  275. package/dist/theme-packs/ledger/meta.json +37 -0
  276. package/dist/theme-packs/ledger/pack.css +463 -0
  277. package/dist/theme-packs/manuscript/fonts/CourierPrime-400-latin-ext.woff2 +0 -0
  278. package/dist/theme-packs/manuscript/fonts/CourierPrime-400-latin.woff2 +0 -0
  279. package/dist/theme-packs/manuscript/fonts/CourierPrime-700-latin-ext.woff2 +0 -0
  280. package/dist/theme-packs/manuscript/fonts/CourierPrime-700-latin.woff2 +0 -0
  281. package/dist/theme-packs/manuscript/fonts/EBGaramond-latin-italic.woff2 +0 -0
  282. package/dist/theme-packs/manuscript/fonts/EBGaramond-latin.woff2 +0 -0
  283. package/dist/theme-packs/manuscript/fonts/OFL.txt +94 -0
  284. package/dist/theme-packs/manuscript/meta.json +37 -0
  285. package/dist/theme-packs/manuscript/pack.css +376 -0
  286. package/dist/theme-packs/matcha/fonts/MPLUS1Code-latin.woff2 +0 -0
  287. package/dist/theme-packs/matcha/fonts/OFL.txt +95 -0
  288. package/dist/theme-packs/matcha/fonts/ShipporiMincho-500-latin.woff2 +0 -0
  289. package/dist/theme-packs/matcha/fonts/ShipporiMincho-700-latin.woff2 +0 -0
  290. package/dist/theme-packs/matcha/fonts/ZenKakuGothicNew-400-latin.woff2 +0 -0
  291. package/dist/theme-packs/matcha/fonts/ZenKakuGothicNew-500-latin.woff2 +0 -0
  292. package/dist/theme-packs/matcha/meta.json +38 -0
  293. package/dist/theme-packs/matcha/pack.css +409 -0
  294. package/dist/theme-packs/nocturne/fonts/CormorantGaramond-italic-latin.woff2 +0 -0
  295. package/dist/theme-packs/nocturne/fonts/CormorantGaramond-latin.woff2 +0 -0
  296. package/dist/theme-packs/nocturne/fonts/IBMPlexMono-400-latin.woff2 +0 -0
  297. package/dist/theme-packs/nocturne/fonts/IBMPlexMono-500-latin.woff2 +0 -0
  298. package/dist/theme-packs/nocturne/fonts/IBMPlexMono-italic-latin.woff2 +0 -0
  299. package/dist/theme-packs/nocturne/fonts/Manrope-latin.woff2 +0 -0
  300. package/dist/theme-packs/nocturne/fonts/OFL.txt +95 -0
  301. package/dist/theme-packs/nocturne/meta.json +38 -0
  302. package/dist/theme-packs/nocturne/pack.css +502 -0
  303. package/dist/theme-packs/observatory/fonts/JosefinSans-latin.woff2 +0 -0
  304. package/dist/theme-packs/observatory/fonts/Jost-italic-latin.woff2 +0 -0
  305. package/dist/theme-packs/observatory/fonts/Jost-latin.woff2 +0 -0
  306. package/dist/theme-packs/observatory/fonts/OFL.txt +95 -0
  307. package/dist/theme-packs/observatory/fonts/SpaceMono-400-latin.woff2 +0 -0
  308. package/dist/theme-packs/observatory/fonts/SpaceMono-700-latin.woff2 +0 -0
  309. package/dist/theme-packs/observatory/fonts/SpaceMono-italic-latin.woff2 +0 -0
  310. package/dist/theme-packs/observatory/meta.json +38 -0
  311. package/dist/theme-packs/observatory/pack.css +728 -0
  312. package/dist/theme-packs/onyx/fonts/CormorantGaramond-italic-latin.woff2 +0 -0
  313. package/dist/theme-packs/onyx/fonts/CormorantGaramond-latin.woff2 +0 -0
  314. package/dist/theme-packs/onyx/fonts/IBMPlexMono-400-latin-ext.woff2 +0 -0
  315. package/dist/theme-packs/onyx/fonts/IBMPlexMono-400-latin.woff2 +0 -0
  316. package/dist/theme-packs/onyx/fonts/IBMPlexMono-500-latin-ext.woff2 +0 -0
  317. package/dist/theme-packs/onyx/fonts/IBMPlexMono-500-latin.woff2 +0 -0
  318. package/dist/theme-packs/onyx/fonts/Jost-latin.woff2 +0 -0
  319. package/dist/theme-packs/onyx/fonts/OFL.txt +95 -0
  320. package/dist/theme-packs/onyx/meta.json +38 -0
  321. package/dist/theme-packs/onyx/pack.css +497 -0
  322. package/dist/theme-packs/phosphor/fonts/JetBrainsMono-latin-ext.woff2 +0 -0
  323. package/dist/theme-packs/phosphor/fonts/JetBrainsMono-latin.woff2 +0 -0
  324. package/dist/theme-packs/phosphor/fonts/OFL.txt +94 -0
  325. package/dist/theme-packs/phosphor/fonts/VT323-latin-ext.woff2 +0 -0
  326. package/dist/theme-packs/phosphor/fonts/VT323-latin.woff2 +0 -0
  327. package/dist/theme-packs/phosphor/meta.json +38 -0
  328. package/dist/theme-packs/phosphor/pack.css +493 -0
  329. package/dist/theme-packs/solar/fonts/OFL.txt +94 -0
  330. package/dist/theme-packs/solar/fonts/SourceCodePro-italic-latin.woff2 +0 -0
  331. package/dist/theme-packs/solar/fonts/SourceCodePro-latin.woff2 +0 -0
  332. package/dist/theme-packs/solar/fonts/SourceSans3-italic-latin.woff2 +0 -0
  333. package/dist/theme-packs/solar/fonts/SourceSans3-latin.woff2 +0 -0
  334. package/dist/theme-packs/solar/meta.json +37 -0
  335. package/dist/theme-packs/solar/pack.css +380 -0
  336. package/dist/theme-packs/sumi/fonts/IBMPlexMono-400-latin-ext.woff2 +0 -0
  337. package/dist/theme-packs/sumi/fonts/IBMPlexMono-400-latin.woff2 +0 -0
  338. package/dist/theme-packs/sumi/fonts/IBMPlexMono-500-latin-ext.woff2 +0 -0
  339. package/dist/theme-packs/sumi/fonts/IBMPlexMono-500-latin.woff2 +0 -0
  340. package/dist/theme-packs/sumi/fonts/OFL.txt +95 -0
  341. package/dist/theme-packs/sumi/fonts/ShipporiMinchoB1-600-latin.woff2 +0 -0
  342. package/dist/theme-packs/sumi/fonts/ShipporiMinchoB1-700-latin.woff2 +0 -0
  343. package/dist/theme-packs/sumi/fonts/ShipporiMinchoB1-800-latin.woff2 +0 -0
  344. package/dist/theme-packs/sumi/fonts/ZenKakuGothicNew-400-latin.woff2 +0 -0
  345. package/dist/theme-packs/sumi/fonts/ZenKakuGothicNew-500-latin.woff2 +0 -0
  346. package/dist/theme-packs/sumi/meta.json +38 -0
  347. package/dist/theme-packs/sumi/pack.css +502 -0
  348. package/dist/theme-packs/swissgrid/fonts/IBMPlexMono-400-latin-ext.woff2 +0 -0
  349. package/dist/theme-packs/swissgrid/fonts/IBMPlexMono-400-latin.woff2 +0 -0
  350. package/dist/theme-packs/swissgrid/fonts/IBMPlexMono-600-latin.woff2 +0 -0
  351. package/dist/theme-packs/swissgrid/fonts/Inter-latin-ext.woff2 +0 -0
  352. package/dist/theme-packs/swissgrid/fonts/Inter-latin.woff2 +0 -0
  353. package/dist/theme-packs/swissgrid/fonts/InterTight-latin.woff2 +0 -0
  354. package/dist/theme-packs/swissgrid/fonts/OFL.txt +95 -0
  355. package/dist/theme-packs/swissgrid/meta.json +38 -0
  356. package/dist/theme-packs/swissgrid/pack.css +518 -0
  357. package/dist/theme-packs/washi/fonts/MPlus1Code-400-latin.woff2 +0 -0
  358. package/dist/theme-packs/washi/fonts/MPlus1Code-500-latin.woff2 +0 -0
  359. package/dist/theme-packs/washi/fonts/OFL.txt +95 -0
  360. package/dist/theme-packs/washi/fonts/ShipporiMincho-500-latin.woff2 +0 -0
  361. package/dist/theme-packs/washi/fonts/ShipporiMincho-600-latin.woff2 +0 -0
  362. package/dist/theme-packs/washi/fonts/ShipporiMincho-700-latin.woff2 +0 -0
  363. package/dist/theme-packs/washi/fonts/ZenKakuGothicNew-400-latin.woff2 +0 -0
  364. package/dist/theme-packs/washi/fonts/ZenKakuGothicNew-500-latin.woff2 +0 -0
  365. package/dist/theme-packs/washi/fonts/ZenKakuGothicNew-700-latin.woff2 +0 -0
  366. package/dist/theme-packs/washi/meta.json +38 -0
  367. package/dist/theme-packs/washi/pack.css +479 -0
  368. package/dist/theme-packs-registry/index.d.ts +5 -0
  369. package/dist/theme-packs-registry/index.js +30 -0
  370. package/dist/theme-packs-registry/load-registry.d.ts +23 -0
  371. package/dist/theme-packs-registry/load-registry.js +64 -0
  372. package/dist/theme-packs-registry/meta-schema.d.ts +70 -0
  373. package/dist/theme-packs-registry/meta-schema.js +38 -0
  374. package/dist/theme-packs-registry/resolve-enabled-packs.d.ts +25 -0
  375. package/dist/theme-packs-registry/resolve-enabled-packs.js +43 -0
  376. package/dist/theme-packs-registry/token-manifest.d.ts +19 -0
  377. package/dist/theme-packs-registry/token-manifest.js +57 -0
  378. package/dist/theme-packs-registry/validator.d.ts +35 -0
  379. package/dist/theme-packs-registry/validator.js +284 -0
  380. package/dist/theme-toggle/color-scheme-sync.d.ts +2 -4
  381. package/dist/theme.css +319 -0
  382. package/dist/versions-page/index.d.ts +2 -2
  383. package/dist/versions-page/index.js +8 -8
  384. package/dist/z-index-defaults/index.d.ts +45 -0
  385. package/dist/z-index-defaults/index.js +34 -0
  386. package/eject/breadcrumb/breadcrumb.tsx +4 -4
  387. package/eject/breadcrumb/find-path.ts +2 -2
  388. package/eject/breadcrumb/index.ts +1 -1
  389. package/eject/breadcrumb/types.ts +0 -6
  390. package/eject/code-group/index.tsx +2 -2
  391. package/eject/doc-history/index.tsx +1 -1
  392. package/eject/doc-pager/index.tsx +1 -1
  393. package/eject/footer/footer.tsx +1 -0
  394. package/eject/header/header.tsx +86 -21
  395. package/eject/header/index.ts +3 -0
  396. package/eject/header/types.ts +39 -1
  397. package/eject/site-tree-nav-island/index.tsx +15 -3
  398. package/eject/site-tree-nav-island/state.ts +9 -0
  399. package/eject/theme-toggle/color-scheme-sync.ts +2 -4
  400. package/package.json +82 -29
  401. package/routes-src/404.tsx +4 -1
  402. package/routes-src/_chrome.tsx +31 -8
  403. package/routes-src/_context.ts +4 -0
  404. package/routes-src/_docs-helpers.ts +9 -29
  405. package/routes-src/_virtual.d.ts +38 -2
  406. package/tsconfig.base.json +29 -0
  407. package/virtual-modules.d.ts +83 -0
  408. package/zfb-config-shim.d.ts +210 -0
  409. package/dist/integrations/llms-txt/index.d.ts +0 -33
  410. package/dist/theme/color-tweak-export-modal.d.ts +0 -16
  411. package/dist/theme/color-tweak-export-modal.js +0 -138
  412. package/dist/theme/design-token-serde.d.ts +0 -183
  413. package/dist/theme/design-token-serde.js +0 -346
  414. package/dist/theme/design-token-types.d.ts +0 -13
  415. package/dist/theme/design-token-types.js +0 -6
  416. package/dist/theme/iframe-bridge.d.ts +0 -42
  417. package/dist/theme/iframe-bridge.js +0 -72
  418. /package/dist/{integrations → plugins/internal}/claude-resources/escape-for-mdx.d.ts +0 -0
  419. /package/dist/{integrations → plugins/internal}/claude-resources/escape-for-mdx.js +0 -0
  420. /package/dist/{integrations → plugins/internal}/claude-resources/generate.d.ts +0 -0
  421. /package/dist/{integrations → plugins/internal}/claude-resources/generate.js +0 -0
  422. /package/dist/{integrations → plugins/internal}/doc-history/pre-build.js +0 -0
  423. /package/dist/{integrations → plugins/internal}/llms-txt/dev-middleware.d.ts +0 -0
  424. /package/dist/{integrations → plugins/internal}/llms-txt/dev-middleware.js +0 -0
  425. /package/dist/{integrations → plugins/internal}/llms-txt/emit.d.ts +0 -0
  426. /package/dist/{integrations → plugins/internal}/llms-txt/emit.js +0 -0
  427. /package/dist/{integrations → plugins/internal}/llms-txt/generate.d.ts +0 -0
  428. /package/dist/{integrations → plugins/internal}/llms-txt/generate.js +0 -0
  429. /package/dist/{integrations → plugins/internal}/llms-txt/index.js +0 -0
  430. /package/dist/{integrations → plugins/internal}/llms-txt/types.js +0 -0
  431. /package/dist/{integrations → plugins/internal}/search-index/build-emitter.d.ts +0 -0
  432. /package/dist/{integrations → plugins/internal}/search-index/build-emitter.js +0 -0
  433. /package/dist/{integrations → plugins/internal}/search-index/collect.d.ts +0 -0
  434. /package/dist/{integrations → plugins/internal}/search-index/dev-middleware.d.ts +0 -0
  435. /package/dist/{integrations → plugins/internal}/search-index/dev-middleware.js +0 -0
  436. /package/dist/{integrations → plugins/internal}/search-index/index.d.ts +0 -0
  437. /package/dist/{integrations → plugins/internal}/search-index/index.js +0 -0
  438. /package/dist/{integrations → plugins/internal}/search-index/types.d.ts +0 -0
  439. /package/dist/{integrations → plugins/internal}/search-index/types.js +0 -0
@@ -0,0 +1,14 @@
1
+ import { type ThemePackRegistry, type ThemePackRegistryEntry } from "../theme-packs-registry/index.js";
2
+ export type { ThemePackRegistry, ThemePackRegistryEntry };
3
+ export interface LoadInstalledThemePackCatalogOptions {
4
+ /** Override for tests — points at a fixture `theme-packs/` directory
5
+ * instead of this module's own shipped one. */
6
+ themePacksDir?: string | URL;
7
+ }
8
+ /**
9
+ * Load the full installed catalog (every pack the running
10
+ * `@takazudo/zudo-doc` ships), validated the same way the package's own
11
+ * build validates it (`loadThemePackRegistry` — throws loudly naming the
12
+ * offending pack on a corrupted install rather than silently degrading).
13
+ */
14
+ export declare function loadInstalledThemePackCatalog(options?: LoadInstalledThemePackCatalogOptions): ThemePackRegistry;
@@ -0,0 +1,13 @@
1
+ import {
2
+ loadThemePackRegistry
3
+ } from "../theme-packs-registry/index.js";
4
+ function defaultThemePacksDir() {
5
+ return new URL("../theme-packs/", import.meta.url);
6
+ }
7
+ function loadInstalledThemePackCatalog(options = {}) {
8
+ const dir = options.themePacksDir ?? defaultThemePacksDir();
9
+ return loadThemePackRegistry(dir);
10
+ }
11
+ export {
12
+ loadInstalledThemePackCatalog
13
+ };
@@ -0,0 +1,25 @@
1
+ import type { ThemePackMeta } from "../theme-packs-registry/index.js";
2
+ /**
3
+ * Structurally parse the `{base}theme-packs/index.json` registry payload
4
+ * (ADR Decision 2: `{ schemaVersion: 1, packs: ThemePackMeta[] }`). This is a
5
+ * defensive shape check against a truncated/malformed fetch response — NOT a
6
+ * re-run of the build-time zod validator (`theme-packs-registry/validator.ts`),
7
+ * which already gated every pack before the manifest was ever written.
8
+ * Re-validating each field client-side would pull `zod` into this dialog's
9
+ * browser bundle for no real benefit (the ADR's "Registry types... come from
10
+ * theme-packs-registry/" note means TYPES only). Returns `null` on any shape
11
+ * mismatch so the caller can show its inline error note instead of crashing
12
+ * on a bad field access later (`isValidThemePackMeta` covers every field
13
+ * `ThemePackCard` reads).
14
+ */
15
+ export declare function parseThemePackRegistryPayload(data: unknown): ThemePackMeta[] | null;
16
+ /**
17
+ * Resolve which `meta.preview` swatch set paints the dialog's cards, matching
18
+ * the CURRENT light/dark UI mode (ADR Decision 7: "Card previews must pick
19
+ * the swatch set matching the CURRENT light/dark mode" — NOT `meta.mode`,
20
+ * which is only the designed-primary badge). Takes the raw `data-theme`
21
+ * attribute value rather than reading `document` itself so it stays
22
+ * plain-Node testable — mirrors `theme-toggle/color-scheme-sync.ts`'s
23
+ * `readColorSchemeFromDom` fallback shape (unknown/missing → "light").
24
+ */
25
+ export declare function resolveDialogMode(dataThemeAttr: string | null): "light" | "dark";
@@ -0,0 +1,40 @@
1
+ function isValidSwatches(value) {
2
+ if (typeof value !== "object" || value === null) return false;
3
+ const v = value;
4
+ if (typeof v["bg"] !== "string" || typeof v["fg"] !== "string" || typeof v["accent"] !== "string") {
5
+ return false;
6
+ }
7
+ const syntax = v["syntax"];
8
+ if (typeof syntax !== "object" || syntax === null) return false;
9
+ const s = syntax;
10
+ return typeof s["keyword"] === "string" && typeof s["string"] === "string" && typeof s["comment"] === "string" && typeof s["callable"] === "string";
11
+ }
12
+ function isValidThemePackMeta(entry) {
13
+ if (typeof entry !== "object" || entry === null) return false;
14
+ const p = entry;
15
+ if (typeof p["slug"] !== "string" || typeof p["name"] !== "string" || typeof p["description"] !== "string") {
16
+ return false;
17
+ }
18
+ if (p["mode"] !== "light" && p["mode"] !== "dark") return false;
19
+ const fonts = p["fonts"];
20
+ if (typeof fonts !== "object" || fonts === null) return false;
21
+ if (typeof fonts["sans"] !== "string") return false;
22
+ const preview = p["preview"];
23
+ if (typeof preview !== "object" || preview === null) return false;
24
+ const pv = preview;
25
+ return isValidSwatches(pv["light"]) && isValidSwatches(pv["dark"]);
26
+ }
27
+ function parseThemePackRegistryPayload(data) {
28
+ if (typeof data !== "object" || data === null) return null;
29
+ const record = data;
30
+ if (record["schemaVersion"] !== 1 || !Array.isArray(record["packs"])) return null;
31
+ const packs = record["packs"];
32
+ return packs.every(isValidThemePackMeta) ? packs : null;
33
+ }
34
+ function resolveDialogMode(dataThemeAttr) {
35
+ return dataThemeAttr === "dark" ? "dark" : "light";
36
+ }
37
+ export {
38
+ parseThemePackRegistryPayload,
39
+ resolveDialogMode
40
+ };
@@ -0,0 +1,5 @@
1
+ import type { ThemePackDialogProps } from "../theme-pack-switcher/index.js";
2
+ export declare function ThemePackDialog({ open, onClose, order, active, base }: ThemePackDialogProps): import("preact").JSX.Element;
3
+ export declare namespace ThemePackDialog {
4
+ var displayName: string;
5
+ }
@@ -0,0 +1,152 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
3
+ import { useCallback, useEffect, useRef, useState } from "preact/compat";
4
+ import { Close } from "../icons/index.js";
5
+ import { AFTER_NAVIGATE_EVENT } from "../transitions/index.js";
6
+ import { applyThemePack, DEFAULT_THEME_PACK_SLUG } from "../theme-pack-switcher/theme-pack-sync.js";
7
+ import { connectActivePackSync } from "../theme-pack-switcher/switcher-state.js";
8
+ import { useModalDialog } from "../use-modal-dialog/index.js";
9
+ import { parseThemePackRegistryPayload, resolveDialogMode } from "./dialog-state.js";
10
+ import { ThemePackCard } from "./theme-pack-card.js";
11
+ const COLOR_SCHEME_CHANGED_EVENT = "color-scheme-changed";
12
+ const LAUNCHER_SELECTOR = "[data-switcher-launcher]";
13
+ function ThemePackDialog({ open, onClose, order, active, base }) {
14
+ const [registryState, setRegistryState] = useState("idle");
15
+ const [packs, setPacks] = useState(null);
16
+ const [mode, setMode] = useState(
17
+ () => typeof document === "undefined" ? "light" : resolveDialogMode(document.documentElement.getAttribute("data-theme"))
18
+ );
19
+ const [activeSlug, setActiveSlug] = useState(active);
20
+ const launcherFocusRef = useRef(null);
21
+ const hasBrowsablePacks = order.some((entry) => entry.slug !== DEFAULT_THEME_PACK_SLUG);
22
+ useEffect(() => connectActivePackSync(setActiveSlug), []);
23
+ useEffect(() => {
24
+ function sync() {
25
+ setMode(resolveDialogMode(document.documentElement.getAttribute("data-theme")));
26
+ }
27
+ window.addEventListener(COLOR_SCHEME_CHANGED_EVENT, sync);
28
+ return () => window.removeEventListener(COLOR_SCHEME_CHANGED_EVENT, sync);
29
+ }, []);
30
+ useEffect(() => {
31
+ if (!open) return;
32
+ launcherFocusRef.current = document.querySelector(LAUNCHER_SELECTOR);
33
+ }, [open]);
34
+ const hasOpenedRef = useRef(false);
35
+ const [fetchToken, setFetchToken] = useState(0);
36
+ useEffect(() => {
37
+ if (open && !hasOpenedRef.current) {
38
+ hasOpenedRef.current = true;
39
+ if (hasBrowsablePacks) setFetchToken((t) => t + 1);
40
+ }
41
+ }, [open, hasBrowsablePacks]);
42
+ useEffect(() => {
43
+ if (fetchToken === 0) return;
44
+ let cancelled = false;
45
+ setRegistryState("loading");
46
+ fetch(`${base}theme-packs/index.json`).then((res) => {
47
+ if (!res.ok) throw new Error(`theme-packs/index.json responded ${res.status}`);
48
+ return res.json();
49
+ }).then((data) => {
50
+ if (cancelled) return;
51
+ const parsed = parseThemePackRegistryPayload(data);
52
+ if (parsed === null) {
53
+ setRegistryState("error");
54
+ return;
55
+ }
56
+ setPacks(parsed);
57
+ setRegistryState("loaded");
58
+ }).catch(() => {
59
+ if (!cancelled) setRegistryState("error");
60
+ });
61
+ return () => {
62
+ cancelled = true;
63
+ };
64
+ }, [fetchToken, base]);
65
+ const retry = useCallback(() => setFetchToken((t) => t + 1), []);
66
+ const { dialogRef, handleBackdropClick } = useModalDialog({
67
+ isOpen: open,
68
+ onClose,
69
+ navigateEvent: AFTER_NAVIGATE_EVENT,
70
+ backdropClickClose: true,
71
+ manageFocus: true,
72
+ returnFocusRef: launcherFocusRef
73
+ });
74
+ return /* @__PURE__ */ jsx(
75
+ "dialog",
76
+ {
77
+ ref: dialogRef,
78
+ onClick: handleBackdropClick,
79
+ "aria-labelledby": "zd-theme-pack-dialog-title",
80
+ className: "z-modal m-auto max-h-[85vh] w-[calc(100vw-2rem)] max-w-[64rem] rounded-lg border border-muted bg-surface p-0 text-fg backdrop:z-modal-backdrop backdrop:bg-bg/80",
81
+ children: /* @__PURE__ */ jsxs("div", { className: "flex max-h-[85vh] flex-col", children: [
82
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center justify-between gap-hsp-sm border-b border-muted px-hsp-lg py-vsp-sm", children: [
83
+ /* @__PURE__ */ jsx("h2", { id: "zd-theme-pack-dialog-title", className: "text-title font-bold text-fg", children: "Preview theme" }),
84
+ /* @__PURE__ */ jsx(
85
+ "button",
86
+ {
87
+ type: "button",
88
+ onClick: () => dialogRef.current?.close(),
89
+ "aria-label": "Close",
90
+ className: "flex items-center justify-center text-muted transition-colors hover:text-fg",
91
+ children: /* @__PURE__ */ jsx(Close, { className: "h-icon-sm w-icon-sm" })
92
+ }
93
+ )
94
+ ] }),
95
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto overscroll-contain px-hsp-lg py-vsp-lg", children: !hasBrowsablePacks ? /* @__PURE__ */ jsx("p", { className: "py-vsp-xl text-center text-small text-muted", children: "No other theme packs are configured \u2014 only the default look is available." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
96
+ registryState === "error" && /* @__PURE__ */ jsxs(
97
+ "div",
98
+ {
99
+ role: "alert",
100
+ className: "mx-auto flex max-w-sm flex-col items-center gap-vsp-xs rounded-[0.75rem] border border-danger bg-bg px-hsp-lg py-vsp-lg text-center text-small text-danger",
101
+ children: [
102
+ /* @__PURE__ */ jsx("p", { children: "Could not load theme previews." }),
103
+ /* @__PURE__ */ jsx(
104
+ "button",
105
+ {
106
+ type: "button",
107
+ onClick: retry,
108
+ className: "rounded border border-danger px-hsp-md py-hsp-2xs text-caption text-danger transition-colors hover:bg-danger/10",
109
+ children: "Retry"
110
+ }
111
+ )
112
+ ]
113
+ }
114
+ ),
115
+ (registryState === "idle" || registryState === "loading") && /* @__PURE__ */ jsxs(Fragment, { children: [
116
+ /* @__PURE__ */ jsx("p", { role: "status", className: "sr-only", children: "Loading theme previews\u2026" }),
117
+ /* @__PURE__ */ jsx(
118
+ "div",
119
+ {
120
+ "aria-hidden": "true",
121
+ className: "grid grid-cols-1 gap-hsp-lg sm:grid-cols-2 lg:grid-cols-3",
122
+ children: order.map((entry) => /* @__PURE__ */ jsx(
123
+ "div",
124
+ {
125
+ className: "h-40 animate-pulse rounded-lg border border-muted bg-surface/50"
126
+ },
127
+ entry.slug
128
+ ))
129
+ }
130
+ )
131
+ ] }),
132
+ packs !== null && /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-hsp-lg sm:grid-cols-2 lg:grid-cols-3", children: packs.map((meta) => /* @__PURE__ */ jsx(
133
+ ThemePackCard,
134
+ {
135
+ meta,
136
+ mode,
137
+ isActive: meta.slug === activeSlug,
138
+ onSelect: () => {
139
+ void applyThemePack(meta.slug);
140
+ }
141
+ },
142
+ meta.slug
143
+ )) })
144
+ ] }) })
145
+ ] })
146
+ }
147
+ );
148
+ }
149
+ ThemePackDialog.displayName = "ThemePackDialog";
150
+ export {
151
+ ThemePackDialog
152
+ };
@@ -0,0 +1,25 @@
1
+ /** @jsxRuntime automatic */
2
+ /** @jsxImportSource preact */
3
+ import type { VNode } from "preact";
4
+ import type { ThemePackMeta } from "../theme-packs-registry/index.js";
5
+ export interface ThemePackCardProps {
6
+ /** Full pack meta (incl. resolved preview swatches) for one registry entry. */
7
+ meta: ThemePackMeta;
8
+ /** Current light/dark UI mode — selects which `meta.preview` swatch set
9
+ * paints the card (NOT `meta.mode`, which is only the designed-primary
10
+ * badge shown alongside the name). */
11
+ mode: "light" | "dark";
12
+ /** Whether this card's pack is the currently active one (selected ring). */
13
+ isActive: boolean;
14
+ /** Apply this pack — the caller wires this to `applyThemePack(meta.slug)`;
15
+ * this component stays a plain presentational click forwarder. */
16
+ onSelect: () => void;
17
+ }
18
+ /**
19
+ * One theme-pack preview card: a mini "Aa Heading" / prose+link / code-line
20
+ * sample painted from `meta.preview[mode]`, plus name, Light/Dark badge, and
21
+ * description. Clicking applies the pack immediately (the dialog stays open
22
+ * — ADR Decision 7 — so the selected ring is driven by `isActive`, not by
23
+ * the click itself).
24
+ */
25
+ export declare function ThemePackCard({ meta, mode, isActive, onSelect }: ThemePackCardProps): VNode;
@@ -0,0 +1,72 @@
1
+ import { jsx, jsxs } from "preact/jsx-runtime";
2
+ function ThemePackCard({ meta, mode, isActive, onSelect }) {
3
+ const swatches = meta.preview[mode];
4
+ const fontCaption = meta.fonts.display ?? meta.fonts.sans;
5
+ return /* @__PURE__ */ jsxs(
6
+ "button",
7
+ {
8
+ type: "button",
9
+ onClick: onSelect,
10
+ "aria-pressed": isActive,
11
+ "aria-label": `Apply ${meta.name} theme pack \u2014 ${meta.mode === "dark" ? "Dark" : "Light"}. ${meta.description}`,
12
+ className: `flex flex-col gap-vsp-2xs rounded-lg border p-hsp-sm text-left transition-colors focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2 ${isActive ? "border-accent ring-2 ring-accent" : "border-muted hover:border-accent"}`,
13
+ children: [
14
+ /* @__PURE__ */ jsxs(
15
+ "div",
16
+ {
17
+ "aria-hidden": "true",
18
+ className: "flex flex-col gap-vsp-3xs rounded-md border p-hsp-sm",
19
+ style: {
20
+ backgroundColor: swatches.bg,
21
+ color: swatches.fg,
22
+ borderColor: `color-mix(in oklch, ${swatches.fg} 15%, transparent)`
23
+ },
24
+ children: [
25
+ /* @__PURE__ */ jsx("p", { className: "text-title font-bold", children: "Aa Heading" }),
26
+ /* @__PURE__ */ jsxs("p", { className: "text-small", children: [
27
+ "The quick brown fox jumps over",
28
+ " ",
29
+ /* @__PURE__ */ jsx("span", { className: "underline", style: { color: swatches.accent }, children: "the lazy dog" }),
30
+ "."
31
+ ] }),
32
+ /* @__PURE__ */ jsxs(
33
+ "p",
34
+ {
35
+ className: "rounded px-hsp-2xs py-hsp-3xs font-mono text-caption",
36
+ style: { backgroundColor: `color-mix(in oklch, ${swatches.fg} 8%, transparent)` },
37
+ children: [
38
+ /* @__PURE__ */ jsx("span", { style: { color: swatches.syntax.keyword }, children: "const" }),
39
+ " ",
40
+ /* @__PURE__ */ jsx("span", { style: { color: swatches.syntax.callable }, children: "theme" }),
41
+ " =",
42
+ " ",
43
+ /* @__PURE__ */ jsxs("span", { style: { color: swatches.syntax.string }, children: [
44
+ '"',
45
+ meta.slug,
46
+ '"'
47
+ ] }),
48
+ ";",
49
+ " ",
50
+ /* @__PURE__ */ jsxs("span", { style: { color: swatches.syntax.comment }, children: [
51
+ "// ",
52
+ meta.mode
53
+ ] })
54
+ ]
55
+ }
56
+ )
57
+ ]
58
+ }
59
+ ),
60
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-hsp-sm", children: [
61
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate text-body font-bold text-fg", children: meta.name }),
62
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 rounded-full border border-muted px-hsp-sm text-micro tracking-wide text-muted uppercase", children: meta.mode === "dark" ? "Dark" : "Light" })
63
+ ] }),
64
+ /* @__PURE__ */ jsx("p", { className: "text-caption text-muted", children: meta.description }),
65
+ /* @__PURE__ */ jsx("p", { className: "text-micro text-muted", children: fontCaption })
66
+ ]
67
+ }
68
+ );
69
+ }
70
+ export {
71
+ ThemePackCard
72
+ };
@@ -0,0 +1,49 @@
1
+ /** @jsxRuntime automatic */
2
+ /** @jsxImportSource preact */
3
+ import type { JSX } from "preact";
4
+ import { type ThemePackOrderEntry } from "./switcher-state.js";
5
+ export type { ThemePackOrderEntry } from "./switcher-state.js";
6
+ /**
7
+ * Island props (ADR Decision 7 "Switcher data flow") — serializable ONLY:
8
+ * they ride the island marker's `data-props` JSON across the SSR → hydrate
9
+ * boundary, so no functions/components may ever be added here.
10
+ */
11
+ export interface ThemePackSwitcherProps {
12
+ /** The SSR-known active pack slug (`settings.themePack`); the user's
13
+ * stored choice is synced from the DOM after hydration. */
14
+ active: string;
15
+ /** The resolved, enabled packs IN SWITCHER ORDER — the Prev/Next cycle
16
+ * order and the dialog grid order. */
17
+ order: ThemePackOrderEntry[];
18
+ /** Base prefix WITH trailing slash (`ctx.withBase("/")`) — forwarded to
19
+ * the browse-all dialog for its `{base}theme-packs/index.json` fetch. */
20
+ base: string;
21
+ }
22
+ /** Props of the browse-all dialog mounted through {@link ThemePackDialogSlot}
23
+ * — the #2825 contract. The dialog fetches `{base}theme-packs/index.json`
24
+ * lazily on first open for the full meta (preview swatches); cards apply
25
+ * via `applyThemePack(slug)` and the dialog stays open (ADR Decision 7). */
26
+ export interface ThemePackDialogProps {
27
+ /** Whether the dialog is currently open. */
28
+ open: boolean;
29
+ /** Close callback (Esc / ✕ / backdrop — the dialog's own close paths). */
30
+ onClose: () => void;
31
+ /** The switcher order — also the dialog grid order. */
32
+ order: ThemePackOrderEntry[];
33
+ /** Currently active pack slug (live — follows `theme-pack-changed`). */
34
+ active: string;
35
+ /** Base prefix WITH trailing slash for the `index.json` fetch. */
36
+ base: string;
37
+ }
38
+ /** The browse-all dialog component contract (#2825). */
39
+ export type ThemePackDialogComponent = (props: ThemePackDialogProps) => JSX.Element | null;
40
+ /**
41
+ * The bottom-right theme-pack switcher flyout. Mounted (settings-gated on
42
+ * `themePackSwitcher`) by the package body-end islands via
43
+ * `Island({ when: "load" })` — see
44
+ * `../doc-body-end-islands/theme-pack-switcher-island.tsx`.
45
+ */
46
+ export declare function ThemePackSwitcher({ active, order, base }: ThemePackSwitcherProps): JSX.Element;
47
+ export declare namespace ThemePackSwitcher {
48
+ var displayName: string;
49
+ }
@@ -0,0 +1,205 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "preact/jsx-runtime";
3
+ import { useEffect, useRef, useState } from "preact/hooks";
4
+ import { ChevronLeft, ChevronRight, Close } from "../icons/index.js";
5
+ import { ThemePackDialog } from "../theme-pack-dialog/index.js";
6
+ import { applyThemePack } from "./theme-pack-sync.js";
7
+ import {
8
+ connectActivePackSync,
9
+ connectEscapeToClose,
10
+ nextPackSlug,
11
+ prevPackSlug,
12
+ resolveActiveEntry
13
+ } from "./switcher-state.js";
14
+ const ThemePackDialogSlot = ThemePackDialog;
15
+ function GridIcon({ className }) {
16
+ return /* @__PURE__ */ jsxs(
17
+ "svg",
18
+ {
19
+ xmlns: "http://www.w3.org/2000/svg",
20
+ class: className || void 0,
21
+ fill: "none",
22
+ viewBox: "0 0 24 24",
23
+ stroke: "currentColor",
24
+ "stroke-width": "2",
25
+ "aria-hidden": "true",
26
+ children: [
27
+ /* @__PURE__ */ jsx("rect", { x: "4", y: "4", width: "7", height: "7", rx: "1" }),
28
+ /* @__PURE__ */ jsx("rect", { x: "13", y: "4", width: "7", height: "7", rx: "1" }),
29
+ /* @__PURE__ */ jsx("rect", { x: "4", y: "13", width: "7", height: "7", rx: "1" }),
30
+ /* @__PURE__ */ jsx("rect", { x: "13", y: "13", width: "7", height: "7", rx: "1" })
31
+ ]
32
+ }
33
+ );
34
+ }
35
+ function PaletteIcon({ className }) {
36
+ return /* @__PURE__ */ jsxs(
37
+ "svg",
38
+ {
39
+ xmlns: "http://www.w3.org/2000/svg",
40
+ class: className || void 0,
41
+ fill: "none",
42
+ viewBox: "0 0 24 24",
43
+ stroke: "currentColor",
44
+ "stroke-width": "2",
45
+ "aria-hidden": "true",
46
+ children: [
47
+ /* @__PURE__ */ jsx(
48
+ "path",
49
+ {
50
+ "stroke-linecap": "round",
51
+ "stroke-linejoin": "round",
52
+ d: "M12 21a9 9 0 1 1 9-9c0 2-1.5 3-3 3h-2a2 2 0 0 0-1.5 3.3c.5.6.2 1.7-.7 1.7H12z"
53
+ }
54
+ ),
55
+ /* @__PURE__ */ jsx("circle", { cx: "7.5", cy: "11.5", r: "1", fill: "currentColor", stroke: "none" }),
56
+ /* @__PURE__ */ jsx("circle", { cx: "10.5", cy: "7.5", r: "1", fill: "currentColor", stroke: "none" }),
57
+ /* @__PURE__ */ jsx("circle", { cx: "15", cy: "7.5", r: "1", fill: "currentColor", stroke: "none" })
58
+ ]
59
+ }
60
+ );
61
+ }
62
+ const CONTROL_BUTTON_CLASS = "flex items-center gap-hsp-xs rounded border border-muted bg-bg px-hsp-md py-hsp-2xs text-caption text-fg transition-colors hover:border-accent focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2 disabled:opacity-50 disabled:pointer-events-none";
63
+ const ICON_BUTTON_CLASS = "flex items-center justify-center rounded p-hsp-2xs text-muted transition-colors hover:text-fg focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2 disabled:opacity-50 disabled:pointer-events-none";
64
+ function ThemePackSwitcher({ active, order, base }) {
65
+ const [open, setOpen] = useState(false);
66
+ const [dialogOpen, setDialogOpen] = useState(false);
67
+ const [activeSlug, setActiveSlug] = useState(active);
68
+ const launcherRef = useRef(null);
69
+ const cardRef = useRef(null);
70
+ useEffect(() => connectActivePackSync(setActiveSlug), []);
71
+ useEffect(() => {
72
+ if (!open || dialogOpen) return void 0;
73
+ return connectEscapeToClose(() => {
74
+ setOpen(false);
75
+ launcherRef.current?.focus();
76
+ });
77
+ }, [open, dialogOpen]);
78
+ useEffect(() => {
79
+ if (open) cardRef.current?.focus();
80
+ }, [open]);
81
+ const entry = resolveActiveEntry(order, activeSlug);
82
+ function cycle(step) {
83
+ const target = step === 1 ? nextPackSlug(order, activeSlug) : prevPackSlug(order, activeSlug);
84
+ if (target !== null && target !== activeSlug) void applyThemePack(target);
85
+ }
86
+ function closeCard() {
87
+ setOpen(false);
88
+ launcherRef.current?.focus();
89
+ }
90
+ function openDialog() {
91
+ setOpen(false);
92
+ setDialogOpen(true);
93
+ }
94
+ return /* @__PURE__ */ jsxs(
95
+ "div",
96
+ {
97
+ class: "fixed right-hsp-lg bottom-hsp-lg z-popover flex flex-col items-end gap-vsp-2xs",
98
+ "data-theme-pack-switcher": true,
99
+ children: [
100
+ open ? /* @__PURE__ */ jsxs(
101
+ "div",
102
+ {
103
+ ref: cardRef,
104
+ tabIndex: -1,
105
+ role: "dialog",
106
+ "aria-label": "Theme pack switcher",
107
+ "data-switcher-card": true,
108
+ class: "flex w-72 max-w-[calc(100vw-2rem)] flex-col gap-vsp-2xs rounded-lg border border-muted bg-surface p-hsp-lg shadow-lg focus-visible:outline-2 focus-visible:outline-accent",
109
+ children: [
110
+ /* @__PURE__ */ jsxs("div", { class: "flex items-start justify-between gap-hsp-sm", children: [
111
+ /* @__PURE__ */ jsx("p", { class: "min-w-0 break-words text-body font-bold text-fg", "aria-live": "polite", children: entry?.name ?? activeSlug }),
112
+ /* @__PURE__ */ jsxs("div", { class: "flex shrink-0 items-center gap-hsp-2xs", children: [
113
+ /* @__PURE__ */ jsx(
114
+ "button",
115
+ {
116
+ type: "button",
117
+ "aria-label": "Browse all theme packs",
118
+ title: "Browse all theme packs",
119
+ disabled: ThemePackDialogSlot === null,
120
+ onClick: openDialog,
121
+ class: ICON_BUTTON_CLASS,
122
+ children: /* @__PURE__ */ jsx(GridIcon, { className: "h-icon-sm w-icon-sm" })
123
+ }
124
+ ),
125
+ /* @__PURE__ */ jsx(
126
+ "button",
127
+ {
128
+ type: "button",
129
+ "aria-label": "Close theme pack switcher",
130
+ title: "Close",
131
+ onClick: closeCard,
132
+ class: ICON_BUTTON_CLASS,
133
+ children: /* @__PURE__ */ jsx(Close, { className: "h-icon-sm w-icon-sm" })
134
+ }
135
+ )
136
+ ] })
137
+ ] }),
138
+ entry !== null && /* @__PURE__ */ jsx("span", { class: "self-start rounded-full border border-muted px-hsp-sm text-micro tracking-wide text-muted uppercase", children: entry.mode === "dark" ? "Dark" : "Light" }),
139
+ entry !== null && entry.description !== "" && /* @__PURE__ */ jsx("p", { class: "text-caption text-muted", children: entry.description }),
140
+ /* @__PURE__ */ jsxs("div", { class: "flex items-center justify-between gap-hsp-sm", children: [
141
+ /* @__PURE__ */ jsxs(
142
+ "button",
143
+ {
144
+ type: "button",
145
+ "aria-label": "Previous theme pack",
146
+ disabled: order.length < 2,
147
+ onClick: () => cycle(-1),
148
+ class: CONTROL_BUTTON_CLASS,
149
+ children: [
150
+ /* @__PURE__ */ jsx(ChevronLeft, { className: "h-icon-xs w-icon-xs" }),
151
+ "Prev"
152
+ ]
153
+ }
154
+ ),
155
+ /* @__PURE__ */ jsxs(
156
+ "button",
157
+ {
158
+ type: "button",
159
+ "aria-label": "Next theme pack",
160
+ disabled: order.length < 2,
161
+ onClick: () => cycle(1),
162
+ class: CONTROL_BUTTON_CLASS,
163
+ children: [
164
+ "Next",
165
+ /* @__PURE__ */ jsx(ChevronRight, { className: "h-icon-xs w-icon-xs" })
166
+ ]
167
+ }
168
+ )
169
+ ] })
170
+ ]
171
+ }
172
+ ) : null,
173
+ /* @__PURE__ */ jsx(
174
+ "button",
175
+ {
176
+ ref: launcherRef,
177
+ type: "button",
178
+ "aria-haspopup": "dialog",
179
+ "aria-expanded": open,
180
+ "aria-label": "Theme pack switcher",
181
+ title: "Theme packs",
182
+ "data-switcher-launcher": true,
183
+ onClick: () => setOpen(!open),
184
+ class: "flex h-10 w-10 items-center justify-center rounded-full border border-muted bg-surface text-fg shadow-lg transition-colors hover:text-accent focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2",
185
+ children: /* @__PURE__ */ jsx(PaletteIcon, { className: "h-icon-md w-icon-md" })
186
+ }
187
+ ),
188
+ ThemePackDialogSlot !== null ? /* @__PURE__ */ jsx(
189
+ ThemePackDialogSlot,
190
+ {
191
+ open: dialogOpen,
192
+ onClose: () => setDialogOpen(false),
193
+ order,
194
+ active: activeSlug,
195
+ base
196
+ }
197
+ ) : null
198
+ ]
199
+ }
200
+ );
201
+ }
202
+ ThemePackSwitcher.displayName = "ThemePackSwitcher";
203
+ export {
204
+ ThemePackSwitcher
205
+ };
@@ -0,0 +1,56 @@
1
+ /**
2
+ * One entry of the flyout's SSR-provided `order` prop — the lightweight
3
+ * projection of a registry entry's meta (ADR Decision 7 "Switcher data
4
+ * flow": `{ slug, name, mode, description }`). The array order IS the
5
+ * Prev/Next cycle order (and the dialog grid order).
6
+ */
7
+ export interface ThemePackOrderEntry {
8
+ /** Pack slug (`meta.slug` — equals the pack's directory name). */
9
+ slug: string;
10
+ /** Display name shown as the flyout card title. */
11
+ name: string;
12
+ /** Designed-primary mode badge — a badge, not a capability flag. */
13
+ mode: "light" | "dark";
14
+ /** 1–2 sentence note shown under the title. */
15
+ description: string;
16
+ }
17
+ /**
18
+ * Resolve the cycle target `step` away from `active` in `order`, wrapping
19
+ * around at both ends (ADR Decision 7: "Ordering IS the switcher order",
20
+ * Prev/Next cycle with wraparound).
21
+ *
22
+ * - Empty `order` → `null` (nothing to cycle to).
23
+ * - `active` not present in `order` (e.g. the html attribute carries a slug
24
+ * the switcher was not configured with) → the first entry for `+1`, the
25
+ * last for `-1`, so the UI recovers onto the cycle instead of dead-ending.
26
+ */
27
+ export declare function cyclePackSlug(order: readonly ThemePackOrderEntry[], active: string, step: 1 | -1): string | null;
28
+ /** The Prev/Next cycle target after `active` (wraparound). */
29
+ export declare function nextPackSlug(order: readonly ThemePackOrderEntry[], active: string): string | null;
30
+ /** The Prev/Next cycle target before `active` (wraparound). */
31
+ export declare function prevPackSlug(order: readonly ThemePackOrderEntry[], active: string): string | null;
32
+ /**
33
+ * The `order` entry matching `active`, or `null` when the active slug is not
34
+ * part of the switcher order (the card then falls back to showing the bare
35
+ * slug with no badge/description).
36
+ */
37
+ export declare function resolveActiveEntry(order: readonly ThemePackOrderEntry[], active: string): ThemePackOrderEntry | null;
38
+ /**
39
+ * Connect a state setter to the live active-pack source of truth: push the
40
+ * CURRENT DOM value once immediately, then re-push on every
41
+ * `theme-pack-changed` event so multiple mounted surfaces (flyout, dialog, a
42
+ * future header trigger) never disagree — the ThemeToggle cross-instance
43
+ * sync pattern (#2012 E3). Returns an unsubscribe function suitable as a
44
+ * `useEffect` cleanup.
45
+ *
46
+ * Note the display state only ever advances FROM this event: a failed or
47
+ * aborted `applyThemePack` never fires it, so the UI never shows a pack that
48
+ * did not commit (ADR Decision 3 failure semantics).
49
+ */
50
+ export declare function connectActivePackSync(onActive: (slug: string) => void): () => void;
51
+ /**
52
+ * Register a document-level Escape handler (used while the flyout card is
53
+ * open — close on Escape, acceptance criterion of #2821). Returns the
54
+ * matching teardown, suitable as a `useEffect` cleanup.
55
+ */
56
+ export declare function connectEscapeToClose(onEscape: () => void): () => void;