@one2x/medeo-rte 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/README.md +209 -2
  2. package/dist/chunks/types-I0yc5X7i.js +18 -0
  3. package/dist/chunks/types-I0yc5X7i.js.map +1 -0
  4. package/dist/formula.js +186 -0
  5. package/dist/formula.js.map +1 -0
  6. package/dist/index.js +5503 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/style.css +718 -0
  9. package/dist/types/commands/index.d.ts +4 -0
  10. package/dist/types/commands/index.d.ts.map +1 -0
  11. package/dist/types/commands/selfcheck.d.ts +2 -0
  12. package/dist/types/commands/selfcheck.d.ts.map +1 -0
  13. package/dist/types/commands/shortcuts.d.ts +48 -0
  14. package/dist/types/commands/shortcuts.d.ts.map +1 -0
  15. package/dist/types/commands/types.d.ts +69 -0
  16. package/dist/types/commands/types.d.ts.map +1 -0
  17. package/dist/types/convert/clipboard.d.ts +7 -0
  18. package/dist/types/convert/clipboard.d.ts.map +1 -0
  19. package/dist/types/convert/markdown.d.ts +30 -0
  20. package/dist/types/convert/markdown.d.ts.map +1 -0
  21. package/dist/types/convert/mdPaste.d.ts +8 -0
  22. package/dist/types/convert/mdPaste.d.ts.map +1 -0
  23. package/dist/types/editor.d.ts +469 -0
  24. package/dist/types/editor.d.ts.map +1 -0
  25. package/dist/types/edits/editResult.d.ts +62 -0
  26. package/dist/types/edits/editResult.d.ts.map +1 -0
  27. package/dist/types/edits/index.d.ts +12 -0
  28. package/dist/types/edits/index.d.ts.map +1 -0
  29. package/dist/types/edits/selfcheck.d.ts +2 -0
  30. package/dist/types/edits/selfcheck.d.ts.map +1 -0
  31. package/dist/types/edits/transaction.d.ts +35 -0
  32. package/dist/types/edits/transaction.d.ts.map +1 -0
  33. package/dist/types/edits/undoStack.d.ts +50 -0
  34. package/dist/types/edits/undoStack.d.ts.map +1 -0
  35. package/dist/types/embed/code.d.ts +9 -0
  36. package/dist/types/embed/code.d.ts.map +1 -0
  37. package/dist/types/embed/formula-katex.d.ts +4 -0
  38. package/dist/types/embed/formula-katex.d.ts.map +1 -0
  39. package/dist/types/embed/formula-mathlive.d.ts +6 -0
  40. package/dist/types/embed/formula-mathlive.d.ts.map +1 -0
  41. package/dist/types/embed/formula.d.ts +8 -0
  42. package/dist/types/embed/formula.d.ts.map +1 -0
  43. package/dist/types/embed/host.d.ts +70 -0
  44. package/dist/types/embed/host.d.ts.map +1 -0
  45. package/dist/types/embed/image.d.ts +3 -0
  46. package/dist/types/embed/image.d.ts.map +1 -0
  47. package/dist/types/embed/index.d.ts +20 -0
  48. package/dist/types/embed/index.d.ts.map +1 -0
  49. package/dist/types/embed/ref.d.ts +25 -0
  50. package/dist/types/embed/ref.d.ts.map +1 -0
  51. package/dist/types/embed/registry.d.ts +6 -0
  52. package/dist/types/embed/registry.d.ts.map +1 -0
  53. package/dist/types/embed/slot.d.ts +15 -0
  54. package/dist/types/embed/slot.d.ts.map +1 -0
  55. package/dist/types/embed/types.d.ts +53 -0
  56. package/dist/types/embed/types.d.ts.map +1 -0
  57. package/dist/types/embed/video.d.ts +3 -0
  58. package/dist/types/embed/video.d.ts.map +1 -0
  59. package/dist/types/formula.d.ts +15 -0
  60. package/dist/types/formula.d.ts.map +1 -0
  61. package/dist/types/index.d.ts +39 -0
  62. package/dist/types/index.d.ts.map +1 -0
  63. package/dist/types/input/ime.d.ts +27 -0
  64. package/dist/types/input/ime.d.ts.map +1 -0
  65. package/dist/types/input/keyboard.d.ts +21 -0
  66. package/dist/types/input/keyboard.d.ts.map +1 -0
  67. package/dist/types/layout/engine.d.ts +55 -0
  68. package/dist/types/layout/engine.d.ts.map +1 -0
  69. package/dist/types/layout/harness.d.ts +3 -0
  70. package/dist/types/layout/harness.d.ts.map +1 -0
  71. package/dist/types/layout/measure.d.ts +37 -0
  72. package/dist/types/layout/measure.d.ts.map +1 -0
  73. package/dist/types/layout/refMetrics.d.ts +5 -0
  74. package/dist/types/layout/refMetrics.d.ts.map +1 -0
  75. package/dist/types/layout/selfcheck.d.ts +2 -0
  76. package/dist/types/layout/selfcheck.d.ts.map +1 -0
  77. package/dist/types/layout/style.d.ts +4 -0
  78. package/dist/types/layout/style.d.ts.map +1 -0
  79. package/dist/types/layout/types.d.ts +133 -0
  80. package/dist/types/layout/types.d.ts.map +1 -0
  81. package/dist/types/layout/wrap.d.ts +65 -0
  82. package/dist/types/layout/wrap.d.ts.map +1 -0
  83. package/dist/types/model/blocks.d.ts +66 -0
  84. package/dist/types/model/blocks.d.ts.map +1 -0
  85. package/dist/types/model/document.d.ts +102 -0
  86. package/dist/types/model/document.d.ts.map +1 -0
  87. package/dist/types/model/fragment.d.ts +7 -0
  88. package/dist/types/model/fragment.d.ts.map +1 -0
  89. package/dist/types/model/markers.d.ts +14 -0
  90. package/dist/types/model/markers.d.ts.map +1 -0
  91. package/dist/types/model/types.d.ts +155 -0
  92. package/dist/types/model/types.d.ts.map +1 -0
  93. package/dist/types/model/virtualBlock.d.ts +44 -0
  94. package/dist/types/model/virtualBlock.d.ts.map +1 -0
  95. package/dist/types/mutations/apply.d.ts +14 -0
  96. package/dist/types/mutations/apply.d.ts.map +1 -0
  97. package/dist/types/mutations/index.d.ts +15 -0
  98. package/dist/types/mutations/index.d.ts.map +1 -0
  99. package/dist/types/mutations/invert.d.ts +21 -0
  100. package/dist/types/mutations/invert.d.ts.map +1 -0
  101. package/dist/types/mutations/ranges.d.ts +39 -0
  102. package/dist/types/mutations/ranges.d.ts.map +1 -0
  103. package/dist/types/mutations/registry.d.ts +27 -0
  104. package/dist/types/mutations/registry.d.ts.map +1 -0
  105. package/dist/types/mutations/selection.d.ts +12 -0
  106. package/dist/types/mutations/selection.d.ts.map +1 -0
  107. package/dist/types/mutations/selfcheck.d.ts +2 -0
  108. package/dist/types/mutations/selfcheck.d.ts.map +1 -0
  109. package/dist/types/mutations/transform.d.ts +33 -0
  110. package/dist/types/mutations/transform.d.ts.map +1 -0
  111. package/dist/types/mutations/types.d.ts +128 -0
  112. package/dist/types/mutations/types.d.ts.map +1 -0
  113. package/dist/types/operations/context.d.ts +47 -0
  114. package/dist/types/operations/context.d.ts.map +1 -0
  115. package/dist/types/operations/entity.d.ts +18 -0
  116. package/dist/types/operations/entity.d.ts.map +1 -0
  117. package/dist/types/operations/harness.d.ts +54 -0
  118. package/dist/types/operations/harness.d.ts.map +1 -0
  119. package/dist/types/operations/index.d.ts +20 -0
  120. package/dist/types/operations/index.d.ts.map +1 -0
  121. package/dist/types/operations/primitives.d.ts +35 -0
  122. package/dist/types/operations/primitives.d.ts.map +1 -0
  123. package/dist/types/operations/resolve.d.ts +31 -0
  124. package/dist/types/operations/resolve.d.ts.map +1 -0
  125. package/dist/types/operations/selfcheck.d.ts +2 -0
  126. package/dist/types/operations/selfcheck.d.ts.map +1 -0
  127. package/dist/types/operations/slice.d.ts +28 -0
  128. package/dist/types/operations/slice.d.ts.map +1 -0
  129. package/dist/types/operations/style.d.ts +20 -0
  130. package/dist/types/operations/style.d.ts.map +1 -0
  131. package/dist/types/operations/table.d.ts +14 -0
  132. package/dist/types/operations/table.d.ts.map +1 -0
  133. package/dist/types/operations/text.d.ts +20 -0
  134. package/dist/types/operations/text.d.ts.map +1 -0
  135. package/dist/types/operations/virtualBlock.d.ts +44 -0
  136. package/dist/types/operations/virtualBlock.d.ts.map +1 -0
  137. package/dist/types/paint/canvasPainter.d.ts +37 -0
  138. package/dist/types/paint/canvasPainter.d.ts.map +1 -0
  139. package/dist/types/paint/decorations.d.ts +19 -0
  140. package/dist/types/paint/decorations.d.ts.map +1 -0
  141. package/dist/types/paint/htmlPainter.d.ts +19 -0
  142. package/dist/types/paint/htmlPainter.d.ts.map +1 -0
  143. package/dist/types/paint/types.d.ts +36 -0
  144. package/dist/types/paint/types.d.ts.map +1 -0
  145. package/package.json +64 -4
