@ant-design/x-markdown-mini 0.1.0-beta.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.
- package/LICENSE +21 -0
- package/README.md +216 -0
- package/dist/components/Markdown/index.acss +103 -0
- package/dist/components/Markdown/index.axml +12 -0
- package/dist/components/Markdown/index.js +93 -0
- package/dist/components/Markdown/index.json +7 -0
- package/dist/components/MiniNodeRenderer/index.acss +11 -0
- package/dist/components/MiniNodeRenderer/index.axml +113 -0
- package/dist/components/MiniNodeRenderer/index.js +37 -0
- package/dist/components/MiniNodeRenderer/index.json +7 -0
- package/dist/components/MiniNodeRenderer/index.sjs +63 -0
- package/dist/es/Markdown/index.acss +103 -0
- package/dist/es/Markdown/index.axml +12 -0
- package/dist/es/Markdown/index.js +93 -0
- package/dist/es/Markdown/index.json +7 -0
- package/dist/es/MiniNodeRenderer/index.acss +11 -0
- package/dist/es/MiniNodeRenderer/index.axml +113 -0
- package/dist/es/MiniNodeRenderer/index.js +37 -0
- package/dist/es/MiniNodeRenderer/index.json +7 -0
- package/dist/es/MiniNodeRenderer/index.sjs +63 -0
- package/dist/index.d.mts +508 -0
- package/dist/index.d.ts +508 -0
- package/dist/index.js +3151 -0
- package/dist/index.mjs +3111 -0
- package/dist/miniprogram_dist/components/Markdown/index.js +85 -0
- package/dist/miniprogram_dist/components/Markdown/index.json +10 -0
- package/dist/miniprogram_dist/components/Markdown/index.wxml +11 -0
- package/dist/miniprogram_dist/components/Markdown/index.wxss +103 -0
- package/dist/miniprogram_dist/components/MiniNodeRenderer/index.js +39 -0
- package/dist/miniprogram_dist/components/MiniNodeRenderer/index.json +10 -0
- package/dist/miniprogram_dist/components/MiniNodeRenderer/index.wxml +112 -0
- package/dist/miniprogram_dist/components/MiniNodeRenderer/index.wxs +40 -0
- package/dist/miniprogram_dist/components/MiniNodeRenderer/index.wxss +11 -0
- package/dist/miniprogram_dist/es/Markdown/index.js +85 -0
- package/dist/miniprogram_dist/es/Markdown/index.json +10 -0
- package/dist/miniprogram_dist/es/Markdown/index.wxml +11 -0
- package/dist/miniprogram_dist/es/Markdown/index.wxss +103 -0
- package/dist/miniprogram_dist/es/MiniNodeRenderer/index.js +39 -0
- package/dist/miniprogram_dist/es/MiniNodeRenderer/index.json +10 -0
- package/dist/miniprogram_dist/es/MiniNodeRenderer/index.wxml +112 -0
- package/dist/miniprogram_dist/es/MiniNodeRenderer/index.wxs +40 -0
- package/dist/miniprogram_dist/es/MiniNodeRenderer/index.wxss +11 -0
- package/dist/miniprogram_dist/index.js +3151 -0
- package/dist/miniprogram_dist/plugins/CodeHighlight/index.js +8038 -0
- package/dist/miniprogram_dist/plugins/CodeHighlight/style.wxss +105 -0
- package/dist/miniprogram_dist/plugins/Latex/index.js +14728 -0
- package/dist/miniprogram_dist/plugins/Latex/style.wxss +648 -0
- package/dist/miniprogram_dist/shared/flattenInline.js +100 -0
- package/dist/plugins/CodeHighlight/index.d.mts +27 -0
- package/dist/plugins/CodeHighlight/index.d.ts +27 -0
- package/dist/plugins/CodeHighlight/index.js +8038 -0
- package/dist/plugins/CodeHighlight/index.mjs +8028 -0
- package/dist/plugins/CodeHighlight/style.acss +105 -0
- package/dist/plugins/Latex/index.d.mts +12 -0
- package/dist/plugins/Latex/index.d.ts +12 -0
- package/dist/plugins/Latex/index.js +14728 -0
- package/dist/plugins/Latex/index.mjs +14705 -0
- package/dist/plugins/Latex/style.acss +648 -0
- package/dist/shared/flattenInline.js +100 -0
- package/dist/types-CegkonfJ.d.mts +83 -0
- package/dist/types-CegkonfJ.d.ts +83 -0
- package/package.json +93 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Ant Group and its affiliates.
|
|
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,216 @@
|
|
|
1
|
+
# @ant-design/x-markdown-mini
|
|
2
|
+
|
|
3
|
+
> 多小程序、轻量、流式友好的 Markdown 渲染器。
|
|
4
|
+
|
|
5
|
+
- **轻**:内置 `marked` lexer,ESM 整库约 103KB / gzip 约 25KB
|
|
6
|
+
- **流**:增量解析,已稳定块只 parse 一次;onPatch 推回全量统一节点
|
|
7
|
+
- **双端**:当前支持微信 / 支付宝,统一组件路径 + 自动识别
|
|
8
|
+
- **可扩展**:marked tokenizer / walkTokens / hooks + colocated `miniRenderer`;内置 LaTeX 和代码高亮扩展
|
|
9
|
+
|
|
10
|
+
## 安装
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @ant-design/x-markdown-mini
|
|
14
|
+
# 或
|
|
15
|
+
pnpm add @ant-design/x-markdown-mini
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## 两种用法
|
|
19
|
+
|
|
20
|
+
### A. 直接用现成的小程序组件(推荐)
|
|
21
|
+
|
|
22
|
+
包内附带了开箱即用的 **Markdown** / **MiniNodeRenderer** 小程序组件。**支付宝、微信使用同一条路径**——
|
|
23
|
+
微信开发者工具读取 `package.json#miniprogram` 字段,自动解析到 wechat 子树;支付宝则走默认包根。
|
|
24
|
+
|
|
25
|
+
```jsonc
|
|
26
|
+
// page.json(支付宝 & 微信都一样写)
|
|
27
|
+
{
|
|
28
|
+
"usingComponents": {
|
|
29
|
+
"markdown": "@ant-design/x-markdown-mini/es/Markdown/index"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```xml
|
|
35
|
+
<!-- 支付宝 page.axml -->
|
|
36
|
+
<markdown
|
|
37
|
+
content="{{content}}"
|
|
38
|
+
animation="{{true}}"
|
|
39
|
+
selectable="{{true}}"
|
|
40
|
+
streaming="{{ { hasNextChunk: hasNextChunk, semantic: true } }}"
|
|
41
|
+
onRenderComplete="onComplete"
|
|
42
|
+
/>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
```xml
|
|
46
|
+
<!-- 微信 page.wxml -->
|
|
47
|
+
<markdown
|
|
48
|
+
content="{{content}}"
|
|
49
|
+
animation="{{true}}"
|
|
50
|
+
selectable="{{true}}"
|
|
51
|
+
streaming="{{ { hasNextChunk: hasNextChunk, semantic: true } }}"
|
|
52
|
+
bindrendercomplete="onComplete"
|
|
53
|
+
/>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
组件内部已经把 `XMarkdownMini` / `StreamingProcessor` 接好,直接 `setData` 节点;
|
|
57
|
+
样式(`.md-paragraph` / `.md-heading` / `.md-code-block` …)随组件 `acss` / `wxss`
|
|
58
|
+
一起加载,可在外层覆盖。
|
|
59
|
+
|
|
60
|
+
### B. 仅取节点数据,自己渲染
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { renderNodes } from '@ant-design/x-markdown-mini';
|
|
64
|
+
|
|
65
|
+
const nodes = renderNodes({
|
|
66
|
+
content: '# Hello\n\nWorld.',
|
|
67
|
+
platform: 'auto', // 默认自动识别 my / wx
|
|
68
|
+
selectable: true,
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
```xml
|
|
73
|
+
<!-- 交给内置的 MiniNodeRenderer 组件渲染(原生 text/view/image/scroll-view) -->
|
|
74
|
+
<mini-node-renderer nodes="{{nodes}}" />
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
> 注意:我们**自己渲染**这棵 `MiniNode` 树,而不是喂给原生 `<rich-text>`。
|
|
78
|
+
> `<rich-text>` 是「HTML 富文本」渲染器,会重新套用标签/属性白名单、屏蔽事件、且无法做逐节点动画——
|
|
79
|
+
> 既然节点树已是我们自己构建的结构化数据,直接用 `MiniNodeRenderer` 渲染更合适。
|
|
80
|
+
|
|
81
|
+
### C. 仅解析 Markdown,自己适配
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { render, parse } from '@ant-design/x-markdown-mini';
|
|
85
|
+
|
|
86
|
+
const tokens = render('# Hello'); // 等同 parse('# Hello'),返回 marked Token[]
|
|
87
|
+
const sameTokens = parse('# Hello');
|
|
88
|
+
|
|
89
|
+
render({
|
|
90
|
+
content: 'hello **wor',
|
|
91
|
+
streaming: { hasNextChunk: true },
|
|
92
|
+
onPatch: (tokens) => {
|
|
93
|
+
// tokens 是经过 AI 流式字符串补全后再 marked.lex 的结果
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 流式渲染(LLM 边出边渲)
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
// 流式进行中:每来一段累计 markdown 就调用一次
|
|
102
|
+
renderNodes({
|
|
103
|
+
content: accumulatedMarkdown,
|
|
104
|
+
platform: 'wechat',
|
|
105
|
+
streaming: { hasNextChunk: true, semantic: true, enableAnimation: true },
|
|
106
|
+
onPatch: (nodes) => this.setData({ nodes }),
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// 最后一轮:hasNextChunk=false,flush 残余并触发 onRenderComplete
|
|
110
|
+
renderNodes({
|
|
111
|
+
content: finalMarkdown,
|
|
112
|
+
platform: 'wechat',
|
|
113
|
+
streaming: { hasNextChunk: false },
|
|
114
|
+
onPatch: (nodes) => this.setData({ nodes }),
|
|
115
|
+
onRenderComplete: () => console.log('done'),
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
底层做了什么:
|
|
120
|
+
|
|
121
|
+
1. 已经被空行收尾的块缓存为 `stableNodes`,不再重解析
|
|
122
|
+
2. 仅未稳定的「最后一段」每轮重 lex
|
|
123
|
+
3. 默认 `chunkDelay = charDelay = 0` 时**完全跳过 setTimeout**,同步推回
|
|
124
|
+
|
|
125
|
+
详见 [docs/streaming.md](./docs/streaming.md)。
|
|
126
|
+
|
|
127
|
+
## 插件:LaTeX & 代码高亮
|
|
128
|
+
|
|
129
|
+
插件按需引入,不影响主包体积(主库 ~105 KB gzip ~25 KB,Latex 插件 ~486 KB,CodeHighlight 插件 ~184 KB)。
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import { XMarkdownMini } from '@ant-design/x-markdown-mini';
|
|
133
|
+
import Latex from '@ant-design/x-markdown-mini/plugins/Latex';
|
|
134
|
+
import CodeHighlight from '@ant-design/x-markdown-mini/plugins/CodeHighlight';
|
|
135
|
+
|
|
136
|
+
const md = new XMarkdownMini({
|
|
137
|
+
extensions: [Latex(), CodeHighlight()],
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**样式引入**(在页面或组件样式文件中):
|
|
142
|
+
|
|
143
|
+
```css
|
|
144
|
+
/* 支付宝 .acss */
|
|
145
|
+
@import "@ant-design/x-markdown-mini/plugins/Latex/style.acss";
|
|
146
|
+
@import "@ant-design/x-markdown-mini/plugins/CodeHighlight/style.acss";
|
|
147
|
+
|
|
148
|
+
/* 微信 .wxss */
|
|
149
|
+
@import "@ant-design/x-markdown-mini/plugins/CodeHighlight/style.wxss";
|
|
150
|
+
@import "@ant-design/x-markdown-mini/plugins/Latex/style.wxss";
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Latex
|
|
154
|
+
|
|
155
|
+
基于 [KaTeX](https://katex.org/) 渲染数学公式。支持行内 `$x^2$` 和块级 `$$...\n...$$` 语法。
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
Latex({
|
|
159
|
+
katexOptions: { throwOnError: false }, // 透传给 katex.renderToString()
|
|
160
|
+
onError(tex, err) { /* 自定义错误回调 */ },
|
|
161
|
+
})
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### CodeHighlight
|
|
165
|
+
|
|
166
|
+
基于 [highlight.js](https://highlightjs.org/) 的代码语法高亮。默认支持 18 种常用语言,可自定义子集。
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import javascript from 'highlight.js/lib/languages/javascript';
|
|
170
|
+
|
|
171
|
+
CodeHighlight({
|
|
172
|
+
languages: { javascript }, // 只注册需要的语言
|
|
173
|
+
hljsOptions: { ignoreIllegals: true },
|
|
174
|
+
})
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
详见 [docs/extensions.md](./docs/extensions.md)。
|
|
178
|
+
|
|
179
|
+
## 平台自动识别 + 能力矩阵
|
|
180
|
+
|
|
181
|
+
| 平台 | `<pre>` | `<table>` | `<blockquote>` | `<ol start>` | https-only 图片 | `<video>` |
|
|
182
|
+
| --------- | :-----: | :-------: | :------------: | :----------: | :-------------: | :-------: |
|
|
183
|
+
| 微信 | ✅ | ✅ | ✅ | ✅ | | |
|
|
184
|
+
| 支付宝 | ✅ | ✅ | ✅ | | ✅ | |
|
|
185
|
+
|
|
186
|
+
当前仅内置微信和支付宝。新增平台时扩展 `src/platforms` 下的 renderer,并补组件输出目录。
|
|
187
|
+
详见 [docs/platforms.md](./docs/platforms.md)。
|
|
188
|
+
|
|
189
|
+
## 在线预览(手机壳模拟)
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
npm run build
|
|
193
|
+
cd docs-site && npm install && npm run dev
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
打开 http://localhost:5173/ ,或 http://localhost:5173/preview.html 看真机壳样式。
|
|
197
|
+
详见 [docs-site/README.md](./docs-site/README.md)。
|
|
198
|
+
|
|
199
|
+
## 文档
|
|
200
|
+
|
|
201
|
+
- [架构](./docs/architecture.md) — 流水线四步、目录结构、为何内置 marked
|
|
202
|
+
- [流式](./docs/streaming.md) — 增量解析、打字机模式、动画 hooks
|
|
203
|
+
- [平台](./docs/platforms.md) — 能力矩阵、降级规则、自定义平台
|
|
204
|
+
- [扩展](./docs/extensions.md) — marked 扩展、`miniRenderer`、Latex、CodeHighlight
|
|
205
|
+
|
|
206
|
+
## 开发
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
pnpm install
|
|
210
|
+
pnpm build
|
|
211
|
+
pnpm test
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## License
|
|
215
|
+
|
|
216
|
+
MIT
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
.md-root {
|
|
2
|
+
display: block;
|
|
3
|
+
font-size: 28rpx;
|
|
4
|
+
line-height: 1.65;
|
|
5
|
+
color: #1f1f1f;
|
|
6
|
+
word-break: break-word;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.md-paragraph {
|
|
10
|
+
display: block;
|
|
11
|
+
margin: 0 0 16rpx;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.md-heading {
|
|
15
|
+
display: block;
|
|
16
|
+
font-weight: 600;
|
|
17
|
+
margin: 24rpx 0 12rpx;
|
|
18
|
+
line-height: 1.3;
|
|
19
|
+
}
|
|
20
|
+
.md-h1 { font-size: 44rpx; }
|
|
21
|
+
.md-h2 { font-size: 38rpx; }
|
|
22
|
+
.md-h3 { font-size: 34rpx; }
|
|
23
|
+
.md-h4 { font-size: 30rpx; }
|
|
24
|
+
.md-h5 { font-size: 28rpx; }
|
|
25
|
+
.md-h6 { font-size: 26rpx; color: #666; }
|
|
26
|
+
|
|
27
|
+
.md-list {
|
|
28
|
+
display: block;
|
|
29
|
+
margin: 8rpx 0 16rpx;
|
|
30
|
+
padding-left: 32rpx;
|
|
31
|
+
}
|
|
32
|
+
.md-list-item {
|
|
33
|
+
display: list-item;
|
|
34
|
+
margin: 4rpx 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.md-blockquote {
|
|
38
|
+
display: block;
|
|
39
|
+
margin: 12rpx 0;
|
|
40
|
+
padding: 8rpx 16rpx;
|
|
41
|
+
border-left: 6rpx solid #d9d9d9;
|
|
42
|
+
color: #555;
|
|
43
|
+
background: #fafafa;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.md-code-block {
|
|
47
|
+
display: block;
|
|
48
|
+
margin: 12rpx 0;
|
|
49
|
+
padding: 16rpx;
|
|
50
|
+
background: #f6f8fa;
|
|
51
|
+
border-radius: 8rpx;
|
|
52
|
+
overflow-x: auto;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.md-code {
|
|
56
|
+
display: block;
|
|
57
|
+
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
|
58
|
+
font-size: 26rpx;
|
|
59
|
+
white-space: pre;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.md-inline-code {
|
|
63
|
+
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
|
64
|
+
font-size: 26rpx;
|
|
65
|
+
background: #f3f3f3;
|
|
66
|
+
padding: 0 6rpx;
|
|
67
|
+
border-radius: 4rpx;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.md-strong { font-weight: 600; }
|
|
71
|
+
.md-em { font-style: italic; }
|
|
72
|
+
|
|
73
|
+
.md-link {
|
|
74
|
+
color: #1677ff;
|
|
75
|
+
text-decoration: underline;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.md-img {
|
|
79
|
+
display: block;
|
|
80
|
+
max-width: 100%;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.md-hr {
|
|
84
|
+
display: block;
|
|
85
|
+
height: 2rpx;
|
|
86
|
+
background: #e5e5e5;
|
|
87
|
+
margin: 16rpx 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.md-table {
|
|
91
|
+
display: block;
|
|
92
|
+
width: 100%;
|
|
93
|
+
margin: 12rpx 0;
|
|
94
|
+
border-collapse: collapse;
|
|
95
|
+
}
|
|
96
|
+
.md-th, .md-td {
|
|
97
|
+
display: table-cell;
|
|
98
|
+
padding: 8rpx 12rpx;
|
|
99
|
+
border: 1rpx solid #e5e5e5;
|
|
100
|
+
}
|
|
101
|
+
.md-th { background: #fafafa; font-weight: 600; }
|
|
102
|
+
|
|
103
|
+
.md-html { display: block; }
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<view class="md-root {{className}}">
|
|
2
|
+
<mini-node-renderer
|
|
3
|
+
nodes="{{nodes}}"
|
|
4
|
+
selectable="{{selectable}}"
|
|
5
|
+
animation="{{animation}}"
|
|
6
|
+
slotComponents="{{slotComponents}}"
|
|
7
|
+
onTap="onTap"
|
|
8
|
+
onAppear="onAppear"
|
|
9
|
+
>
|
|
10
|
+
<slot slot-scope="prop" data="{{prop.data}}" />
|
|
11
|
+
</mini-node-renderer>
|
|
12
|
+
</view>
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// src/components/alipay/Markdown/index.ts
|
|
4
|
+
var import__ = require("../../index.js");
|
|
5
|
+
var import_flattenInline = require("../../shared/flattenInline.js");
|
|
6
|
+
var defaultProps = {
|
|
7
|
+
content: "",
|
|
8
|
+
streaming: false,
|
|
9
|
+
selectable: true,
|
|
10
|
+
className: "",
|
|
11
|
+
extensions: null,
|
|
12
|
+
components: null,
|
|
13
|
+
footnote: false
|
|
14
|
+
};
|
|
15
|
+
function sameList(a, b) {
|
|
16
|
+
const x = a != null ? a : [];
|
|
17
|
+
const y = b != null ? b : [];
|
|
18
|
+
if (x.length !== y.length) return false;
|
|
19
|
+
for (let i = 0; i < x.length; i++) if (x[i] !== y[i]) return false;
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
Component({
|
|
23
|
+
props: defaultProps,
|
|
24
|
+
data: {
|
|
25
|
+
nodes: [],
|
|
26
|
+
slotComponents: []
|
|
27
|
+
},
|
|
28
|
+
md: null,
|
|
29
|
+
didMount() {
|
|
30
|
+
this._build(this.props);
|
|
31
|
+
this._render(this.props);
|
|
32
|
+
},
|
|
33
|
+
didUpdate(prevProps) {
|
|
34
|
+
const p = this.props;
|
|
35
|
+
if (!sameList(prevProps.components, p.components) || prevProps.footnote !== p.footnote) {
|
|
36
|
+
this._build(p);
|
|
37
|
+
this._render(p);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (prevProps.content !== p.content || prevProps.streaming !== p.streaming || prevProps.selectable !== p.selectable || prevProps.extensions !== p.extensions || prevProps.gfm !== p.gfm || prevProps.breaks !== p.breaks) {
|
|
41
|
+
this._render(p);
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
didUnmount() {
|
|
45
|
+
var _a;
|
|
46
|
+
(_a = this.md) == null ? void 0 : _a.reset();
|
|
47
|
+
this.md = null;
|
|
48
|
+
},
|
|
49
|
+
methods: {
|
|
50
|
+
_build(props) {
|
|
51
|
+
var _a, _b;
|
|
52
|
+
const components = (_a = props.components) != null ? _a : [];
|
|
53
|
+
const extensions = props.footnote ? [(0, import__.Footnote)()] : [];
|
|
54
|
+
(_b = this.md) == null ? void 0 : _b.reset();
|
|
55
|
+
this.md = new import__.XMarkdownMini({ escapeText: false, components, extensions });
|
|
56
|
+
const slotComponents = props.footnote ? components.concat(["footnote"]) : components;
|
|
57
|
+
this.setData({ slotComponents });
|
|
58
|
+
},
|
|
59
|
+
_render(props) {
|
|
60
|
+
var _a;
|
|
61
|
+
this.md.renderNodes({
|
|
62
|
+
content: props.content,
|
|
63
|
+
platform: "alipay",
|
|
64
|
+
streaming: props.streaming,
|
|
65
|
+
selectable: props.selectable,
|
|
66
|
+
gfm: props.gfm,
|
|
67
|
+
breaks: props.breaks,
|
|
68
|
+
extensions: (_a = props.extensions) != null ? _a : void 0,
|
|
69
|
+
onRenderStart: () => {
|
|
70
|
+
var _a2;
|
|
71
|
+
return (_a2 = props.onRenderStart) == null ? void 0 : _a2.call(props);
|
|
72
|
+
},
|
|
73
|
+
onRenderProgress: (payload) => {
|
|
74
|
+
var _a2;
|
|
75
|
+
return (_a2 = props.onRenderProgress) == null ? void 0 : _a2.call(props, payload);
|
|
76
|
+
},
|
|
77
|
+
onRenderComplete: () => {
|
|
78
|
+
var _a2;
|
|
79
|
+
return (_a2 = props.onRenderComplete) == null ? void 0 : _a2.call(props);
|
|
80
|
+
},
|
|
81
|
+
onPatch: (nodes) => this.setData({ nodes: (0, import_flattenInline.flattenInlineNodes)(nodes) })
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
onTap(e) {
|
|
85
|
+
var _a, _b;
|
|
86
|
+
(_b = (_a = this.props).onTap) == null ? void 0 : _b.call(_a, e);
|
|
87
|
+
},
|
|
88
|
+
onAppear(e) {
|
|
89
|
+
var _a, _b;
|
|
90
|
+
(_b = (_a = this.props).onAppear) == null ? void 0 : _b.call(_a, e);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
.md-animate-block {
|
|
2
|
+
animation-fill-mode: forwards;
|
|
3
|
+
animation-name: md-block-appear;
|
|
4
|
+
animation-timing-function: var(--md-animation-timing, ease-in);
|
|
5
|
+
animation-duration: var(--md-animation-duration, 300ms);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
@keyframes md-block-appear {
|
|
9
|
+
0% { opacity: 0; transform: translateY(4rpx); }
|
|
10
|
+
100% { opacity: 1; transform: translateY(0); }
|
|
11
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<import-sjs from="./index.sjs" name="u" />
|
|
2
|
+
|
|
3
|
+
<block a:for="{{nodes}}" a:for-item="node" a:for-index="i" a:key="i">
|
|
4
|
+
<!-- text leaf -->
|
|
5
|
+
<text
|
|
6
|
+
a:if="{{u.isText(node.name)}}"
|
|
7
|
+
class="{{u.classOf(node)}}"
|
|
8
|
+
selectable="{{selectable}}"
|
|
9
|
+
>{{u.valueOf(node)}}</text>
|
|
10
|
+
|
|
11
|
+
<!-- br -->
|
|
12
|
+
<text a:elif="{{u.isBr(node.name)}}">{{'\n'}}</text>
|
|
13
|
+
|
|
14
|
+
<!-- hr -->
|
|
15
|
+
<view a:elif="{{u.isHr(node.name)}}" class="{{u.classOf(node)}}" />
|
|
16
|
+
|
|
17
|
+
<!-- img -->
|
|
18
|
+
<image
|
|
19
|
+
a:elif="{{u.isImg(node.name)}}"
|
|
20
|
+
class="{{u.classOf(node)}}"
|
|
21
|
+
style="{{u.styleOf(node)}}"
|
|
22
|
+
src="{{u.srcOf(node)}}"
|
|
23
|
+
mode="widthFix"
|
|
24
|
+
data-data="{{node}}"
|
|
25
|
+
catchTap="_tap"
|
|
26
|
+
onAppear="_appear"
|
|
27
|
+
/>
|
|
28
|
+
|
|
29
|
+
<!-- pre: scrollable code container -->
|
|
30
|
+
<scroll-view
|
|
31
|
+
a:elif="{{u.isPre(node.name)}}"
|
|
32
|
+
scroll-x
|
|
33
|
+
class="{{u.classOf(node)}}"
|
|
34
|
+
style="{{u.styleOf(node)}}"
|
|
35
|
+
data-data="{{node}}"
|
|
36
|
+
catchTap="_tap"
|
|
37
|
+
>
|
|
38
|
+
<mini-node-renderer
|
|
39
|
+
a:if="{{node.children}}"
|
|
40
|
+
nodes="{{node.children}}"
|
|
41
|
+
selectable="{{selectable}}"
|
|
42
|
+
animation="{{false}}"
|
|
43
|
+
slotComponents="{{slotComponents}}"
|
|
44
|
+
onTap="onTap"
|
|
45
|
+
onAppear="onAppear"
|
|
46
|
+
>
|
|
47
|
+
<slot slot-scope="prop" data="{{prop.data}}" />
|
|
48
|
+
</mini-node-renderer>
|
|
49
|
+
</scroll-view>
|
|
50
|
+
|
|
51
|
+
<!-- anchor: kept interactive, children are already flattened text runs -->
|
|
52
|
+
<text
|
|
53
|
+
a:elif="{{node.name === 'a'}}"
|
|
54
|
+
class="{{u.classOf(node)}}"
|
|
55
|
+
style="{{u.styleOf(node)}}"
|
|
56
|
+
selectable="{{selectable}}"
|
|
57
|
+
data-data="{{node}}"
|
|
58
|
+
catchTap="_tap"
|
|
59
|
+
>
|
|
60
|
+
<text
|
|
61
|
+
a:for="{{node.children}}"
|
|
62
|
+
a:for-item="c"
|
|
63
|
+
a:for-index="ci"
|
|
64
|
+
a:key="ci"
|
|
65
|
+
class="{{u.classOf(c)}}"
|
|
66
|
+
>{{u.valueOf(c)}}</text>
|
|
67
|
+
</text>
|
|
68
|
+
|
|
69
|
+
<!-- inline tag rendered as <text>: children are flat text runs -->
|
|
70
|
+
<text
|
|
71
|
+
a:elif="{{u.isInline(node.name)}}"
|
|
72
|
+
class="{{u.classOf(node)}}"
|
|
73
|
+
style="{{u.styleOf(node)}}"
|
|
74
|
+
selectable="{{selectable}}"
|
|
75
|
+
data-data="{{node}}"
|
|
76
|
+
catchTap="_tap"
|
|
77
|
+
>
|
|
78
|
+
<text
|
|
79
|
+
a:for="{{node.children}}"
|
|
80
|
+
a:for-item="c"
|
|
81
|
+
a:for-index="ci"
|
|
82
|
+
a:key="ci"
|
|
83
|
+
class="{{u.classOf(c)}}"
|
|
84
|
+
>{{u.valueOf(c)}}</text>
|
|
85
|
+
</text>
|
|
86
|
+
|
|
87
|
+
<!-- custom component: hand off to host scoped slot, keyed by node.tag -->
|
|
88
|
+
<slot
|
|
89
|
+
a:elif="{{u.isSlot(node.name, slotComponents)}}"
|
|
90
|
+
data="{{node}}"
|
|
91
|
+
/>
|
|
92
|
+
|
|
93
|
+
<!-- block tag rendered as <view> -->
|
|
94
|
+
<view
|
|
95
|
+
a:else
|
|
96
|
+
class="{{u.classOf(node)}}"
|
|
97
|
+
style="{{u.styleOf(node)}}"
|
|
98
|
+
data-data="{{node}}"
|
|
99
|
+
catchTap="_tap"
|
|
100
|
+
>
|
|
101
|
+
<mini-node-renderer
|
|
102
|
+
a:if="{{node.children}}"
|
|
103
|
+
nodes="{{node.children}}"
|
|
104
|
+
selectable="{{selectable}}"
|
|
105
|
+
animation="{{animation}}"
|
|
106
|
+
slotComponents="{{slotComponents}}"
|
|
107
|
+
onTap="onTap"
|
|
108
|
+
onAppear="onAppear"
|
|
109
|
+
>
|
|
110
|
+
<slot slot-scope="prop" data="{{prop.data}}" />
|
|
111
|
+
</mini-node-renderer>
|
|
112
|
+
</view>
|
|
113
|
+
</block>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __copyProps = (to, from, except, desc) => {
|
|
7
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
8
|
+
for (let key of __getOwnPropNames(from))
|
|
9
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
10
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
11
|
+
}
|
|
12
|
+
return to;
|
|
13
|
+
};
|
|
14
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
15
|
+
|
|
16
|
+
// src/components/alipay/MiniNodeRenderer/index.ts
|
|
17
|
+
var MiniNodeRenderer_exports = {};
|
|
18
|
+
module.exports = __toCommonJS(MiniNodeRenderer_exports);
|
|
19
|
+
var defaultProps = {
|
|
20
|
+
nodes: [],
|
|
21
|
+
selectable: true,
|
|
22
|
+
animation: false,
|
|
23
|
+
slotComponents: []
|
|
24
|
+
};
|
|
25
|
+
Component({
|
|
26
|
+
props: defaultProps,
|
|
27
|
+
methods: {
|
|
28
|
+
_tap(e) {
|
|
29
|
+
var _a, _b;
|
|
30
|
+
(_b = (_a = this.props).onTap) == null ? void 0 : _b.call(_a, e);
|
|
31
|
+
},
|
|
32
|
+
_appear(e) {
|
|
33
|
+
var _a, _b;
|
|
34
|
+
(_b = (_a = this.props).onAppear) == null ? void 0 : _b.call(_a, e);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
var INLINE = { strong: 1, em: 1, del: 1, code: 1, a: 1, span: 1 };
|
|
2
|
+
var BLOCK = {
|
|
3
|
+
p: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1,
|
|
4
|
+
div: 1, blockquote: 1, ul: 1, ol: 1, li: 1,
|
|
5
|
+
pre: 1, hr: 1,
|
|
6
|
+
table: 1, thead: 1, tbody: 1, tr: 1, th: 1, td: 1,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
function isInline(name) { return INLINE[name] === 1; }
|
|
10
|
+
function isBlock(name) { return BLOCK[name] === 1; }
|
|
11
|
+
function isText(name) { return name === 'text'; }
|
|
12
|
+
function isBr(name) { return name === 'br'; }
|
|
13
|
+
function isImg(name) { return name === 'img'; }
|
|
14
|
+
function isHr(name) { return name === 'hr'; }
|
|
15
|
+
function isPre(name) { return name === 'pre'; }
|
|
16
|
+
function isSlot(name, slotComponents) {
|
|
17
|
+
return !!slotComponents && slotComponents.indexOf(name) > -1;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function classOf(node) {
|
|
21
|
+
var attrs = node.attrs || {};
|
|
22
|
+
var cls = attrs['class'] || '';
|
|
23
|
+
if (node.animate) {
|
|
24
|
+
cls = cls ? cls + ' md-animate-block' : 'md-animate-block';
|
|
25
|
+
}
|
|
26
|
+
return cls;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function styleOf(node) {
|
|
30
|
+
var attrs = node.attrs || {};
|
|
31
|
+
return attrs.style || '';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function srcOf(node) {
|
|
35
|
+
var attrs = node.attrs || {};
|
|
36
|
+
return attrs.src || '';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function altOf(node) {
|
|
40
|
+
var attrs = node.attrs || {};
|
|
41
|
+
return attrs.alt || '';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function valueOf(node) {
|
|
45
|
+
var attrs = node.attrs || {};
|
|
46
|
+
return attrs.value || '';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export default {
|
|
50
|
+
isInline: isInline,
|
|
51
|
+
isBlock: isBlock,
|
|
52
|
+
isText: isText,
|
|
53
|
+
isBr: isBr,
|
|
54
|
+
isImg: isImg,
|
|
55
|
+
isHr: isHr,
|
|
56
|
+
isPre: isPre,
|
|
57
|
+
isSlot: isSlot,
|
|
58
|
+
classOf: classOf,
|
|
59
|
+
styleOf: styleOf,
|
|
60
|
+
srcOf: srcOf,
|
|
61
|
+
altOf: altOf,
|
|
62
|
+
valueOf: valueOf,
|
|
63
|
+
};
|