mio-previewer 0.1.1
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.
- package/LICENSE +21 -0
- package/README.md +218 -0
- package/README.zh-CN.md +206 -0
- package/dist/MdRenderer.vue_vue_type_style_index_0_lang-ClzqKjX4.js +4562 -0
- package/dist/MdRenderer.vue_vue_type_style_index_0_lang-Dpnz3CdM.cjs +16 -0
- package/dist/_basePickBy-CZxbwAvt.cjs +1 -0
- package/dist/_basePickBy-nvL1-X4h.js +151 -0
- package/dist/_baseUniq-Cwhfu1XM.js +614 -0
- package/dist/_baseUniq-DunUk-cd.cjs +1 -0
- package/dist/_commonjsHelpers-DKOUU3wS.cjs +1 -0
- package/dist/_commonjsHelpers-DaMA6jEr.js +8 -0
- package/dist/_plugin-vue_export-helper-BHFhmbuH.cjs +1 -0
- package/dist/_plugin-vue_export-helper-CHgC5LLL.js +9 -0
- package/dist/arc-C9I4pYLv.js +83 -0
- package/dist/arc-fCflz0gB.cjs +1 -0
- package/dist/architecture-O4VJ6CD3-D00QJU0o.js +5 -0
- package/dist/architecture-O4VJ6CD3-dKuizgWO.cjs +1 -0
- package/dist/architectureDiagram-VXUJARFQ-DQ-YD3RX.cjs +36 -0
- package/dist/architectureDiagram-VXUJARFQ-VWr1UuPv.js +4662 -0
- package/dist/assets/parser.worker-67NQKZt5.js +16 -0
- package/dist/blockDiagram-VD42YOAC-DuC96I2Q.js +2261 -0
- package/dist/blockDiagram-VD42YOAC-EC2x5LwN.cjs +122 -0
- package/dist/c4Diagram-YG6GDRKO-Dm5d0BWL.cjs +10 -0
- package/dist/c4Diagram-YG6GDRKO-OB8wIuF8.js +1580 -0
- package/dist/channel-C-uR528Z.js +5 -0
- package/dist/channel-YfH5CBV-.cjs +1 -0
- package/dist/chunk-4BX2VUAB-3Liht_XN.cjs +1 -0
- package/dist/chunk-4BX2VUAB-j8LeaMvy.js +8 -0
- package/dist/chunk-55IACEB6-Dm3mi3ha.cjs +1 -0
- package/dist/chunk-55IACEB6-IYAIzfR4.js +8 -0
- package/dist/chunk-B4BG7PRW-CpqTB0S5.cjs +165 -0
- package/dist/chunk-B4BG7PRW-DB5df3Iz.js +1375 -0
- package/dist/chunk-DI55MBZ5-BoFZpvY3.js +1370 -0
- package/dist/chunk-DI55MBZ5-wqsoqtNw.cjs +220 -0
- package/dist/chunk-FMBD7UC4-BZS_4hun.cjs +15 -0
- package/dist/chunk-FMBD7UC4-CdmoYYnM.js +19 -0
- package/dist/chunk-QN33PNHL-BuyP9RXS.js +19 -0
- package/dist/chunk-QN33PNHL-CHI_-zix.cjs +1 -0
- package/dist/chunk-QZHKN3VN-15dJyQk0.js +15 -0
- package/dist/chunk-QZHKN3VN-DfH9qQ3T.cjs +1 -0
- package/dist/chunk-TZMSLE5B-BgFWf03M.js +64 -0
- package/dist/chunk-TZMSLE5B-qIo1h7Gz.cjs +1 -0
- package/dist/classDiagram-2ON5EDUG-BQz3UzKi.js +16 -0
- package/dist/classDiagram-2ON5EDUG-CZWeacVd.cjs +1 -0
- package/dist/classDiagram-v2-WZHVMYZB-BQz3UzKi.js +16 -0
- package/dist/classDiagram-v2-WZHVMYZB-CZWeacVd.cjs +1 -0
- package/dist/clone-ByeQKKoW.cjs +1 -0
- package/dist/clone-D6h_cwF4.js +8 -0
- package/dist/cose-bilkent-S5V4N54A-5dO3qpr4.cjs +1 -0
- package/dist/cose-bilkent-S5V4N54A-D2q7jBXB.js +2609 -0
- package/dist/cytoscape.esm-DHF7mANN.cjs +331 -0
- package/dist/cytoscape.esm-DfdJODL8.js +18735 -0
- package/dist/dagre-6UL2VRFP-Cfh4UdSr.js +444 -0
- package/dist/dagre-6UL2VRFP-DS2Ki9Dv.cjs +4 -0
- package/dist/defaultLocale-D7EN2tov.js +171 -0
- package/dist/defaultLocale-DIVzfLaQ.cjs +1 -0
- package/dist/diagram-PSM6KHXK-BZDEX43o.js +531 -0
- package/dist/diagram-PSM6KHXK-CTsP6f2a.cjs +24 -0
- package/dist/diagram-QEK2KX5R-BDKMNi97.cjs +43 -0
- package/dist/diagram-QEK2KX5R-Dda_FEDc.js +217 -0
- package/dist/diagram-S2PKOQOG-CmfsKOvs.cjs +24 -0
- package/dist/diagram-S2PKOQOG-Cnw4b7LB.js +142 -0
- package/dist/entries/md.cjs.js +1 -0
- package/dist/entries/md.es.js +5 -0
- package/dist/entries/plugin-alert.cjs.js +1 -0
- package/dist/entries/plugin-alert.es.js +27 -0
- package/dist/entries/plugin-codeblock.cjs.js +9 -0
- package/dist/entries/plugin-codeblock.es.js +3441 -0
- package/dist/entries/plugin-emoji.cjs.js +1 -0
- package/dist/entries/plugin-emoji.es.js +28 -0
- package/dist/entries/plugin-katex.cjs.js +1 -0
- package/dist/entries/plugin-katex.es.js +92 -0
- package/dist/entries/plugin-mermaid.cjs.js +1 -0
- package/dist/entries/plugin-mermaid.es.js +4 -0
- package/dist/erDiagram-Q2GNP2WA-DE4JLeNF.cjs +60 -0
- package/dist/erDiagram-Q2GNP2WA-qAdA8fbE.js +841 -0
- package/dist/favicon.ico +0 -0
- package/dist/flowDiagram-NV44I4VS-C7YBx4JP.js +1620 -0
- package/dist/flowDiagram-NV44I4VS-j3dB-fjF.cjs +162 -0
- package/dist/ganttDiagram-LVOFAZNH-BL-Yjadx.js +2506 -0
- package/dist/ganttDiagram-LVOFAZNH-CBhzET57.cjs +267 -0
- package/dist/gitGraph-ZV4HHKMB-Dr9sn7R3.js +5 -0
- package/dist/gitGraph-ZV4HHKMB-DyXW77WY.cjs +1 -0
- package/dist/gitGraphDiagram-NY62KEGX-DDklxVnY.cjs +65 -0
- package/dist/gitGraphDiagram-NY62KEGX-DFn7h5BH.js +699 -0
- package/dist/graph-CHoeKkVR.cjs +1 -0
- package/dist/graph-DiGqaw_6.js +247 -0
- package/dist/info-63CPKGFF-BGxbI0Qv.cjs +1 -0
- package/dist/info-63CPKGFF-xflgSxfH.js +5 -0
- package/dist/infoDiagram-F6ZHWCRC-DOtGa28U.js +24 -0
- package/dist/infoDiagram-F6ZHWCRC-Duylo4r7.cjs +2 -0
- package/dist/init-CHZsXQcr.cjs +1 -0
- package/dist/init-DjUOC4st.js +16 -0
- package/dist/journeyDiagram-XKPGCS4Q-bJncB3oe.js +834 -0
- package/dist/journeyDiagram-XKPGCS4Q-h-CtcfbS.cjs +139 -0
- package/dist/kanban-definition-3W4ZIXB7-C3y0C_bw.cjs +89 -0
- package/dist/kanban-definition-3W4ZIXB7-nMPCi8GW.js +719 -0
- package/dist/katex-CmGeg_OO.js +11692 -0
- package/dist/katex-DEiiRhcn.cjs +261 -0
- package/dist/layout-BG4AbhIW.cjs +1 -0
- package/dist/layout-CHaNS4g6.js +1324 -0
- package/dist/linear-Bqd4C_Yb.cjs +1 -0
- package/dist/linear-CPFNaVnw.js +259 -0
- package/dist/mermaid-parser.core-CR8Rcyps.cjs +128 -0
- package/dist/mermaid-parser.core-CkQKh-yb.js +12966 -0
- package/dist/mindmap-definition-VGOIOE7T-C63AEIdU.js +784 -0
- package/dist/mindmap-definition-VGOIOE7T-CHI9UFtA.cjs +68 -0
- package/dist/mio-previewer.cjs.js +3 -0
- package/dist/mio-previewer.css +1 -0
- package/dist/mio-previewer.es.js +25 -0
- package/dist/ordinal-CagbB1m8.cjs +1 -0
- package/dist/ordinal-DfAQgscy.js +61 -0
- package/dist/packet-HUATNLJX-BeAGxpDF.cjs +1 -0
- package/dist/packet-HUATNLJX-dnmrn2-l.js +5 -0
- package/dist/parser.worker.js +21 -0
- package/dist/pie-WTHONI2E-BKoHQt0i.js +5 -0
- package/dist/pie-WTHONI2E-BifrFKgo.cjs +1 -0
- package/dist/pieDiagram-ADFJNKIX-B9OONHi_.cjs +30 -0
- package/dist/pieDiagram-ADFJNKIX-CEMFAt9B.js +161 -0
- package/dist/plugin-mermaid-FTki7cN8.cjs +255 -0
- package/dist/plugin-mermaid-y4lbJ7sL.js +15369 -0
- package/dist/quadrantDiagram-AYHSOK5B-DobvzsAU.js +1022 -0
- package/dist/quadrantDiagram-AYHSOK5B-DqXDgyBD.cjs +7 -0
- package/dist/radar-NJJJXTRR-BPN19Spv.cjs +1 -0
- package/dist/radar-NJJJXTRR-Bj9rI8mr.js +5 -0
- package/dist/requirementDiagram-UZGBJVZJ-CVbmNF7M.cjs +64 -0
- package/dist/requirementDiagram-UZGBJVZJ-M-MPvTnX.js +850 -0
- package/dist/sankeyDiagram-TZEHDZUN-C-ESiLJA.cjs +10 -0
- package/dist/sankeyDiagram-TZEHDZUN-Czsin99f.js +810 -0
- package/dist/sequenceDiagram-WL72ISMW-BJByNQsK.js +2511 -0
- package/dist/sequenceDiagram-WL72ISMW-DApIQwP-.cjs +145 -0
- package/dist/stateDiagram-FKZM4ZOC-BuKL2w66.cjs +1 -0
- package/dist/stateDiagram-FKZM4ZOC-jAiBDhVn.js +263 -0
- package/dist/stateDiagram-v2-4FDKWEC3-Ct5PFxdd.cjs +1 -0
- package/dist/stateDiagram-v2-4FDKWEC3-umSVoFht.js +16 -0
- package/dist/timeline-definition-IT6M3QCI-BfAvK0gf.cjs +61 -0
- package/dist/timeline-definition-IT6M3QCI-I--lBLTi.js +795 -0
- package/dist/treemap-75Q7IDZK-DNt-zuL8.cjs +1 -0
- package/dist/treemap-75Q7IDZK-bjql9DgL.js +5 -0
- package/dist/types/entries/md.d.ts +3 -0
- package/dist/types/entries/plugin-alert.d.ts +1 -0
- package/dist/types/entries/plugin-codeblock.d.ts +1 -0
- package/dist/types/entries/plugin-emoji.d.ts +1 -0
- package/dist/types/entries/plugin-katex.d.ts +1 -0
- package/dist/types/entries/plugin-mermaid.d.ts +1 -0
- package/dist/types/helpers/containerHelpers.d.ts +47 -0
- package/dist/types/helpers/index.d.ts +4 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/main-plugin-demo.d.ts +1 -0
- package/dist/types/main.d.ts +1 -0
- package/dist/types/plugins/AlertPlugin.d.ts +16 -0
- package/dist/types/plugins/CodeBlockPlugin.d.ts +9 -0
- package/dist/types/plugins/EmojiPlugin.d.ts +11 -0
- package/dist/types/plugins/katexPlugin.d.ts +8 -0
- package/dist/types/plugins/mermaidPlugin.d.ts +13 -0
- package/dist/types/types.d.ts +77 -0
- package/dist/xychartDiagram-PRI3JC2R-BN9e47xe.cjs +7 -0
- package/dist/xychartDiagram-PRI3JC2R-XrOK_egj.js +1340 -0
- package/package.json +114 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Mio-FCIP
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# mio-previewer
|
|
2
|
+
|
|
3
|
+
[中文文档](./README.zh-CN.md) | English
|
|
4
|
+
|
|
5
|
+
A small Vue 3 markdown previewer optimized for streaming updates. It
|
|
6
|
+
converts Markdown -> HTML -> htmlparser2 AST and renders the AST to Vue
|
|
7
|
+
VNode with a tiny recursive renderer. There's an optional module Worker
|
|
8
|
+
(`public/parser.worker.js`) that can handle Markdown parsing off the main
|
|
9
|
+
|
|
10
|
+
This project is also configured to be published as an npm library (see
|
|
11
|
+
`package.json` scripts). The library exposes a named export `MdRenderer`
|
|
12
|
+
from the package root (import { MdRenderer } from 'mio-previewer').
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
Prerequisites: Node 18+ recommended, pnpm (or npm/yarn).
|
|
16
|
+
|
|
17
|
+
Install dependencies:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pnpm install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Run dev server:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pnpm dev
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Open http://localhost:5173/ to view the live preview.
|
|
30
|
+
|
|
31
|
+
Build for production:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pnpm build
|
|
35
|
+
pnpm preview
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Install the package (after publishing or using a local install):
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# from npm (when published)
|
|
42
|
+
pnpm add mio-previewer
|
|
43
|
+
|
|
44
|
+
# or install from a local folder
|
|
45
|
+
pnpm add /path/to/mio-previewer
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Usage example (consumer project with Vue 3):
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
import { createApp } from 'vue'
|
|
52
|
+
import { MdRenderer } from 'mio-previewer'
|
|
53
|
+
import 'github-markdown-css/github-markdown.css'
|
|
54
|
+
|
|
55
|
+
const app = createApp({})
|
|
56
|
+
app.component('MdRenderer', MdRenderer)
|
|
57
|
+
app.mount('#app')
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Notes for bundlers and consumers
|
|
61
|
+
- `vue` is marked as external in the library bundle. Add `vue@^3` to
|
|
62
|
+
your project's dependencies (or peerDependencies) when publishing.
|
|
63
|
+
- Types are emitted to `dist/types` during build; the package `types`
|
|
64
|
+
field points to the generated declaration file.
|
|
65
|
+
|
|
66
|
+
Publishing checklist
|
|
67
|
+
- Ensure `package.json` has `name`, `version`, `description`, `repository`,
|
|
68
|
+
and `peerDependencies: { "vue": "^3" }` (recommended).
|
|
69
|
+
- Run `pnpm run build` (this runs the lib build and emits types).
|
|
70
|
+
- Publish with `pnpm publish --access public` (or use CI automation).
|
|
71
|
+
## Project overview
|
|
72
|
+
|
|
73
|
+
- `src/MdRenderer.vue` — core component. Accepts props `md` (string),
|
|
74
|
+
`isStreaming` (boolean) and `useWorker` (boolean). Handles parsing,
|
|
75
|
+
streaming-friendly incremental updates, and manages a special cursor
|
|
76
|
+
component node while streaming.
|
|
77
|
+
- `src/components/RecursiveRenderer.vue` — recursively renders the
|
|
78
|
+
htmlparser2 AST to Vue VNodes. Supports a `plugins` array where each
|
|
79
|
+
plugin is `{ test, render }`.
|
|
80
|
+
- `src/components/BlinkingCursor.vue` — small visual cursor used during
|
|
81
|
+
streaming.
|
|
82
|
+
- `public/parser.worker.js` — (optional) module Worker. When enabled
|
|
83
|
+
(`useWorker`), `MdRenderer` posts `{ markdownText }` and expects a
|
|
84
|
+
response `{ ast }` where `ast` matches `parseDocument(html).children`.
|
|
85
|
+
|
|
86
|
+
## Streaming behavior and cursor management
|
|
87
|
+
|
|
88
|
+
The `isStreaming` prop controls whether a blinking cursor is displayed at the end of the rendered content:
|
|
89
|
+
|
|
90
|
+
- `isStreaming=false` — No cursor is shown. Use this for static content or when streaming has finished.
|
|
91
|
+
- `isStreaming=true` — A blinking cursor is displayed at the end, indicating that content is actively streaming/updating.
|
|
92
|
+
|
|
93
|
+
When `isStreaming` is `true`, a special AST node `{ type: 'component', name: 'cursor' }` is inserted at the end of the AST to render the `BlinkingCursor` component. The helper `manageCursor(ast, 'add'|'remove')` handles insertion/removal of this cursor node.
|
|
94
|
+
|
|
95
|
+
## Plugin System
|
|
96
|
+
|
|
97
|
+
mio-previewer provides a powerful two-tier plugin system:
|
|
98
|
+
|
|
99
|
+
### 1. Markdown-it Plugins (Syntax Extension)
|
|
100
|
+
|
|
101
|
+
Extend Markdown syntax by using standard markdown-it plugins:
|
|
102
|
+
|
|
103
|
+
```js
|
|
104
|
+
import { MdRenderer } from 'mio-previewer'
|
|
105
|
+
import markdownItSub from 'markdown-it-sub'
|
|
106
|
+
import markdownItSup from 'markdown-it-sup'
|
|
107
|
+
|
|
108
|
+
const markdownItPlugins = [
|
|
109
|
+
{ plugin: markdownItSub },
|
|
110
|
+
{ plugin: markdownItSup, options: { /* plugin options */ } }
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
// Use in component
|
|
114
|
+
<MdRenderer
|
|
115
|
+
:md="text"
|
|
116
|
+
:markdownItPlugins="markdownItPlugins"
|
|
117
|
+
:markdownItOptions="{ html: true, linkify: true }"
|
|
118
|
+
/>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### 2. Custom Plugins (Rendering Extension)
|
|
122
|
+
|
|
123
|
+
Create custom renderers for specific AST nodes:
|
|
124
|
+
|
|
125
|
+
```js
|
|
126
|
+
import { AlertPlugin, EmojiPlugin } from 'mio-previewer'
|
|
127
|
+
|
|
128
|
+
// Built-in plugins
|
|
129
|
+
const customPlugins = [AlertPlugin, EmojiPlugin]
|
|
130
|
+
|
|
131
|
+
// Or create your own
|
|
132
|
+
const MyPlugin = {
|
|
133
|
+
name: 'my-plugin',
|
|
134
|
+
priority: 50, // Higher priority executes first
|
|
135
|
+
test: (node) => node.type === 'tag' && node.name === 'custom',
|
|
136
|
+
render: (node, renderChildren, h) => {
|
|
137
|
+
return h('div', { class: 'my-custom' }, renderChildren())
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
<MdRenderer :md="text" :customPlugins="[MyPlugin, ...customPlugins]" />
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Built-in Plugins
|
|
145
|
+
|
|
146
|
+
- **AlertPlugin**: Renders custom alert boxes with types (info, warning, error, success)
|
|
147
|
+
- **EmojiPlugin**: Converts emoji codes like `:smile:` → 😊
|
|
148
|
+
- **CodeBlockPlugin**: Prism syntax highlighting with copy & HTML preview buttons (20+ languages)
|
|
149
|
+
- **katexPlugin**: Renders math formulas with KaTeX (supports `$...$`, `$$...$$`, `\(...\)`, `\[...\]` delimiters)
|
|
150
|
+
- **mermaidPlugin**: Renders diagrams with Mermaid (flowcharts, sequence diagrams, state diagrams, class diagrams, etc.) with dark/light theme support
|
|
151
|
+
|
|
152
|
+
### Plugin Priority
|
|
153
|
+
|
|
154
|
+
Plugins are executed in priority order (higher first). Built-in CursorPlugin has priority 100.
|
|
155
|
+
|
|
156
|
+
**Recommended ranges:**
|
|
157
|
+
- 100+: System plugins
|
|
158
|
+
- 50-99: High priority (containers, alerts)
|
|
159
|
+
- 10-49: Medium priority (icons, badges)
|
|
160
|
+
- 0-9: Low priority (text processing, emoji)
|
|
161
|
+
|
|
162
|
+
### Documentation
|
|
163
|
+
|
|
164
|
+
See [Plugin Guide](./docs/PLUGIN_GUIDE.md) for detailed documentation, examples, and best practices.
|
|
165
|
+
|
|
166
|
+
### Demo
|
|
167
|
+
|
|
168
|
+
Run the plugin demo:
|
|
169
|
+
```bash
|
|
170
|
+
pnpm dev
|
|
171
|
+
# Open http://localhost:5173/plugin-demo.html
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Worker contract
|
|
175
|
+
|
|
176
|
+
When `useWorker` is `true`, `MdRenderer` creates a module Worker with:
|
|
177
|
+
|
|
178
|
+
```js
|
|
179
|
+
worker = new Worker(new URL('/parser.worker.js', import.meta.url), { type: 'module' })
|
|
180
|
+
worker.postMessage({ markdownText: newMd })
|
|
181
|
+
// worker should respond with: postMessage({ ast })
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
The `ast` must be the same shape as `parseDocument(html).children` so
|
|
185
|
+
that `RecursiveRenderer` can consume it directly.
|
|
186
|
+
|
|
187
|
+
## TypeScript migration notes
|
|
188
|
+
|
|
189
|
+
This repo was migrated progressively to TypeScript. To keep the
|
|
190
|
+
conversion low-risk, a temporary `src/types-shims.d.ts` provides minimal
|
|
191
|
+
module declarations. Recommended next steps to tighten types:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
pnpm add -D vue-tsc @types/htmlparser2 @types/markdown-it
|
|
195
|
+
npx vue-tsc --noEmit
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Then replace the shim declarations with real types from the installed
|
|
199
|
+
packages.
|
|
200
|
+
|
|
201
|
+
## Development tips
|
|
202
|
+
|
|
203
|
+
- To debug AST output, add a `console.log(parseDocument(html).children)`
|
|
204
|
+
in `MdRenderer.vue` before assigning `ast` — this helps inspect node
|
|
205
|
+
shapes for plugin writing.
|
|
206
|
+
- If you change streaming logic, ensure `manageCursor` is called to
|
|
207
|
+
preserve cursor visibility during incremental updates.
|
|
208
|
+
|
|
209
|
+
## Files of interest
|
|
210
|
+
|
|
211
|
+
- `src/MdRenderer.vue` — main parsing & streaming logic
|
|
212
|
+
- `src/components/RecursiveRenderer.vue` — renderer & plugin system
|
|
213
|
+
- `src/components/BlinkingCursor.vue` — streaming cursor
|
|
214
|
+
- `public/parser.worker.js` — optional worker parsing contract
|
|
215
|
+
|
|
216
|
+
## License
|
|
217
|
+
|
|
218
|
+
MIT
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# mio-previewer
|
|
2
|
+
|
|
3
|
+
[English](./README.md) | 中文文档
|
|
4
|
+
|
|
5
|
+
一个针对流式更新优化的小型 Vue 3 Markd## 流式行为与光标管理
|
|
6
|
+
|
|
7
|
+
`isStreaming` prop 控制是否在渲染内容末尾显示闪烁的光标:
|
|
8
|
+
|
|
9
|
+
- `isStreaming=false` — 不显示光标。用于静态内容或流式更新已结束的情况。
|
|
10
|
+
- `isStreaming=true` — 在末尾显示闪烁光标,表示内容正在流式更新中。
|
|
11
|
+
|
|
12
|
+
当 `isStreaming` 为 `true` 时,会在 AST 末尾插入一个特殊节点 `{ type: 'component', name: 'cursor' }` 来渲染 `BlinkingCursor` 组件。辅助函数 `manageCursor(ast, 'add'|'remove')` 负责插入与移除该光标节点。渲染流程为:Markdown -> HTML -> htmlparser2 AST,然后将 AST 渲染为 Vue VNode。项目提供可选的模块 Worker(`public/parser.worker.js`)以将 Markdown 解析卸载到主线程之外。
|
|
13
|
+
|
|
14
|
+
本项目已配置为可发布的 npm 库(见 `package.json` 的脚本)。库从包根导出命名导出 `MdRenderer`(可通过 `import { MdRenderer } from 'mio-previewer'` 使用)。
|
|
15
|
+
|
|
16
|
+
## 快速开始
|
|
17
|
+
|
|
18
|
+
先决条件:建议使用 Node 18+,以及 pnpm(或 npm/yarn)。
|
|
19
|
+
|
|
20
|
+
安装依赖:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pnpm install
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
本项目已配置为可发布的 npm 库(见 `package.json` 的脚本)。库从包根导出命名导出 `MdRenderer`(可通过 `import { MdRenderer } from 'mio-previewer'` 使用)。
|
|
27
|
+
|
|
28
|
+
启动开发服务器:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pnpm dev
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
在浏览器打开 http://localhost:5173/ 以查看实时预览。
|
|
35
|
+
|
|
36
|
+
生产构建:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pnpm build
|
|
40
|
+
pnpm preview
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
安装库(发布后或本地安装):
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# 从 npm 安装(发布后)
|
|
47
|
+
pnpm add mio-previewer
|
|
48
|
+
|
|
49
|
+
# 或从本地目录安装
|
|
50
|
+
pnpm add /path/to/mio-previewer
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
使用示例(在 Vue 3 项目中):
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
import { createApp } from 'vue'
|
|
57
|
+
import { MdRenderer } from 'mio-previewer'
|
|
58
|
+
import 'github-markdown-css/github-markdown.css'
|
|
59
|
+
|
|
60
|
+
const app = createApp({})
|
|
61
|
+
app.component('MdRenderer', MdRenderer)
|
|
62
|
+
app.mount('#app')
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
注意事项
|
|
66
|
+
- 库打包时将 `vue` 标记为 external。发布时建议在你的 `package.json` 中加入 `peerDependencies: { "vue": "^3" }`,或在宿主项目中安装兼容的 Vue。
|
|
67
|
+
- 类型声明会输出到 `dist/types`,顶级 `types` 字段已指向生成的声明文件。
|
|
68
|
+
|
|
69
|
+
发布清单
|
|
70
|
+
- 确保 `package.json` 中包含 `name`、`version`、`description`、`repository` 等字段,并建议添加 `peerDependencies: { "vue": "^3" }`。
|
|
71
|
+
- 运行 `pnpm run build`(会生成 bundle 和类型声明)。
|
|
72
|
+
- 使用 `pnpm publish --access public` 发布,或在 CI 中自动化发布流程。
|
|
73
|
+
|
|
74
|
+
## 项目概览
|
|
75
|
+
|
|
76
|
+
- `src/MdRenderer.vue` — 核心组件。接收 `md`(字符串)、`isStreaming`(布尔)和 `useWorker`(布尔)三个 prop。负责解析、流式增量更新,以及在流式模式下管理特殊的光标组件节点。
|
|
77
|
+
- `src/components/RecursiveRenderer.vue` — 将 htmlparser2 的 AST 递归渲染为 Vue VNode。支持 `plugins` 数组(每个 plugin 为 `{ test, render }`)。
|
|
78
|
+
- `src/components/BlinkingCursor.vue` — 流式渲染时显示的光标组件。
|
|
79
|
+
- `public/parser.worker.js` —(可选)模块 Worker。当 `useWorker` 为 true 时,`MdRenderer` 会向 Worker 发送 `{ markdownText }` 并期望收到 `{ ast }`,其中 `ast` 的结构应与 `parseDocument(html).children` 一致。
|
|
80
|
+
|
|
81
|
+
## 流式行为与光标管理
|
|
82
|
+
|
|
83
|
+
该项目支持两种模式:
|
|
84
|
+
|
|
85
|
+
- 非流式(`isStreaming=false`):每次更新都会对 Markdown 进行全量解析。
|
|
86
|
+
- 流式(`isStreaming=true`):对更新按增量块处理。`MdRenderer` 对简单纯文本块会尝试“追加到最后文本节点”的快速路径优化;若发现新块包含 Markdown 语法(例如 `#`, `` ` ``, `*` 等),则退回到重解析整串的安全路径。
|
|
87
|
+
|
|
88
|
+
在流式模式下,代码会在 AST 末尾插入一个特殊节点 `{ type: 'component', name: 'cursor' }`,用于渲染 `BlinkingCursor`。辅助函数 `manageCursor(ast, 'add'|'remove')` 负责插入与移除该节点。
|
|
89
|
+
|
|
90
|
+
## 插件系统
|
|
91
|
+
|
|
92
|
+
mio-previewer 提供强大的双层插件系统:
|
|
93
|
+
|
|
94
|
+
### 1. Markdown-it 插件(语法扩展)
|
|
95
|
+
|
|
96
|
+
通过标准 markdown-it 插件扩展 Markdown 语法:
|
|
97
|
+
|
|
98
|
+
```js
|
|
99
|
+
import { MdRenderer } from 'mio-previewer'
|
|
100
|
+
import markdownItSub from 'markdown-it-sub'
|
|
101
|
+
import markdownItSup from 'markdown-it-sup'
|
|
102
|
+
|
|
103
|
+
const markdownItPlugins = [
|
|
104
|
+
{ plugin: markdownItSub },
|
|
105
|
+
{ plugin: markdownItSup, options: { /* 插件选项 */ } }
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
// 在组件中使用
|
|
109
|
+
<MdRenderer
|
|
110
|
+
:md="text"
|
|
111
|
+
:markdownItPlugins="markdownItPlugins"
|
|
112
|
+
:markdownItOptions="{ html: true, linkify: true }"
|
|
113
|
+
/>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 2. 自定义插件(渲染扩展)
|
|
117
|
+
|
|
118
|
+
为特定 AST 节点创建自定义渲染器:
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
import { AlertPlugin, EmojiPlugin } from 'mio-previewer'
|
|
122
|
+
|
|
123
|
+
// 内置插件
|
|
124
|
+
const customPlugins = [AlertPlugin, EmojiPlugin]
|
|
125
|
+
|
|
126
|
+
// 或创建自己的插件
|
|
127
|
+
const MyPlugin = {
|
|
128
|
+
name: 'my-plugin',
|
|
129
|
+
priority: 50, // 更高优先级先执行
|
|
130
|
+
test: (node) => node.type === 'tag' && node.name === 'custom',
|
|
131
|
+
render: (node, renderChildren, h) => {
|
|
132
|
+
return h('div', { class: 'my-custom' }, renderChildren())
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
<MdRenderer :md="text" :customPlugins="[MyPlugin, ...customPlugins]" />
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### 内置插件
|
|
140
|
+
|
|
141
|
+
- **AlertPlugin**:渲染自定义警告框,支持类型(info、warning、error、success)
|
|
142
|
+
- **EmojiPlugin**:将表情代码如 `:smile:` 转换为 😊
|
|
143
|
+
- **CodeBlockPlugin**:使用 Prism 语法高亮,支持复制和 HTML 预览按钮(20+ 种语言)
|
|
144
|
+
- **katexPlugin**:使用 KaTeX 渲染数学公式(支持 `$...$`、`$$...$$`、`\(...\)`、`\[...\]` 定界符)
|
|
145
|
+
- **mermaidPlugin**:使用 Mermaid 渲染图表(流程图、时序图、状态图、类图等),支持深色/浅色主题
|
|
146
|
+
|
|
147
|
+
### 插件优先级
|
|
148
|
+
|
|
149
|
+
插件按优先级顺序执行(优先级高的先执行)。内置 CursorPlugin 优先级为 100。
|
|
150
|
+
|
|
151
|
+
**推荐范围:**
|
|
152
|
+
- 100+:系统插件
|
|
153
|
+
- 50-99:高优先级(容器、警告框)
|
|
154
|
+
- 10-49:中优先级(图标、徽章)
|
|
155
|
+
- 0-9:低优先级(文本处理、表情)
|
|
156
|
+
|
|
157
|
+
### 文档
|
|
158
|
+
|
|
159
|
+
详细文档、示例和最佳实践请参见 [插件指南](./docs/PLUGIN_GUIDE.md)。
|
|
160
|
+
|
|
161
|
+
### 演示
|
|
162
|
+
|
|
163
|
+
运行插件演示:
|
|
164
|
+
```bash
|
|
165
|
+
pnpm dev
|
|
166
|
+
# 打开 http://localhost:5173/plugin-demo.html
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Worker 合约
|
|
170
|
+
|
|
171
|
+
当 `useWorker` 为 `true` 时,`MdRenderer` 会创建一个模块 Worker:
|
|
172
|
+
|
|
173
|
+
```js
|
|
174
|
+
worker = new Worker(new URL('/parser.worker.js', import.meta.url), { type: 'module' })
|
|
175
|
+
worker.postMessage({ markdownText: newMd })
|
|
176
|
+
// worker 应返回: postMessage({ ast })
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
返回的 `ast` 必须与 `parseDocument(html).children` 的结构保持一致,`RecursiveRenderer` 将直接消费该 AST。
|
|
180
|
+
|
|
181
|
+
## TypeScript 迁移说明
|
|
182
|
+
|
|
183
|
+
项目已逐步迁移为 TypeScript 风格。为降低迁移风险,仓库中添加了临时的 `src/types-shims.d.ts` 用于最小化类型声明噪声。建议的下一步:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
pnpm add -D vue-tsc @types/htmlparser2 @types/markdown-it
|
|
187
|
+
npx vue-tsc --noEmit
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
安装真实类型后,可删除临时 shim 并进行更严格的类型检查。
|
|
191
|
+
|
|
192
|
+
## 开发建议
|
|
193
|
+
|
|
194
|
+
- 如需调试 AST 输出,可在 `MdRenderer.vue` 中分配 `ast` 前打印 `parseDocument(html).children`,方便为插件设计节点匹配器。
|
|
195
|
+
- 在更改流式逻辑时,注意调用 `manageCursor` 以在增量更新期间保持光标显示一致性。
|
|
196
|
+
|
|
197
|
+
## 关注文件
|
|
198
|
+
|
|
199
|
+
- `src/MdRenderer.vue` — 解析与流式逻辑
|
|
200
|
+
- `src/components/RecursiveRenderer.vue` — 渲染器与插件系统
|
|
201
|
+
- `src/components/BlinkingCursor.vue` — 用于流式的光标
|
|
202
|
+
- `public/parser.worker.js` — 可选的 worker 解析契约
|
|
203
|
+
|
|
204
|
+
## License
|
|
205
|
+
|
|
206
|
+
MIT
|