@mteditor/renderer-mini 0.1.0 → 0.2.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/README.md +77 -88
- package/components/README.md +11 -8
- package/components/mt-node/index.js +3 -3
- package/components/mt-node/index.wxml +4 -4
- package/components/mt-node/index.wxss +1 -1
- package/components/mt-renderer/index.js +2 -2
- package/components/mt-renderer/index.wxml +1 -1
- package/components/mt-theme.wxss +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -10
- package/dist/index.d.ts +10 -10
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/{theme-COcEGLOF.d.cts → theme-CXitJYrs.d.cts} +24 -24
- package/dist/{theme-COcEGLOF.d.ts → theme-CXitJYrs.d.ts} +24 -24
- package/dist/wechat/index.cjs +2 -2
- package/dist/wechat/index.cjs.map +1 -1
- package/dist/wechat/index.d.cts +7 -7
- package/dist/wechat/index.d.ts +7 -7
- package/dist/wechat/index.js +2 -2
- package/dist/wechat/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,19 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
> 小程序 / uni-app / Taro / 鸿蒙 ArkTS 只读渲染器 —— 子路径导出多端。
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 定位
|
|
6
6
|
|
|
7
7
|
> **小程序端不提供完整富文本编辑。** 小程序无稳定 `contenteditable`,业界无可靠原生富文本方案。
|
|
8
8
|
> MtEditor 在小程序端提供 **100% 保真的只读渲染**;如需编辑,引导用户跳转 H5 / App 编辑页,
|
|
9
9
|
> 编辑后回传 `MtDocument`。
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
**M4-a 已落地**(ADR-0030)。`/wechat` 可用;`/alipay` `/bytedance` `/uni-app` `/taro` `/arkts`
|
|
14
|
-
仍为占位入口 —— 前两者的 `rich-text` 白名单需各自开发者工具**实测**,排期 M4-b,
|
|
15
|
-
按 AGENTS.md §4.4 禁止凭猜测提供(传给 `renderMiniDocument` 会被 `RangeError` 拒绝)。
|
|
16
|
-
|
|
17
|
-
## 本包做什么:只做三件事,不自己序列化 nodes
|
|
11
|
+
本包只做三件事,**不自己序列化 nodes**:
|
|
18
12
|
|
|
19
13
|
| 职责 | API |
|
|
20
14
|
|---|---|
|
|
@@ -22,16 +16,23 @@
|
|
|
22
16
|
| ② 主题字面量注入(小程序无 CSS 变量) | `resolveThemeTokens` / `MT_MINI_TOKENS_*` |
|
|
23
17
|
| ③ 平台能力表(准入) | `resolveCapabilities` / `MT_MINI_CAPABILITIES` |
|
|
24
18
|
|
|
25
|
-
`nodes` 一律由 `@mteditor/document` 的 `serializeDocumentToMini`
|
|
26
|
-
与 `renderer-web` 不自己序列化 HTML(ADR-0021)是同一条原则,
|
|
19
|
+
`nodes` 一律由 `@mteditor/document` 的 `serializeDocumentToMini` 产出,
|
|
27
20
|
保证「编辑、详情页、小程序、导出」四处看到的是同一份真相。
|
|
28
21
|
|
|
29
|
-
##
|
|
22
|
+
## 可用平台
|
|
30
23
|
|
|
31
|
-
| 子路径 |
|
|
32
|
-
|
|
33
|
-
|
|
|
34
|
-
| `/
|
|
24
|
+
| 子路径 | 状态 |
|
|
25
|
+
|---|---|
|
|
26
|
+
| `@mteditor/renderer-mini/wechat` | ✅ 可用(微信小程序) |
|
|
27
|
+
| `/alipay` `/bytedance` `/uni-app` `/taro` `/arkts` | ⏳ 规划中。各端 `rich-text` 白名单不一致,**未实测前拒绝执行**(调用会抛 `RangeError`),不拿微信表硬跑 |
|
|
28
|
+
|
|
29
|
+
## 安装
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm i @mteditor/renderer-mini
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 用法
|
|
35
36
|
|
|
36
37
|
```ts
|
|
37
38
|
import { render } from '@mteditor/renderer-mini/wechat'
|
|
@@ -43,22 +44,28 @@ const { mode, nodes, report, stats, autoSwitched } = render(doc, { theme: 'dark'
|
|
|
43
44
|
// report 为空数组表示内容无损;autoSwitched 非 null 表示触发了阈值降级
|
|
44
45
|
```
|
|
45
46
|
|
|
47
|
+
通用入口(自己传 `platform`):
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { renderMiniDocument } from '@mteditor/renderer-mini'
|
|
51
|
+
|
|
52
|
+
const result = renderMiniDocument(doc, { platform: 'wechat', mode: 'auto' })
|
|
53
|
+
```
|
|
54
|
+
|
|
46
55
|
### 返回值(`MtMiniRenderResult`)
|
|
47
56
|
|
|
48
57
|
| 字段 | 说明 |
|
|
49
58
|
|---|---|
|
|
50
59
|
| `platform` | 目标平台 |
|
|
51
60
|
| `mode` | **实际使用**的通道;入参 `'auto'` 时这里是解析结果 |
|
|
52
|
-
| `nodes` | 小程序 nodes(**Array
|
|
61
|
+
| `nodes` | 小程序 nodes(**Array 形式**) |
|
|
53
62
|
| `report` | 降级报告(`MT_DEG_*`),无降级时为空数组。**始终返回、不可关闭** |
|
|
54
63
|
| `stats` | 序列化统计(节点数 / 最大深度 / 字节数) |
|
|
55
64
|
| `autoSwitched` | 自动通道切换记录(`from` / `to` / `nodeCount` / `maxNodes`);未触发为 `null` |
|
|
56
65
|
|
|
57
66
|
> `report` 与 `autoSwitched` 刻意分开:前者是**内容表达损失**,后者是**渲染策略**。
|
|
58
|
-
>
|
|
59
|
-
>
|
|
60
|
-
> 本包**不提供关闭降级报告的开关**(与 `renderer-web` 不同):`rich-text` 通道会把
|
|
61
|
-
> `video` / `audio` / 公式降级成文本,这类损失用户直接看得见,留开关等于给静默留后门(§12.2)。
|
|
67
|
+
> 本包**不提供关闭降级报告的开关**:`rich-text` 通道会把 `video` / `audio` / 公式降级成文本,
|
|
68
|
+
> 这类损失用户直接看得见,留开关等于给静默留后门。
|
|
62
69
|
|
|
63
70
|
### 选项(`MtMiniRenderOptions`)
|
|
64
71
|
|
|
@@ -68,94 +75,76 @@ const { mode, nodes, report, stats, autoSwitched } = render(doc, { theme: 'dark'
|
|
|
68
75
|
| `mode` | `'auto'` | `'auto' \| 'richText' \| 'component'` |
|
|
69
76
|
| `maxNodes` | `3000` | `auto` 的降级阈值,单位是**文档节点数**;判定在序列化**之前** |
|
|
70
77
|
| `theme` | `'light'` | 内置主题名,或自定义字面量表(键含 `--` 前缀) |
|
|
71
|
-
| `themeTokens` | — |
|
|
72
|
-
| `preRendered` | — | 预渲染产物索引(公式 SVG /
|
|
78
|
+
| `themeTokens` | — | 主题字面量补充 / 覆盖,与 `theme` 合并后**后者优先** |
|
|
79
|
+
| `preRendered` | — | 预渲染产物索引(公式 SVG / 代码高亮) |
|
|
73
80
|
|
|
74
|
-
##
|
|
81
|
+
## 双通道渲染
|
|
75
82
|
|
|
76
83
|
| 通道 | 实现 | 适用 | 样式来源 |
|
|
77
84
|
|---|---|---|---|
|
|
78
|
-
| **B. 递归自定义组件**(默认) | JSON → 递归 `view
|
|
85
|
+
| **B. 递归自定义组件**(默认) | JSON → 递归 `view` / `text` 树 | 复杂内容、需要交互(图片预览、表格横滑) | 组件 wxss + CSS 变量 |
|
|
79
86
|
| **A. `rich-text` 原生组件** | JSON → `nodes` 数组 | 内容简单、性能优先 | 序列化时**内联的字面量** |
|
|
80
87
|
|
|
81
|
-
`mode: 'auto'`
|
|
82
|
-
|
|
83
|
-
不采用「输出节点数」:那要先序列化一次才能判定。
|
|
84
|
-
|
|
85
|
-
`auto` 触发降级时,`autoSwitched` 会带上 `from` / `to` / `nodeCount` / `maxNodes`。
|
|
86
|
-
本包**不持有事件总线**,所以「降级警告」的载体是这个显式字段,而非 `console.warn`
|
|
87
|
-
(后者在宿主项目里会被淹没,而「功能没生效但也没报错」是本项目出现最多的失败模式)。
|
|
88
|
-
|
|
89
|
-
## 关键约束
|
|
88
|
+
`mode: 'auto'` 的判据是**文档节点数**(与 `maxNodes` 比较),**判定发生在序列化之前** ——
|
|
89
|
+
判定的意义正是避免一次昂贵序列化。触发降级时 `autoSwitched` 会带上切换前后的通道与节点数。
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
`tsconfig.json` 的 `lib` 已剔除 `DOM`,由 `pnpm check:boundaries` 强制。
|
|
93
|
-
测试配置(`vitest.config.ts` / `tsconfig.test.json`)**刻意不用 jsdom**,
|
|
94
|
-
否则会掩盖「不小心用了浏览器全局」。
|
|
95
|
-
2. **各端映射表独立**(§4.4):微信 / 支付宝 / 抖音的 `rich-text` 白名单**不完全一致**,
|
|
96
|
-
禁止共用一份映射表。未实测的平台**拒绝执行**,不猜。
|
|
97
|
-
3. **CSS 变量不可用**(§9.3):`rich-text` 内的 `style` 不参与宿主变量继承,
|
|
98
|
-
序列化时必须把主题变量**解析为字面量**。本包内置 light / dark 两套,键名与
|
|
99
|
-
`theme-default/src/tokens.css` 逐键对应,由 `pnpm check:theme-tokens` 卡口守着。
|
|
100
|
-
4. **无客户端运行时**:代码高亮与公式必须在 `document` 层预渲染(内联 `style` 的 `span` / 内联 SVG)。
|
|
101
|
-
5. **降级必须可见**(§12.2):`video` / `audio` / `mention` 等在 `rich-text` 下不可表达的
|
|
102
|
-
节点必须写入降级报告,禁止静默丢弃。
|
|
103
|
-
6. 体积预算:`dist/wechat/index.js` gzip ≤ 30 KB(ADR-0020:esbuild minify + zlib level 9)。
|
|
91
|
+
## 小程序组件(随包分发)
|
|
104
92
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
`components/` 是**递归自定义组件通道的实现**,作为**唯一权威副本(canonical)**随包发布:
|
|
93
|
+
通道 B 的实现就在包里,**它是唯一权威副本**:
|
|
108
94
|
|
|
109
95
|
| 文件 | 作用 |
|
|
110
96
|
|---|---|
|
|
111
|
-
| `mt-renderer/` | 入口组件:按 `render()` 返回的 `mode` 在 `<rich-text>` 与递归组件之间分支 |
|
|
112
|
-
| `mt-node/` | 递归节点组件:按 `node.name` 分派到 `<view>` / `<text>` / `<image>` / `<video>` / `<audio>` |
|
|
113
|
-
| `mt-theme.wxss` | 主题变量表(宿主 `@import` 一次),亮色默认 + `mt-theme-dark` 覆盖 |
|
|
114
|
-
|
|
115
|
-
接入三步、两条通道的样式差异、三处有意的额外包裹(表格 `scroll-view scroll-x` / 公式 data URI /
|
|
116
|
-
附件独立分支)、组件选项(`virtualHost` + `addGlobalClass`,最低基础库 2.21.0)
|
|
117
|
-
见 [`components/README.md`](./components/README.md)。
|
|
118
|
-
|
|
119
|
-
> **产物形态的例外**(ADR-0030 决策 6):`components/` 不经 tsup 编译、**不进 bundle**、
|
|
120
|
-
> 因此**不计入 30 KB 体积预算**;它是 `files` 的一部分,由 `check-artifacts.mjs` 断言四件套齐备。
|
|
121
|
-
> 依据:ADR-0005 通道 B 的名字就是「递归自定义组件」—— 组件是通道实现的一部分,不是示例的私事;
|
|
122
|
-
> 放示例里则 canonical 副本与后续更新没有任何同步机制。
|
|
97
|
+
| `components/mt-renderer/` | 入口组件:按 `render()` 返回的 `mode` 在 `<rich-text>` 与递归组件之间分支 |
|
|
98
|
+
| `components/mt-node/` | 递归节点组件:按 `node.name` 分派到 `<view>` / `<text>` / `<image>` / `<video>` / `<audio>` |
|
|
99
|
+
| `components/mt-theme.wxss` | 主题变量表(宿主 `@import` 一次),亮色默认 + `mt-theme-dark` 覆盖 |
|
|
123
100
|
|
|
124
|
-
|
|
101
|
+
接入三步:
|
|
125
102
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
| `dist/*/index.d.ts` | 类型定义 |
|
|
132
|
-
| `components/**` | 通道 B 的小程序组件(canonical,见上) |
|
|
103
|
+
1. **复制组件**:小程序无法从 `node_modules` 直读组件,把 `components/` 下的
|
|
104
|
+
`mt-renderer` / `mt-node` 复制进项目(如 `components/mt/`),组件的 `usingComponents`
|
|
105
|
+
用的是相对路径,复制后无需改动;
|
|
106
|
+
2. **页面声明**:`"usingComponents": { "mt-renderer": "/components/mt/mt-renderer/index" }`;
|
|
107
|
+
3. **渲染**:
|
|
133
108
|
|
|
134
|
-
|
|
109
|
+
```js
|
|
110
|
+
import { render } from '@mteditor/renderer-mini/wechat'
|
|
135
111
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
112
|
+
Page({
|
|
113
|
+
data: { mode: 'component', nodes: [] },
|
|
114
|
+
|
|
115
|
+
onLoad() {
|
|
116
|
+
const { mode, nodes, report, autoSwitched } = render(doc, { theme: 'dark' })
|
|
117
|
+
this.setData({ mode, nodes })
|
|
118
|
+
if (report.length > 0) console.warn('内容有降级', report)
|
|
119
|
+
if (autoSwitched) console.warn('已自动切换通道', autoSwitched)
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
/** 图片点击 → 预览;附件点击 → 下载 */
|
|
123
|
+
onItemTap(event) {
|
|
124
|
+
const { kind, value } = event.detail
|
|
125
|
+
if (kind === 'image') wx.previewImage({ urls: [value] })
|
|
126
|
+
if (kind === 'attachment') wx.downloadFile({ url: value })
|
|
127
|
+
},
|
|
128
|
+
})
|
|
140
129
|
```
|
|
141
130
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|---|---|---|
|
|
146
|
-
| 单元 / 契约 | Vitest(`environment: 'node'`) | 能力表 / 通道解析 / 主题 / 渲染编排 / `/wechat` / 公开面;**35 篇基线 × 两条通道**逐字节比对 |
|
|
147
|
-
| 端到端 | `miniprogram-automator` | 渲染器全部节点在**真实小程序运行时**下的渲染 |
|
|
131
|
+
```xml
|
|
132
|
+
<mt-renderer mode="{{mode}}" nodes="{{nodes}}" bind:mttap="onItemTap" />
|
|
133
|
+
```
|
|
148
134
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
> 只在 GUI 手动导入时可用,CLI 会校验 AppID 并报 `APPID_ERROR`(详见
|
|
153
|
-
> `examples/miniprogram/README.md`)。
|
|
135
|
+
`mode` **必须是 `render()` 返回的值**,不要传你传进去的 `'auto'` ——
|
|
136
|
+
`'auto'` 的解析结果只有渲染器知道。两条通道的样式接入方式与组件选项(`virtualHost` +
|
|
137
|
+
`addGlobalClass`)见 [`components/README.md`](./components/README.md)。
|
|
154
138
|
|
|
155
|
-
##
|
|
139
|
+
## 注意事项
|
|
156
140
|
|
|
157
|
-
|
|
158
|
-
|
|
141
|
+
- **最低基础库 2.21.0**。
|
|
142
|
+
- **主题必须走字面量**:`rich-text` 内的 `style` 不参与宿主 CSS 变量继承,
|
|
143
|
+
所以 `theme` / `themeTokens` 是唯一入口(组件通道则用 `mt-theme.wxss` + CSS 变量)。
|
|
144
|
+
- **降级必须可见**:`video` / `audio` / `mention` 等在 `rich-text` 下不可表达的节点会写入 `report`,
|
|
145
|
+
禁止静默丢弃;`autoSwitched` 是「策略降级」的载体(本包不持有事件总线,故不用 `console.warn`)。
|
|
146
|
+
- 各端 `rich-text` 白名单**不完全一致**,映射表逐端独立维护;未实测的平台不猜。
|
|
147
|
+
- 小程序没有 `window`:本包不含任何 DOM 依赖,可在 Node 侧先算好 `nodes` 再下发。
|
|
159
148
|
|
|
160
149
|
## 许可
|
|
161
150
|
|
package/components/README.md
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
# renderer-mini
|
|
1
|
+
# renderer-mini 的小程序组件
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
>
|
|
5
|
-
> 不是某个示例的私事(ADR-0030 决策 6)。
|
|
3
|
+
> 「递归自定义组件」通道的实现,随包分发 —— 通道的名字就是它,所以它是渲染器的一部分,
|
|
4
|
+
> 不是某个示例的私事。
|
|
6
5
|
|
|
7
6
|
## 目录
|
|
8
7
|
|
|
@@ -67,15 +66,15 @@ Page({
|
|
|
67
66
|
| `component`(默认) | 组件 wxss + CSS 变量 | 覆盖 `page { --mt-*: … }`,或加 `mt-theme-dark` class |
|
|
68
67
|
| `richText` | 序列化时**内联的字面量** | `render(doc, { theme, themeTokens })` |
|
|
69
68
|
|
|
70
|
-
|
|
69
|
+
原因是 `rich-text` 内的 `style` 不参与宿主 CSS 变量继承,
|
|
71
70
|
所以那条通道的主题必须在序列化阶段就解析成字面量。
|
|
72
71
|
|
|
73
72
|
## 三处有意的额外包裹
|
|
74
73
|
|
|
75
|
-
|
|
74
|
+
跨端一致性要求「无多余包裹」,下面三处是**明确记录在案**的例外,
|
|
76
75
|
都是小程序能力约束所致:
|
|
77
76
|
|
|
78
|
-
1. **表格**:外包一层 `<scroll-view scroll-x>` ——
|
|
77
|
+
1. **表格**:外包一层 `<scroll-view scroll-x>` —— 宽表格必须能横滑;
|
|
79
78
|
2. **公式**:`<view class="mt-math">` 里的 SVG 文本由组件转成 `data:image/svg+xml,` URI 后交给 `<image>`;
|
|
80
79
|
3. **附件**:独立分支以便绑定点击。
|
|
81
80
|
|
|
@@ -86,4 +85,8 @@ Page({
|
|
|
86
85
|
- `virtualHost: true` —— 组件自身不产生包裹节点(基础库 ≥ 2.19.2,本包基线 2.21.0);
|
|
87
86
|
- `addGlobalClass: true` —— 允许宿主的全局样式作用进组件,宿主才有办法微调外观。
|
|
88
87
|
|
|
89
|
-
最低基础库:**2.21.0
|
|
88
|
+
最低基础库:**2.21.0**。
|
|
89
|
+
|
|
90
|
+
## 许可
|
|
91
|
+
|
|
92
|
+
MIT
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `mt-node` ——
|
|
2
|
+
* `mt-node` —— 递归节点组件(「通道 B:递归自定义组件」)。
|
|
3
3
|
*
|
|
4
4
|
* ## 输入契约
|
|
5
5
|
*
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
*
|
|
16
16
|
* ## 两个必须显式打开的能力
|
|
17
17
|
*
|
|
18
|
-
*
|
|
18
|
+
* `virtualHost: true`:组件自身不产生包裹节点。 要求跨端「节点数与层级结构
|
|
19
19
|
* 一一对应,无多余包裹」,默认的包裹行为会让 35 篇基线全部多出一层。
|
|
20
|
-
* 基础库要求 ≥ 2.19.2,本包基线 2.21.0
|
|
20
|
+
* 基础库要求 ≥ 2.19.2,本包基线 2.21.0满足。
|
|
21
21
|
* - `addGlobalClass: true`:允许宿主的全局样式(`app.wxss`)作用到本组件内,
|
|
22
22
|
* 宿主才有办法微调外观而不必改组件源码。
|
|
23
23
|
*
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<!--
|
|
2
|
-
mt-node ——
|
|
2
|
+
mt-node —— 递归渲染单个节点(通道 B)
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
分派规则与「递归组件通道」一列逐行对应
|
|
5
5
|
文本 → <text>;图片/视频/音频 → 原生组件;其余 → <view> 并递归 children。
|
|
6
6
|
|
|
7
7
|
三处**有意的额外包裹**,都是小程序的能力约束所致,不是设计疏漏:
|
|
8
|
-
1. 表格:包一层 <scroll-view scroll-x> ——
|
|
8
|
+
1. 表格:包一层 <scroll-view scroll-x> —— 宽表格必须能横滑;
|
|
9
9
|
2. 公式:<view class="mt-math"> 里的 SVG 文本在 JS 里转成 data URI 后由 <image> 承载;
|
|
10
10
|
3. 附件:需要绑定点击,故独立分支而非走通用 <view>。
|
|
11
11
|
-->
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
user-select="{{selectable}}"
|
|
19
19
|
>{{node.text}}</text>
|
|
20
20
|
|
|
21
|
-
<!-- 图片:mode=widthFix
|
|
21
|
+
<!-- 图片:mode=widthFix 是「宽度自适应、高度按比例」的唯一可靠方式 -->
|
|
22
22
|
<image
|
|
23
23
|
wx:elif="{{node.name === 'image'}}"
|
|
24
24
|
class="{{node.attrs.class}}"
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* | 组件通道(本文件) | WXSS + CSS 变量 | 宿主覆盖 `page { --mt-*: … }`,或用 `mt-theme.wxss` |
|
|
9
9
|
* | `rich-text` 通道 | 序列化时**内联的字面量** | `render(doc, { theme, themeTokens })` |
|
|
10
10
|
*
|
|
11
|
-
* 原因是硬约束:`rich-text` 内的 `style` 不参与宿主 CSS
|
|
11
|
+
* 原因是硬约束:`rich-text` 内的 `style` 不参与宿主 CSS 变量继承,
|
|
12
12
|
* 而组件通道里的元素是宿主的真实节点,CSS 变量照常生效。
|
|
13
13
|
*
|
|
14
14
|
* ## 每个取值都带 fallback
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*
|
|
15
15
|
* ## 为什么由组件分支,而不是让页面写 `wx:if`
|
|
16
16
|
*
|
|
17
|
-
*
|
|
17
|
+
* 通道选择是**渲染器**的职责:`mode: 'auto'` 的解析结果
|
|
18
18
|
* 只有渲染器知道。要求页面自己写两条分支,等于把这个知识推给每一个宿主,
|
|
19
19
|
* 而宿主写错时不会报错 —— 只会渲染出空白。
|
|
20
20
|
*
|
|
@@ -30,7 +30,7 @@ Component({
|
|
|
30
30
|
},
|
|
31
31
|
|
|
32
32
|
properties: {
|
|
33
|
-
/** `render()` 产出的 nodes(**Array
|
|
33
|
+
/** `render()` 产出的 nodes(**Array 形式**) */
|
|
34
34
|
nodes: { type: Array, value: [] },
|
|
35
35
|
/** `render()` 返回的**实际**通道:`'component' | 'richText'` */
|
|
36
36
|
mode: { type: String, value: 'component' },
|
package/components/mt-theme.wxss
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -91,7 +91,7 @@ var MT_MINI_CAPABILITIES = {
|
|
|
91
91
|
supportsId: false,
|
|
92
92
|
tagAttrs: MT_WECHAT_TAG_ATTRS,
|
|
93
93
|
/**
|
|
94
|
-
* `rich-text`
|
|
94
|
+
* `rich-text` 下不可表达、必须拆到组件外的节点。
|
|
95
95
|
* 组件通道下这些节点走原生组件,不受 `rich-text` 白名单限制。
|
|
96
96
|
*/
|
|
97
97
|
nativeComponents: ["video", "audio"]
|
|
@@ -101,7 +101,7 @@ var resolveCapabilities = (platform) => {
|
|
|
101
101
|
const found = MT_MINI_CAPABILITIES[platform];
|
|
102
102
|
if (found === void 0) {
|
|
103
103
|
throw new RangeError(
|
|
104
|
-
`@mteditor/renderer-mini \u5C1A\u672A\u652F\u6301\u5E73\u53F0 "${platform}"\uFF1A\u5176 rich-text \u767D\u540D\u5355\u672A\u7ECF\u5B9E\u6D4B\u6838\u5B9E\uFF0C\
|
|
104
|
+
`@mteditor/renderer-mini \u5C1A\u672A\u652F\u6301\u5E73\u53F0 "${platform}"\uFF1A\u5176 rich-text \u767D\u540D\u5355\u672A\u7ECF\u5B9E\u6D4B\u6838\u5B9E\uFF0C\u4E0D\u63A5\u53D7\u51ED\u731C\u6D4B\u63D0\u4F9B\u7684\u6620\u5C04\u8868\u3002\u5F53\u524D\u53EF\u7528\u5E73\u53F0\uFF1Awechat\u3002`
|
|
105
105
|
);
|
|
106
106
|
}
|
|
107
107
|
return found;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/capabilities.ts","../src/channel.ts","../src/options.ts","../src/theme.ts","../src/render.ts"],"names":["computeTreeStats","serializeDocumentToMini"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * 各端 `rich-text` 能力表(`docs/document-model.md` §9.1 / §9.4)。\n *\n * **准入条件:必须实测核实。** §4.4 明令「各子路径必须各自维护映射差异,\n * 禁止共用一份映射表」;反过来说,**没有实测过就不能让别人用**——\n * 一份「看起来能跑」的错误白名单比明确的报错危险得多(ADR-0030 决策 5)。\n *\n * 因此本文件当前只包含 `wechat`。支付宝 / 抖音的表在各自实测完成后\n * (M4-b,需各自开发者工具)追加,并同时回填 §9.4 的待确认项。\n */\n\nimport type { MtMiniCapabilities, MtMiniPlatform } from './types'\n\n/**\n * 微信小程序 `rich-text` 受信任标签白名单(§9.1,**已核实**)。\n *\n * 顺序与官方文档一致,便于逐条比对;`Set` 查询由调用方按需构造。\n */\nexport const MT_WECHAT_RICH_TEXT_TAGS: readonly string[] = [\n 'a',\n 'abbr',\n 'address',\n 'article',\n 'aside',\n 'b',\n 'bdi',\n 'bdo',\n 'big',\n 'blockquote',\n 'br',\n 'caption',\n 'center',\n 'cite',\n 'code',\n 'col',\n 'colgroup',\n 'dd',\n 'del',\n 'div',\n 'dl',\n 'dt',\n 'em',\n 'fieldset',\n 'font',\n 'footer',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'header',\n 'hr',\n 'i',\n 'img',\n 'ins',\n 'label',\n 'legend',\n 'li',\n 'mark',\n 'nav',\n 'ol',\n 'p',\n 'pre',\n 'q',\n 'rt',\n 'ruby',\n 's',\n 'section',\n 'small',\n 'span',\n 'strong',\n 'sub',\n 'sup',\n 'table',\n 'tbody',\n 'td',\n 'tfoot',\n 'th',\n 'thead',\n 'tr',\n 'tt',\n 'u',\n 'ul',\n]\n\n/**\n * 逐标签属性白名单(§9.1,**已核实**)。\n *\n * 未在表中的标签不接受额外属性;全局属性(`class` / `style`)单独由\n * `globalAttrs` 描述。**`id` 不在任何一张表里** —— 微信全局不支持 `id`。\n */\nexport const MT_WECHAT_TAG_ATTRS: Readonly<Record<string, readonly string[]>> = {\n img: ['alt', 'src', 'height', 'width'],\n table: ['width'],\n col: ['span', 'width'],\n colgroup: ['span', 'width'],\n td: ['colspan', 'height', 'rowspan', 'width'],\n th: ['colspan', 'height', 'rowspan', 'width'],\n tr: ['colspan', 'height', 'rowspan', 'width'],\n ol: ['start', 'type'],\n}\n\n/**\n * 小程序平台能力表。\n *\n * 当前只登记 `wechat`(§9.1 已核实)。缺失的平台在\n * `resolveCapabilities` 处**抛错**,不做容错。\n */\nexport const MT_MINI_CAPABILITIES: Readonly<Partial<Record<MtMiniPlatform, MtMiniCapabilities>>> = {\n wechat: {\n platform: 'wechat',\n verified: true,\n tags: MT_WECHAT_RICH_TEXT_TAGS,\n globalAttrs: ['class', 'style'],\n supportsId: false,\n tagAttrs: MT_WECHAT_TAG_ATTRS,\n /**\n * `rich-text` 下不可表达、必须拆到组件外的节点(§9.2)。\n * 组件通道下这些节点走原生组件,不受 `rich-text` 白名单限制。\n */\n nativeComponents: ['video', 'audio'],\n },\n}\n\n/**\n * 取某个平台的能力表。\n *\n * @param platform 平台标识\n * @returns 该平台的能力描述\n * @throws {RangeError} 该平台尚未实测核实(ADR-0030 决策 5)\n *\n * @example\n * ```ts\n * resolveCapabilities('wechat').supportsId // false\n * resolveCapabilities('alipay') // 抛 RangeError:尚未实测\n * ```\n */\nexport const resolveCapabilities = (platform: MtMiniPlatform): MtMiniCapabilities => {\n const found = MT_MINI_CAPABILITIES[platform]\n if (found === undefined) {\n throw new RangeError(\n `@mteditor/renderer-mini 尚未支持平台 \"${platform}\":其 rich-text 白名单未经实测核实,` +\n '按 AGENTS.md §4.4 禁止凭猜测提供映射表。当前可用平台:wechat。',\n )\n }\n return found\n}\n","/**\n * 通道解析(ADR-0005 双通道 / ADR-0030 决策 3)。\n *\n * `@mteditor/document` 只接受显式的 `'component' | 'richText'`;把 `'auto'`\n * 解析成具体通道是**渲染层**的职责 —— 因为它需要知道 `maxNodes` 这类\n * 宿主侧的渲染成本概念,而 `document` 是零框架的文档模型层。\n */\n\nimport { computeTreeStats } from '@mteditor/document'\nimport type { MtDocument } from '@mteditor/document'\nimport type { MtMiniChannelOption, MtMiniChannelSwitch, MtMiniMode } from './types'\n\n/** 通道解析结果 */\nexport interface MtChannelResolution {\n /** 实际使用的通道 */\n mode: MtMiniMode\n /** 自动切换记录;未发生切换时为 `null` */\n switched: MtMiniChannelSwitch | null\n}\n\n/**\n * 解析渲染通道。\n *\n * 规则(§9.2):\n * - 显式给出 `'component'` / `'richText'` 时**原样采用**,不做阈值判定\n * —— 宿主显式指定就代表它知道自己在做什么;\n * - `'auto'` 时按**文档节点数**判定:`nodeCount > maxNodes` 走 `richText`。\n *\n * @param doc 文档\n * @param option 通道选择\n * @param maxNodes `'auto'` 的阈值(文档节点数)\n * @returns 通道与该次判定是否发生了切换\n *\n * @example\n * ```ts\n * // 3000 节点以内:组件通道\n * resolveChannel(doc, 'auto', 3000).mode // 'component'\n * // 显式指定时不看阈值\n * resolveChannel(hugeDoc, 'component', 1).mode // 'component'\n * ```\n */\nexport const resolveChannel = (\n doc: MtDocument,\n option: MtMiniChannelOption,\n maxNodes: number,\n): MtChannelResolution => {\n if (option !== 'auto') return { mode: option, switched: null }\n\n const { nodeCount } = computeTreeStats(doc.content)\n if (nodeCount <= maxNodes) return { mode: 'component', switched: null }\n\n return {\n mode: 'richText',\n switched: { from: 'component', to: 'richText', nodeCount, maxNodes },\n }\n}\n","/**\n * 渲染层默认值。\n *\n * 单独成文件的理由:这些数值同时出现在**文档**(AGENTS.md §9.2)与\n * **测试**(阈值边界用例)里,散落在实现里会让「改默认值」变成一次考古。\n */\n\nimport type { MtMiniMode } from './types'\n\n/**\n * `mode: 'auto'` 的降级阈值,单位是**文档节点数**(§9.2)。\n *\n * 判定依据不是「输出 nodes 数」:那需要先序列化一次才能判定,而判定的意义\n * 正是避免一次昂贵序列化(ADR-0030 决策 3)。\n */\nexport const MT_DEFAULT_MAX_NODES = 3000\n\n/** 缺省通道选择 */\nexport const MT_DEFAULT_MODE: 'auto' | MtMiniMode = 'auto'\n\n/** 缺省主题名 */\nexport const MT_DEFAULT_THEME = 'light'\n\n/** 缺省平台 */\nexport const MT_DEFAULT_PLATFORM = 'wechat'\n","/**\n * 内置主题字面量(ADR-0030 决策 4)。\n *\n * ## 为什么这份数据必须存在于本包\n *\n * 小程序端 `rich-text` 内的 `style` **不参与宿主 CSS 变量继承**(§9.3),\n * 所有主题值必须在序列化时解析为字面量,而 `@mteditor/theme-default` 按 §6.1\n * 只产出 CSS、没有 JS 导出 —— 若要求宿主自备这份表,每个项目都要手抄\n * `tokens.css` 的 65 个键,抄错还**没有报错**(本仓库自己就踩过:\n * `mini.ts` 读的 `--mt-font-mono` 与 `tokens.css` 的 `--mt-font-family-mono`\n * 不一致,两个引用点恒走 fallback)。\n *\n * ## 与 tokens.css 的关系:允许独立,禁止无守卫地独立\n *\n * 本文件是 `packages/theme-default/src/tokens.css` 的**逐键镜像**\n * (`dark` 是 `light` 上的部分覆盖,与 CSS 的层叠语义一致)。\n * `scripts/check-theme-tokens.mjs` 断言两者键集合与取值完全一致 ——\n * 改任一侧而漏改另一侧会让 `pnpm verify` 失败。\n *\n * 取值风格与 CSS 一致:保留 `rgb(37 99 235 / 18%)` 这类现代空格语法,\n * 不自作主张转换为逗号语法(`@mteditor/document` 原样内联,不做解析)。\n */\n\nimport type { MtMiniTheme } from './types'\n\n/** 亮色主题:`tokens.css` 中 `:root, [data-mt-theme='light']` 块的完整镜像 */\nexport const MT_MINI_TOKENS_LIGHT: Readonly<Record<string, string>> = {\n '--mt-color-primary': '#2563eb',\n '--mt-color-primary-hover': '#1d4ed8',\n '--mt-color-primary-active': '#1e40af',\n '--mt-color-success': '#16a34a',\n '--mt-color-warning': '#d97706',\n '--mt-color-danger': '#dc2626',\n '--mt-color-link': '#2563eb',\n '--mt-color-text': '#1f2329',\n '--mt-color-text-secondary': '#646a73',\n '--mt-color-text-disabled': '#a6a9ad',\n '--mt-color-text-inverse': '#fff',\n '--mt-color-bg': '#fff',\n '--mt-color-bg-elevated': '#fff',\n '--mt-color-bg-muted': '#f5f7fa',\n '--mt-color-bg-hover': '#f2f3f5',\n '--mt-color-border': '#dee0e3',\n '--mt-color-border-strong': '#babdbf',\n '--mt-color-selection': 'rgb(37 99 235 / 18%)',\n '--mt-color-code-bg': '#f5f5f5',\n '--mt-color-code-text': '#c0392b',\n '--mt-color-quote-border': '#dee0e3',\n '--mt-color-mark-bg': '#fff3a3',\n '--mt-font-family':\n \"-apple-system, blinkmacsystemfont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif\",\n '--mt-font-family-mono': \"'SFMono-Regular', consolas, 'Liberation Mono', menlo, monospace\",\n '--mt-font-size': '15px',\n '--mt-font-size-sm': '13px',\n '--mt-font-size-lg': '17px',\n '--mt-line-height': '1.7',\n '--mt-letter-spacing': 'normal',\n '--mt-h1-font-size': '28px',\n '--mt-h2-font-size': '24px',\n '--mt-h3-font-size': '20px',\n '--mt-h4-font-size': '18px',\n '--mt-h5-font-size': '16px',\n '--mt-h6-font-size': '15px',\n '--mt-space-1': '4px',\n '--mt-space-2': '8px',\n '--mt-space-3': '12px',\n '--mt-space-4': '16px',\n '--mt-space-5': '24px',\n '--mt-space-6': '32px',\n '--mt-radius-sm': '3px',\n '--mt-radius-md': '6px',\n '--mt-radius-lg': '10px',\n '--mt-radius-full': '9999px',\n '--mt-shadow-sm': '0 1px 3px rgb(0 0 0 / 8%)',\n '--mt-shadow-md': '0 4px 12px rgb(0 0 0 / 10%)',\n '--mt-toolbar-height': '40px',\n '--mt-content-max-width': '860px',\n '--mt-content-padding': '20px',\n '--mt-control-size': '30px',\n '--mt-control-icon-size': '18px',\n '--mt-control-gap': '2px',\n '--mt-popup-padding': '4px',\n '--mt-popup-gap': '6px',\n '--mt-drawer-max-height': '60vh',\n '--mt-block-handle-width': '46px',\n '--mt-block-indicator-height': '2px',\n '--mt-outline-width': '200px',\n '--mt-outline-top': '0px',\n '--mt-z-toolbar': '100',\n '--mt-z-dropdown': '200',\n '--mt-z-popover': '300',\n '--mt-z-modal': '400',\n '--mt-z-toast': '500',\n '--mt-transition-fast': '120ms ease',\n '--mt-transition-base': '200ms ease',\n}\n\n/**\n * 暗色主题对亮色的**覆盖项**(与 `tokens.css` 的 `[data-mt-theme='dark']` 块一致)。\n *\n * 单独导出是为了让卡口脚本能分别比对「覆盖集」与「派生全集」——\n * 若只导出派生的全集,CSS 里删掉一个覆盖项(于是暗色回退到亮色值)\n * 在 TS 侧不可见。\n */\nexport const MT_MINI_TOKENS_DARK_OVERRIDES: Readonly<Record<string, string>> = {\n '--mt-color-primary': '#3b82f6',\n '--mt-color-primary-hover': '#60a5fa',\n '--mt-color-primary-active': '#2563eb',\n '--mt-color-success': '#22c55e',\n '--mt-color-warning': '#f59e0b',\n '--mt-color-danger': '#ef4444',\n '--mt-color-link': '#60a5fa',\n '--mt-color-text': '#e5e6eb',\n '--mt-color-text-secondary': '#a3a6ad',\n '--mt-color-text-disabled': '#6b6f76',\n '--mt-color-text-inverse': '#1f2329',\n '--mt-color-bg': '#1f2329',\n '--mt-color-bg-elevated': '#282c33',\n '--mt-color-bg-muted': '#282c33',\n '--mt-color-bg-hover': '#32363d',\n '--mt-color-border': '#3a3f47',\n '--mt-color-border-strong': '#4e545d',\n '--mt-color-selection': 'rgb(59 130 246 / 28%)',\n '--mt-color-code-bg': '#2b2f36',\n '--mt-color-code-text': '#f87171',\n '--mt-color-quote-border': '#3a3f47',\n '--mt-color-mark-bg': '#6b5a1a',\n '--mt-shadow-sm': '0 1px 3px rgb(0 0 0 / 40%)',\n '--mt-shadow-md': '0 4px 12px rgb(0 0 0 / 50%)',\n}\n\n/** 暗色主题全集(亮色为基底 + 覆盖项) */\nexport const MT_MINI_TOKENS_DARK: Readonly<Record<string, string>> = {\n ...MT_MINI_TOKENS_LIGHT,\n ...MT_MINI_TOKENS_DARK_OVERRIDES,\n}\n\n/**\n * 解析主题字面量表。\n *\n * 合并顺序:内置名(或自定义表)→ `themeTokens` 覆盖项。\n *\n * @param theme 内置主题名或自定义字面量表,缺省 `'light'`\n * @param override 覆盖项,键含 `--` 前缀;缺省不覆盖\n * @returns 可直接传给 `serializeDocumentToMini` 的 `themeTokens`\n *\n * @example\n * ```ts\n * resolveThemeTokens('dark') // 65 个键的暗色表\n * resolveThemeTokens(undefined, { '--mt-color-link': '#f00' })\n * // 亮色表,但链接色为 #f00\n * ```\n */\nexport const resolveThemeTokens = (\n theme?: MtMiniTheme,\n override?: Record<string, string>,\n): Record<string, string> => {\n const base =\n theme === undefined || theme === 'light'\n ? MT_MINI_TOKENS_LIGHT\n : theme === 'dark'\n ? MT_MINI_TOKENS_DARK\n : theme\n return override === undefined ? { ...base } : { ...base, ...override }\n}\n","/**\n * 渲染层主入口(ADR-0030)。\n *\n * 本函数的职责边界刻意很窄 —— 只做三件事,**不自己拼 nodes**:\n *\n * | 步骤 | 说明 |\n * |---|---|\n * | ① 平台准入 | 能力表未登记的平台直接抛错,不做容错 |\n * | ② 通道解析 | `'auto'` → 按 `maxNodes` 判定,并记录是否发生切换 |\n * | ③ 主题注入 | 内置 light / dark 字面量(小程序无 CSS 变量) |\n *\n * `nodes` 一律由 `@mteditor/document` 的 `serializeDocumentToMini` 产出\n * —— 这是 ADR-0021「序列化真相源唯一」在小程序端的同一条原则。\n */\n\nimport { serializeDocumentToMini } from '@mteditor/document'\nimport type { MtDocument } from '@mteditor/document'\nimport { resolveCapabilities } from './capabilities'\nimport { resolveChannel } from './channel'\nimport { MT_DEFAULT_MAX_NODES, MT_DEFAULT_MODE, MT_DEFAULT_PLATFORM } from './options'\nimport { resolveThemeTokens } from './theme'\nimport type { MtMiniRenderOptions, MtMiniRenderResult } from './types'\n\n/**\n * 把 `MtDocument` 渲染为小程序可直接 `setData` 的 payload。\n *\n * @param doc 文档(唯一真相源)\n * @param options 渲染选项\n * @returns 通道、nodes、降级报告、统计与自动切换记录\n * @throws {RangeError} `options.platform` 的能力表未经实测核实(ADR-0030 决策 5)\n *\n * @example\n * ```ts\n * import { renderMiniDocument } from '@mteditor/renderer-mini'\n *\n * const { mode, nodes, report, autoSwitched } = renderMiniDocument(doc, {\n * theme: 'dark',\n * mode: 'auto',\n * })\n *\n * if (autoSwitched) console.warn(`节点数 ${autoSwitched.nodeCount} 超过阈值,已切到 rich-text`)\n * if (report.length > 0) console.warn('内容有降级', report)\n * ```\n */\nexport const renderMiniDocument = (\n doc: MtDocument,\n options: MtMiniRenderOptions = {},\n): MtMiniRenderResult => {\n const platform = options.platform ?? MT_DEFAULT_PLATFORM\n // 平台准入:未实测核实的平台在此抛错,而不是拿微信的表硬跑(§4.4)\n void resolveCapabilities(platform)\n\n const { mode, switched } = resolveChannel(\n doc,\n options.mode ?? MT_DEFAULT_MODE,\n options.maxNodes ?? MT_DEFAULT_MAX_NODES,\n )\n\n const { output, report, stats } = serializeDocumentToMini(doc, {\n platform,\n mode,\n themeTokens: resolveThemeTokens(options.theme, options.themeTokens),\n ...(options.preRendered === undefined ? {} : { preRendered: options.preRendered }),\n })\n\n return { platform, mode, nodes: output, report, stats, autoSwitched: switched }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/capabilities.ts","../src/channel.ts","../src/options.ts","../src/theme.ts","../src/render.ts"],"names":["computeTreeStats","serializeDocumentToMini"],"mappings":";;;;;;;AAkBO,IAAM,wBAAA,GAA8C;AAAA,EACzD,GAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA,GAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,YAAA;AAAA,EACA,IAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,UAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,UAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA;AAAA,EACA,IAAA;AAAA,EACA,GAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,GAAA;AAAA,EACA,KAAA;AAAA,EACA,GAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,GAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,IAAA;AAAA,EACA,OAAA;AAAA,EACA,IAAA;AAAA,EACA,OAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AAAA,EACA,GAAA;AAAA,EACA;AACF,CAAA;AAQO,IAAM,mBAAA,GAAmE;AAAA,EAC9E,GAAA,EAAK,CAAC,KAAA,EAAO,KAAA,EAAO,UAAU,OAAO,CAAA;AAAA,EACrC,KAAA,EAAO,CAAC,OAAO,CAAA;AAAA,EACf,GAAA,EAAK,CAAC,MAAA,EAAQ,OAAO,CAAA;AAAA,EACrB,QAAA,EAAU,CAAC,MAAA,EAAQ,OAAO,CAAA;AAAA,EAC1B,EAAA,EAAI,CAAC,SAAA,EAAW,QAAA,EAAU,WAAW,OAAO,CAAA;AAAA,EAC5C,EAAA,EAAI,CAAC,SAAA,EAAW,QAAA,EAAU,WAAW,OAAO,CAAA;AAAA,EAC5C,EAAA,EAAI,CAAC,SAAA,EAAW,QAAA,EAAU,WAAW,OAAO,CAAA;AAAA,EAC5C,EAAA,EAAI,CAAC,OAAA,EAAS,MAAM;AACtB,CAAA;AAQO,IAAM,oBAAA,GAAsF;AAAA,EACjG,MAAA,EAAQ;AAAA,IACN,QAAA,EAAU,QAAA;AAAA,IACV,QAAA,EAAU,IAAA;AAAA,IACV,IAAA,EAAM,wBAAA;AAAA,IACN,WAAA,EAAa,CAAC,OAAA,EAAS,OAAO,CAAA;AAAA,IAC9B,UAAA,EAAY,KAAA;AAAA,IACZ,QAAA,EAAU,mBAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAKV,gBAAA,EAAkB,CAAC,OAAA,EAAS,OAAO;AAAA;AAEvC;AAeO,IAAM,mBAAA,GAAsB,CAAC,QAAA,KAAiD;AACnF,EAAA,MAAM,KAAA,GAAQ,qBAAqB,QAAQ,CAAA;AAC3C,EAAA,IAAI,UAAU,MAAA,EAAW;AACvB,IAAA,MAAM,IAAI,UAAA;AAAA,MACR,iEAAmC,QAAQ,CAAA,wNAAA;AAAA,KAE7C;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT;AC1GO,IAAM,cAAA,GAAiB,CAC5B,GAAA,EACA,MAAA,EACA,QAAA,KACwB;AACxB,EAAA,IAAI,WAAW,MAAA,EAAQ,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,UAAU,IAAA,EAAK;AAE7D,EAAA,MAAM,EAAE,SAAA,EAAU,GAAIA,yBAAA,CAAiB,IAAI,OAAO,CAAA;AAClD,EAAA,IAAI,aAAa,QAAA,EAAU,OAAO,EAAE,IAAA,EAAM,WAAA,EAAa,UAAU,IAAA,EAAK;AAEtE,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,UAAA;AAAA,IACN,UAAU,EAAE,IAAA,EAAM,aAAa,EAAA,EAAI,UAAA,EAAY,WAAW,QAAA;AAAS,GACrE;AACF;;;ACxCO,IAAM,oBAAA,GAAuB;AAG7B,IAAM,eAAA,GAAuC;AAM7C,IAAM,mBAAA,GAAsB;;;ACE5B,IAAM,oBAAA,GAAyD;AAAA,EACpE,oBAAA,EAAsB,SAAA;AAAA,EACtB,0BAAA,EAA4B,SAAA;AAAA,EAC5B,2BAAA,EAA6B,SAAA;AAAA,EAC7B,oBAAA,EAAsB,SAAA;AAAA,EACtB,oBAAA,EAAsB,SAAA;AAAA,EACtB,mBAAA,EAAqB,SAAA;AAAA,EACrB,iBAAA,EAAmB,SAAA;AAAA,EACnB,iBAAA,EAAmB,SAAA;AAAA,EACnB,2BAAA,EAA6B,SAAA;AAAA,EAC7B,0BAAA,EAA4B,SAAA;AAAA,EAC5B,yBAAA,EAA2B,MAAA;AAAA,EAC3B,eAAA,EAAiB,MAAA;AAAA,EACjB,wBAAA,EAA0B,MAAA;AAAA,EAC1B,qBAAA,EAAuB,SAAA;AAAA,EACvB,qBAAA,EAAuB,SAAA;AAAA,EACvB,mBAAA,EAAqB,SAAA;AAAA,EACrB,0BAAA,EAA4B,SAAA;AAAA,EAC5B,sBAAA,EAAwB,sBAAA;AAAA,EACxB,oBAAA,EAAsB,SAAA;AAAA,EACtB,sBAAA,EAAwB,SAAA;AAAA,EACxB,yBAAA,EAA2B,SAAA;AAAA,EAC3B,oBAAA,EAAsB,SAAA;AAAA,EACtB,kBAAA,EACE,iHAAA;AAAA,EACF,uBAAA,EAAyB,iEAAA;AAAA,EACzB,gBAAA,EAAkB,MAAA;AAAA,EAClB,mBAAA,EAAqB,MAAA;AAAA,EACrB,mBAAA,EAAqB,MAAA;AAAA,EACrB,kBAAA,EAAoB,KAAA;AAAA,EACpB,qBAAA,EAAuB,QAAA;AAAA,EACvB,mBAAA,EAAqB,MAAA;AAAA,EACrB,mBAAA,EAAqB,MAAA;AAAA,EACrB,mBAAA,EAAqB,MAAA;AAAA,EACrB,mBAAA,EAAqB,MAAA;AAAA,EACrB,mBAAA,EAAqB,MAAA;AAAA,EACrB,mBAAA,EAAqB,MAAA;AAAA,EACrB,cAAA,EAAgB,KAAA;AAAA,EAChB,cAAA,EAAgB,KAAA;AAAA,EAChB,cAAA,EAAgB,MAAA;AAAA,EAChB,cAAA,EAAgB,MAAA;AAAA,EAChB,cAAA,EAAgB,MAAA;AAAA,EAChB,cAAA,EAAgB,MAAA;AAAA,EAChB,gBAAA,EAAkB,KAAA;AAAA,EAClB,gBAAA,EAAkB,KAAA;AAAA,EAClB,gBAAA,EAAkB,MAAA;AAAA,EAClB,kBAAA,EAAoB,QAAA;AAAA,EACpB,gBAAA,EAAkB,2BAAA;AAAA,EAClB,gBAAA,EAAkB,6BAAA;AAAA,EAClB,qBAAA,EAAuB,MAAA;AAAA,EACvB,wBAAA,EAA0B,OAAA;AAAA,EAC1B,sBAAA,EAAwB,MAAA;AAAA,EACxB,mBAAA,EAAqB,MAAA;AAAA,EACrB,wBAAA,EAA0B,MAAA;AAAA,EAC1B,kBAAA,EAAoB,KAAA;AAAA,EACpB,oBAAA,EAAsB,KAAA;AAAA,EACtB,gBAAA,EAAkB,KAAA;AAAA,EAClB,wBAAA,EAA0B,MAAA;AAAA,EAC1B,yBAAA,EAA2B,MAAA;AAAA,EAC3B,6BAAA,EAA+B,KAAA;AAAA,EAC/B,oBAAA,EAAsB,OAAA;AAAA,EACtB,kBAAA,EAAoB,KAAA;AAAA,EACpB,gBAAA,EAAkB,KAAA;AAAA,EAClB,iBAAA,EAAmB,KAAA;AAAA,EACnB,gBAAA,EAAkB,KAAA;AAAA,EAClB,cAAA,EAAgB,KAAA;AAAA,EAChB,cAAA,EAAgB,KAAA;AAAA,EAChB,sBAAA,EAAwB,YAAA;AAAA,EACxB,sBAAA,EAAwB;AAC1B;AASO,IAAM,6BAAA,GAAkE;AAAA,EAC7E,oBAAA,EAAsB,SAAA;AAAA,EACtB,0BAAA,EAA4B,SAAA;AAAA,EAC5B,2BAAA,EAA6B,SAAA;AAAA,EAC7B,oBAAA,EAAsB,SAAA;AAAA,EACtB,oBAAA,EAAsB,SAAA;AAAA,EACtB,mBAAA,EAAqB,SAAA;AAAA,EACrB,iBAAA,EAAmB,SAAA;AAAA,EACnB,iBAAA,EAAmB,SAAA;AAAA,EACnB,2BAAA,EAA6B,SAAA;AAAA,EAC7B,0BAAA,EAA4B,SAAA;AAAA,EAC5B,yBAAA,EAA2B,SAAA;AAAA,EAC3B,eAAA,EAAiB,SAAA;AAAA,EACjB,wBAAA,EAA0B,SAAA;AAAA,EAC1B,qBAAA,EAAuB,SAAA;AAAA,EACvB,qBAAA,EAAuB,SAAA;AAAA,EACvB,mBAAA,EAAqB,SAAA;AAAA,EACrB,0BAAA,EAA4B,SAAA;AAAA,EAC5B,sBAAA,EAAwB,uBAAA;AAAA,EACxB,oBAAA,EAAsB,SAAA;AAAA,EACtB,sBAAA,EAAwB,SAAA;AAAA,EACxB,yBAAA,EAA2B,SAAA;AAAA,EAC3B,oBAAA,EAAsB,SAAA;AAAA,EACtB,gBAAA,EAAkB,4BAAA;AAAA,EAClB,gBAAA,EAAkB;AACpB;AAGO,IAAM,mBAAA,GAAwD;AAAA,EACnE,GAAG,oBAAA;AAAA,EACH,GAAG;AACL;AAkBO,IAAM,kBAAA,GAAqB,CAChC,KAAA,EACA,QAAA,KAC2B;AAC3B,EAAA,MAAM,IAAA,GACJ,UAAU,MAAA,IAAa,KAAA,KAAU,UAC7B,oBAAA,GACA,KAAA,KAAU,SACR,mBAAA,GACA,KAAA;AACR,EAAA,OAAO,QAAA,KAAa,MAAA,GAAY,EAAE,GAAG,IAAA,KAAS,EAAE,GAAG,IAAA,EAAM,GAAG,QAAA,EAAS;AACvE;;;ACxHO,IAAM,kBAAA,GAAqB,CAChC,GAAA,EACA,OAAA,GAA+B,EAAC,KACT;AACvB,EAAA,MAAM,QAAA,GAAW,QAAQ,QAAA,IAAY,mBAAA;AAErC,EAAA,KAAK,oBAAoB,QAAQ,CAAA;AAEjC,EAAA,MAAM,EAAE,IAAA,EAAM,QAAA,EAAS,GAAI,cAAA;AAAA,IACzB,GAAA;AAAA,IACA,QAAQ,IAAA,IAAQ,eAAA;AAAA,IAChB,QAAQ,QAAA,IAAY;AAAA,GACtB;AAEA,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAM,GAAIC,iCAAwB,GAAA,EAAK;AAAA,IAC7D,QAAA;AAAA,IACA,IAAA;AAAA,IACA,WAAA,EAAa,kBAAA,CAAmB,OAAA,CAAQ,KAAA,EAAO,QAAQ,WAAW,CAAA;AAAA,IAClE,GAAI,QAAQ,WAAA,KAAgB,MAAA,GAAY,EAAC,GAAI,EAAE,WAAA,EAAa,OAAA,CAAQ,WAAA;AAAY,GACjF,CAAA;AAED,EAAA,OAAO,EAAE,UAAU,IAAA,EAAM,KAAA,EAAO,QAAQ,MAAA,EAAQ,KAAA,EAAO,cAAc,QAAA,EAAS;AAChF","file":"index.cjs","sourcesContent":["/**\n * 各端 `rich-text` 能力表。\n *\n * **准入条件:必须实测核实。** 各子路径必须各自维护映射差异,\n * 禁止共用一份映射表;反过来说,**没有实测过就不能让别人用**——\n * 一份「看起来能跑」的错误白名单比明确的报错危险得多。\n *\n * 因此本文件当前只包含 `wechat`。支付宝 / 抖音的表在各自实测完成后\n * (需各自开发者工具)追加,并同时回填待确认项。\n */\n\nimport type { MtMiniCapabilities, MtMiniPlatform } from './types'\n\n/**\n * 微信小程序 `rich-text` 受信任标签白名单(**已核实**)。\n *\n * 顺序与官方文档一致,便于逐条比对;`Set` 查询由调用方按需构造。\n */\nexport const MT_WECHAT_RICH_TEXT_TAGS: readonly string[] = [\n 'a',\n 'abbr',\n 'address',\n 'article',\n 'aside',\n 'b',\n 'bdi',\n 'bdo',\n 'big',\n 'blockquote',\n 'br',\n 'caption',\n 'center',\n 'cite',\n 'code',\n 'col',\n 'colgroup',\n 'dd',\n 'del',\n 'div',\n 'dl',\n 'dt',\n 'em',\n 'fieldset',\n 'font',\n 'footer',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'header',\n 'hr',\n 'i',\n 'img',\n 'ins',\n 'label',\n 'legend',\n 'li',\n 'mark',\n 'nav',\n 'ol',\n 'p',\n 'pre',\n 'q',\n 'rt',\n 'ruby',\n 's',\n 'section',\n 'small',\n 'span',\n 'strong',\n 'sub',\n 'sup',\n 'table',\n 'tbody',\n 'td',\n 'tfoot',\n 'th',\n 'thead',\n 'tr',\n 'tt',\n 'u',\n 'ul',\n]\n\n/**\n * 逐标签属性白名单(**已核实**)。\n *\n * 未在表中的标签不接受额外属性;全局属性(`class` / `style`)单独由\n * `globalAttrs` 描述。**`id` 不在任何一张表里** —— 微信全局不支持 `id`。\n */\nexport const MT_WECHAT_TAG_ATTRS: Readonly<Record<string, readonly string[]>> = {\n img: ['alt', 'src', 'height', 'width'],\n table: ['width'],\n col: ['span', 'width'],\n colgroup: ['span', 'width'],\n td: ['colspan', 'height', 'rowspan', 'width'],\n th: ['colspan', 'height', 'rowspan', 'width'],\n tr: ['colspan', 'height', 'rowspan', 'width'],\n ol: ['start', 'type'],\n}\n\n/**\n * 小程序平台能力表。\n *\n * 当前只登记 `wechat`(已核实)。缺失的平台在\n * `resolveCapabilities` 处**抛错**,不做容错。\n */\nexport const MT_MINI_CAPABILITIES: Readonly<Partial<Record<MtMiniPlatform, MtMiniCapabilities>>> = {\n wechat: {\n platform: 'wechat',\n verified: true,\n tags: MT_WECHAT_RICH_TEXT_TAGS,\n globalAttrs: ['class', 'style'],\n supportsId: false,\n tagAttrs: MT_WECHAT_TAG_ATTRS,\n /**\n * `rich-text` 下不可表达、必须拆到组件外的节点。\n * 组件通道下这些节点走原生组件,不受 `rich-text` 白名单限制。\n */\n nativeComponents: ['video', 'audio'],\n },\n}\n\n/**\n * 取某个平台的能力表。\n *\n * @param platform 平台标识\n * @returns 该平台的能力描述\n * @throws {RangeError} 该平台尚未实测核实\n *\n * @example\n * ```ts\n * resolveCapabilities('wechat').supportsId // false\n * resolveCapabilities('alipay') // 抛 RangeError:尚未实测\n * ```\n */\nexport const resolveCapabilities = (platform: MtMiniPlatform): MtMiniCapabilities => {\n const found = MT_MINI_CAPABILITIES[platform]\n if (found === undefined) {\n throw new RangeError(\n `@mteditor/renderer-mini 尚未支持平台 \"${platform}\":其 rich-text 白名单未经实测核实,` +\n '不接受凭猜测提供的映射表。当前可用平台:wechat。',\n )\n }\n return found\n}\n","/**\n * 通道解析(双通道)。\n *\n * `@mteditor/document` 只接受显式的 `'component' | 'richText'`;把 `'auto'`\n * 解析成具体通道是**渲染层**的职责 —— 因为它需要知道 `maxNodes` 这类\n * 宿主侧的渲染成本概念,而 `document` 是零框架的文档模型层。\n */\n\nimport { computeTreeStats } from '@mteditor/document'\nimport type { MtDocument } from '@mteditor/document'\nimport type { MtMiniChannelOption, MtMiniChannelSwitch, MtMiniMode } from './types'\n\n/** 通道解析结果 */\nexport interface MtChannelResolution {\n /** 实际使用的通道 */\n mode: MtMiniMode\n /** 自动切换记录;未发生切换时为 `null` */\n switched: MtMiniChannelSwitch | null\n}\n\n/**\n * 解析渲染通道。\n *\n * 规则:\n * - 显式给出 `'component'` / `'richText'` 时**原样采用**,不做阈值判定\n * —— 宿主显式指定就代表它知道自己在做什么;\n * - `'auto'` 时按**文档节点数**判定:`nodeCount > maxNodes` 走 `richText`。\n *\n * @param doc 文档\n * @param option 通道选择\n * @param maxNodes `'auto'` 的阈值(文档节点数)\n * @returns 通道与该次判定是否发生了切换\n *\n * @example\n * ```ts\n * // 3000 节点以内:组件通道\n * resolveChannel(doc, 'auto', 3000).mode // 'component'\n * // 显式指定时不看阈值\n * resolveChannel(hugeDoc, 'component', 1).mode // 'component'\n * ```\n */\nexport const resolveChannel = (\n doc: MtDocument,\n option: MtMiniChannelOption,\n maxNodes: number,\n): MtChannelResolution => {\n if (option !== 'auto') return { mode: option, switched: null }\n\n const { nodeCount } = computeTreeStats(doc.content)\n if (nodeCount <= maxNodes) return { mode: 'component', switched: null }\n\n return {\n mode: 'richText',\n switched: { from: 'component', to: 'richText', nodeCount, maxNodes },\n }\n}\n","/**\n * 渲染层默认值。\n *\n * 单独成文件的理由:这些数值同时出现在**文档**与\n * **测试**(阈值边界用例)里,散落在实现里会让「改默认值」变成一次考古。\n */\n\nimport type { MtMiniMode } from './types'\n\n/**\n * `mode: 'auto'` 的降级阈值,单位是**文档节点数**。\n *\n * 判定依据不是「输出 nodes 数」:那需要先序列化一次才能判定,而判定的意义\n * 正是避免一次昂贵序列化。\n */\nexport const MT_DEFAULT_MAX_NODES = 3000\n\n/** 缺省通道选择 */\nexport const MT_DEFAULT_MODE: 'auto' | MtMiniMode = 'auto'\n\n/** 缺省主题名 */\nexport const MT_DEFAULT_THEME = 'light'\n\n/** 缺省平台 */\nexport const MT_DEFAULT_PLATFORM = 'wechat'\n","/**\n * 内置主题字面量。\n *\n * ## 为什么这份数据必须存在于本包\n *\n * 小程序端 `rich-text` 内的 `style` **不参与宿主 CSS 变量继承**,\n * 所有主题值必须在序列化时解析为字面量,而 `@mteditor/theme-default`\n * 只产出 CSS、没有 JS 导出 —— 若要求宿主自备这份表,每个项目都要手抄\n * `tokens.css` 的 65 个键,抄错还**没有报错**(本仓库自己就踩过:\n * `mini.ts` 读的 `--mt-font-mono` 与 `tokens.css` 的 `--mt-font-family-mono`\n * 不一致,两个引用点恒走 fallback)。\n *\n * ## 与 tokens.css 的关系:允许独立,禁止无守卫地独立\n *\n * 本文件是 `packages/theme-default/src/tokens.css` 的**逐键镜像**\n * (`dark` 是 `light` 上的部分覆盖,与 CSS 的层叠语义一致)。\n * `scripts/check-theme-tokens.mjs` 断言两者键集合与取值完全一致 ——\n * 改任一侧而漏改另一侧会让 `pnpm verify` 失败。\n *\n * 取值风格与 CSS 一致:保留 `rgb(37 99 235 / 18%)` 这类现代空格语法,\n * 不自作主张转换为逗号语法(`@mteditor/document` 原样内联,不做解析)。\n */\n\nimport type { MtMiniTheme } from './types'\n\n/** 亮色主题:`tokens.css` 中 `:root, [data-mt-theme='light']` 块的完整镜像 */\nexport const MT_MINI_TOKENS_LIGHT: Readonly<Record<string, string>> = {\n '--mt-color-primary': '#2563eb',\n '--mt-color-primary-hover': '#1d4ed8',\n '--mt-color-primary-active': '#1e40af',\n '--mt-color-success': '#16a34a',\n '--mt-color-warning': '#d97706',\n '--mt-color-danger': '#dc2626',\n '--mt-color-link': '#2563eb',\n '--mt-color-text': '#1f2329',\n '--mt-color-text-secondary': '#646a73',\n '--mt-color-text-disabled': '#a6a9ad',\n '--mt-color-text-inverse': '#fff',\n '--mt-color-bg': '#fff',\n '--mt-color-bg-elevated': '#fff',\n '--mt-color-bg-muted': '#f5f7fa',\n '--mt-color-bg-hover': '#f2f3f5',\n '--mt-color-border': '#dee0e3',\n '--mt-color-border-strong': '#babdbf',\n '--mt-color-selection': 'rgb(37 99 235 / 18%)',\n '--mt-color-code-bg': '#f5f5f5',\n '--mt-color-code-text': '#c0392b',\n '--mt-color-quote-border': '#dee0e3',\n '--mt-color-mark-bg': '#fff3a3',\n '--mt-font-family':\n \"-apple-system, blinkmacsystemfont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif\",\n '--mt-font-family-mono': \"'SFMono-Regular', consolas, 'Liberation Mono', menlo, monospace\",\n '--mt-font-size': '15px',\n '--mt-font-size-sm': '13px',\n '--mt-font-size-lg': '17px',\n '--mt-line-height': '1.7',\n '--mt-letter-spacing': 'normal',\n '--mt-h1-font-size': '28px',\n '--mt-h2-font-size': '24px',\n '--mt-h3-font-size': '20px',\n '--mt-h4-font-size': '18px',\n '--mt-h5-font-size': '16px',\n '--mt-h6-font-size': '15px',\n '--mt-space-1': '4px',\n '--mt-space-2': '8px',\n '--mt-space-3': '12px',\n '--mt-space-4': '16px',\n '--mt-space-5': '24px',\n '--mt-space-6': '32px',\n '--mt-radius-sm': '3px',\n '--mt-radius-md': '6px',\n '--mt-radius-lg': '10px',\n '--mt-radius-full': '9999px',\n '--mt-shadow-sm': '0 1px 3px rgb(0 0 0 / 8%)',\n '--mt-shadow-md': '0 4px 12px rgb(0 0 0 / 10%)',\n '--mt-toolbar-height': '40px',\n '--mt-content-max-width': '860px',\n '--mt-content-padding': '20px',\n '--mt-control-size': '30px',\n '--mt-control-icon-size': '18px',\n '--mt-control-gap': '2px',\n '--mt-popup-padding': '4px',\n '--mt-popup-gap': '6px',\n '--mt-drawer-max-height': '60vh',\n '--mt-block-handle-width': '46px',\n '--mt-block-indicator-height': '2px',\n '--mt-outline-width': '200px',\n '--mt-outline-top': '0px',\n '--mt-z-toolbar': '100',\n '--mt-z-dropdown': '200',\n '--mt-z-popover': '300',\n '--mt-z-modal': '400',\n '--mt-z-toast': '500',\n '--mt-transition-fast': '120ms ease',\n '--mt-transition-base': '200ms ease',\n}\n\n/**\n * 暗色主题对亮色的**覆盖项**(与 `tokens.css` 的 `[data-mt-theme='dark']` 块一致)。\n *\n * 单独导出是为了让卡口脚本能分别比对「覆盖集」与「派生全集」——\n * 若只导出派生的全集,CSS 里删掉一个覆盖项(于是暗色回退到亮色值)\n * 在 TS 侧不可见。\n */\nexport const MT_MINI_TOKENS_DARK_OVERRIDES: Readonly<Record<string, string>> = {\n '--mt-color-primary': '#3b82f6',\n '--mt-color-primary-hover': '#60a5fa',\n '--mt-color-primary-active': '#2563eb',\n '--mt-color-success': '#22c55e',\n '--mt-color-warning': '#f59e0b',\n '--mt-color-danger': '#ef4444',\n '--mt-color-link': '#60a5fa',\n '--mt-color-text': '#e5e6eb',\n '--mt-color-text-secondary': '#a3a6ad',\n '--mt-color-text-disabled': '#6b6f76',\n '--mt-color-text-inverse': '#1f2329',\n '--mt-color-bg': '#1f2329',\n '--mt-color-bg-elevated': '#282c33',\n '--mt-color-bg-muted': '#282c33',\n '--mt-color-bg-hover': '#32363d',\n '--mt-color-border': '#3a3f47',\n '--mt-color-border-strong': '#4e545d',\n '--mt-color-selection': 'rgb(59 130 246 / 28%)',\n '--mt-color-code-bg': '#2b2f36',\n '--mt-color-code-text': '#f87171',\n '--mt-color-quote-border': '#3a3f47',\n '--mt-color-mark-bg': '#6b5a1a',\n '--mt-shadow-sm': '0 1px 3px rgb(0 0 0 / 40%)',\n '--mt-shadow-md': '0 4px 12px rgb(0 0 0 / 50%)',\n}\n\n/** 暗色主题全集(亮色为基底 + 覆盖项) */\nexport const MT_MINI_TOKENS_DARK: Readonly<Record<string, string>> = {\n ...MT_MINI_TOKENS_LIGHT,\n ...MT_MINI_TOKENS_DARK_OVERRIDES,\n}\n\n/**\n * 解析主题字面量表。\n *\n * 合并顺序:内置名(或自定义表)→ `themeTokens` 覆盖项。\n *\n * @param theme 内置主题名或自定义字面量表,缺省 `'light'`\n * @param override 覆盖项,键含 `--` 前缀;缺省不覆盖\n * @returns 可直接传给 `serializeDocumentToMini` 的 `themeTokens`\n *\n * @example\n * ```ts\n * resolveThemeTokens('dark') // 65 个键的暗色表\n * resolveThemeTokens(undefined, { '--mt-color-link': '#f00' })\n * // 亮色表,但链接色为 #f00\n * ```\n */\nexport const resolveThemeTokens = (\n theme?: MtMiniTheme,\n override?: Record<string, string>,\n): Record<string, string> => {\n const base =\n theme === undefined || theme === 'light'\n ? MT_MINI_TOKENS_LIGHT\n : theme === 'dark'\n ? MT_MINI_TOKENS_DARK\n : theme\n return override === undefined ? { ...base } : { ...base, ...override }\n}\n","/**\n * 渲染层主入口。\n *\n * 本函数的职责边界刻意很窄 —— 只做三件事,**不自己拼 nodes**:\n *\n * | 步骤 | 说明 |\n * |---|---|\n * | ① 平台准入 | 能力表未登记的平台直接抛错,不做容错 |\n * | ② 通道解析 | `'auto'` → 按 `maxNodes` 判定,并记录是否发生切换 |\n * | ③ 主题注入 | 内置 light / dark 字面量(小程序无 CSS 变量) |\n *\n * `nodes` 一律由 `@mteditor/document` 的 `serializeDocumentToMini` 产出\n * —— 这是 「序列化真相源唯一」在小程序端的同一条原则。\n */\n\nimport { serializeDocumentToMini } from '@mteditor/document'\nimport type { MtDocument } from '@mteditor/document'\nimport { resolveCapabilities } from './capabilities'\nimport { resolveChannel } from './channel'\nimport { MT_DEFAULT_MAX_NODES, MT_DEFAULT_MODE, MT_DEFAULT_PLATFORM } from './options'\nimport { resolveThemeTokens } from './theme'\nimport type { MtMiniRenderOptions, MtMiniRenderResult } from './types'\n\n/**\n * 把 `MtDocument` 渲染为小程序可直接 `setData` 的 payload。\n *\n * @param doc 文档(唯一真相源)\n * @param options 渲染选项\n * @returns 通道、nodes、降级报告、统计与自动切换记录\n * @throws {RangeError} `options.platform` 的能力表未经实测核实\n *\n * @example\n * ```ts\n * import { renderMiniDocument } from '@mteditor/renderer-mini'\n *\n * const { mode, nodes, report, autoSwitched } = renderMiniDocument(doc, {\n * theme: 'dark',\n * mode: 'auto',\n * })\n *\n * if (autoSwitched) console.warn(`节点数 ${autoSwitched.nodeCount} 超过阈值,已切到 rich-text`)\n * if (report.length > 0) console.warn('内容有降级', report)\n * ```\n */\nexport const renderMiniDocument = (\n doc: MtDocument,\n options: MtMiniRenderOptions = {},\n): MtMiniRenderResult => {\n const platform = options.platform ?? MT_DEFAULT_PLATFORM\n // 平台准入:未实测核实的平台在此抛错,而不是拿微信的表硬跑\n void resolveCapabilities(platform)\n\n const { mode, switched } = resolveChannel(\n doc,\n options.mode ?? MT_DEFAULT_MODE,\n options.maxNodes ?? MT_DEFAULT_MAX_NODES,\n )\n\n const { output, report, stats } = serializeDocumentToMini(doc, {\n platform,\n mode,\n themeTokens: resolveThemeTokens(options.theme, options.themeTokens),\n ...(options.preRendered === undefined ? {} : { preRendered: options.preRendered }),\n })\n\n return { platform, mode, nodes: output, report, stats, autoSwitched: switched }\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { MtDocument, MtMiniMode } from '@mteditor/document';
|
|
2
2
|
export { MtMiniMode, MtMiniNode, MtMiniPlatform } from '@mteditor/document';
|
|
3
|
-
import { M as MtMiniRenderOptions, a as MtMiniRenderResult, i as MtMiniChannelSwitch, h as MtMiniChannelOption } from './theme-
|
|
4
|
-
export { b as MT_MINI_CAPABILITIES, c as MT_MINI_TOKENS_DARK, l as MT_MINI_TOKENS_DARK_OVERRIDES, d as MT_MINI_TOKENS_LIGHT, g as MtMiniCapabilities, j as MtMiniTheme, r as resolveCapabilities, k as resolveThemeTokens } from './theme-
|
|
3
|
+
import { M as MtMiniRenderOptions, a as MtMiniRenderResult, i as MtMiniChannelSwitch, h as MtMiniChannelOption } from './theme-CXitJYrs.cjs';
|
|
4
|
+
export { b as MT_MINI_CAPABILITIES, c as MT_MINI_TOKENS_DARK, l as MT_MINI_TOKENS_DARK_OVERRIDES, d as MT_MINI_TOKENS_LIGHT, g as MtMiniCapabilities, j as MtMiniTheme, r as resolveCapabilities, k as resolveThemeTokens } from './theme-CXitJYrs.cjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* 渲染层主入口。
|
|
8
8
|
*
|
|
9
9
|
* 本函数的职责边界刻意很窄 —— 只做三件事,**不自己拼 nodes**:
|
|
10
10
|
*
|
|
@@ -15,7 +15,7 @@ export { b as MT_MINI_CAPABILITIES, c as MT_MINI_TOKENS_DARK, l as MT_MINI_TOKEN
|
|
|
15
15
|
* | ③ 主题注入 | 内置 light / dark 字面量(小程序无 CSS 变量) |
|
|
16
16
|
*
|
|
17
17
|
* `nodes` 一律由 `@mteditor/document` 的 `serializeDocumentToMini` 产出
|
|
18
|
-
* —— 这是
|
|
18
|
+
* —— 这是 「序列化真相源唯一」在小程序端的同一条原则。
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -24,7 +24,7 @@ export { b as MT_MINI_CAPABILITIES, c as MT_MINI_TOKENS_DARK, l as MT_MINI_TOKEN
|
|
|
24
24
|
* @param doc 文档(唯一真相源)
|
|
25
25
|
* @param options 渲染选项
|
|
26
26
|
* @returns 通道、nodes、降级报告、统计与自动切换记录
|
|
27
|
-
* @throws {RangeError} `options.platform`
|
|
27
|
+
* @throws {RangeError} `options.platform` 的能力表未经实测核实
|
|
28
28
|
*
|
|
29
29
|
* @example
|
|
30
30
|
* ```ts
|
|
@@ -42,7 +42,7 @@ export { b as MT_MINI_CAPABILITIES, c as MT_MINI_TOKENS_DARK, l as MT_MINI_TOKEN
|
|
|
42
42
|
declare const renderMiniDocument: (doc: MtDocument, options?: MtMiniRenderOptions) => MtMiniRenderResult;
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
45
|
+
* 通道解析(双通道)。
|
|
46
46
|
*
|
|
47
47
|
* `@mteditor/document` 只接受显式的 `'component' | 'richText'`;把 `'auto'`
|
|
48
48
|
* 解析成具体通道是**渲染层**的职责 —— 因为它需要知道 `maxNodes` 这类
|
|
@@ -59,7 +59,7 @@ interface MtChannelResolution {
|
|
|
59
59
|
/**
|
|
60
60
|
* 解析渲染通道。
|
|
61
61
|
*
|
|
62
|
-
*
|
|
62
|
+
* 规则:
|
|
63
63
|
* - 显式给出 `'component'` / `'richText'` 时**原样采用**,不做阈值判定
|
|
64
64
|
* —— 宿主显式指定就代表它知道自己在做什么;
|
|
65
65
|
* - `'auto'` 时按**文档节点数**判定:`nodeCount > maxNodes` 走 `richText`。
|
|
@@ -82,15 +82,15 @@ declare const resolveChannel: (doc: MtDocument, option: MtMiniChannelOption, max
|
|
|
82
82
|
/**
|
|
83
83
|
* 渲染层默认值。
|
|
84
84
|
*
|
|
85
|
-
*
|
|
85
|
+
* 单独成文件的理由:这些数值同时出现在**文档**与
|
|
86
86
|
* **测试**(阈值边界用例)里,散落在实现里会让「改默认值」变成一次考古。
|
|
87
87
|
*/
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
|
-
* `mode: 'auto'`
|
|
90
|
+
* `mode: 'auto'` 的降级阈值,单位是**文档节点数**。
|
|
91
91
|
*
|
|
92
92
|
* 判定依据不是「输出 nodes 数」:那需要先序列化一次才能判定,而判定的意义
|
|
93
|
-
*
|
|
93
|
+
* 正是避免一次昂贵序列化。
|
|
94
94
|
*/
|
|
95
95
|
declare const MT_DEFAULT_MAX_NODES = 3000;
|
|
96
96
|
/** 缺省通道选择 */
|