@coderminer/vue-markdown 0.0.0-stage → 1.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 (291) hide show
  1. package/CHANGELOG.md +110 -0
  2. package/LICENSE +21 -0
  3. package/README.md +579 -3
  4. package/README.zh-CN.md +547 -0
  5. package/dist/chunks/MarkdownBlockquote-DVXziX2t.js +18 -0
  6. package/dist/chunks/MarkdownBlockquote-DVXziX2t.js.map +1 -0
  7. package/dist/chunks/MarkdownBreak-BwCi2Itt.js +18 -0
  8. package/dist/chunks/MarkdownBreak-BwCi2Itt.js.map +1 -0
  9. package/dist/chunks/MarkdownCode-B1k9tmW5.js +65 -0
  10. package/dist/chunks/MarkdownCode-B1k9tmW5.js.map +1 -0
  11. package/dist/chunks/MarkdownConfigProvider-5N3ylrIu.js +51 -0
  12. package/dist/chunks/MarkdownConfigProvider-5N3ylrIu.js.map +1 -0
  13. package/dist/chunks/MarkdownContent-BAK6dqo7.js +15 -0
  14. package/dist/chunks/MarkdownContent-BAK6dqo7.js.map +1 -0
  15. package/dist/chunks/MarkdownCustomTag-BBdn3-WO.js +42 -0
  16. package/dist/chunks/MarkdownCustomTag-BBdn3-WO.js.map +1 -0
  17. package/dist/chunks/MarkdownEmphasis-CppivOEu.js +18 -0
  18. package/dist/chunks/MarkdownEmphasis-CppivOEu.js.map +1 -0
  19. package/dist/chunks/MarkdownEmpty-Av5k6bqa.js +16 -0
  20. package/dist/chunks/MarkdownEmpty-Av5k6bqa.js.map +1 -0
  21. package/dist/chunks/MarkdownError-C0sPs5W0.js +19 -0
  22. package/dist/chunks/MarkdownError-C0sPs5W0.js.map +1 -0
  23. package/dist/chunks/MarkdownFootnoteReference-Dy3Khwyj.js +24 -0
  24. package/dist/chunks/MarkdownFootnoteReference-Dy3Khwyj.js.map +1 -0
  25. package/dist/chunks/MarkdownFootnotes-BRPzkbXv.js +23 -0
  26. package/dist/chunks/MarkdownFootnotes-BRPzkbXv.js.map +1 -0
  27. package/dist/chunks/MarkdownHeading-DaNcP0_6.js +31 -0
  28. package/dist/chunks/MarkdownHeading-DaNcP0_6.js.map +1 -0
  29. package/dist/chunks/MarkdownHorizontalRule-QNe_cuUI.js +18 -0
  30. package/dist/chunks/MarkdownHorizontalRule-QNe_cuUI.js.map +1 -0
  31. package/dist/chunks/MarkdownHtml-66lYkvwM.js +15 -0
  32. package/dist/chunks/MarkdownHtml-66lYkvwM.js.map +1 -0
  33. package/dist/chunks/MarkdownImage-BRy76svs.js +53 -0
  34. package/dist/chunks/MarkdownImage-BRy76svs.js.map +1 -0
  35. package/dist/chunks/MarkdownInlineCode-MXZYFwex.js +18 -0
  36. package/dist/chunks/MarkdownInlineCode-MXZYFwex.js.map +1 -0
  37. package/dist/chunks/MarkdownLink-Dbx3NwgV.js +47 -0
  38. package/dist/chunks/MarkdownLink-Dbx3NwgV.js.map +1 -0
  39. package/dist/chunks/MarkdownList-BJ-_C71k.js +22 -0
  40. package/dist/chunks/MarkdownList-BJ-_C71k.js.map +1 -0
  41. package/dist/chunks/MarkdownListItem-Z1EHIY26.js +18 -0
  42. package/dist/chunks/MarkdownListItem-Z1EHIY26.js.map +1 -0
  43. package/dist/chunks/MarkdownLoading-D-RYtXxf.js +17 -0
  44. package/dist/chunks/MarkdownLoading-D-RYtXxf.js.map +1 -0
  45. package/dist/chunks/MarkdownParagraph-BxLSmSaG.js +18 -0
  46. package/dist/chunks/MarkdownParagraph-BxLSmSaG.js.map +1 -0
  47. package/dist/chunks/MarkdownRenderer-DLRRfsdI.js +416 -0
  48. package/dist/chunks/MarkdownRenderer-DLRRfsdI.js.map +1 -0
  49. package/dist/chunks/MarkdownRoot-DEE6iVfh.js +25 -0
  50. package/dist/chunks/MarkdownRoot-DEE6iVfh.js.map +1 -0
  51. package/dist/chunks/MarkdownStrikethrough-CblvbqDk.js +18 -0
  52. package/dist/chunks/MarkdownStrikethrough-CblvbqDk.js.map +1 -0
  53. package/dist/chunks/MarkdownStrong-uU5MzAoJ.js +18 -0
  54. package/dist/chunks/MarkdownStrong-uU5MzAoJ.js.map +1 -0
  55. package/dist/chunks/MarkdownTable-DmBTg_CR.js +18 -0
  56. package/dist/chunks/MarkdownTable-DmBTg_CR.js.map +1 -0
  57. package/dist/chunks/MarkdownTableCell-eiCJe847.js +33 -0
  58. package/dist/chunks/MarkdownTableCell-eiCJe847.js.map +1 -0
  59. package/dist/chunks/MarkdownTableRow-DuJaPntg.js +18 -0
  60. package/dist/chunks/MarkdownTableRow-DuJaPntg.js.map +1 -0
  61. package/dist/chunks/MarkdownTableSection-PFHz-R33.js +26 -0
  62. package/dist/chunks/MarkdownTableSection-PFHz-R33.js.map +1 -0
  63. package/dist/chunks/MarkdownTaskItem-BcmKo1lk.js +40 -0
  64. package/dist/chunks/MarkdownTaskItem-BcmKo1lk.js.map +1 -0
  65. package/dist/chunks/MarkdownToc-BdOHF-Yo.js +51 -0
  66. package/dist/chunks/MarkdownToc-BdOHF-Yo.js.map +1 -0
  67. package/dist/chunks/MarkdownTocItem-DT9mR3vL.js +27 -0
  68. package/dist/chunks/MarkdownTocItem-DT9mR3vL.js.map +1 -0
  69. package/dist/chunks/MermaidLiveEditor-W-qf3G-5.js +416 -0
  70. package/dist/chunks/MermaidLiveEditor-W-qf3G-5.js.map +1 -0
  71. package/dist/chunks/VueSyntaxHighlighter-DyLsYMwy.js +262 -0
  72. package/dist/chunks/VueSyntaxHighlighter-DyLsYMwy.js.map +1 -0
  73. package/dist/chunks/adapters-CMwX_NEI.js +28 -0
  74. package/dist/chunks/adapters-CMwX_NEI.js.map +1 -0
  75. package/dist/chunks/asyncToGenerator-ChigusFD.js +26 -0
  76. package/dist/chunks/blank-line-Cb-JBP_5.js +90 -0
  77. package/dist/chunks/blank-line-Cb-JBP_5.js.map +1 -0
  78. package/dist/chunks/codemirror-DyphMAEg.js +84 -0
  79. package/dist/chunks/codemirror-DyphMAEg.js.map +1 -0
  80. package/dist/chunks/config-aRYo2R8_.js +12 -0
  81. package/dist/chunks/config-aRYo2R8_.js.map +1 -0
  82. package/dist/chunks/context-8NfW6fxI.js +32 -0
  83. package/dist/chunks/context-8NfW6fxI.js.map +1 -0
  84. package/dist/chunks/default-DWVS-I_8.js +23 -0
  85. package/dist/chunks/default-DWVS-I_8.js.map +1 -0
  86. package/dist/chunks/diagnostics-CtHoJyiX.js +25 -0
  87. package/dist/chunks/diagnostics-CtHoJyiX.js.map +1 -0
  88. package/dist/chunks/export-DZQ3cUry.js +1575 -0
  89. package/dist/chunks/export-DZQ3cUry.js.map +1 -0
  90. package/dist/chunks/hast-nodes-C0bX3M5Z.js +35 -0
  91. package/dist/chunks/hast-nodes-C0bX3M5Z.js.map +1 -0
  92. package/dist/chunks/highlightjs-BEh-YwEG.js +6041 -0
  93. package/dist/chunks/highlightjs-BEh-YwEG.js.map +1 -0
  94. package/dist/chunks/identity-jZEhX2d5.js +6244 -0
  95. package/dist/chunks/identity-jZEhX2d5.js.map +1 -0
  96. package/dist/chunks/labels-BtHiUTQI.js +49 -0
  97. package/dist/chunks/labels-BtHiUTQI.js.map +1 -0
  98. package/dist/chunks/lib-BQiWGWpu.js +5087 -0
  99. package/dist/chunks/lib-BQiWGWpu.js.map +1 -0
  100. package/dist/chunks/lib-LwqA_W3J.js +127 -0
  101. package/dist/chunks/lib-LwqA_W3J.js.map +1 -0
  102. package/dist/chunks/longest-streak-DZE_EqsU.js +10 -0
  103. package/dist/chunks/longest-streak-DZE_EqsU.js.map +1 -0
  104. package/dist/chunks/micromark-factory-space-Db040TnW.js +139 -0
  105. package/dist/chunks/micromark-factory-space-Db040TnW.js.map +1 -0
  106. package/dist/chunks/normalize-CRYv3Wqt.js +220 -0
  107. package/dist/chunks/normalize-CRYv3Wqt.js.map +1 -0
  108. package/dist/chunks/objectSpread2-CtBNx0TF.js +57 -0
  109. package/dist/chunks/plugin-DqkFHyny.js +28 -0
  110. package/dist/chunks/plugin-DqkFHyny.js.map +1 -0
  111. package/dist/chunks/preset-BjaOuJUL.js +46 -0
  112. package/dist/chunks/preset-BjaOuJUL.js.map +1 -0
  113. package/dist/chunks/registry-DLjr93-V.js +6144 -0
  114. package/dist/chunks/registry-DLjr93-V.js.map +1 -0
  115. package/dist/chunks/render-Cs8iKrgz.js +1724 -0
  116. package/dist/chunks/render-Cs8iKrgz.js.map +1 -0
  117. package/dist/chunks/runtime-DJMnzjah.js +546 -0
  118. package/dist/chunks/runtime-DJMnzjah.js.map +1 -0
  119. package/dist/chunks/security-y4EwUyAs.js +214 -0
  120. package/dist/chunks/security-y4EwUyAs.js.map +1 -0
  121. package/dist/chunks/shared-DNAvZ-UY.js +76 -0
  122. package/dist/chunks/shared-DNAvZ-UY.js.map +1 -0
  123. package/dist/chunks/space-separated-tokens-CmBjEPdR.js +1099 -0
  124. package/dist/chunks/space-separated-tokens-CmBjEPdR.js.map +1 -0
  125. package/dist/chunks/url-D2BoivaE.js +26 -0
  126. package/dist/chunks/url-D2BoivaE.js.map +1 -0
  127. package/dist/chunks/useActiveHeading-BaGVMJnB.js +316 -0
  128. package/dist/chunks/useActiveHeading-BaGVMJnB.js.map +1 -0
  129. package/dist/components/CodeBlock.d.ts +73 -0
  130. package/dist/components/CodeBlock.js +1 -0
  131. package/dist/components/Icon.d.ts +6 -0
  132. package/dist/components/MarkdownBlockquote.d.ts +18 -0
  133. package/dist/components/MarkdownBlockquote.js +1 -0
  134. package/dist/components/MarkdownBreak.d.ts +8 -0
  135. package/dist/components/MarkdownBreak.js +1 -0
  136. package/dist/components/MarkdownChildren.d.ts +17 -0
  137. package/dist/components/MarkdownCode.d.ts +29 -0
  138. package/dist/components/MarkdownCode.js +1 -0
  139. package/dist/components/MarkdownConfigProvider.d.ts +33 -0
  140. package/dist/components/MarkdownConfigProvider.js +1 -0
  141. package/dist/components/MarkdownContent.d.ts +16 -0
  142. package/dist/components/MarkdownContent.js +1 -0
  143. package/dist/components/MarkdownCustomTag.d.ts +20 -0
  144. package/dist/components/MarkdownCustomTag.js +1 -0
  145. package/dist/components/MarkdownEmphasis.d.ts +18 -0
  146. package/dist/components/MarkdownEmphasis.js +1 -0
  147. package/dist/components/MarkdownEmpty.d.ts +8 -0
  148. package/dist/components/MarkdownEmpty.js +1 -0
  149. package/dist/components/MarkdownError.d.ts +11 -0
  150. package/dist/components/MarkdownError.js +1 -0
  151. package/dist/components/MarkdownFootnoteReference.d.ts +19 -0
  152. package/dist/components/MarkdownFootnoteReference.js +1 -0
  153. package/dist/components/MarkdownFootnotes.d.ts +17 -0
  154. package/dist/components/MarkdownFootnotes.js +1 -0
  155. package/dist/components/MarkdownHeading.d.ts +18 -0
  156. package/dist/components/MarkdownHeading.js +1 -0
  157. package/dist/components/MarkdownHorizontalRule.d.ts +8 -0
  158. package/dist/components/MarkdownHorizontalRule.js +1 -0
  159. package/dist/components/MarkdownHtml.d.ts +8 -0
  160. package/dist/components/MarkdownHtml.js +1 -0
  161. package/dist/components/MarkdownImage.d.ts +15 -0
  162. package/dist/components/MarkdownImage.js +1 -0
  163. package/dist/components/MarkdownInlineCode.d.ts +18 -0
  164. package/dist/components/MarkdownInlineCode.js +1 -0
  165. package/dist/components/MarkdownLink.d.ts +22 -0
  166. package/dist/components/MarkdownLink.js +1 -0
  167. package/dist/components/MarkdownList.d.ts +18 -0
  168. package/dist/components/MarkdownList.js +1 -0
  169. package/dist/components/MarkdownListItem.d.ts +18 -0
  170. package/dist/components/MarkdownListItem.js +1 -0
  171. package/dist/components/MarkdownLoading.d.ts +8 -0
  172. package/dist/components/MarkdownLoading.js +1 -0
  173. package/dist/components/MarkdownMath.d.ts +12 -0
  174. package/dist/components/MarkdownMath.js +1 -0
  175. package/dist/components/MarkdownMermaid.d.ts +78 -0
  176. package/dist/components/MarkdownMermaid.js +1 -0
  177. package/dist/components/MarkdownParagraph.d.ts +18 -0
  178. package/dist/components/MarkdownParagraph.js +1 -0
  179. package/dist/components/MarkdownRenderer.d.ts +170 -0
  180. package/dist/components/MarkdownRenderer.js +1 -0
  181. package/dist/components/MarkdownRoot.d.ts +24 -0
  182. package/dist/components/MarkdownRoot.js +1 -0
  183. package/dist/components/MarkdownStrikethrough.d.ts +18 -0
  184. package/dist/components/MarkdownStrikethrough.js +1 -0
  185. package/dist/components/MarkdownStrong.d.ts +18 -0
  186. package/dist/components/MarkdownStrong.js +1 -0
  187. package/dist/components/MarkdownTable.d.ts +18 -0
  188. package/dist/components/MarkdownTable.js +1 -0
  189. package/dist/components/MarkdownTableCell.d.ts +20 -0
  190. package/dist/components/MarkdownTableCell.js +1 -0
  191. package/dist/components/MarkdownTableRow.d.ts +18 -0
  192. package/dist/components/MarkdownTableRow.js +1 -0
  193. package/dist/components/MarkdownTableSection.d.ts +18 -0
  194. package/dist/components/MarkdownTableSection.js +1 -0
  195. package/dist/components/MarkdownTaskItem.d.ts +20 -0
  196. package/dist/components/MarkdownTaskItem.js +1 -0
  197. package/dist/components/MarkdownToc.d.ts +36 -0
  198. package/dist/components/MarkdownToc.js +1 -0
  199. package/dist/components/MarkdownTocItem.d.ts +14 -0
  200. package/dist/components/MarkdownTocItem.js +1 -0
  201. package/dist/components/MermaidBlock.d.ts +50 -0
  202. package/dist/components/MermaidBlock.js +1 -0
  203. package/dist/components/MermaidLiveEditor.d.ts +44 -0
  204. package/dist/components/MermaidLiveEditor.js +1 -0
  205. package/dist/components/VueSyntaxHighlighter.d.ts +39 -0
  206. package/dist/components/VueSyntaxHighlighter.js +1 -0
  207. package/dist/components/codeRegion.d.ts +14 -0
  208. package/dist/components/config.d.ts +7 -0
  209. package/dist/components/context.d.ts +45 -0
  210. package/dist/components/index.d.ts +42 -0
  211. package/dist/components/index.js +38 -0
  212. package/dist/components/render.d.ts +9 -0
  213. package/dist/components/scroll-lock.d.ts +7 -0
  214. package/dist/components/types.d.ts +29 -0
  215. package/dist/composables/useActiveHeading.d.ts +12 -0
  216. package/dist/composables/useCodeHighlighter.d.ts +30 -0
  217. package/dist/composables/useLineWindow.d.ts +38 -0
  218. package/dist/composables/useMarkdownDocument.d.ts +23 -0
  219. package/dist/core/adapters.d.ts +7 -0
  220. package/dist/core/config.d.ts +5 -0
  221. package/dist/core/diagnostics.d.ts +9 -0
  222. package/dist/core/finalize.d.ts +18 -0
  223. package/dist/core/hast-nodes.d.ts +6 -0
  224. package/dist/core/highlight-lines.d.ts +8 -0
  225. package/dist/core/identity.d.ts +4 -0
  226. package/dist/core/labels.d.ts +4 -0
  227. package/dist/core/manifest.d.ts +38 -0
  228. package/dist/core/memo.d.ts +5 -0
  229. package/dist/core/model-hast.d.ts +8 -0
  230. package/dist/core/model.d.ts +10 -0
  231. package/dist/core/normalize.d.ts +27 -0
  232. package/dist/core/parts.d.ts +135 -0
  233. package/dist/core/preset.d.ts +10 -0
  234. package/dist/core/run.d.ts +16 -0
  235. package/dist/core/search.d.ts +5 -0
  236. package/dist/core/security.d.ts +21 -0
  237. package/dist/core/slugger.d.ts +6 -0
  238. package/dist/core/types.d.ts +390 -0
  239. package/dist/core/url.d.ts +10 -0
  240. package/dist/editor/codemirror.d.ts +14 -0
  241. package/dist/editor/index.d.ts +2 -0
  242. package/dist/editor/index.js +1 -0
  243. package/dist/export/index.d.ts +6 -0
  244. package/dist/headless.d.ts +21 -0
  245. package/dist/headless.js +12 -0
  246. package/dist/highlight/highlightjs.d.ts +7 -0
  247. package/dist/highlight/index.d.ts +3 -0
  248. package/dist/highlight/index.js +3 -0
  249. package/dist/highlight/shared.d.ts +16 -0
  250. package/dist/highlight/shiki.d.ts +7 -0
  251. package/dist/highlight/shiki.js +76 -0
  252. package/dist/highlight/shiki.js.map +1 -0
  253. package/dist/html/index.d.ts +17 -0
  254. package/dist/html/index.js +13 -0
  255. package/dist/html/index.js.map +1 -0
  256. package/dist/index.d.ts +24 -0
  257. package/dist/index.js +55 -0
  258. package/dist/index.js.map +1 -0
  259. package/dist/math/index.d.ts +4 -0
  260. package/dist/math/index.js +583 -0
  261. package/dist/math/index.js.map +1 -0
  262. package/dist/math/katex.d.ts +4 -0
  263. package/dist/math/plugin.d.ts +20 -0
  264. package/dist/mermaid/index.d.ts +5 -0
  265. package/dist/mermaid/index.js +3 -0
  266. package/dist/mermaid/plugin.d.ts +14 -0
  267. package/dist/mermaid/runtime.d.ts +12 -0
  268. package/dist/mermaid/sanitize.d.ts +12 -0
  269. package/dist/node-components.d.ts +1 -0
  270. package/dist/node-components.js +39 -0
  271. package/dist/pipeline/custom.d.ts +8 -0
  272. package/dist/pipeline/identity.d.ts +12 -0
  273. package/dist/pipeline/index.d.ts +5 -0
  274. package/dist/pipeline/official.d.ts +6 -0
  275. package/dist/pipeline.d.ts +1 -0
  276. package/dist/pipeline.js +1 -0
  277. package/dist/plugins/builtin.d.ts +15 -0
  278. package/dist/plugins/define.d.ts +7 -0
  279. package/dist/plugins/registry.d.ts +16 -0
  280. package/dist/plugins/source.d.ts +7 -0
  281. package/dist/plugins.d.ts +3 -0
  282. package/dist/plugins.js +1 -0
  283. package/dist/presets.d.ts +3 -0
  284. package/dist/presets.js +1 -0
  285. package/dist/style.css +2 -0
  286. package/dist/styles/components.css +712 -0
  287. package/dist/styles/index.d.ts +1 -0
  288. package/dist/styles/math-full.css +3 -0
  289. package/dist/styles/math.css +18 -0
  290. package/dist/styles/tokens.css +96 -0
  291. package/package.json +211 -6