package/README.md CHANGED
@@ -1,3 +1,210 @@
1
- # Temporary Holding Version
1
+ # medeo-rte
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 自绘的文档渲染引擎。不使用 `contenteditable` —— 文档是一条字符流,排版自己算出每个字的坐标,绘制后端可替换。
4
+
5
+ 同一份排版结果可以画到 DOM,也可以一键切到 Canvas,光标和选区不变。
6
+
7
+ 在线 demo:<https://editor-html-demo.pages.dev/>
8
+
9
+ ## 仓库结构
10
+
11
+ ```
12
+ src/ SDK。发布出去的就是这部分
13
+ demo/ 演示应用。同时是 SDK 的用法样例,不参与发布
14
+ ```
15
+
16
+ SDK 只负责编辑区本身。工具栏、状态栏、小地图、基线网格这些**宿主外壳**全在 `demo/`,
17
+ 产品接入时应自己实现——照着 `demo/main.ts` 抄即可。模板混排样例在 `demo/vblocks.ts`。
18
+
19
+ ## 在其它项目里使用
20
+
21
+ ```bash
22
+ npm i @one2x/medeo-rte
23
+ ```
24
+
25
+ ```ts
26
+ import { Editor } from '@one2x/medeo-rte';
27
+ import '@one2x/medeo-rte/style.css';
28
+
29
+ const editor = new Editor(document.getElementById('app')!);
30
+
31
+ // 下命令
32
+ editor.commands.toggleBold();
33
+
34
+ // 同步自己的工具栏
35
+ editor.on('statechange', () => renderToolbar(editor.getState()));
36
+
37
+ // 存取内容(Slice 可 JSON 序列化)
38
+ const json = editor.getContent();
39
+ editor.setContent(json);
40
+ ```
41
+
42
+ **公式需要单独引入**,因为它依赖 KaTeX + MathLive,是包体积的大头:
43
+
44
+ ```ts
45
+ import { builtinEmbedPlugins, Editor } from '@one2x/medeo-rte';
46
+ import { formulaPlugin } from '@one2x/medeo-rte/formula';
47
+
48
+ new Editor(el, { plugins: [...builtinEmbedPlugins, formulaPlugin] });
49
+ ```
50
+
51
+ 不引入就完全不会打进产物(`katex` / `mathlive` 是可选 peer 依赖)。
52
+
53
+ ## 主要能力
54
+
55
+ 文字与段落样式、列表、表格、链接、图文绕排、Markdown 边打边转、撤销重做、中文 IME。
56
+
57
+ 嵌入对象走同一套插件接口:图片、视频、代码块、公式、行内胶囊插槽、同步块引用、**host**(宿主自绘)。其中:
58
+
59
+ - **同步块** —— 任意选区提成一份内容,多处平等复用,改一处全变
60
+ - **host 胶囊** —— `*` 占位,内部 DOM 由宿主渲染(下拉、开关、上传、`@` 芯片)。整颗换行
61
+ - **虚拟块** —— 盖在字符流上的假块(region 皮 + 文本槽)。槽里的字跟外层句子一起折行,不是实体
62
+
63
+ 模板句里「可填写的那截灰字」用虚拟块文本槽,不要用胶囊 `slotPlugin`。胶囊插槽是另一颗盒子,点进去才填,不能按字切开。
64
+
65
+ ## 模板混排
66
+
67
+ 插入一份模板(文案 + 文本槽 + 胶囊)走 `insertSlice`,不要再开子文档。
68
+
69
+ ```ts
70
+ editor.insertSlice({
71
+ text: 'Write a prompt for Input a theme.\n',
72
+ styles: [],
73
+ entities: [],
74
+ virtualBlocks: [
75
+ {
76
+ id: 'region',
77
+ parentId: null,
78
+ kind: 'region',
79
+ start: 0,
80
+ end: 33,
81
+ chrome: { background: 'rgba(43,108,255,0.08)', radius: 8 }
82
+ },
83
+ {
84
+ id: 'slot',
85
+ parentId: 'region',
86
+ kind: 'slot',
87
+ start: 19,
88
+ end: 32,
89
+ placeholder: 'Input a theme',
90
+ empty: true,
91
+ chrome: { background: 'rgba(16,185,129,0.18)', placeholderColor: '#98a2b3' }
92
+ }
93
+ ]
94
+ });
95
+ ```
96
+
97
+ 槽上的 Sample / AI 菜单是宿主浮层:看 `getState().vblockStack` 是否进了 editing,用 `getLayout()` 里该槽的 `vblocks` 矩形定位,写入走打字或再 `insertSlice` 一段纯文本。SDK 不认识业务菜单。
98
+
99
+ 自定义芯片:
100
+
101
+ ```ts
102
+ const editor = new Editor(el, {
103
+ hostEmbed: {
104
+ mount(container, ctx) {
105
+ // 按 ctx.entity.hostType 画自己的组件
106
+ return { update(next) {}, destroy() {} };
107
+ }
108
+ }
109
+ });
110
+ editor.commands.insertHostEmbed('Upscale', { label: '@Upscale' }, { width: 88, height: 24 });
111
+ ```
112
+
113
+ 口径和交互见 [virtual-blocks.md](./docs/virtual-blocks.md)。
114
+
115
+ ### API 一览
116
+
117
+ | 成员 | 说明 |
118
+ | --- | --- |
119
+ | `new Editor(el, options?)` | `doc` / `paint` / `plugins` / `hostEmbed` / `width` / `padding` / `placeholder` / `textDefaults` / `shortcuts` / `autofocus` / `chrome` |
120
+ | `commands` | 公开编辑命令(加粗、插表、插图、`insertHostEmbed`、同步块等),宿主工具栏调这些 |
121
+ | `on(event, fn)` | `change` / `selectionchange` / `statechange` / `layoutchange`,返回退订函数 |
122
+ | `getState()` | 当前状态快照(含 `vblockStack`),用于同步 UI |
123
+ | `getContent()` / `setContent()` | 整篇内容读写,`Slice` 结构(含 `virtualBlocks`) |
124
+ | `insertSlice(slice, at?)` | 插入切片;模板混排走这条 |
125
+ | `insertVirtualBlock` / `updateVirtualBlock` / `removeVirtualBlock` | 套皮、改 chrome、拆皮 |
126
+ | `insertHostEmbed(hostType, data?, size?, at?)` | 插入宿主自绘胶囊 |
127
+ | `getSelection()` / `setSelection()` | 选区读写 |
128
+ | `getLayout()` | 排版几何(只读),做标尺、小地图、槽上浮层用 |
129
+ | `getDocument()` | 文档模型,做批量操作或自定义命令用 |
130
+ | `setPaintMode('html'\|'canvas')` | 切换绘制后端 |
131
+ | `setChrome` / `setTextDefaults` | 光标选区外观;默认字号/颜色(主题切换) |
132
+ | `root` / `scroller` / `pageElement` | 根节点 / 滚动容器 / 内容定位上下文 |
133
+ | `focus()` / `destroy()` | |
134
+ | `setPlaceholder(text)` | 空态占位;组合输入一开始即隐藏 |
135
+ | `composing()` / `setDisabled()` | 组合态查询;禁用输入与快捷键 |
136
+ | `INPUT_SHORTCUTS` / `inputShortcuts()` | 输入框快捷键;默认 Enter 换行,Cmd+Enter 留给宿主 |
137
+
138
+ 脚本化改文档也可 `import { operations, runOperation } from '@one2x/medeo-rte'`,不要直接改 `DocumentModel` 的内部表。
139
+
140
+ ## 设计文档
141
+
142
+ `docs/` 下是分层架构与技术方案:
143
+
144
+ | 文档 | 内容 |
145
+ | --- | --- |
146
+ | [architecture.md](./docs/architecture.md) | 分层结构、五条不变式、样式模型 |
147
+ | [mutations.md](./docs/mutations.md) | 原子操作的类型、坐标语义、三套 handler 契约 |
148
+ | [operations.md](./docs/operations.md) | 编排层规范与 Operation 清单 |
149
+ | [edits.md](./docs/edits.md) | 事务边界、撤销栈、片段坐标空间、协同预留 |
150
+ | [rendering.md](./docs/rendering.md) | 块级增量排版、脏区带、绘制后端 |
151
+ | [virtual-blocks.md](./docs/virtual-blocks.md) | 虚拟块:模板混排、文本槽、按层选区 |
152
+
153
+ 改动模型前先读 architecture.md 的不变式那一节。
154
+
155
+ ## 本地开发
156
+
157
+ ```bash
158
+ npm install
159
+ npm run dev # http://localhost:5273/ 跑 demo
160
+ ```
161
+
162
+ | 命令 | 作用 |
163
+ | ------------------- | ----------------------------- |
164
+ | `npm run dev` | 起 demo 开发服务器 |
165
+ | `npm run build` | 构建 demo 站点 → `dist-demo/` |
166
+ | `npm run build:lib` | 构建 SDK → `dist/`(含 `.d.ts`) |
167
+ | `npm run selfcheck` | 分层自检:编辑语义、变换算术、撤销栈、快捷键表、增量排版 |
168
+
169
+ ## 发布到 npm
170
+
171
+ 包名 `@one2x/medeo-rte`(npm 组织 **one2x**)。CI:`.github/workflows/publish.yml`。
172
+ GitHub 仓库在 **one2x-ai/medeo-rte** —— 和 npm scope 不是同一个名字。
173
+
174
+ ### 日常发版(main 打 tag)
175
+
176
+ 1. 合进 **main**,并把 `package.json` 的 `version` 改成目标版本(如 `0.1.0`)
177
+ 2. 在 **main** tip 打同名 tag 并推送:
178
+
179
+ ```bash
180
+ git checkout main && git pull
181
+ git tag v0.1.0
182
+ git push origin v0.1.0
183
+ ```
184
+
185
+ 3. Actions 里应出现 **Publish**;tag 必须指向 main 上的提交,且 `v*` 与 `package.json` version 一致,否则会失败
186
+
187
+ 也可在 Actions → Publish → **Run workflow**(必须选 **main**;选 `dev` 会被拒绝)。
188
+
189
+ ### 第一次上架(包还不存在)
190
+
191
+ Trusted Publishing 配不上尚未存在的包,先用 token:
192
+
193
+ 1. [npm Access Tokens](https://www.npmjs.com/settings/~/tokens) → **Generate New Token** → **Granular Access Token**
194
+ - Permissions:**Read and write**
195
+ - Packages and scopes:选组织 **one2x** / 勾选 `@one2x`
196
+ - **Bypass two-factor authentication**:打开(给 CI)
197
+ 2. GitHub 仓库 → Settings → Secrets and variables → Actions → New secret
198
+ 名称:`NPM_TOKEN`,值:刚生成的 token
199
+ 3. 按上面「日常发版」打 `v0.1.0`(或对 main 手动 Run workflow)
200
+ 4. 确认 [npm 包页](https://www.npmjs.com/package/@one2x/medeo-rte) 出现 `0.1.0`
201
+
202
+ ### 上架后改走 OIDC(可选,推荐)
203
+
204
+ 1. 包 Settings → **Trusted Publisher** → GitHub Actions
205
+ - Organization:`one2x-ai`
206
+ - Repository:`medeo-rte`
207
+ - Workflow:`publish.yml`
208
+ - Environment:留空
209
+ - Allowed:勾选 `npm publish`
210
+ 2. 删掉仓库 Secret `NPM_TOKEN`(publish 步骤带着 token 时不会走 OIDC)
@@ -0,0 +1,18 @@
1
+ const s = "mini-embed-change", n = "mini-embed-commit", a = "mini-embed-exit-edit", E = "mini-embed-measure";
2
+ function d(t, e) {
3
+ t.style.left = `${e.x}px`, t.style.top = `${e.y}px`, e.entity.kind === "host" ? (t.style.width = "auto", t.style.height = "auto") : (t.style.width = `${e.w}px`, t.classList.contains("is-editing") || (t.style.height = `${e.h}px`)), t.dataset.index = String(e.index), t.dataset.entity = e.entity.id;
4
+ }
5
+ function m(t, e, i = !1) {
6
+ t.dispatchEvent(
7
+ new CustomEvent(i ? n : s, { bubbles: !0, detail: e })
8
+ );
9
+ }
10
+ export {
11
+ a as E,
12
+ n as a,
13
+ s as b,
14
+ E as c,
15
+ m as e,
16
+ d as p
17
+ };
18
+ //# sourceMappingURL=types-I0yc5X7i.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-I0yc5X7i.js","sources":["../../src/embed/types.ts"],"sourcesContent":["import { DocumentModel } from '../model/document';\nimport { EmbedEntity, EmbedKind } from '../model/types';\nimport type { DocLayout } from '../layout/types';\n\nexport interface EmbedBox {\n index: number;\n x: number;\n y: number;\n w: number;\n h: number;\n entity: EmbedEntity;\n inner?: DocLayout;\n}\n\nexport const EMBED_CHANGE = 'mini-embed-change';\nexport const EMBED_COMMIT = 'mini-embed-commit';\nexport const EMBED_EXIT_EDIT = 'mini-embed-exit-edit';\n/**\n * 宿主渲染块回报自身布局尺寸。这是渲染副产物、不是用户意图,编辑器只据此重排,\n * 既不进撤销栈、也不开启编辑事务(区别于表示用户改动的 CHANGE / COMMIT)。\n */\nexport const EMBED_MEASURE = 'mini-embed-measure';\n\nexport interface EmbedMeasureDetail {\n id: string;\n width: number;\n height: number;\n}\n\nexport interface EmbedExitDetail {\n id: string;\n side: 'before' | 'after';\n}\n\nexport interface EmbedChangeDetail {\n id: string;\n patch: Partial<EmbedEntity>;\n before?: Partial<EmbedEntity>;\n}\n\nexport interface EmbedPlugin {\n kind: EmbedKind;\n keepAspectRatio: boolean;\n interactive: boolean;\n /** Canvas 上是否叠 DOM(视频/代码/公式);图片只画到 canvas */\n overlayOnCanvas: boolean;\n measure(entity: EmbedEntity, contentWidth: number, host?: DocumentModel): { width: number; height: number };\n create(box: EmbedBox): HTMLElement;\n update(el: HTMLElement, box: EmbedBox): void;\n /** 节点从文档移除前调用,供插件清理副作用(观察器、外部组件等)。可选。 */\n destroy?(el: HTMLElement): void;\n paintCanvasBackdrop(ctx: CanvasRenderingContext2D, box: EmbedBox, imageOf: (src: string) => HTMLImageElement): void;\n}\n\nexport function placeEmbed(el: HTMLElement, box: EmbedBox) {\n el.style.left = `${box.x}px`;\n el.style.top = `${box.y}px`;\n // host 外层若按尚未测到的 0×0 锁宽高,内层会被挤成竖排文字,ResizeObserver 再把竖排尺寸写回,恶性循环。\n if (box.entity.kind === 'host') {\n el.style.width = 'auto';\n el.style.height = 'auto';\n } else {\n el.style.width = `${box.w}px`;\n if (!el.classList.contains('is-editing')) el.style.height = `${box.h}px`;\n }\n el.dataset.index = String(box.index);\n el.dataset.entity = box.entity.id;\n}\n\nexport function emitEmbedChange(el: HTMLElement, detail: EmbedChangeDetail, commit = false) {\n el.dispatchEvent(\n new CustomEvent(commit ? EMBED_COMMIT : EMBED_CHANGE, { bubbles: true, detail })\n );\n}\n"],"names":["EMBED_CHANGE","EMBED_COMMIT","EMBED_EXIT_EDIT","EMBED_MEASURE","placeEmbed","el","box","emitEmbedChange","detail","commit"],"mappings":"AAcO,MAAMA,IAAe,qBACfC,IAAe,qBACfC,IAAkB,wBAKlBC,IAAgB;AAiCtB,SAASC,EAAWC,GAAiBC,GAAe;AACzD,EAAAD,EAAG,MAAM,OAAO,GAAGC,EAAI,CAAC,MACxBD,EAAG,MAAM,MAAM,GAAGC,EAAI,CAAC,MAEnBA,EAAI,OAAO,SAAS,UACtBD,EAAG,MAAM,QAAQ,QACjBA,EAAG,MAAM,SAAS,WAElBA,EAAG,MAAM,QAAQ,GAAGC,EAAI,CAAC,MACpBD,EAAG,UAAU,SAAS,YAAY,MAAGA,EAAG,MAAM,SAAS,GAAGC,EAAI,CAAC,QAEtED,EAAG,QAAQ,QAAQ,OAAOC,EAAI,KAAK,GACnCD,EAAG,QAAQ,SAASC,EAAI,OAAO;AACjC;AAEO,SAASC,EAAgBF,GAAiBG,GAA2BC,IAAS,IAAO;AAC1F,EAAAJ,EAAG;AAAA,IACD,IAAI,YAAYI,IAASR,IAAeD,GAAc,EAAE,SAAS,IAAM,QAAAQ,EAAA,CAAQ;AAAA,EAAA;AAEnF;"}
@@ -0,0 +1,186 @@
1
+ import M from "katex";
2
+ import "katex/dist/katex.min.css";
3
+ import { MathfieldElement as E } from "mathlive";
4
+ import "mathlive/fonts.css";
5
+ import { e as w, E as L } from "./chunks/types-I0yc5X7i.js";
6
+ const C = {
7
+ "\\wideparen": "\\overgroup{#1}",
8
+ "\\overarc": "\\overgroup{#1}",
9
+ "\\overparen": "\\overgroup{#1}",
10
+ "\\exponentialE": "\\mathrm{e}",
11
+ "\\imaginaryI": "\\mathrm{i}",
12
+ "\\imaginaryJ": "\\mathrm{j}",
13
+ "\\differentialD": "\\mathrm{d}",
14
+ "\\capitalDifferentialD": "\\mathrm{D}"
15
+ }, D = [
16
+ { name: "frac", build: (e, t) => `\\frac{${e}}{${t}}` },
17
+ { name: "sqrt", build: (e, t) => `\\sqrt[${t}]{${e}}` },
18
+ { name: "int", build: (e, t) => `\\int_{${t}}^{${e}}` },
19
+ { name: "overbrace", build: (e, t) => `\\overbrace{${e}}^{${t}}` }
20
+ ];
21
+ function $(e) {
22
+ let t = e;
23
+ for (const r of D) t = k(t, r);
24
+ return t = g(t, "index", (r) => `_{${r}}`), t.replace(
25
+ /\\(Uparrow|Downarrow|Updownarrow|uparrow|downarrow|updownarrow|Rightarrow|Leftarrow|Leftrightarrow)(?=[A-Za-z])/g,
26
+ "\\$1 "
27
+ );
28
+ }
29
+ function k(e, t) {
30
+ return g(e, t.name, (r) => {
31
+ const i = A(r);
32
+ return i === void 0 ? `\\${t.name}{${r}}` : t.build(i[0], i[1]);
33
+ });
34
+ }
35
+ function g(e, t, r) {
36
+ const i = `\\${t}{`;
37
+ let n = "", o = 0;
38
+ for (; o < e.length; ) {
39
+ const s = e.indexOf(i, o);
40
+ if (s < 0) return n + e.slice(o);
41
+ const f = s + i.length - 1, l = b(e, f);
42
+ if (l < 0) return n + e.slice(o);
43
+ n += e.slice(o, s) + r(e.slice(f + 1, l)), o = l + 1;
44
+ }
45
+ return n;
46
+ }
47
+ function b(e, t) {
48
+ let r = 0;
49
+ for (let i = t; i < e.length; i += 1)
50
+ if (e[i] === "{" && !c(e, i) && (r += 1), e[i] === "}" && !c(e, i) && (r -= 1, r === 0))
51
+ return i;
52
+ return -1;
53
+ }
54
+ function A(e) {
55
+ let t = 0, r = -1;
56
+ for (let i = 0; i < e.length; i += 1)
57
+ if (e[i] === "{" && !c(e, i)) t += 1;
58
+ else if (e[i] === "}" && !c(e, i)) t -= 1;
59
+ else if (e[i] === "|" && t === 0 && !c(e, i)) {
60
+ if (r >= 0) return;
61
+ r = i;
62
+ }
63
+ return r < 0 ? void 0 : [e.slice(0, r), e.slice(r + 1)];
64
+ }
65
+ function c(e, t) {
66
+ let r = 0;
67
+ for (let i = t - 1; i >= 0 && e[i] === "\\"; i -= 1) r += 1;
68
+ return r % 2 === 1;
69
+ }
70
+ function p(e, t, r) {
71
+ e.replaceChildren();
72
+ const i = t.trim() || "\\square";
73
+ try {
74
+ M.render($(i), e, {
75
+ throwOnError: !1,
76
+ displayMode: r,
77
+ output: "html",
78
+ macros: C
79
+ });
80
+ } catch {
81
+ e.textContent = i;
82
+ }
83
+ }
84
+ E.fontsDirectory = null;
85
+ function P() {
86
+ const e = new E();
87
+ return e.className = "mini-formula-math", e.mathVirtualKeyboardPolicy = "auto", e;
88
+ }
89
+ function y(e) {
90
+ return e.getValue("latex");
91
+ }
92
+ function N(e, t) {
93
+ const r = Math.max(48, e.width || Math.min(400, t));
94
+ if (typeof document > "u")
95
+ return { width: r, height: e.displayMode === !1 ? 32 : 56 };
96
+ const i = document.createElement("div");
97
+ i.style.cssText = "position:absolute;left:-9999px;top:0;visibility:hidden;", document.body.appendChild(i), p(i, e.latex ?? "", e.displayMode !== !1);
98
+ const n = i.getBoundingClientRect();
99
+ return i.remove(), {
100
+ width: Math.min(t, Math.max(48, Math.ceil(n.width) + 24)),
101
+ height: Math.max(36, Math.ceil(n.height) + 16)
102
+ };
103
+ }
104
+ function m(e, t) {
105
+ return e.dataset.entity || t;
106
+ }
107
+ const K = {
108
+ kind: "formula",
109
+ keepAspectRatio: !1,
110
+ interactive: !0,
111
+ overlayOnCanvas: !0,
112
+ measure: N,
113
+ create(e) {
114
+ const t = document.createElement("div");
115
+ t.className = "mini-embed mini-formula mini-embed-interactive";
116
+ const r = document.createElement("div");
117
+ r.className = "mini-formula-view";
118
+ const i = document.createElement("div");
119
+ i.className = "mini-formula-host", i.hidden = !0, p(r, e.entity.latex ?? "", e.entity.displayMode !== !1), t.append(r, i);
120
+ let n = null, o = !1, s = e.entity.latex ?? "";
121
+ const f = () => n || (n = P(), i.appendChild(n), n.addEventListener("mount", () => {
122
+ o = !0, n == null || n.setValue(s, { silenceNotifications: !0 }), n == null || n.focus();
123
+ }, { once: !0 }), n.addEventListener("input", () => {
124
+ n && w(t, { id: m(t, e.entity.id), patch: { latex: y(n) } });
125
+ }), n.addEventListener("focusout", () => {
126
+ window.setTimeout(() => {
127
+ i.contains(document.activeElement) || u();
128
+ }, 0);
129
+ }), n.addEventListener(
130
+ "keydown",
131
+ (a) => {
132
+ const d = n;
133
+ if (d) {
134
+ if (a.key === "ArrowLeft" && d.selectionIsCollapsed && d.position === 0) {
135
+ a.preventDefault(), a.stopPropagation(), v("before");
136
+ return;
137
+ }
138
+ if (a.key === "ArrowRight" && d.selectionIsCollapsed && d.position === d.lastOffset) {
139
+ a.preventDefault(), a.stopPropagation(), v("after");
140
+ return;
141
+ }
142
+ a.key === "Enter" && !a.shiftKey && (a.preventDefault(), u()), a.key === "Escape" && (a.preventDefault(), x());
143
+ }
144
+ },
145
+ !0
146
+ ), n), l = () => {
147
+ s = t.dataset.latex ?? s, t.classList.add("is-editing"), r.hidden = !0, i.hidden = !1;
148
+ const a = f();
149
+ o && (a.setValue(s, { silenceNotifications: !0 }), a.focus());
150
+ }, h = () => {
151
+ t.classList.remove("is-editing"), i.hidden = !0, r.hidden = !1;
152
+ }, u = () => {
153
+ if (!t.classList.contains("is-editing")) return;
154
+ const a = n && o ? y(n) : s;
155
+ s = a, t.dataset.latex = a, h(), w(t, { id: m(t, e.entity.id), patch: { latex: a } }, !0);
156
+ }, x = () => {
157
+ n && o && n.setValue(s, { silenceNotifications: !0 }), h();
158
+ }, v = (a) => {
159
+ u(), t.dispatchEvent(
160
+ new CustomEvent(L, {
161
+ bubbles: !0,
162
+ detail: { id: m(t, e.entity.id), side: a }
163
+ })
164
+ );
165
+ };
166
+ return t.addEventListener("dblclick", (a) => {
167
+ a.preventDefault(), l();
168
+ }), t.addEventListener("mini-formula-edit", () => l()), (e.entity.latex ?? "").trim() || l(), t;
169
+ },
170
+ update(e, t) {
171
+ if (e.dataset.latex = t.entity.latex ?? "", e.classList.contains("is-editing")) return;
172
+ const r = e.querySelector(".mini-formula-view");
173
+ r && p(r, t.entity.latex ?? "", t.entity.displayMode !== !1);
174
+ },
175
+ paintCanvasBackdrop(e, t) {
176
+ e.fillStyle = "#f7f8fa", e.fillRect(t.x, t.y, t.w, t.h);
177
+ }
178
+ };
179
+ export {
180
+ P as createFormulaMathfield,
181
+ K as formulaPlugin,
182
+ y as mathfieldLatex,
183
+ N as measureFormula,
184
+ p as renderKatex
185
+ };
186
+ //# sourceMappingURL=formula.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formula.js","sources":["../src/embed/formula-katex.ts","../src/embed/formula-mathlive.ts","../src/embed/formula.ts"],"sourcesContent":["import katex from 'katex';\nimport 'katex/dist/katex.min.css';\n\n/** MathLive 输出转成 KaTeX 能吃的宏。 */\nconst KATEX_COMPAT_MACROS = {\n '\\\\wideparen': '\\\\overgroup{#1}',\n '\\\\overarc': '\\\\overgroup{#1}',\n '\\\\overparen': '\\\\overgroup{#1}',\n '\\\\exponentialE': '\\\\mathrm{e}',\n '\\\\imaginaryI': '\\\\mathrm{i}',\n '\\\\imaginaryJ': '\\\\mathrm{j}',\n '\\\\differentialD': '\\\\mathrm{d}',\n '\\\\capitalDifferentialD': '\\\\mathrm{D}'\n} as const;\n\ntype PipeCommand = { name: string; build: (left: string, right: string) => string };\n\nconst PIPE_COMMANDS: PipeCommand[] = [\n { name: 'frac', build: (left, right) => `\\\\frac{${left}}{${right}}` },\n { name: 'sqrt', build: (left, right) => `\\\\sqrt[${right}]{${left}}` },\n { name: 'int', build: (left, right) => `\\\\int_{${right}}^{${left}}` },\n { name: 'overbrace', build: (left, right) => `\\\\overbrace{${left}}^{${right}}` }\n];\n\nexport function normalizeMathLiveLatexForKatex(latex: string): string {\n let normalized = latex;\n for (const command of PIPE_COMMANDS) normalized = rewritePipeCommand(normalized, command);\n normalized = rewriteSingleArgumentCommand(normalized, 'index', (value) => `_{${value}}`);\n return normalized.replace(\n /\\\\(Uparrow|Downarrow|Updownarrow|uparrow|downarrow|updownarrow|Rightarrow|Leftarrow|Leftrightarrow)(?=[A-Za-z])/g,\n '\\\\$1 '\n );\n}\n\nfunction rewritePipeCommand(input: string, command: PipeCommand): string {\n return rewriteSingleArgumentCommand(input, command.name, (argument) => {\n const parts = splitTopLevelPipe(argument);\n return parts === undefined ? `\\\\${command.name}{${argument}}` : command.build(parts[0], parts[1]);\n });\n}\n\nfunction rewriteSingleArgumentCommand(input: string, command: string, build: (argument: string) => string): string {\n const marker = `\\\\${command}{`;\n let result = '';\n let cursor = 0;\n while (cursor < input.length) {\n const start = input.indexOf(marker, cursor);\n if (start < 0) return result + input.slice(cursor);\n const open = start + marker.length - 1;\n const close = matchingBrace(input, open);\n if (close < 0) return result + input.slice(cursor);\n result += input.slice(cursor, start) + build(input.slice(open + 1, close));\n cursor = close + 1;\n }\n return result;\n}\n\nfunction matchingBrace(input: string, open: number): number {\n let depth = 0;\n for (let index = open; index < input.length; index += 1) {\n if (input[index] === '{' && !isEscaped(input, index)) depth += 1;\n if (input[index] === '}' && !isEscaped(input, index)) {\n depth -= 1;\n if (depth === 0) return index;\n }\n }\n return -1;\n}\n\nfunction splitTopLevelPipe(value: string): readonly [string, string] | undefined {\n let depth = 0;\n let split = -1;\n for (let index = 0; index < value.length; index += 1) {\n if (value[index] === '{' && !isEscaped(value, index)) depth += 1;\n else if (value[index] === '}' && !isEscaped(value, index)) depth -= 1;\n else if (value[index] === '|' && depth === 0 && !isEscaped(value, index)) {\n if (split >= 0) return undefined;\n split = index;\n }\n }\n return split < 0 ? undefined : [value.slice(0, split), value.slice(split + 1)];\n}\n\nfunction isEscaped(value: string, index: number): boolean {\n let slashes = 0;\n for (let cursor = index - 1; cursor >= 0 && value[cursor] === '\\\\'; cursor -= 1) slashes += 1;\n return slashes % 2 === 1;\n}\n\nexport function renderKatex(host: HTMLElement, latex: string, displayMode: boolean) {\n host.replaceChildren();\n const src = latex.trim() || '\\\\square';\n try {\n katex.render(normalizeMathLiveLatexForKatex(src), host, {\n throwOnError: false,\n displayMode,\n output: 'html',\n macros: KATEX_COMPAT_MACROS\n });\n } catch {\n host.textContent = src;\n }\n}\n","import { MathfieldElement } from 'mathlive';\nimport 'mathlive/fonts.css';\n\n/** 不走 CDN 字体目录,用打包进来的 fonts.css。 */\nMathfieldElement.fontsDirectory = null;\n\nexport type FormulaMathfield = MathfieldElement;\n\nexport function createFormulaMathfield(): FormulaMathfield {\n const field = new MathfieldElement();\n field.className = 'mini-formula-math';\n field.mathVirtualKeyboardPolicy = 'auto';\n return field;\n}\n\nexport function mathfieldLatex(field: FormulaMathfield): string {\n return field.getValue('latex');\n}\n","import { EmbedEntity } from '../model/types';\nimport { renderKatex } from './formula-katex';\nimport { createFormulaMathfield, FormulaMathfield, mathfieldLatex } from './formula-mathlive';\nimport { EMBED_EXIT_EDIT, EmbedBox, EmbedPlugin, emitEmbedChange } from './types';\n\nexport function measureFormula(entity: EmbedEntity, contentWidth: number): { width: number; height: number } {\n const width = Math.max(48, entity.width || Math.min(400, contentWidth));\n if (typeof document === 'undefined') {\n return { width, height: entity.displayMode === false ? 32 : 56 };\n }\n const probe = document.createElement('div');\n probe.style.cssText = 'position:absolute;left:-9999px;top:0;visibility:hidden;';\n document.body.appendChild(probe);\n renderKatex(probe, entity.latex ?? '', entity.displayMode !== false);\n const rect = probe.getBoundingClientRect();\n probe.remove();\n return {\n width: Math.min(contentWidth, Math.max(48, Math.ceil(rect.width) + 24)),\n height: Math.max(36, Math.ceil(rect.height) + 16)\n };\n}\n\nfunction formulaId(root: HTMLElement, fallback: string): string {\n return root.dataset.entity || fallback;\n}\n\nexport const formulaPlugin: EmbedPlugin = {\n kind: 'formula',\n keepAspectRatio: false,\n interactive: true,\n overlayOnCanvas: true,\n measure: measureFormula,\n create(box) {\n const root = document.createElement('div');\n root.className = 'mini-embed mini-formula mini-embed-interactive';\n const view = document.createElement('div');\n view.className = 'mini-formula-view';\n const host = document.createElement('div');\n host.className = 'mini-formula-host';\n host.hidden = true;\n renderKatex(view, box.entity.latex ?? '', box.entity.displayMode !== false);\n root.append(view, host);\n\n let field: FormulaMathfield | null = null;\n let mounted = false;\n let baseline = box.entity.latex ?? '';\n\n const ensureField = (): FormulaMathfield => {\n if (field) return field;\n field = createFormulaMathfield();\n host.appendChild(field);\n field.addEventListener('mount', () => {\n mounted = true;\n field?.setValue(baseline, { silenceNotifications: true });\n field?.focus();\n }, { once: true });\n field.addEventListener('input', () => {\n if (!field) return;\n emitEmbedChange(root, { id: formulaId(root, box.entity.id), patch: { latex: mathfieldLatex(field) } });\n });\n field.addEventListener('focusout', () => {\n window.setTimeout(() => {\n if (host.contains(document.activeElement)) return;\n commit();\n }, 0);\n });\n field.addEventListener(\n 'keydown',\n (e) => {\n const mf = field;\n if (!mf) return;\n if (e.key === 'ArrowLeft' && mf.selectionIsCollapsed && mf.position === 0) {\n e.preventDefault();\n e.stopPropagation();\n exitEdit('before');\n return;\n }\n if (\n e.key === 'ArrowRight' &&\n mf.selectionIsCollapsed &&\n mf.position === mf.lastOffset\n ) {\n e.preventDefault();\n e.stopPropagation();\n exitEdit('after');\n return;\n }\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n commit();\n }\n if (e.key === 'Escape') {\n e.preventDefault();\n cancel();\n }\n },\n true\n );\n return field;\n };\n\n const startEdit = () => {\n baseline = root.dataset.latex ?? baseline;\n root.classList.add('is-editing');\n view.hidden = true;\n host.hidden = false;\n const mf = ensureField();\n if (mounted) {\n mf.setValue(baseline, { silenceNotifications: true });\n mf.focus();\n }\n };\n\n const leaveEdit = () => {\n root.classList.remove('is-editing');\n host.hidden = true;\n view.hidden = false;\n };\n\n const commit = () => {\n if (!root.classList.contains('is-editing')) return;\n const latex = field && mounted ? mathfieldLatex(field) : baseline;\n baseline = latex;\n root.dataset.latex = latex;\n leaveEdit();\n emitEmbedChange(root, { id: formulaId(root, box.entity.id), patch: { latex } }, true);\n };\n\n const cancel = () => {\n if (field && mounted) field.setValue(baseline, { silenceNotifications: true });\n leaveEdit();\n };\n\n const exitEdit = (side: 'before' | 'after') => {\n commit();\n root.dispatchEvent(\n new CustomEvent(EMBED_EXIT_EDIT, {\n bubbles: true,\n detail: { id: formulaId(root, box.entity.id), side }\n })\n );\n };\n\n root.addEventListener('dblclick', (e) => {\n e.preventDefault();\n startEdit();\n });\n root.addEventListener('mini-formula-edit', () => startEdit());\n\n if (!(box.entity.latex ?? '').trim()) startEdit();\n return root;\n },\n update(el, box) {\n el.dataset.latex = box.entity.latex ?? '';\n if (el.classList.contains('is-editing')) return;\n const view = el.querySelector<HTMLElement>('.mini-formula-view');\n if (view) renderKatex(view, box.entity.latex ?? '', box.entity.displayMode !== false);\n },\n paintCanvasBackdrop(ctx, box) {\n ctx.fillStyle = '#f7f8fa';\n ctx.fillRect(box.x, box.y, box.w, box.h);\n }\n};\n"],"names":["KATEX_COMPAT_MACROS","PIPE_COMMANDS","left","right","normalizeMathLiveLatexForKatex","latex","normalized","command","rewritePipeCommand","rewriteSingleArgumentCommand","value","input","argument","parts","splitTopLevelPipe","build","marker","result","cursor","start","open","close","matchingBrace","depth","index","isEscaped","split","slashes","renderKatex","host","displayMode","src","katex","MathfieldElement","createFormulaMathfield","field","mathfieldLatex","measureFormula","entity","contentWidth","width","probe","rect","formulaId","root","fallback","formulaPlugin","box","view","mounted","baseline","ensureField","emitEmbedChange","commit","e","mf","exitEdit","cancel","startEdit","leaveEdit","side","EMBED_EXIT_EDIT","el","ctx"],"mappings":"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"}