blume 2.0.1 → 2.0.3

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 (492) hide show
  1. package/CHANGELOG.md +147 -0
  2. package/dist/cli/{chunk-qwsrynx5.js → chunk-1d7ve1dm.js} +38 -19
  3. package/dist/cli/{chunk-qwsrynx5.js.map → chunk-1d7ve1dm.js.map} +4 -4
  4. package/dist/cli/{chunk-s6jhgk0q.js → chunk-2eytanqx.js} +2 -2
  5. package/dist/cli/{chunk-kdp5q7ke.js → chunk-2hsdwb9n.js} +18 -19
  6. package/dist/cli/{chunk-kdp5q7ke.js.map → chunk-2hsdwb9n.js.map} +2 -2
  7. package/dist/cli/{chunk-hdpx1tax.js → chunk-2z928egk.js} +5 -5
  8. package/dist/cli/{chunk-jwyddg7y.js → chunk-35d4wj9f.js} +30 -24
  9. package/dist/cli/chunk-35d4wj9f.js.map +15 -0
  10. package/dist/cli/{chunk-ah61y8py.js → chunk-364znk6q.js} +2 -2
  11. package/dist/cli/{chunk-jts8mvcz.js → chunk-3em5wd2y.js} +25 -6
  12. package/dist/cli/{chunk-jts8mvcz.js.map → chunk-3em5wd2y.js.map} +3 -3
  13. package/dist/cli/{chunk-s1p84fyh.js → chunk-5f86nr5m.js} +63 -22
  14. package/dist/cli/chunk-5f86nr5m.js.map +11 -0
  15. package/dist/cli/{chunk-2hn4b8z7.js → chunk-5m5nmvyq.js} +170 -76
  16. package/dist/cli/chunk-5m5nmvyq.js.map +13 -0
  17. package/dist/cli/{chunk-epjnccmv.js → chunk-5xvm6tfj.js} +18 -15
  18. package/dist/cli/chunk-5xvm6tfj.js.map +10 -0
  19. package/dist/cli/{chunk-fz5wtpmh.js → chunk-6dsbexzp.js} +18 -15
  20. package/dist/cli/chunk-6dsbexzp.js.map +10 -0
  21. package/dist/cli/{chunk-vtk4a6dg.js → chunk-8ktnccpt.js} +1 -1
  22. package/dist/cli/{chunk-6hsn950k.js → chunk-9t7a85s3.js} +178 -48
  23. package/dist/cli/chunk-9t7a85s3.js.map +10 -0
  24. package/dist/cli/{chunk-fxypxtvm.js → chunk-a58773jm.js} +2 -2
  25. package/dist/cli/{chunk-mb2919y2.js → chunk-acanzt5p.js} +17 -6
  26. package/dist/cli/chunk-acanzt5p.js.map +10 -0
  27. package/dist/cli/{chunk-27g6wdth.js → chunk-akbpwfxc.js} +90 -26
  28. package/dist/cli/chunk-akbpwfxc.js.map +10 -0
  29. package/dist/cli/{chunk-wm7js3j9.js → chunk-b07cmahc.js} +2 -2
  30. package/dist/cli/{chunk-wgm7m9qk.js → chunk-c8chx29p.js} +179 -51
  31. package/dist/cli/chunk-c8chx29p.js.map +36 -0
  32. package/dist/cli/{chunk-qs4q5p4e.js → chunk-crgn1q09.js} +32 -14
  33. package/dist/cli/chunk-crgn1q09.js.map +10 -0
  34. package/dist/cli/chunk-e04dxsz1.js +39 -0
  35. package/dist/cli/chunk-e04dxsz1.js.map +10 -0
  36. package/dist/cli/{chunk-yt5n7ppj.js → chunk-ey84smr6.js} +17 -7
  37. package/dist/cli/chunk-ey84smr6.js.map +10 -0
  38. package/dist/cli/{chunk-f2z5v128.js → chunk-g4hq16wv.js} +14 -15
  39. package/dist/cli/{chunk-f2z5v128.js.map → chunk-g4hq16wv.js.map} +2 -2
  40. package/dist/cli/{chunk-fa25z98p.js → chunk-ga0pf4aj.js} +9 -8
  41. package/dist/cli/chunk-ga0pf4aj.js.map +11 -0
  42. package/dist/cli/{chunk-kpf8rrjc.js → chunk-hm3vjy5s.js} +109 -58
  43. package/dist/cli/chunk-hm3vjy5s.js.map +19 -0
  44. package/dist/cli/{chunk-fs23ddbb.js → chunk-j85vccga.js} +625 -750
  45. package/dist/cli/chunk-j85vccga.js.map +36 -0
  46. package/dist/cli/{chunk-ch6g3ar0.js → chunk-p3v96n38.js} +6 -6
  47. package/dist/cli/{chunk-ch6g3ar0.js.map → chunk-p3v96n38.js.map} +3 -3
  48. package/dist/cli/{chunk-q5163e60.js → chunk-p73c0m7w.js} +21 -19
  49. package/dist/cli/chunk-p73c0m7w.js.map +11 -0
  50. package/dist/cli/{chunk-dh8cwk36.js → chunk-pehfxfta.js} +24 -9
  51. package/dist/cli/chunk-pehfxfta.js.map +10 -0
  52. package/dist/cli/{chunk-qkqwkpte.js → chunk-pv29h0wf.js} +3688 -1313
  53. package/dist/cli/chunk-pv29h0wf.js.map +190 -0
  54. package/dist/cli/{chunk-6vm74dry.js → chunk-q58y5e6a.js} +10 -10
  55. package/dist/cli/{chunk-6vm74dry.js.map → chunk-q58y5e6a.js.map} +3 -3
  56. package/dist/cli/{chunk-zxcczpyx.js → chunk-r20tn01b.js} +1 -1
  57. package/dist/cli/{chunk-m3vmjgmq.js → chunk-r9rcc4w7.js} +16 -8
  58. package/dist/cli/chunk-r9rcc4w7.js.map +10 -0
  59. package/dist/cli/{chunk-5shv93fd.js → chunk-tkacnehg.js} +2 -2
  60. package/dist/cli/{chunk-zxh4d9vy.js → chunk-tzmab476.js} +4 -4
  61. package/dist/cli/{chunk-yw7dm696.js → chunk-vg9r4eb9.js} +24 -11
  62. package/dist/cli/chunk-vg9r4eb9.js.map +14 -0
  63. package/dist/cli/{chunk-79jhk4py.js → chunk-wrr3j9w9.js} +260 -132
  64. package/dist/cli/chunk-wrr3j9w9.js.map +35 -0
  65. package/dist/cli/{chunk-6crbhc3x.js → chunk-yfyb25rh.js} +54 -27
  66. package/dist/cli/chunk-yfyb25rh.js.map +14 -0
  67. package/dist/cli/index.js +162 -35
  68. package/dist/cli/index.js.map +4 -4
  69. package/dist/types/ai/agent-surface.d.ts +32 -0
  70. package/dist/types/ai/api-catalog.d.ts +7 -1
  71. package/dist/types/ai/ask-context.d.ts +7 -0
  72. package/dist/types/ai/component-markdown.d.ts +4 -4
  73. package/dist/types/ai/link-headers.d.ts +8 -1
  74. package/dist/types/ai/openapi-components.d.ts +5 -2
  75. package/dist/types/ai/relative-links.d.ts +11 -4
  76. package/dist/types/ai/skills.d.ts +4 -1
  77. package/dist/types/ai/static-expression.d.ts +28 -0
  78. package/dist/types/ai/tar.d.ts +1 -3
  79. package/dist/types/analytics/databuddy.d.ts +43 -0
  80. package/dist/types/analytics/index.d.ts +4 -0
  81. package/dist/types/analytics/one-dollar-stats.d.ts +48 -0
  82. package/dist/types/analytics/schema.d.ts +28 -0
  83. package/dist/types/astro/integration.d.ts +3 -2
  84. package/dist/types/cli/env.d.ts +5 -0
  85. package/dist/types/cli/init/scaffold.d.ts +19 -3
  86. package/dist/types/cli/init/starter-spec.d.ts +11 -0
  87. package/dist/types/core/base-path.d.ts +24 -1
  88. package/dist/types/core/config-input.d.ts +13 -11
  89. package/dist/types/core/config.d.ts +2 -2
  90. package/dist/types/core/directive-diagnostics.d.ts +12 -0
  91. package/dist/types/core/graph.d.ts +2 -0
  92. package/dist/types/core/heading-markers.d.ts +5 -7
  93. package/dist/types/core/i18n-ui.d.ts +31 -0
  94. package/dist/types/core/i18n.d.ts +9 -1
  95. package/dist/types/core/last-modified.d.ts +10 -0
  96. package/dist/types/core/links.d.ts +3 -1
  97. package/dist/types/core/load-module.d.ts +10 -0
  98. package/dist/types/core/locale-links.d.ts +12 -2
  99. package/dist/types/core/meta.d.ts +13 -1
  100. package/dist/types/core/nav-diagnostics.d.ts +10 -0
  101. package/dist/types/core/navigation.d.ts +38 -0
  102. package/dist/types/core/ordering-prefix.d.ts +4 -0
  103. package/dist/types/core/safe-links.d.ts +3 -1
  104. package/dist/types/core/schema.d.ts +59 -13
  105. package/dist/types/core/sources/github-releases.d.ts +5 -0
  106. package/dist/types/core/sources/lower.d.ts +38 -13
  107. package/dist/types/core/sources/normalize.d.ts +23 -2
  108. package/dist/types/core/sources/remote.d.ts +11 -1
  109. package/dist/types/core/sources/resolve.d.ts +12 -0
  110. package/dist/types/core/sources/types.d.ts +31 -0
  111. package/dist/types/core/sources/watch.d.ts +12 -5
  112. package/dist/types/core/standard-schema.d.ts +5 -0
  113. package/dist/types/core/types.d.ts +9 -0
  114. package/dist/types/deploy/adapters/node.d.ts +5 -2
  115. package/dist/types/deploy/adapters/types.d.ts +7 -0
  116. package/dist/types/deploy/artifacts.d.ts +6 -4
  117. package/dist/types/deploy/cloudflare-negotiation.d.ts +3 -2
  118. package/dist/types/deploy/headers.d.ts +36 -7
  119. package/dist/types/deploy/node-headers.d.ts +43 -8
  120. package/dist/types/deploy/platforms/netlify.d.ts +27 -2
  121. package/dist/types/deploy/platforms/node.d.ts +6 -5
  122. package/dist/types/deploy/platforms/types.d.ts +15 -0
  123. package/dist/types/deploy/platforms/vercel.d.ts +3 -2
  124. package/dist/types/deploy/redirects.d.ts +31 -15
  125. package/dist/types/deploy/vercel-negotiation.d.ts +3 -2
  126. package/dist/types/markdown/directives.d.ts +62 -0
  127. package/dist/types/markdown/features.d.ts +21 -0
  128. package/dist/types/markdown/mdast.d.ts +63 -0
  129. package/dist/types/openapi/asyncapi.d.ts +4 -2
  130. package/dist/types/openapi/model.d.ts +20 -6
  131. package/dist/types/search/sync/algolia.d.ts +3 -1
  132. package/docs/01-quickstart.mdx +3 -2
  133. package/docs/02-deployment.mdx +20 -9
  134. package/docs/08-faq.mdx +10 -3
  135. package/docs/advanced/changelog.mdx +1 -1
  136. package/docs/advanced/custom-pages.mdx +7 -5
  137. package/docs/cli/audit.mdx +19 -3
  138. package/docs/cli/doctor.mdx +2 -2
  139. package/docs/cli/evals.mdx +4 -4
  140. package/docs/cli/index.mdx +4 -1
  141. package/docs/cli/translate.mdx +4 -4
  142. package/docs/cli/version.mdx +1 -1
  143. package/docs/configuration/analytics.mdx +42 -2
  144. package/docs/configuration/assistant.mdx +1 -1
  145. package/docs/configuration/customization.mdx +6 -3
  146. package/docs/configuration/index.mdx +5 -3
  147. package/docs/configuration/search.mdx +2 -2
  148. package/docs/content/components.mdx +2 -2
  149. package/docs/content/frontmatter.mdx +5 -1
  150. package/docs/content/i18n.mdx +3 -1
  151. package/docs/content/index.mdx +8 -4
  152. package/docs/content/islands.mdx +1 -1
  153. package/docs/content/meta.mdx +7 -3
  154. package/docs/content/navigation.mdx +29 -4
  155. package/docs/content/sources.mdx +18 -16
  156. package/docs/content/syntax.mdx +14 -0
  157. package/docs/content/versioning.mdx +2 -1
  158. package/docs/discoverability/agent-discovery.mdx +22 -8
  159. package/docs/discoverability/index.mdx +4 -3
  160. package/docs/discoverability/llms-txt.mdx +2 -5
  161. package/docs/discoverability/markdown.mdx +6 -4
  162. package/docs/discoverability/mcp.mdx +4 -0
  163. package/docs/discoverability/metadata.mdx +3 -2
  164. package/docs/discoverability/open-graph.mdx +8 -4
  165. package/docs/discoverability/rss.mdx +4 -2
  166. package/docs/references/asyncapi.mdx +2 -2
  167. package/docs/references/graphql.mdx +2 -2
  168. package/docs/references/openapi.mdx +6 -4
  169. package/package.json +1 -1
  170. package/skills/blume-migrate/SKILL.md +6 -6
  171. package/skills/blume-migrate/references/docusaurus.md +6 -6
  172. package/skills/blume-migrate/references/fumadocs.md +1 -1
  173. package/skills/blume-migrate/references/mintlify.md +3 -3
  174. package/skills/blume-migrate/references/monorepo.md +1 -1
  175. package/skills/blume-migrate/references/nextra.md +2 -2
  176. package/skills/blume-migrate/references/starlight.md +5 -5
  177. package/skills/blume-migrate/scripts/mintlify-codemod.mjs +9 -4
  178. package/skills/blume-update-docs/references/audit-checklist.md +1 -1
  179. package/src/ai/agent-readability.ts +2 -2
  180. package/src/ai/agent-surface.ts +56 -0
  181. package/src/ai/ai-catalog.ts +6 -2
  182. package/src/ai/api/handlers.ts +2 -2
  183. package/src/ai/api/spec.ts +17 -4
  184. package/src/ai/api-catalog.ts +13 -3
  185. package/src/ai/ask-context.ts +14 -2
  186. package/src/ai/ask-data.ts +26 -12
  187. package/src/ai/changelog-markdown.ts +2 -2
  188. package/src/ai/component-markdown.ts +43 -37
  189. package/src/ai/link-headers.ts +22 -8
  190. package/src/ai/llms.ts +22 -10
  191. package/src/ai/markdown.ts +23 -11
  192. package/src/ai/mcp/discovery.ts +2 -2
  193. package/src/ai/mcp/query.ts +2 -2
  194. package/src/ai/mcp/server.ts +80 -9
  195. package/src/ai/openapi-components.ts +22 -6
  196. package/src/ai/relative-links.ts +99 -15
  197. package/src/ai/serializers.ts +2 -1
  198. package/src/ai/skills.ts +14 -1
  199. package/src/ai/static-expression.ts +416 -0
  200. package/src/ai/tar.ts +139 -12
  201. package/src/ai/visibility.ts +45 -14
  202. package/src/analytics/databuddy.ts +67 -0
  203. package/src/analytics/head.ts +8 -0
  204. package/src/analytics/index.ts +7 -0
  205. package/src/analytics/one-dollar-stats.ts +86 -0
  206. package/src/analytics/posthog.ts +21 -3
  207. package/src/analytics/schema.ts +4 -0
  208. package/src/astro/generate.ts +72 -28
  209. package/src/astro/include-hmr.ts +31 -12
  210. package/src/astro/include-refresh.ts +19 -8
  211. package/src/astro/integration.ts +108 -14
  212. package/src/astro/runtime-modules.ts +28 -13
  213. package/src/astro/templates.ts +139 -57
  214. package/src/audit/catalog.ts +2 -2
  215. package/src/audit/checks/assets.ts +25 -5
  216. package/src/audit/checks/content.ts +20 -2
  217. package/src/audit/checks/i18n.ts +46 -8
  218. package/src/audit/checks/indexability.ts +39 -19
  219. package/src/audit/checks/links.ts +22 -1
  220. package/src/audit/checks/llms.ts +6 -3
  221. package/src/audit/checks/network.ts +3 -1
  222. package/src/audit/checks/og-image.ts +10 -0
  223. package/src/audit/checks/robots.ts +6 -1
  224. package/src/audit/checks/sitemap.ts +56 -31
  225. package/src/audit/checks/social.ts +21 -2
  226. package/src/audit/crawl.ts +88 -15
  227. package/src/audit/graph.ts +3 -1
  228. package/src/audit/report.ts +54 -17
  229. package/src/audit/run.ts +13 -9
  230. package/src/audit/snapshot.ts +5 -0
  231. package/src/audit/types.ts +18 -0
  232. package/src/audit/url.ts +37 -6
  233. package/src/cli/args.ts +32 -0
  234. package/src/cli/build-failure.ts +50 -0
  235. package/src/cli/commands/audit.ts +11 -1
  236. package/src/cli/commands/build.ts +19 -5
  237. package/src/cli/commands/check.ts +2 -0
  238. package/src/cli/commands/doctor.ts +3 -1
  239. package/src/cli/commands/eval.ts +20 -18
  240. package/src/cli/commands/init.ts +15 -5
  241. package/src/cli/commands/preview.ts +15 -0
  242. package/src/cli/commands/sync.ts +2 -0
  243. package/src/cli/commands/translate.ts +18 -18
  244. package/src/cli/commands/upgrade.ts +11 -0
  245. package/src/cli/commands/validate.ts +3 -1
  246. package/src/cli/dev-lock.ts +157 -37
  247. package/src/cli/eject-scripts.ts +32 -7
  248. package/src/cli/env.ts +12 -1
  249. package/src/cli/init/scaffold.ts +117 -11
  250. package/src/cli/init/starter-spec.ts +235 -0
  251. package/src/cli/report-format.ts +11 -6
  252. package/src/components/colors.ts +19 -0
  253. package/src/components/content/AccordionItem.astro +26 -22
  254. package/src/components/content/Badge.astro +7 -12
  255. package/src/components/content/Card.astro +2 -2
  256. package/src/components/content/Component.astro +11 -5
  257. package/src/components/content/Expandable.astro +5 -1
  258. package/src/components/content/Frame.astro +2 -7
  259. package/src/components/content/GithubInfo.astro +12 -2
  260. package/src/components/content/Prompt.astro +2 -7
  261. package/src/components/content/Tab.astro +0 -1
  262. package/src/components/content/Tabs.astro +58 -5
  263. package/src/components/content/Tile.astro +1 -1
  264. package/src/components/content/Tooltip.astro +69 -7
  265. package/src/components/content/Tree.astro +7 -2
  266. package/src/components/content/TypeTable.astro +10 -5
  267. package/src/components/content/Update.astro +8 -2
  268. package/src/components/content/auto-type-table.ts +4 -1
  269. package/src/components/content/badge-color.ts +20 -0
  270. package/src/components/content/base-href.ts +14 -22
  271. package/src/components/content/inline-markdown.ts +27 -7
  272. package/src/components/copy-feedback.ts +35 -8
  273. package/src/components/islands/assistant.tsx +37 -6
  274. package/src/components/islands/base-path.ts +47 -10
  275. package/src/components/islands/hooks.ts +42 -21
  276. package/src/components/islands/webmcp.ts +16 -10
  277. package/src/components/layout/Banner.astro +23 -4
  278. package/src/components/layout/Breadcrumbs.astro +5 -2
  279. package/src/components/layout/DiscoveryLinks.astro +9 -5
  280. package/src/components/layout/Header.astro +23 -10
  281. package/src/components/layout/LanguageSwitcher.astro +2 -2
  282. package/src/components/layout/Logo.astro +5 -0
  283. package/src/components/layout/NavSelector.astro +8 -3
  284. package/src/components/layout/NavTabMenu.astro +133 -0
  285. package/src/components/layout/NavTree.astro +31 -12
  286. package/src/components/layout/NavTreeCache.astro +5 -2
  287. package/src/components/layout/NavTreeScript.astro +45 -5
  288. package/src/components/layout/PageActions.astro +4 -3
  289. package/src/components/layout/PageLayout.astro +28 -13
  290. package/src/components/layout/Pagination.astro +3 -3
  291. package/src/components/layout/ReferenceLayout.astro +4 -1
  292. package/src/components/layout/RootLayout.astro +25 -12
  293. package/src/components/layout/Search.astro +38 -14
  294. package/src/components/layout/VersionBanner.astro +2 -2
  295. package/src/components/layout/analytics-client.ts +14 -0
  296. package/src/components/layout/toc-active.ts +41 -0
  297. package/src/components/layout/toc-element.ts +8 -14
  298. package/src/components/openapi/ApiTagOperations.astro +2 -2
  299. package/src/components/openapi/AsyncApiOperation.astro +7 -4
  300. package/src/components/openapi/GraphqlChip.astro +2 -2
  301. package/src/components/openapi/GraphqlType.astro +11 -3
  302. package/src/components/openapi/MessageComposer.astro +1 -1
  303. package/src/components/openapi/Operation.astro +23 -5
  304. package/src/components/openapi/PanelTabs.astro +4 -1
  305. package/src/components/openapi/Playground.astro +8 -2
  306. package/src/components/openapi/RequestPanel.astro +13 -6
  307. package/src/components/openapi/SchemaProperty.astro +11 -33
  308. package/src/components/openapi/SchemaTable.astro +34 -52
  309. package/src/components/openapi/async.ts +38 -6
  310. package/src/components/openapi/helpers.ts +100 -12
  311. package/src/components/openapi/message-composer.ts +14 -1
  312. package/src/components/openapi/message-model.ts +12 -2
  313. package/src/components/openapi/message.ts +21 -3
  314. package/src/components/openapi/operation-model.ts +119 -17
  315. package/src/components/openapi/panel.ts +31 -5
  316. package/src/components/openapi/param-style.ts +181 -0
  317. package/src/components/openapi/playground-client.ts +110 -23
  318. package/src/components/openapi/playground-schema.ts +25 -6
  319. package/src/components/openapi/request.ts +192 -26
  320. package/src/components/openapi/schema-tree.ts +209 -0
  321. package/src/components/openapi/snippets.ts +113 -19
  322. package/src/components/openapi/validate-json.ts +1 -1
  323. package/src/components/openapi/ws-client.ts +18 -2
  324. package/src/core/base-path.ts +69 -8
  325. package/src/core/config-input.ts +13 -11
  326. package/src/core/config.ts +18 -4
  327. package/src/core/diagnostics.ts +219 -30
  328. package/src/core/directive-diagnostics.ts +99 -0
  329. package/src/core/frontmatter.ts +21 -18
  330. package/src/core/graph.ts +120 -11
  331. package/src/core/heading-markers.ts +5 -18
  332. package/src/core/i18n-ui.ts +39 -2
  333. package/src/core/i18n.ts +44 -5
  334. package/src/core/last-modified.ts +25 -3
  335. package/src/core/links.ts +7 -4
  336. package/src/core/load-module.ts +20 -0
  337. package/src/core/locale-links.ts +22 -18
  338. package/src/core/manifest.ts +3 -2
  339. package/src/core/meta.ts +89 -12
  340. package/src/core/nav-diagnostics.ts +56 -1
  341. package/src/core/navigation.ts +272 -83
  342. package/src/core/ordering-prefix.ts +27 -0
  343. package/src/core/project-graph.ts +50 -6
  344. package/src/core/safe-href.ts +53 -1
  345. package/src/core/safe-links.ts +11 -2
  346. package/src/core/schema.ts +94 -18
  347. package/src/core/sources/assets.ts +83 -41
  348. package/src/core/sources/contentful-rich-text.ts +28 -20
  349. package/src/core/sources/contentful.ts +25 -12
  350. package/src/core/sources/filesystem.ts +25 -3
  351. package/src/core/sources/github-releases.ts +131 -11
  352. package/src/core/sources/lexical.ts +30 -20
  353. package/src/core/sources/lower.ts +276 -56
  354. package/src/core/sources/mdx-remote.ts +52 -16
  355. package/src/core/sources/normalize.ts +456 -119
  356. package/src/core/sources/notion.ts +77 -34
  357. package/src/core/sources/obsidian.ts +40 -9
  358. package/src/core/sources/payload.ts +1 -0
  359. package/src/core/sources/portable-text.ts +85 -49
  360. package/src/core/sources/remote.ts +18 -2
  361. package/src/core/sources/resolve.ts +52 -33
  362. package/src/core/sources/sanity.ts +1 -0
  363. package/src/core/sources/strapi-blocks.ts +28 -19
  364. package/src/core/sources/strapi.ts +1 -0
  365. package/src/core/sources/types.ts +31 -0
  366. package/src/core/sources/watch.ts +20 -7
  367. package/src/core/standard-schema.ts +10 -6
  368. package/src/core/types.ts +9 -0
  369. package/src/core/ui-packs/ar.ts +13 -0
  370. package/src/core/ui-packs/bg.ts +13 -0
  371. package/src/core/ui-packs/bn.ts +13 -0
  372. package/src/core/ui-packs/ca.ts +13 -0
  373. package/src/core/ui-packs/cs.ts +13 -0
  374. package/src/core/ui-packs/da.ts +13 -0
  375. package/src/core/ui-packs/de.ts +13 -0
  376. package/src/core/ui-packs/el.ts +13 -0
  377. package/src/core/ui-packs/es.ts +13 -0
  378. package/src/core/ui-packs/fa.ts +13 -0
  379. package/src/core/ui-packs/fi.ts +13 -0
  380. package/src/core/ui-packs/fr.ts +13 -0
  381. package/src/core/ui-packs/he.ts +13 -0
  382. package/src/core/ui-packs/hi.ts +13 -0
  383. package/src/core/ui-packs/hr.ts +13 -0
  384. package/src/core/ui-packs/hu.ts +13 -0
  385. package/src/core/ui-packs/id.ts +13 -0
  386. package/src/core/ui-packs/it.ts +13 -0
  387. package/src/core/ui-packs/ja.ts +13 -0
  388. package/src/core/ui-packs/ko.ts +13 -0
  389. package/src/core/ui-packs/nl.ts +13 -0
  390. package/src/core/ui-packs/no.ts +13 -0
  391. package/src/core/ui-packs/pl.ts +13 -0
  392. package/src/core/ui-packs/pt-br.ts +13 -0
  393. package/src/core/ui-packs/pt.ts +13 -0
  394. package/src/core/ui-packs/ro.ts +13 -0
  395. package/src/core/ui-packs/ru.ts +13 -0
  396. package/src/core/ui-packs/sk.ts +13 -0
  397. package/src/core/ui-packs/sr.ts +13 -0
  398. package/src/core/ui-packs/sv.ts +13 -0
  399. package/src/core/ui-packs/th.ts +13 -0
  400. package/src/core/ui-packs/tr.ts +13 -0
  401. package/src/core/ui-packs/uk.ts +13 -0
  402. package/src/core/ui-packs/vi.ts +13 -0
  403. package/src/core/ui-packs/zh-tw.ts +13 -0
  404. package/src/core/ui-packs/zh.ts +13 -0
  405. package/src/core/version-cut.ts +69 -17
  406. package/src/core/versions.ts +4 -1
  407. package/src/deploy/adapters/node.ts +5 -2
  408. package/src/deploy/adapters/registry.ts +2 -1
  409. package/src/deploy/adapters/types.ts +13 -1
  410. package/src/deploy/artifacts.ts +52 -11
  411. package/src/deploy/cloudflare-negotiation.ts +27 -16
  412. package/src/deploy/headers.ts +75 -55
  413. package/src/deploy/node-headers.ts +148 -27
  414. package/src/deploy/platforms/cloudflare.ts +13 -3
  415. package/src/deploy/platforms/netlify.ts +83 -5
  416. package/src/deploy/platforms/node.ts +8 -5
  417. package/src/deploy/platforms/static.ts +2 -0
  418. package/src/deploy/platforms/types.ts +15 -0
  419. package/src/deploy/platforms/vercel.ts +10 -3
  420. package/src/deploy/redirects.ts +68 -21
  421. package/src/deploy/robots.ts +2 -2
  422. package/src/deploy/rss.ts +4 -3
  423. package/src/deploy/sitemap.ts +7 -5
  424. package/src/deploy/vercel-negotiation.ts +35 -3
  425. package/src/eval/agents.ts +10 -2
  426. package/src/eval/run.ts +25 -0
  427. package/src/markdown/base-links.ts +74 -29
  428. package/src/markdown/directives.ts +242 -36
  429. package/src/markdown/features.ts +17 -0
  430. package/src/markdown/index.ts +13 -9
  431. package/src/markdown/mdast.ts +5 -2
  432. package/src/markdown/relative-links.ts +15 -27
  433. package/src/markdown/route-snapshot.ts +37 -0
  434. package/src/og/card.ts +149 -9
  435. package/src/og/derive.ts +156 -5
  436. package/src/og/index.ts +1 -0
  437. package/src/openapi/asyncapi.ts +4 -2
  438. package/src/openapi/graphql-build.ts +28 -2
  439. package/src/openapi/model.ts +99 -27
  440. package/src/openapi/proxy.ts +63 -10
  441. package/src/openapi/render-mdx.ts +51 -3
  442. package/src/registry/eject.ts +297 -43
  443. package/src/search/adapters/version-scope.ts +30 -0
  444. package/src/search/documents.ts +89 -27
  445. package/src/search/popular.ts +2 -1
  446. package/src/search/sync/algolia.ts +36 -2
  447. package/src/seo/jsonld.ts +7 -3
  448. package/src/sources/registry.ts +5 -0
  449. package/src/theme/entry.ts +11 -4
  450. package/src/translate/agents.ts +6 -1
  451. package/src/translate/ledger.ts +26 -3
  452. package/src/translate/meta.ts +76 -24
  453. package/src/translate/run.ts +14 -8
  454. package/src/translate/validate.ts +14 -2
  455. package/src/translate/work-list.ts +91 -19
  456. package/src/upgrade/upgrade.ts +36 -4
  457. package/dist/cli/chunk-27g6wdth.js.map +0 -10
  458. package/dist/cli/chunk-2hn4b8z7.js.map +0 -12
  459. package/dist/cli/chunk-6crbhc3x.js.map +0 -14
  460. package/dist/cli/chunk-6hsn950k.js.map +0 -10
  461. package/dist/cli/chunk-79jhk4py.js.map +0 -35
  462. package/dist/cli/chunk-82bbrxdn.js +0 -51
  463. package/dist/cli/chunk-82bbrxdn.js.map +0 -10
  464. package/dist/cli/chunk-abh8yjkn.js +0 -31
  465. package/dist/cli/chunk-abh8yjkn.js.map +0 -10
  466. package/dist/cli/chunk-ce574jw2.js +0 -23
  467. package/dist/cli/chunk-ce574jw2.js.map +0 -10
  468. package/dist/cli/chunk-dh8cwk36.js.map +0 -10
  469. package/dist/cli/chunk-epjnccmv.js.map +0 -10
  470. package/dist/cli/chunk-fa25z98p.js.map +0 -11
  471. package/dist/cli/chunk-fs23ddbb.js.map +0 -35
  472. package/dist/cli/chunk-fz5wtpmh.js.map +0 -10
  473. package/dist/cli/chunk-jwyddg7y.js.map +0 -15
  474. package/dist/cli/chunk-kpf8rrjc.js.map +0 -19
  475. package/dist/cli/chunk-m3vmjgmq.js.map +0 -10
  476. package/dist/cli/chunk-mb2919y2.js.map +0 -10
  477. package/dist/cli/chunk-q5163e60.js.map +0 -11
  478. package/dist/cli/chunk-qkqwkpte.js.map +0 -182
  479. package/dist/cli/chunk-qs4q5p4e.js.map +0 -10
  480. package/dist/cli/chunk-s1p84fyh.js.map +0 -10
  481. package/dist/cli/chunk-wgm7m9qk.js.map +0 -36
  482. package/dist/cli/chunk-yt5n7ppj.js.map +0 -10
  483. package/dist/cli/chunk-yw7dm696.js.map +0 -14
  484. /package/dist/cli/{chunk-s6jhgk0q.js.map → chunk-2eytanqx.js.map} +0 -0
  485. /package/dist/cli/{chunk-hdpx1tax.js.map → chunk-2z928egk.js.map} +0 -0
  486. /package/dist/cli/{chunk-ah61y8py.js.map → chunk-364znk6q.js.map} +0 -0
  487. /package/dist/cli/{chunk-vtk4a6dg.js.map → chunk-8ktnccpt.js.map} +0 -0
  488. /package/dist/cli/{chunk-fxypxtvm.js.map → chunk-a58773jm.js.map} +0 -0
  489. /package/dist/cli/{chunk-wm7js3j9.js.map → chunk-b07cmahc.js.map} +0 -0
  490. /package/dist/cli/{chunk-zxcczpyx.js.map → chunk-r20tn01b.js.map} +0 -0
  491. /package/dist/cli/{chunk-5shv93fd.js.map → chunk-tkacnehg.js.map} +0 -0
  492. /package/dist/cli/{chunk-zxh4d9vy.js.map → chunk-tzmab476.js.map} +0 -0