package/README.md CHANGED
@@ -1,3 +1,579 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
1
+ # @coderminer/vue-markdown
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@coderminer/vue-markdown.svg)](https://www.npmjs.com/package/@coderminer/vue-markdown)
4
+ [![CI](https://github.com/coderminer/vue-markdown/actions/workflows/ci.yml/badge.svg)](https://github.com/coderminer/vue-markdown/actions/workflows/ci.yml)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
+ [![Docs](https://img.shields.io/badge/docs-live-8250df)](https://coderminer.github.io/vue-markdown/)
7
+
8
+ English | [简体中文](./README.zh-CN.md) | [Changelog](./CHANGELOG.md)
9
+
10
+ A general-purpose, customizable, plugin-driven **Vue 3 Markdown component suite**.
11
+
12
+ `@coderminer/vue-markdown` renders Markdown directly into Vue VNodes with the official
13
+ `unified` pipeline (`remark-parse` + `remark-rehype`). There is no HTML string
14
+ round-trip and no `v-html`. The parsed document is a serializable, DOM-free model,
15
+ so the same run can drive the styled renderer, a headless host, or static HTML
16
+ export.
17
+
18
+ - **Vue-native** — `shallowRef` documents, stable keys, a text fast path, and
19
+ parse memoization keep re-renders cheap.
20
+ - **Customizable** — replace any tag, address every visual part through
21
+ `data-vmd-part` and stable `vmd-*` classes, and theme with `--vmd-*` tokens.
22
+ - **Plugin-driven** — plugins contribute remark/rehype plugins, source and
23
+ document transforms, components, labels, tokens, and lifecycle hooks.
24
+ - **Safe by default** — raw HTML is dropped, URLs are validated, and
25
+ `htmlPlugin()` pairs the parser with the built-in sanitizer when the host opts in.
26
+ - **SSR-ready** — deterministic heading IDs, a synchronous path, and static HTML
27
+ export that applies the same sanitization, filtering, and URL policy.
28
+ - **Optional engines** — highlight.js, Shiki, KaTeX, Mermaid, and CodeMirror
29
+ stay behind their own entries and lazy chunks.
30
+
31
+ **Live documentation:** <https://coderminer.github.io/vue-markdown/>
32
+
33
+ **Chinese documentation:** [docs/zh](docs/zh/index.md) (`/zh/` on the documentation site).
34
+
35
+ ## Install
36
+
37
+ ```bash
38
+ npm install @coderminer/vue-markdown
39
+ ```
40
+
41
+ Requires Node 20+ and Vue 3.5+.
42
+
43
+ Optional engines are peer dependencies. Install only the ones you use:
44
+
45
+ ```bash
46
+ # Syntax highlighting
47
+ npm install highlight.js
48
+ # or
49
+ npm install shiki
50
+
51
+ # Math
52
+ npm install katex
53
+
54
+ # Diagrams
55
+ npm install mermaid
56
+
57
+ # Sanitized raw HTML through @coderminer/vue-markdown/html
58
+ npm install rehype-raw
59
+
60
+ # Mermaid live editor
61
+ npm install @codemirror/state @codemirror/view @codemirror/language @codemirror/commands
62
+ ```
63
+
64
+ ## Quick start
65
+
66
+ ```vue
67
+ <script setup lang="ts">
68
+ import { ref } from 'vue'
69
+ import { MarkdownRenderer } from '@coderminer/vue-markdown'
70
+ import '@coderminer/vue-markdown/style.css'
71
+
72
+ const source = ref(`
73
+ # Hello, Markdown
74
+
75
+ A **bold** paragraph with a [link](https://example.com).
76
+
77
+ - Vue components
78
+ - Safe by default
79
+ - SSR ready
80
+ `)
81
+ </script>
82
+
83
+ <template>
84
+ <MarkdownRenderer v-model:source="source" toc />
85
+ </template>
86
+ ```
87
+
88
+ The stylesheet is optional. Every component is semantic and works unstyled.
89
+
90
+ ## Basic usage
91
+
92
+ ### Input
93
+
94
+ Pass Markdown through `source`, bind it with `v-model:source`, or use the default
95
+ slot:
96
+
97
+ ```vue
98
+ <MarkdownRenderer source="# From the prop" />
99
+ <MarkdownRenderer v-model:source="source" />
100
+ <MarkdownRenderer># From the slot</MarkdownRenderer>
101
+ ```
102
+
103
+ `source` is controlled and wins over the slot. The slot is text-only and is
104
+ re-read when its text content changes. A non-string `source` reports a diagnostic
105
+ and renders the empty state instead of throwing.
106
+
107
+ ### Styling
108
+
109
+ ```ts
110
+ import '@coderminer/vue-markdown/style.css'
111
+ // or import the pieces separately
112
+ import '@coderminer/vue-markdown/styles/tokens.css'
113
+ import '@coderminer/vue-markdown/styles/components.css'
114
+ ```
115
+
116
+ Override tokens on any ancestor or through the `tokens` prop:
117
+
118
+ ```vue
119
+ <MarkdownRenderer
120
+ :source="source"
121
+ theme="auto"
122
+ :tokens="{ '--vmd-color-accent': '#8250df' }"
123
+ />
124
+ ```
125
+
126
+ Every visual part exposes both a stable class and a `data-vmd-part` attribute:
127
+
128
+ ```css
129
+ [data-vmd-part='heading'] {
130
+ letter-spacing: -0.01em;
131
+ }
132
+
133
+ [data-vmd-part='code'] {
134
+ --vmd-code-bg: #0d1117;
135
+ color: #e6edf3;
136
+ }
137
+ ```
138
+
139
+ ### Events and actions
140
+
141
+ ```vue
142
+ <script setup lang="ts">
143
+ const renderer = ref<InstanceType<typeof MarkdownRenderer>>()
144
+
145
+ function onToc(toc) {
146
+ console.log(toc)
147
+ }
148
+ </script>
149
+
150
+ <template>
151
+ <MarkdownRenderer
152
+ ref="renderer"
153
+ :source="source"
154
+ @toc-change="onToc"
155
+ @link-click="onLink"
156
+ @render-error="onError"
157
+ />
158
+ </template>
159
+ ```
160
+
161
+ Exposed actions: `scrollToHeading(id)`, `getDocument()`, `getToc()`, `refresh()`,
162
+ and `updateSource(source)`.
163
+
164
+ ## Customization
165
+
166
+ Customization is layered and stable: target tags, semantic nodes, regions, design
167
+ tokens, or documented CSS parts. The full guide with a live preview is in the
168
+ [live customization section](https://coderminer.github.io/vue-markdown/guide/customization.html).
169
+
170
+ ### Customize your own elements
171
+
172
+ ```vue [BadgeLink.vue]
173
+ <script setup lang="ts">
174
+ import type { MarkdownNode } from '@coderminer/vue-markdown'
175
+
176
+ defineProps<{
177
+ node?: MarkdownNode
178
+ href?: string
179
+ }>()
180
+ </script>
181
+
182
+ <template>
183
+ <a :href="href" class="badge-link">
184
+ <span class="badge">link</span>
185
+ <slot />
186
+ </a>
187
+ </template>
188
+ ```
189
+
190
+ ```vue [Callout.vue]
191
+ <script setup lang="ts">
192
+ import type { MarkdownNode } from '@coderminer/vue-markdown'
193
+
194
+ defineProps<{ node?: MarkdownNode }>()
195
+ </script>
196
+
197
+ <template>
198
+ <aside class="callout">
199
+ <slot />
200
+ </aside>
201
+ </template>
202
+ ```
203
+
204
+ ```vue [App.vue]
205
+ <script setup lang="ts">
206
+ import { MarkdownRenderer } from '@coderminer/vue-markdown'
207
+ import BadgeLink from './BadgeLink.vue'
208
+ import Callout from './Callout.vue'
209
+
210
+ const components = {
211
+ h1: 'h2',
212
+ a: BadgeLink,
213
+ }
214
+
215
+ const nodeComponents = {
216
+ blockquote: Callout,
217
+ }
218
+
219
+ const regions = {
220
+ toc: MyToc,
221
+ empty: MyEmpty,
222
+ }
223
+ </script>
224
+
225
+ <template>
226
+ <MarkdownRenderer
227
+ :source="source"
228
+ :components="components"
229
+ :node-components="nodeComponents"
230
+ :regions="regions"
231
+ />
232
+ </template>
233
+ ```
234
+
235
+ `components` is the tag-keyed map. `nodeComponents` targets the semantic model
236
+ (`code`, `math`, `mermaid`, `custom`, and element tags) and also accepts function
237
+ renderers. `regions` replaces structural areas such as the TOC, content, error,
238
+ empty, and loading states. Named slots are the last layer and receive scoped data
239
+ plus actions. For custom syntax, `customTagsPlugin({ tags: ['x-note'] })` turns
240
+ selected elements into custom nodes that map to your own components. Fenced code
241
+ always wraps through `components.pre`; its inner element resolves through
242
+ `components.code` or `nodeComponents.code`.
243
+
244
+ For a full component-based customization walkthrough, including a
245
+ `CodeBlock`-powered custom element, see the
246
+ [Rich components guide](docs/guide/rich-components.md#build-a-custom-code-block-with-codeblock).
247
+
248
+ ### Customize the theme
249
+
250
+ ```vue
251
+ <!-- Preset: light | dark | auto | custom -->
252
+ <MarkdownRenderer theme="auto" :source="source" toc />
253
+
254
+ <!-- Per-instance tokens -->
255
+ <MarkdownRenderer
256
+ theme="auto"
257
+ :source="source"
258
+ :tokens="{
259
+ '--vmd-color-accent': '#8250df',
260
+ '--vmd-radius-md': '12px',
261
+ }"
262
+ />
263
+
264
+ <!-- App-wide defaults -->
265
+ <MarkdownConfigProvider theme="auto" :tokens="brandTokens">
266
+ <MarkdownRenderer :source="source" toc />
267
+ </MarkdownConfigProvider>
268
+ ```
269
+
270
+ The renderer writes `data-vmd-theme` on its own root and never touches the host
271
+ page. `auto` follows `prefers-color-scheme`, while `custom` applies no preset
272
+ colors so your token overrides win unchanged. Tokens cascade from any ancestor,
273
+ so a scoped theme is just a class with `--vmd-*` properties.
274
+
275
+ ### Customize CSS
276
+
277
+ ```ts
278
+ import '@coderminer/vue-markdown/style.css'
279
+ ```
280
+
281
+ ```css
282
+ .my-docs {
283
+ --vmd-font-size: 1.0625rem;
284
+ --vmd-line-height: 1.8;
285
+ --vmd-color-accent: #8250df;
286
+ }
287
+
288
+ [data-vmd-part='heading'] {
289
+ letter-spacing: -0.01em;
290
+ }
291
+
292
+ [data-vmd-part='code'] {
293
+ --vmd-code-bg: #0d1117;
294
+ color: #e6edf3;
295
+ }
296
+ ```
297
+
298
+ The stylesheet is optional and split into `styles/tokens.css` and
299
+ `styles/components.css`. Target the documented `data-vmd-part` / `vmd-*` parts
300
+ and `--vmd-*` tokens, never internal DOM structure, because a host may replace
301
+ any tag component. Unstyled usage keeps the same behavior and accessibility.
302
+
303
+ See [Styled usage](docs/guide/styling.md) and
304
+ [Customization](docs/guide/customization.md) for the full contract.
305
+
306
+ ## Advanced usage
307
+
308
+ ### Plugins and presets
309
+
310
+ ```ts
311
+ import { defineMarkdownPlugin } from '@coderminer/vue-markdown/plugins'
312
+ import { defineMarkdownPreset, composePresets } from '@coderminer/vue-markdown/presets'
313
+
314
+ export const docsPlugin = defineMarkdownPlugin({
315
+ name: 'docs',
316
+ phase: 'normal',
317
+ remarkPlugins: [],
318
+ rehypePlugins: [],
319
+ components: { h2: 'h3' },
320
+ labels: { toc: 'On this page' },
321
+ tokens: { '--vmd-color-accent': '#8250df' },
322
+ transformDocument(document) {
323
+ return { ...document, frontmatter: { ...document.frontmatter, docs: true } }
324
+ },
325
+ setup() {
326
+ // Runs once per resolved plugin set inside an effectScope.
327
+ return () => {
328
+ // Cleanup on reconfiguration and unmount.
329
+ }
330
+ },
331
+ })
332
+
333
+ export const docsPreset = composePresets(
334
+ defineMarkdownPreset({ name: 'base', theme: 'auto' }),
335
+ defineMarkdownPreset({ name: 'docs', tokens: { '--vmd-radius-md': '10px' } }),
336
+ )
337
+ ```
338
+
339
+ ```vue
340
+ <script setup lang="ts">
341
+ const plugins = [docsPlugin]
342
+ </script>
343
+
344
+ <template>
345
+ <MarkdownRenderer :source="source" :plugins="plugins" :preset="docsPreset" toc />
346
+ </template>
347
+ ```
348
+
349
+ Order is `pre` → `normal` → `post`, then registration order. Duplicate names
350
+ replace deterministically. Keep the plugin array stable: plugin identity is part
351
+ of the parse memo key, so `:plugins="[docsPlugin]"` created inline in a template
352
+ re-parses on every parent render. A failing plugin is isolated and never corrupts
353
+ the last good document.
354
+
355
+ ### Headless rendering
356
+
357
+ ```ts
358
+ import { useMarkdownDocument } from '@coderminer/vue-markdown/headless'
359
+
360
+ const { document, toc, status, diagnostics, refresh } = useMarkdownDocument(source, {
361
+ plugins: [docsPlugin],
362
+ })
363
+ ```
364
+
365
+ The composable owns parsing, memoization, plugin lifecycle, status, and
366
+ diagnostics. It renders nothing, so a host can map the serializable model to its
367
+ own markup.
368
+
369
+ ### Syntax highlighting, math, and diagrams
370
+
371
+ ```ts
372
+ import { highlightjs } from '@coderminer/vue-markdown/highlight'
373
+ import { shiki } from '@coderminer/vue-markdown/highlight/shiki'
374
+ import { fullPlugins } from '@coderminer/vue-markdown/plugins'
375
+ import { mathPlugin, katexEngine } from '@coderminer/vue-markdown/math'
376
+ import { mermaidPlugin, renderMermaid } from '@coderminer/vue-markdown/mermaid'
377
+ import '@coderminer/vue-markdown/styles/math-full.css'
378
+
379
+ const plugins = [...fullPlugins, mathPlugin(), mermaidPlugin()]
380
+ ```
381
+
382
+ ```vue
383
+ <MarkdownRenderer
384
+ :source="source"
385
+ :highlighter="shiki"
386
+ :math-engine="katexEngine"
387
+ :plugins="plugins"
388
+ />
389
+ ```
390
+
391
+ Each engine is a small adapter with an `id` and one method, so a host can provide
392
+ its own highlighter, math renderer, or Mermaid renderer. See the
393
+ [highlighting](docs/guide/highlighting.md), [math](docs/guide/math.md), and
394
+ [Mermaid](docs/guide/mermaid.md) guides, or the
395
+ [rich components guide](docs/guide/rich-components.md) for standalone
396
+ `CodeBlock`, `VueSyntaxHighlighter`, `MermaidBlock`, and `MermaidLiveEditor`
397
+ usage.
398
+
399
+ ### Server rendering and static export
400
+
401
+ ```ts
402
+ import { exportMarkdownHtml, exportMarkdownHtmlSync } from '@coderminer/vue-markdown'
403
+
404
+ const html = exportMarkdownHtmlSync(source)
405
+ const asyncHtml = await exportMarkdownHtml(source, { plugins: [docsPlugin] })
406
+ ```
407
+
408
+ Export uses the same pipeline, plugins, sanitizer, URL policy, transforms, and
409
+ heading IDs as rendering. `exportMarkdownHtmlSync` requires a synchronous
410
+ pipeline; the official pipeline supports both paths.
411
+
412
+ ## Complete example
413
+
414
+ The live docs include a complete docs-portal example that combines:
415
+
416
+ - frontmatter, GFM, search, and TOC
417
+ - presets, plugins, and custom blockquote/link node components
418
+ - KaTeX math and a lazy Mermaid diagram
419
+ - theme switching and static HTML export
420
+ - the same public API used by the rest of the documentation
421
+
422
+ Open the [complete example](https://coderminer.github.io/vue-markdown/guide/complete-example.html),
423
+ or browse [`docs/.vitepress/theme/components/CompleteExample.vue`](docs/.vitepress/theme/components/CompleteExample.vue)
424
+ in the repository.
425
+
426
+ ## API reference
427
+
428
+ The full reference, including every slot, region, adapter contract, and
429
+ component manifest, lives in the
430
+ [live API reference](https://coderminer.github.io/vue-markdown/reference/renderer.html).
431
+
432
+ ### `MarkdownRenderer` props
433
+
434
+ | Prop | Type | Default | Notes |
435
+ | --- | --- | --- | --- |
436
+ | `source` | `string` | `''` | Controlled Markdown input. Wins over the default slot. Supports `v-model:source`. |
437
+ | `components` | `Record<string, Component \| string>` | `{}` | Tag-keyed overrides. |
438
+ | `regions` | `Partial<Record<string, Component \| string>>` | `{}` | Root, content, TOC, TOC item, code block, Mermaid block, error, empty, and loading region overrides. |
439
+ | `nodeComponents` | `Record<string, Component \| string \| NodeRenderer>` | `{}` | Semantic node overrides and function renderers. |
440
+ | `labels` | `Partial<MarkdownLabels>` | `{}` | String or function labels for built-in text. |
441
+ | `preset` | `MarkdownPreset \| MarkdownPreset[]` | — | Applies one or more presets. |
442
+ | `plugins` | `PluginInput[]` | `defaultPlugins` | Replaces the default plugin set when provided. Add `htmlPlugin()` for sanitized raw HTML. |
443
+ | `disablePlugins` | `string[]` | `[]` | Removes named plugins from the resolved set. |
444
+ | `remarkPlugins` | `PluggableList` | `[]` | Runs after library remark plugins. |
445
+ | `rehypePlugins` | `PluggableList` | `[]` | Runs after library rehype plugins and the built-in sanitizer. |
446
+ | `remarkRehypeOptions` | `Record<string, unknown>` | `{}` | Merged into the conversion step. |
447
+ | `pipeline` | `MarkdownPipeline` | official | Advanced escape hatch; must return hast. |
448
+ | `slugger` | `MarkdownSlugger` | `github-slugger` | Heading ID generator. |
449
+ | `highlighter` | `MarkdownHighlighter` | — | Syntax highlighting adapter. |
450
+ | `mathEngine` | `MathEngine` | — | Math rendering adapter. |
451
+ | `mermaidRenderer` | `MermaidRenderer` | — | Mermaid rendering adapter. |
452
+ | `diagnosticsFormatter` | `DiagnosticFormatter` | — | Formats render errors. |
453
+ | `allowedElements` | `string[]` | — | Mutually exclusive with `disallowedElements`; wins on conflict. |
454
+ | `disallowedElements` | `string[]` | — | Deny list. |
455
+ | `unwrapDisallowed` | `boolean` | `false` | Keeps the children of removed elements. |
456
+ | `allowElement` | `(node, index, parent) => boolean \| null \| undefined` | — | Runs after the allow/deny lists; any falsy result rejects the element. |
457
+ | `urlTransform` | `(url, key, node) => string \| null \| undefined` | `defaultUrlTransform` | Applies to every URL-bearing attribute; `null` removes it and the result is revalidated. |
458
+ | `linkTarget` | `string` | `'_self'` | Applied to links. |
459
+ | `externalLinkTarget` | `'_self' \| '_blank'` | `'_self'` | `_blank` adds `rel="noopener noreferrer"`. |
460
+ | `baseUrl` | `string` | — | Resolves relative URLs before `urlTransform`. |
461
+ | `idPrefix` | `string` | `''` | Prefixes generated heading IDs. Use a unique prefix for multiple renderers on one page. |
462
+ | `syncHash` | `boolean` | `false` | Updates the URL hash on heading activation. |
463
+ | `toc` | `boolean` | `false` | Renders the TOC region. |
464
+ | `tocDepth` | `number` | `0` | Maximum heading level in the TOC. `0` means every level. |
465
+ | `tocPlacement` | `'top' \| 'left' \| 'right' \| 'hidden'` | `'top'` | Stack the TOC, place it beside the content, or hide it. |
466
+ | `search` | `string` | `''` | Highlights matches and emits `search-change`. |
467
+ | `searchCaseSensitive` | `boolean` | `false` | Makes the `search` match case-sensitive. |
468
+ | `showError` | `boolean` | `true` | Renders the error region on failure. |
469
+ | `tokens` | `Record<string, string>` | `{}` | Inline `--vmd-*` custom properties on the root. |
470
+ | `theme` | `'light' \| 'dark' \| 'auto' \| 'custom'` | `'light'` | Sets `data-vmd-theme` on the root. |
471
+ | `as` | `string \| Component` | `'div'` | Root element or component. |
472
+
473
+ ### Events
474
+
475
+ | Event | Payload |
476
+ | --- | --- |
477
+ | `update:source` | `source: string` |
478
+ | `toc-change` | `toc: TocItem[]` |
479
+ | `link-click` | `{ url, target, node, event }` |
480
+ | `custom-tag-click` | `{ tag, props, node, event }` |
481
+ | `task-change` | `{ checked, node }` |
482
+ | `search-change` | `{ query, caseSensitive, matches }` |
483
+ | `math-error` | `MarkdownDiagnostic` |
484
+ | `render-error` | `MarkdownDiagnostic` |
485
+ | `ready` | `MarkdownDocument` |
486
+
487
+ `toc-change` is signature-gated: it only fires when the serialized TOC changes.
488
+ `search-change` follows the `search` prop and reports the current match count
489
+ after the rendered document has settled for that query.
490
+ `ready` fires once for the first successful document.
491
+
492
+ ### Slots
493
+
494
+ The `default` slot is raw Markdown text. Named region slots fully replace their
495
+ default region and receive scoped context: `root`, `toc`, `toc-item`, `content`,
496
+ `error`, `empty`, and `loading`. An absent or empty slot keeps the default
497
+ rendering. See the [customization guide](docs/guide/customization.md#slots).
498
+
499
+ ### Entry points
500
+
501
+ | Entry | Contents |
502
+ | --- | --- |
503
+ | `@coderminer/vue-markdown` | Renderer, preset components, composables, core helpers |
504
+ | `@coderminer/vue-markdown/headless` | Types, model helpers, composables; no preset components or CSS |
505
+ | `@coderminer/vue-markdown/pipeline` | Official pipeline, custom pipeline validation, identity |
506
+ | `@coderminer/vue-markdown/plugins` | `defineMarkdownPlugin`, registry, built-in plugins |
507
+ | `@coderminer/vue-markdown/presets` | `defineMarkdownPreset`, `composePresets`, configuration types |
508
+ | `@coderminer/vue-markdown/highlight` | highlight.js adapter and normalization helpers |
509
+ | `@coderminer/vue-markdown/highlight/shiki` | Optional Shiki adapter |
510
+ | `@coderminer/vue-markdown/math` | `mathPlugin`, `katexEngine`, math types |
511
+ | `@coderminer/vue-markdown/mermaid` | Lazy Mermaid runtime and SVG sanitizer |
512
+ | `@coderminer/vue-markdown/editor` | Lazy CodeMirror integration |
513
+ | `@coderminer/vue-markdown/html` | `htmlPlugin()` and sanitized raw HTML |
514
+ | `@coderminer/vue-markdown/node-components` | The node component catalog only |
515
+ | `@coderminer/vue-markdown/components/*` | One entry per public component |
516
+ | `@coderminer/vue-markdown/style.css` | Full stylesheet |
517
+ | `@coderminer/vue-markdown/styles/tokens.css` | Design tokens only |
518
+ | `@coderminer/vue-markdown/styles/components.css` | Part-based component styles |
519
+ | `@coderminer/vue-markdown/styles/math.css` | Math container styles; import KaTeX CSS separately |
520
+ | `@coderminer/vue-markdown/styles/math-full.css` | KaTeX CSS plus math container styles |
521
+
522
+ ## Security defaults
523
+
524
+ - Raw HTML is dropped. Add `htmlPlugin()` from `@coderminer/vue-markdown/html` to
525
+ enable it; the sanitizer then runs immediately after raw parsing.
526
+ - URL protocols are limited to `http`, `https`, `irc`, `ircs`, `mailto`,
527
+ `xmpp`, and relative URLs.
528
+ - Image `data:` URLs are raster-only; `data:image/svg+xml` is rejected.
529
+ - Event handler attributes and `style` are stripped from raw HTML and custom
530
+ tags.
531
+ - The render path uses no `v-html`, no `eval`, and no inline script.
532
+ - Mermaid is rendered with strict security and its SVG is sanitized before it
533
+ becomes nodes.
534
+
535
+ See [docs/guide/security.md](docs/guide/security.md) for the full policy.
536
+
537
+ ## Documentation
538
+
539
+ | Guide | What it covers |
540
+ | --- | --- |
541
+ | [Rich components](docs/guide/rich-components.md) | `CodeBlock`, `VueSyntaxHighlighter`, `MermaidBlock`, and `MermaidLiveEditor` usage |
542
+ | [Styling and themes](docs/guide/styling.md) | Tokens, themes, parts, and unstyled mode |
543
+ | [Customization](docs/guide/customization.md) | Precedence, regions, node components, slots, manifests |
544
+ | [Cookbook](docs/guide/cookbook.md) | Copy-paste recipes for common tasks |
545
+ | [Headless usage](docs/guide/headless.md) | `useMarkdownDocument`, the model, and helper APIs |
546
+ | [Pipeline](docs/guide/pipeline.md) | The official unified pipeline and stage order |
547
+ | [Custom pipeline](docs/guide/custom-pipeline.md) | Authoring and validating a replacement pipeline |
548
+ | [Plugins](docs/guide/plugins.md) | Plugin contracts, ordering, lifecycle, and remark/rehype |
549
+ | [CommonMark and GFM](docs/guide/commonmark-gfm.md) | Syntax coverage and conformance |
550
+ | [Raw HTML and security](docs/guide/security.md) | Sanitization, URL policy, CSP, and custom tags |
551
+ | [Syntax highlighting](docs/guide/highlighting.md) | Adapters, Shiki, caching, and server rendering |
552
+ | [Math](docs/guide/math.md) | `mathPlugin`, delimiters, engines, and fallbacks |
553
+ | [Mermaid](docs/guide/mermaid.md) | Lazy runtime, sanitizer, block states, and editor |
554
+ | [SSR and static export](docs/guide/ssr.md) | Server rendering and static HTML helpers |
555
+ | [Audits](docs/guide/audits.md) | Accessibility, reduced motion, RTL, and cleanup |
556
+
557
+ ## Development
558
+
559
+ ```bash
560
+ npm install
561
+ npm run docs:dev # documentation site (VitePress)
562
+ npm run docs:build # static documentation site
563
+ npm run dev # interactive demo
564
+ npm run build:lib # library, declarations, styles
565
+ npm test # node + happy-dom projects
566
+ npm run typecheck
567
+ npm run lint
568
+ npm run size # bundle entry guard
569
+ npm run bench # parse/render budget gate
570
+ ```
571
+
572
+ The documentation site is deployed to GitHub Pages by
573
+ `.github/workflows/pages.yml`. The repository also contains `AGENTS.md`, which
574
+ documents the layered architecture and the rules that keep the core DOM-free and
575
+ the dependency direction one-way.
576
+
577
+ ## License
578
+
579
+ [MIT](LICENSE) © CoderMiner