@@ -1,7 +1,11 @@
1
1
  ---
2
+ import data from "blume:data";
3
+
2
4
  import AccordionItem from "./AccordionItem.astro";
5
+ import { contentStrings } from "./content-strings.ts";
3
6
 
4
- const { defaultOpen = false, title = "Show more" } = Astro.props;
7
+ const { content: strings } = contentStrings(data, Astro.currentLocale);
8
+ const { defaultOpen = false, title = strings.showMore } = Astro.props;
5
9
  ---
6
10
 
7
11
  <div class="not-prose my-4 overflow-hidden rounded-blume border border-border">
@@ -1,7 +1,5 @@
1
1
  ---
2
- import { createSatteriMarkdownProcessor } from "@astrojs/markdown-satteri";
3
-
4
- import { escapeRawHtml, unwrapParagraph } from "./inline-markdown.ts";
2
+ import { renderInlineMarkdown } from "./inline-markdown.ts";
5
3
 
6
4
  interface Props {
7
5
  caption?: string;
@@ -10,10 +8,7 @@ interface Props {
10
8
 
11
9
  const { caption, hint } = Astro.props;
12
10
 
13
- const markdownProcessor = await createSatteriMarkdownProcessor();
14
- const captionHtml = caption
15
- ? unwrapParagraph((await markdownProcessor.render(escapeRawHtml(caption))).code)
16
- : undefined;
11
+ const captionHtml = caption ? await renderInlineMarkdown(caption) : undefined;
17
12
  ---
18
13
 
19
14
  <blume-frame class="not-prose my-6 block">
@@ -9,6 +9,7 @@ import { NEW_TAB_ATTRS } from "../../core/new-tab.ts";
9
9
  import { resolveIcon } from "../../theme/icons.ts";
10
10
  import data from "blume:data";
11
11
  import { GITHUB_MARK } from "../github-mark.ts";
12
+ import { contentStrings } from "./content-strings.ts";
12
13
  import { fetchRepositoryInfo } from "./github-info.ts";
13
14
 
14
15
  // Star/fork glyphs resolve from Lucide at build time; the `<svg>` wrappers below
@@ -63,6 +64,9 @@ const numbers = new Intl.NumberFormat("en", {
63
64
 
64
65
  const statIcon =
65
66
  "size-3.5 shrink-0 text-muted-foreground"; /* shared classes for stat icons */
67
+ // The glyphs are decorative, so each count carries a text label for screen
68
+ // readers ("Stars: 1.2K"), in the page's language.
69
+ const { content: strings } = contentStrings(data, Astro.currentLocale);
66
70
  ---
67
71
 
68
72
  {
@@ -108,7 +112,10 @@ const statIcon =
108
112
  width="14"
109
113
  set:html={starIcon}
110
114
  />
111
- <span>{numbers.format(info.stars)}</span>
115
+ <span>
116
+ <span class="sr-only">{strings.stars}: </span>
117
+ {numbers.format(info.stars)}
118
+ </span>
112
119
  </span>
113
120
  <span class="flex items-center gap-1.5">
114
121
  <svg
@@ -124,7 +131,10 @@ const statIcon =
124
131
  width="14"
125
132
  set:html={forkIcon}
126
133
  />
127
- <span>{numbers.format(info.forks)}</span>
134
+ <span>
135
+ <span class="sr-only">{strings.forks}: </span>
136
+ {numbers.format(info.forks)}
137
+ </span>
128
138
  </span>
129
139
  </span>
130
140
  )}
@@ -1,9 +1,8 @@
1
1
  ---
2
- import { createSatteriMarkdownProcessor } from "@astrojs/markdown-satteri";
3
2
  import data from "blume:data";
4
3
 
5
4
  import { contentStrings } from "./content-strings.ts";
6
- import { escapeRawHtml, unwrapParagraph } from "./inline-markdown.ts";
5
+ import { renderInlineMarkdown } from "./inline-markdown.ts";
7
6
  import { promptMarkdown } from "./prompt-markdown.ts";
8
7
 
9
8
  interface Props {
@@ -24,11 +23,7 @@ const normalizeActions = (value: Props["actions"]): string[] => {
24
23
  };
25
24
 
26
25
  const enabledActions = new Set(normalizeActions(actions));
27
- const markdownProcessor = await createSatteriMarkdownProcessor();
28
- const renderedDescription = await markdownProcessor.render(
29
- escapeRawHtml(description)
30
- );
31
- const descriptionHtml = unwrapParagraph(renderedDescription.code);
26
+ const descriptionHtml = await renderInlineMarkdown(description);
32
27
  // The prompt as Markdown, for the copy button and the Cursor link: the rendered
33
28
  // body's text alone would drop its links, list markers, and code fences.
34
29
  const promptSource = Astro.slots.has("default")
@@ -44,7 +44,6 @@ const tabId = id ?? componentSlug(title);
44
44
  data-tab-id={tabId}
45
45
  data-title={title}
46
46
  id={id}
47
- role="tabpanel"
48
47
  >
49
48
  <slot />
50
49
  {
@@ -1,4 +1,8 @@
1
1
  ---
2
+ import data from "blume:data";
3
+
4
+ import { contentStrings } from "./content-strings.ts";
5
+
2
6
  interface Props {
3
7
  borderBottom?: boolean;
4
8
  defaultTabIndex?: number;
@@ -45,6 +49,8 @@ const hashEnabled = String(hash) !== "false";
45
49
  // The dropdown (select) affordance belongs to the boxed layout; inline always
46
50
  // renders a tab strip.
47
51
  const useDropdown = dropdown && !inline;
52
+ // The labels the client script builds the strip with, in the page's locale.
53
+ const { content: strings } = contentStrings(data, Astro.currentLocale);
48
54
  ---
49
55
 
50
56
  <blume-tabs
@@ -58,6 +64,8 @@ const useDropdown = dropdown && !inline;
58
64
  data-default-tab-index={defaultTabIndex}
59
65
  data-dropdown={useDropdown ? "true" : "false"}
60
66
  data-hash={hashEnabled ? "true" : "false"}
67
+ data-i18n-select-tab={strings.selectTab}
68
+ data-i18n-tab={strings.tab}
61
69
  data-param={param}
62
70
  data-sync={sync ? "true" : "false"}
63
71
  data-sync-key={syncKey}
@@ -112,8 +120,12 @@ const useDropdown = dropdown && !inline;
112
120
  // in several <Tabs> instances on one page.
113
121
  let instanceCount = 0;
114
122
 
123
+ // An untitled panel is numbered with its group's localized `Tab {n}`.
115
124
  const panelTitle = (panel: HTMLElement, index: number) =>
116
- panel.dataset.title ?? `Tab ${index + 1}`;
125
+ panel.dataset.title ??
126
+ (
127
+ panel.closest<HTMLElement>("blume-tabs")?.dataset.i18nTab ?? "Tab {n}"
128
+ ).replace("{n}", String(index + 1));
117
129
  const panelId = (panel: HTMLElement) => panel.dataset.tabId ?? panel.id;
118
130
  const boundedIndex = (value: number, length: number) =>
119
131
  Math.min(Math.max(value, 0), Math.max(length - 1, 0));
@@ -149,6 +161,8 @@ const useDropdown = dropdown && !inline;
149
161
  // CodeGroup passes raw code fences instead of <Tab> elements, so adopt
150
162
  // the content wrapper's direct code blocks as panels. The tab label comes
151
163
  // from each block's title (the text after the language in the fence).
164
+ // A ts2js fence arrives as its own TypeScript/JavaScript group; it is
165
+ // one panel too, labeled by the fence title both of its blocks carry.
152
166
  if (panels.length === 0) {
153
167
  const wrapper = this.querySelector<HTMLElement>(
154
168
  ":scope > [data-blume-tab-content]"
@@ -156,11 +170,19 @@ const useDropdown = dropdown && !inline;
156
170
  const blocks = wrapper
157
171
  ? Array.from(wrapper.children).filter(
158
172
  (child): child is HTMLElement =>
159
- child instanceof HTMLElement && child.matches("pre, figure")
173
+ child instanceof HTMLElement &&
174
+ child.matches("pre, figure, blume-tabs")
160
175
  )
161
176
  : [];
162
177
  for (const block of blocks) {
163
178
  block.setAttribute("data-blume-tab-panel", "");
179
+ const fenceTitle = block.matches("blume-tabs")
180
+ ? block.querySelector<HTMLElement>("pre[data-title]")?.dataset
181
+ .title
182
+ : undefined;
183
+ if (fenceTitle && !block.dataset.title) {
184
+ block.dataset.title = fenceTitle;
185
+ }
164
186
  }
165
187
  panels = blocks;
166
188
  }
@@ -184,7 +206,10 @@ const useDropdown = dropdown && !inline;
184
206
  this.#select = document.createElement("select");
185
207
  this.#select.className = SELECT_CLASS;
186
208
  // Neutral default: tab sets aren't necessarily code examples.
187
- this.#select.setAttribute("aria-label", "Select tab");
209
+ this.#select.setAttribute(
210
+ "aria-label",
211
+ this.dataset.i18nSelectTab ?? "Select tab"
212
+ );
188
213
  panels.forEach((panel, index) => {
189
214
  const option = document.createElement("option");
190
215
  option.value = String(index);
@@ -212,6 +237,10 @@ const useDropdown = dropdown && !inline;
212
237
  }
213
238
  trigger.id = `blume-tab-${slug}-${instance}`;
214
239
  trigger.setAttribute("aria-controls", panel.id);
240
+ // The role rides with the labelling tab: adopted panels (CodeGroup
241
+ // fences, ts2js pairs, nested groups) have none of their own, and
242
+ // dropdown mode renders no tabs, so its panels take no role.
243
+ panel.setAttribute("role", "tabpanel");
215
244
  panel.setAttribute("aria-labelledby", trigger.id);
216
245
  trigger.setAttribute(
217
246
  "aria-selected",
@@ -298,6 +327,14 @@ const useDropdown = dropdown && !inline;
298
327
  }
299
328
  }
300
329
 
330
+ /**
331
+ * Re-pick the tab from the current URL, as on first load. Neither syncs
332
+ * other groups nor writes history, exactly like the initial selection.
333
+ */
334
+ selectFromUrl() {
335
+ this.activate(this.#initialIndex(), false, false);
336
+ }
337
+
301
338
  #activateByHash() {
302
339
  if (!this.#hashEnabled()) {
303
340
  return false;
@@ -348,10 +385,12 @@ const useDropdown = dropdown && !inline;
348
385
 
349
386
  #onTriggerKeydown(event: KeyboardEvent, index: number) {
350
387
  const lastIndex = this.#triggers.length - 1;
388
+ // The strip runs right to left under dir="rtl", so the arrows swap.
389
+ const rtl = getComputedStyle(this).direction === "rtl";
351
390
  let nextIndex: number | undefined;
352
- if (event.key === "ArrowRight") {
391
+ if (event.key === (rtl ? "ArrowLeft" : "ArrowRight")) {
353
392
  nextIndex = index === lastIndex ? 0 : index + 1;
354
- } else if (event.key === "ArrowLeft") {
393
+ } else if (event.key === (rtl ? "ArrowRight" : "ArrowLeft")) {
355
394
  nextIndex = index === 0 ? lastIndex : index - 1;
356
395
  } else if (event.key === "Home") {
357
396
  nextIndex = 0;
@@ -414,5 +453,19 @@ const useDropdown = dropdown && !inline;
414
453
 
415
454
  if (!customElements.get("blume-tabs")) {
416
455
  customElements.define("blume-tabs", BlumeTabs);
456
+
457
+ // The client router inserts the next page (connecting its tabs, which
458
+ // read the URL then) before it moves history to that page's URL, so
459
+ // those tabs saw the previous page's hash and query. `astro:after-swap`
460
+ // fires once the URL is the new page's and before the reader can
461
+ // interact, so selecting again here honors `?install=windows` and
462
+ // `#windows` deep links as a full load does.
463
+ document.addEventListener("astro:after-swap", () => {
464
+ for (const tabs of document.querySelectorAll("blume-tabs")) {
465
+ if (tabs instanceof BlumeTabs) {
466
+ tabs.selectFromUrl();
467
+ }
468
+ }
469
+ });
417
470
  }
418
471
  </script>
@@ -28,7 +28,7 @@ const previewPattern =
28
28
  <p class="m-0! flex items-center gap-1.5 font-semibold">
29
29
  {title}
30
30
  {href && (
31
- <Icon class="text-muted-foreground" name="arrow-right" size={14} />
31
+ <Icon class="text-muted-foreground rtl:-scale-x-100" name="arrow-right" size={14} />
32
32
  )}
33
33
  </p>
34
34
  )
@@ -38,7 +38,7 @@ const tooltipId = tooltipIdFor(Astro.locals, [
38
38
  set:html={labelHtml}
39
39
  />
40
40
  <span
41
- class="absolute bottom-full left-1/2 z-20 mb-2 w-max max-w-xs -translate-x-1/2 rounded-blume border border-border bg-background p-3 text-start font-sans text-foreground text-sm shadow-lg"
41
+ class="absolute bottom-full left-1/2 z-20 mb-2 w-max max-w-[min(20rem,calc(100vw-1rem))] -translate-x-1/2 rounded-blume border border-border bg-background p-3 text-start font-sans text-foreground text-sm shadow-lg"
42
42
  data-blume-tooltip-panel
43
43
  id={tooltipId}
44
44
  role="tooltip"
@@ -60,23 +60,33 @@ const tooltipId = tooltipIdFor(Astro.locals, [
60
60
  </span>
61
61
 
62
62
  <style>
63
+ /* Out of layout while hidden, not just invisible: a hidden panel past the
64
+ inline end of a line would otherwise still widen the page. */
63
65
  [data-blume-tooltip-panel] {
64
- pointer-events: none;
65
- visibility: hidden;
66
+ display: none;
66
67
  }
67
68
 
68
69
  /* Focus anywhere inside keeps it open, so a keyboard reader can Tab from
69
70
  the trigger to the call-to-action link without the panel vanishing. */
70
71
  [data-blume-tooltip]:hover [data-blume-tooltip-panel],
71
72
  [data-blume-tooltip]:focus-within [data-blume-tooltip-panel] {
72
- pointer-events: auto;
73
- visibility: visible;
73
+ display: block;
74
+ }
75
+
76
+ /* Bridge the gap down to the trigger, so the pointer keeps the tooltip
77
+ hovered on its way to the panel's link (WCAG 1.4.13). The extra pixel is
78
+ the bottom border, which top: 100% starts inside. */
79
+ [data-blume-tooltip-panel]::after {
80
+ content: "";
81
+ height: calc(0.5rem + 1px);
82
+ inset-inline: 0;
83
+ position: absolute;
84
+ top: 100%;
74
85
  }
75
86
 
76
87
  /* Escape hides it until the pointer or focus leaves (WCAG 1.4.13). */
77
88
  [data-blume-tooltip][data-dismissed] [data-blume-tooltip-panel] {
78
- pointer-events: none;
79
- visibility: hidden;
89
+ display: none;
80
90
  }
81
91
  </style>
82
92
 
@@ -110,4 +120,56 @@ const tooltipId = tooltipIdFor(Astro.locals, [
110
120
  };
111
121
  document.addEventListener("focusout", rearm);
112
122
  document.addEventListener("pointerout", rearm);
123
+
124
+ // The panel centers over its trigger, so near either edge of the viewport
125
+ // it would run off-screen. As it shows, shift it in by the overhang.
126
+ const VIEWPORT_MARGIN = 8;
127
+ const place = (tooltip: Element) => {
128
+ const panel = tooltip.querySelector<HTMLElement>(
129
+ "[data-blume-tooltip-panel]"
130
+ );
131
+ if (!panel) {
132
+ return true;
133
+ }
134
+ // Measure it parked off the side the page can't scroll toward: a panel
135
+ // laid out past the viewport's end even for a moment leaves WebKit's page
136
+ // scroll width stuck wide.
137
+ const rtl = getComputedStyle(document.documentElement).direction === "rtl";
138
+ panel.style.marginLeft = rtl ? "100vw" : "-100vw";
139
+ const { width } = panel.getBoundingClientRect();
140
+ // Zero width: not showing (yet, or any more).
141
+ if (width === 0) {
142
+ return false;
143
+ }
144
+ const anchor = tooltip.getBoundingClientRect();
145
+ const left = anchor.left + anchor.width / 2 - width / 2;
146
+ const end = document.documentElement.clientWidth - VIEWPORT_MARGIN;
147
+ let shift = 0;
148
+ if (left < VIEWPORT_MARGIN) {
149
+ shift = VIEWPORT_MARGIN - left;
150
+ } else if (left + width > end) {
151
+ shift = end - left - width;
152
+ }
153
+ panel.style.marginLeft = `${shift}px`;
154
+ return true;
155
+ };
156
+
157
+ // Hover and focus styles already apply when these events fire; should the
158
+ // panel not show yet, place it in the next frame, before it paints.
159
+ const show = (event: FocusEvent | PointerEvent) => {
160
+ const tooltip =
161
+ event.target instanceof Element ? event.target.closest(TOOLTIP) : null;
162
+ const { relatedTarget } = event;
163
+ if (
164
+ tooltip &&
165
+ !(relatedTarget instanceof Node && tooltip.contains(relatedTarget)) &&
166
+ !place(tooltip)
167
+ ) {
168
+ requestAnimationFrame(() => {
169
+ place(tooltip);
170
+ });
171
+ }
172
+ };
173
+ document.addEventListener("focusin", show);
174
+ document.addEventListener("pointerover", show);
113
175
  </script>
@@ -239,6 +239,11 @@
239
239
  }
240
240
 
241
241
  const folder = folderForItem(item);
242
+ // Deeper items sit further toward the inline end (the left under
243
+ // dir="rtl"), so the expand and collapse arrows swap there.
244
+ const rtl = getComputedStyle(this).direction === "rtl";
245
+ const expandKey = rtl ? "ArrowLeft" : "ArrowRight";
246
+ const collapseKey = rtl ? "ArrowRight" : "ArrowLeft";
242
247
  if (event.key === "ArrowDown") {
243
248
  event.preventDefault();
244
249
  this.#move(1);
@@ -251,7 +256,7 @@
251
256
  } else if (event.key === "End") {
252
257
  event.preventDefault();
253
258
  this.#moveToEdge("last");
254
- } else if (event.key === "ArrowRight" && folder) {
259
+ } else if (event.key === expandKey && folder) {
255
260
  event.preventDefault();
256
261
  if (isOpenableDetails(folder) && !folder.open) {
257
262
  folder.open = true;
@@ -259,7 +264,7 @@
259
264
  } else {
260
265
  this.#setActive(this.#firstChild(folder), true);
261
266
  }
262
- } else if (event.key === "ArrowLeft") {
267
+ } else if (event.key === collapseKey) {
263
268
  const parent = this.#parentItem(item);
264
269
  if (isOpenableDetails(folder) && folder.open) {
265
270
  event.preventDefault();
@@ -4,7 +4,11 @@
4
4
  // the accent-colored prop name (with a `?` suffix when optional) and its type;
5
5
  // expanded, the row lifts into a card showing the description and a Type/Default
6
6
  // detail grid. Uses native <details>/<summary> so the core stays React-free.
7
+ import data from "blume:data";
8
+
7
9
  import { resolveIcon } from "../../theme/icons.ts";
10
+ import { contentHref } from "./base-href.ts";
11
+ import { contentStrings } from "./content-strings.ts";
8
12
 
9
13
  // The row disclosure caret; resolved from Lucide at build time and injected into
10
14
  // the summary's `<svg>` (which supplies size and the rotate-on-open transition).
@@ -25,6 +29,7 @@ interface Props {
25
29
 
26
30
  const { type = {} } = Astro.props;
27
31
  const entries = Object.entries(type);
32
+ const { content: strings } = contentStrings(data, Astro.currentLocale);
28
33
 
29
34
  // Shared column track so the header, every summary, and the detail grid align.
30
35
  const columns = "grid grid-cols-[1fr_2fr_auto] items-center gap-4";
@@ -34,8 +39,8 @@ const columns = "grid grid-cols-[1fr_2fr_auto] items-center gap-4";
34
39
  entries.length > 0 && (
35
40
  <div class="not-prose my-6 rounded-blume border border-border bg-muted/30 p-1.5">
36
41
  <div class={`${columns} px-3 py-2 font-medium text-muted-foreground text-xs`}>
37
- <span>Prop</span>
38
- <span>Type</span>
42
+ <span>{strings.prop}</span>
43
+ <span>{strings.type}</span>
39
44
  <span aria-hidden="true" class="size-3.5" />
40
45
  </div>
41
46
 
@@ -50,7 +55,7 @@ const columns = "grid grid-cols-[1fr_2fr_auto] items-center gap-4";
50
55
  {info.typeDescriptionLink ? (
51
56
  <a
52
57
  class="break-words font-mono text-foreground text-xs underline-offset-2 hover:underline"
53
- href={info.typeDescriptionLink}
58
+ href={contentHref(info.typeDescriptionLink)}
54
59
  >
55
60
  {info.type}
56
61
  </a>
@@ -85,7 +90,7 @@ const columns = "grid grid-cols-[1fr_2fr_auto] items-center gap-4";
85
90
  )}
86
91
  <div class="space-y-1.5">
87
92
  <div class={columns}>
88
- <span class="text-muted-foreground">Type</span>
93
+ <span class="text-muted-foreground">{strings.type}</span>
89
94
  <code class="break-words font-mono text-foreground">
90
95
  {info.type}
91
96
  </code>
@@ -93,7 +98,7 @@ const columns = "grid grid-cols-[1fr_2fr_auto] items-center gap-4";
93
98
  </div>
94
99
  {info.default && (
95
100
  <div class={columns}>
96
- <span class="text-muted-foreground">Default</span>
101
+ <span class="text-muted-foreground">{strings.default}</span>
97
102
  <code class="break-words font-mono text-foreground">
98
103
  {info.default}
99
104
  </code>
@@ -1,6 +1,9 @@
1
1
  ---
2
+ import data from "blume:data";
3
+
2
4
  import { componentSlug } from "../slug.ts";
3
5
  import { contentHref } from "./base-href.ts";
6
+ import { contentStrings } from "./content-strings.ts";
4
7
 
5
8
  interface RssMetadata {
6
9
  description?: string;
@@ -32,8 +35,11 @@ const {
32
35
  tags,
33
36
  title,
34
37
  } = Astro.props;
35
- const updateLabel = label ?? title ?? "Update";
36
- const id = providedId ?? (componentSlug(updateLabel) || "update");
38
+ const { content: strings } = contentStrings(data, Astro.currentLocale);
39
+ const updateLabel = label ?? title ?? strings.update;
40
+ // The anchor comes from the authored label only: the localized fallback
41
+ // heading would give an unlabeled update a different anchor per locale.
42
+ const id = providedId ?? (componentSlug(label ?? title ?? "") || "update");
37
43
  const tagList = Array.isArray(tags) ? tags : tags ? [tags] : [];
38
44
  ---
39
45
 
@@ -128,8 +128,11 @@ export const extractTypeTable = async (
128
128
  return checker.getPropertiesOfType(type).map((symbol) => {
129
129
  const decl = symbol.declarations?.[0];
130
130
  const signature = decl && ts.isPropertySignature(decl) ? decl : undefined;
131
+ // Slice the text from the file that declares the property: an inherited
132
+ // member (`Props extends Base`, Base imported) lives in another file, and
133
+ // its positions mean nothing in the documented one.
131
134
  const typeText = signature?.type
132
- ? signature.type.getText(sourceFile)
135
+ ? signature.type.getText(signature.getSourceFile())
133
136
  : checker.typeToString(
134
137
  checker.getTypeOfSymbolAtLocation(symbol, decl ?? declaration)
135
138
  );
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The named color each documented Badge `variant` paints with; `accent` is
3
+ * the site's theme accent rather than a fixed hue.
4
+ */
5
+ const VARIANT_COLOR = new Map([
6
+ ["accent", "accent"],
7
+ ["danger", "red"],
8
+ ["default", "gray"],
9
+ ["success", "green"],
10
+ ["warning", "orange"],
11
+ ]);
12
+
13
+ /**
14
+ * The color a badge renders with: an explicit `color` wins, then the
15
+ * variant's hue. MDX props aren't type-checked, so a variant Badge doesn't
16
+ * know (`info`, which Callout accepts) renders as the default gray badge
17
+ * instead of failing the page build.
18
+ */
19
+ export const badgeColorName = (variant: string, color?: string): string =>
20
+ color ?? VARIANT_COLOR.get(variant) ?? "gray";
@@ -1,33 +1,25 @@
1
1
  import data from "blume:data";
2
2
 
3
3
  import {
4
- isInternalPath,
5
4
  normalizeBasePath,
6
- withComposedBasePath,
5
+ withAuthoredBasePath,
7
6
  } from "../../core/base-path.ts";
8
-
9
- // Mirrors `markdown/base-links.ts`: a path whose final segment carries a file
10
- // extension is a `public/` asset, served at the site root and never moved
11
- // under `basePath`.
12
- const ASSET_PATH = /\.[a-z0-9]+$/iu;
13
-
14
- /** Strip any `#fragment`/`?query` so only the path is extension-tested. */
15
- const pathOf = (url: string): string => url.replace(/[#?].*$/u, "");
7
+ import { routeSetFor, servesRoute } from "../../core/locale-links.ts";
16
8
 
17
9
  /**
18
10
  * Rebase a component-emitted `href` the way `markdown/base-links.ts` rebases
19
11
  * `[x](/guide)`: a root-relative internal page link gains the composed
20
- * `deployment.base` + `basePath` prefix, so authors write component links
21
- * (`<Card href="/guide">`) under the same "as if mounted at root" contract as
22
- * markdown links. Idempotent per layer (a hand-written `/docs/x` isn't
23
- * double-prefixed) and inert for external URLs, fragments, relative paths, and
24
- * asset links.
12
+ * `deployment.base` + `basePath` prefix, and a public asset (`/spec.pdf`, with
13
+ * no page served there) the deployment base alone, so authors write component
14
+ * links (`<Card href="/guide">`) under the same "as if mounted at root"
15
+ * contract as markdown links (see `withAuthoredBasePath`). Idempotent per
16
+ * layer (a hand-written `/docs/x` isn't double-prefixed) and inert for
17
+ * external URLs, fragments, and relative paths.
25
18
  */
26
19
  export const contentHref = (href: string): string =>
27
- isInternalPath(href) && !ASSET_PATH.test(pathOf(href))
28
- ? withComposedBasePath(
29
- normalizeBasePath(import.meta.env.BASE_URL),
30
- data.config.basePath,
31
- href
32
- )
33
- : href;
20
+ withAuthoredBasePath(
21
+ normalizeBasePath(import.meta.env.BASE_URL),
22
+ data.config.basePath,
23
+ href,
24
+ (route) => servesRoute(routeSetFor(data.routes), route)
25
+ );
@@ -1,3 +1,6 @@
1
+ import { createSatteriMarkdownProcessor } from "@astrojs/markdown-satteri";
2
+ import { defineMdastPlugin } from "satteri";
3
+
1
4
  /**
2
5
  * Shared helpers for components that render a short Markdown prop (a caption,
3
6
  * a description, a tooltip label) into inline HTML injected via `set:html`.
@@ -5,14 +8,19 @@
5
8
  */
6
9
 
7
10
  /**
8
- * Neutralize raw HTML in a Markdown-rendered text prop by escaping only
9
- * `<`/`>`. `&` deliberately stays: CommonMark already renders a bare `&` as
10
- * `&amp;` and resolves real entity references, so leaving it alone keeps
11
- * `&copy;`-style authoring working — a full HTML escape would render it as
12
- * the literal text `&copy;`.
11
+ * Neutralize raw HTML in a Markdown-rendered text prop: each raw HTML node
12
+ * the parser finds (an inline tag, a block, a comment) renders as its literal
13
+ * text instead. Deciding in the tree rather than escaping `<`/`>` in the
14
+ * source keeps what only looks like HTML intact — a code span's
15
+ * `` `Array<string>` `` and an autolink's `<https://…>` — and `&` entity
16
+ * references keep resolving (`&copy;` renders as ©).
13
17
  */
14
- export const escapeRawHtml = (value: string): string =>
15
- value.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
18
+ export const rawHtmlAsTextPlugin = defineMdastPlugin({
19
+ html(node, ctx) {
20
+ ctx.replaceNode(node, { type: "text", value: node.value });
21
+ },
22
+ name: "blume-raw-html-as-text",
23
+ });
16
24
 
17
25
  /**
18
26
  * Unwrap the `<p>` a block-level Markdown render wraps around single-line
@@ -26,3 +34,15 @@ export const unwrapParagraph = (html: string): string => {
26
34
  const match = trimmed.match(/^<p>(?<content>(?:(?!<\/p>)[\s\S])*)<\/p>$/u);
27
35
  return match?.groups?.content ?? trimmed;
28
36
  };
37
+
38
+ /**
39
+ * Render a short Markdown text prop to inline HTML, its raw HTML shown as
40
+ * text (see {@link rawHtmlAsTextPlugin}) and a single paragraph unwrapped.
41
+ */
42
+ export const renderInlineMarkdown = async (value: string): Promise<string> => {
43
+ const processor = await createSatteriMarkdownProcessor({
44
+ mdastPlugins: [rawHtmlAsTextPlugin],
45
+ });
46
+ const rendered = await processor.render(value);
47
+ return unwrapParagraph(rendered.code);
48
+ };