@mteditor/vue2 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -83
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,10 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
> MtEditor 的 Vue 2.7 适配层 —— **薄壳,不含任何编辑逻辑**。
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 安装
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
```bash
|
|
8
|
+
npm i @mteditor/vue2
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import '@mteditor/theme-default/index.css'
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`@mteditor/core` 由本包作为普通依赖带进来。peer 依赖为 `vue: >=2.7.0 <3.0.0`
|
|
16
|
+
(Vue 2.7 是末版,且内置 Composition API)。
|
|
9
17
|
|
|
10
18
|
## 用法
|
|
11
19
|
|
|
@@ -35,8 +43,7 @@ export default {
|
|
|
35
43
|
</script>
|
|
36
44
|
```
|
|
37
45
|
|
|
38
|
-
按 **Options API** 书写,用 `Vue.extend
|
|
39
|
-
只写 Options API 的老项目里接入方式与手写组件没有任何区别。
|
|
46
|
+
按 **Options API** 书写,用 `Vue.extend`,只写 Options API 的老项目里接入方式与手写组件没有区别。
|
|
40
47
|
|
|
41
48
|
## `v-model` 双兼容
|
|
42
49
|
|
|
@@ -73,7 +80,7 @@ Vue 2 的 `v-model` 编译产物是 `props.value` + `on.input`;Vue 2.7 起也
|
|
|
73
80
|
|
|
74
81
|
## 事件
|
|
75
82
|
|
|
76
|
-
|
|
83
|
+
内核事件名**原样**沿用,不改名也不合并。
|
|
77
84
|
|
|
78
85
|
| 事件 | 载荷 | 来源 |
|
|
79
86
|
|---|---|---|
|
|
@@ -83,12 +90,11 @@ Vue 2 的 `v-model` 编译产物是 `props.value` + `on.input`;Vue 2.7 起也
|
|
|
83
90
|
| `ready` | `{ instance }` | 内核 |
|
|
84
91
|
| `focus` / `blur` | `{ instance }` | 内核 |
|
|
85
92
|
| `selectionChange` | `MtSelectionInfo`(100ms 节流,leading + trailing) | 内核 |
|
|
86
|
-
| `error` | `MtErrorPayload
|
|
93
|
+
| `error` | `MtErrorPayload`(**所有「闸口拒绝」都走这里**) | 内核 |
|
|
87
94
|
| `destroy` | `{ instance }` | 内核 |
|
|
88
95
|
|
|
89
96
|
`ready` 在内核的**构造函数里**就派发了,因此组件把它当**构造选项**(`onReady`)传入,
|
|
90
97
|
而不是事后 `on('ready')` 订阅 —— 后者永远收不到。
|
|
91
|
-
也正因如此,`onReady` 是**唯一**能直接拿到「刚建好的实例」的时机。
|
|
92
98
|
|
|
93
99
|
## 通过模板 ref 拿到内核实例
|
|
94
100
|
|
|
@@ -101,83 +107,14 @@ const handle = this.$refs.ed as unknown as MtEditorVue2Handle
|
|
|
101
107
|
handle.editor?.command('focus')
|
|
102
108
|
```
|
|
103
109
|
|
|
104
|
-
适配层**只暴露 `editor`
|
|
105
|
-
否则内核每加一个方法就要改五个适配包,且「适配层的方法」会与内核文档分叉。
|
|
106
|
-
卸载后该字段为 `null`。
|
|
107
|
-
|
|
108
|
-
## 边界(AGENTS.md §8.1)
|
|
109
|
-
|
|
110
|
-
允许做:
|
|
111
|
-
|
|
112
|
-
1. 挂载 / 卸载底层实例;
|
|
113
|
-
2. `props` → `MtEditorOptions` 映射;
|
|
114
|
-
3. `options` 变更时**增量更新**(不重建实例);
|
|
115
|
-
4. 内核事件 → 宿主事件透传;
|
|
116
|
-
5. `v-model` 双向绑定(两条协议)。
|
|
117
|
-
|
|
118
|
-
**不允许做**:任何编辑逻辑、任何依赖 Vue 2 生态辅助包(`vuelidate` / `vuex` 等)。
|
|
119
|
-
|
|
120
|
-
两条具体的禁止(ADR-0028 决策 4):
|
|
121
|
-
|
|
122
|
-
- **不在这里做回声抑制**。「灌回来的是同一份内容就不该碰视图」这条判据写在**内核**
|
|
123
|
-
(`MtEngine.setDocument()` 的结构等价短路)。适配层再判一次等于两处判据,
|
|
124
|
-
且六个适配端会各判各的。
|
|
125
|
-
- **不为了「同步内容」而重建实例**。重建会丢选区、撤销栈与 IME composition 状态。
|
|
126
|
-
|
|
127
|
-
## 两处 Vue 2 特有的实现要点
|
|
128
|
-
|
|
129
|
-
### 用 `Vue.extend`,不用 `defineComponent`
|
|
130
|
-
|
|
131
|
-
Vue 2.7 也导出了 `defineComponent`,但它在 Vue 2 里**运行时只是原样返回 options 对象**,
|
|
132
|
-
类型上却假装自己是构造器。用 `Vue.extend` 得到的是真正的构造器:既能被 `new`,
|
|
133
|
-
也能直接交给 `h()` 或 `components:` —— 后者正是宿主要做的事。
|
|
134
|
-
它还换来了 `ThisType`,让 `mounted` / `watch` / `render` 里的 `this` 全部有类型。
|
|
135
|
-
|
|
136
|
-
### 内核实例必须 `markRaw`
|
|
137
|
-
|
|
138
|
-
Vue 2 的 `observe()` 用 `Object.prototype.toString` 判断「是不是普通对象」,
|
|
139
|
-
**类实例会被判成普通对象**而遭深度遍历 —— 那会把整个编辑器(含 ProseMirror 视图)
|
|
140
|
-
塞满 getter/setter。因此写进 `data` 前必须 `markRaw(editor)`。
|
|
141
|
-
|
|
142
|
-
事件退订函数则**不放进 `data`**(数组的 `push` 被 Vue 2 改写后会触发重渲染),
|
|
143
|
-
改用一个模块级 `WeakMap` 挂在实例上,卸载时随实例一起回收。
|
|
144
|
-
|
|
145
|
-
## 依赖
|
|
146
|
-
|
|
147
|
-
| 类型 | 内容 |
|
|
148
|
-
|---|---|
|
|
149
|
-
| `dependencies` | `@mteditor/core` |
|
|
150
|
-
| `peerDependencies` | `vue: >=2.7.0 <3.0.0`(Vue 2.7 是末版,且内置 Composition API) |
|
|
151
|
-
| devDependencies | 含 `vue-template-compiler@^2.7.16` —— `@vue/test-utils@1` 的必需 peer,见下 |
|
|
152
|
-
|
|
153
|
-
### 为什么需要 `vue-template-compiler`
|
|
154
|
-
|
|
155
|
-
`@vue/test-utils@1`(Vue 2 专用,Vue 3 用的是 `@2`)在入口就
|
|
156
|
-
`import { compileToFunctions } from 'vue-template-compiler'`,
|
|
157
|
-
而 Vue 2.7 已把该包废弃(改用 `vue/compiler-sfc`)。
|
|
158
|
-
缺了它,单测会在**收集阶段**就报 `Failed to resolve import "vue-template-compiler"`。
|
|
159
|
-
|
|
160
|
-
它是**测试期依赖**,不进任何产物。这一处就地声明记在 ADR-0028 决策 7。
|
|
161
|
-
|
|
162
|
-
## 测试
|
|
163
|
-
|
|
164
|
-
```bash
|
|
165
|
-
pnpm --filter @mteditor/vue2 test # 单测(happy-dom + @vue/test-utils@1)
|
|
166
|
-
pnpm --filter @mteditor/vue2 typecheck
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
12 条单测覆盖四组:挂载与卸载、`v-model` 双兼容(两条协议各一条用例 + 同时派发 +
|
|
170
|
-
`null` 的「没给」语义)、回灌短路、选项映射。
|
|
171
|
-
|
|
172
|
-
端到端在 [`../../tests/e2e/adapters.spec.ts`](../../tests/e2e/adapters.spec.ts):
|
|
173
|
-
真实浏览器里挂载 → 输入 → 读回**宿主侧的绑定值**。
|
|
174
|
-
适配包不设覆盖率阈值(ADR-0019 只覆盖 `document` / `core` / `renderer-web`),
|
|
175
|
-
但示例必须纳入 E2E(§8.3,ADR-0028 决策 6)。
|
|
110
|
+
适配层**只暴露 `editor` 一个字段**,不把内核方法再转发一遍。卸载后该字段为 `null`。
|
|
176
111
|
|
|
177
|
-
##
|
|
112
|
+
## 注意事项
|
|
178
113
|
|
|
179
|
-
|
|
180
|
-
|
|
114
|
+
- **不要自己写回声抑制**。「灌回来的是同一份内容就不该碰视图」这条判据在**内核**
|
|
115
|
+
(`setDocument()` 的结构等价短路)。
|
|
116
|
+
- **不要用重建实例来「同步内容」**。重建会丢选区、撤销栈与 IME composition 状态。
|
|
117
|
+
- 浮层(气泡 / 下拉 / 抽屉)挂在 `document.body` 上,不在组件容器内。
|
|
181
118
|
|
|
182
119
|
## 许可
|
|
183
120
|
|
package/dist/index.cjs
CHANGED
|
@@ -61,7 +61,7 @@ var MtEditor = Vue__default.default.extend({
|
|
|
61
61
|
},
|
|
62
62
|
watch: {
|
|
63
63
|
// 「编辑器 → 宿主」由 onChange 完成;这里只做「宿主 → 编辑器」。
|
|
64
|
-
//
|
|
64
|
+
// 内核的结构等价短路保证回灌同一个文档时不会重置光标。
|
|
65
65
|
boundValue(next) {
|
|
66
66
|
if (next === null || next === void 0 || this.editor === null) return;
|
|
67
67
|
this.editor.setJSON(next);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/component.ts"],"names":["Vue","MtCoreEditor","markRaw"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Vue 2.7
|
|
1
|
+
{"version":3,"sources":["../src/component.ts"],"names":["Vue","MtCoreEditor","markRaw"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Vue 2.7 适配组件。\n *\n * 它是**薄壳**:只做挂载 / 卸载、props → 选项映射、增量更新、事件透传与双向绑定。\n * 任何编辑逻辑都写在 `@mteditor/core`,写在这里视为违规。\n *\n * ## 为什么用 `Vue.extend` 而不是 `defineComponent`\n *\n * Vue 2.7 也导出了 `defineComponent`,但它在 Vue 2 里**运行时只是原样返回 options 对象**,\n * 类型上却假装自己是构造器。用 `Vue.extend` 得到的是真正的构造器:既能被 `new`,\n * 也能直接丢给 `h()` / `components:` —— 后者正是宿主要做的事。\n *\n * ## `v-model` 双兼容\n *\n * Vue 2 的 `v-model` 编译产物是 `props.value` + `on.input`;Vue 2.7 起也支持\n * `modelValue` + `update:modelValue`。本组件**两个 prop 都收、两个事件都发**:\n *\n * | 宿主写法 | 走哪条 |\n * |---|---|\n * | `<mt-editor v-model=\"doc\" />` | `value` 进 / `input` 出 |\n * | `<mt-editor :modelValue=\"doc\" @update:modelValue=\"doc = $event\" />` | `modelValue` 进 / `update:modelValue` 出 |\n *\n * 两者同时给出时 `modelValue` 优先(见 `boundValue` 计算属性)。\n *\n * ## 两条关键设计\n *\n * 1. **这里不做回声抑制**。宿主把编辑器刚给出的文档灌回来是 `v-model` 的必然结果,\n * 而「灌回来的是同一份内容就不该碰视图」这条判据写在**内核**\n * (`MtEngine.setDocument()` 的结构等价短路)。适配层再判一次等于两处判据,\n * 且 6 个适配端会各判各的。\n * 2. **结构性选项挂载时读取一次**。内核没有「运行时换档」的能力\n * (`platform` / `ui` / `placeholder` / `historyDepth` 等都没有 setter),\n * 因此本组件不假装支持它。要换档请用 Vue 重挂载机制(`:key`)。\n */\n\nimport Vue, { markRaw } from 'vue'\n\nimport { MtEditor as MtCoreEditor } from '@mteditor/core'\nimport type { MtAdapterOptions, MtChangePayload, MtDocument, MtErrorPayload } from '@mteditor/core'\n\n/**\n * 能就地同步的选项子集。类型取自 `MtAdapterOptions`,不另立一份定义\n * (三者的 setter 分别是 `setTheme` / `setLocale` / `setReadonly`)。\n */\ntype MtRuntimeOptions = Pick<MtAdapterOptions, 'theme' | 'locale' | 'readonly'>\n\n/**\n * 把可在**运行时**就地同步的选项写进已存在的内核实例。\n *\n * 白名单是刻意的:内核将来新增运行时 setter 时,需要**显式**加进这里才会生效 ——\n * 比「默认尝试同步」安全,因为后者会让 `ui` 之类的结构性选项被半途写入而非完整重建。\n *\n * @param instance 内核实例\n * @param options 只含「能就地改」的三项\n */\nconst applyRuntimeOptions = (instance: MtCoreEditor, options: MtRuntimeOptions): void => {\n if (options.theme !== undefined) instance.setTheme(options.theme)\n if (options.locale !== undefined) instance.setLocale(options.locale)\n if (options.readonly !== undefined) instance.setReadonly(options.readonly)\n}\n\n/**\n * 每个组件实例的事件退订函数。\n *\n * 不放进 `data`:Vue 2 会把 `data` **深度 observe**,数组的 `push` 会被改写成\n * 触发重渲染的版本;而这些函数与渲染无关。用 `WeakMap` 挂在实例上,\n * 卸载后随实例一起被回收。\n */\nconst teardown = new WeakMap<object, (() => void)[]>()\n\n/**\n * 从 `$refs` 里取挂载容器。\n *\n * `$refs` 的值可能是组件实例、DOM 元素或它们的数组,因此必须走类型守卫。\n *\n * @param refs 组件实例的 `$refs`\n * @returns 命中且确为 HTMLElement 时返回它,否则 `null`\n */\nconst hostFrom = (refs: unknown): HTMLElement | null => {\n const ref = (refs as Record<string, unknown>)['host']\n return ref instanceof HTMLElement ? ref : null\n}\n\n/** `<MtEditor>` —— Vue 2.7 的 MtEditor 组件 */\nexport const MtEditor = Vue.extend({\n name: 'MtEditor',\n\n props: {\n /**\n * 文档(真相源)。Vue 2 的 `v-model` 默认走这里。\n *\n * 类型里带上 `null`:Vue 2 的宿主习惯写 `data() { return { doc: null } }`,\n * 且在 `null` 上做 `=== null` 判空是必需的分支(`undefined` 覆盖不到它)。\n */\n value: { type: Object as () => MtDocument | null | undefined, default: undefined },\n /** 文档(真相源)。Vue 2.7 的 `v-model` 新写法走这里 */\n modelValue: { type: Object as () => MtDocument | null | undefined, default: undefined },\n /** 其余内核选项 */\n options: { type: Object as () => MtAdapterOptions, default: (): MtAdapterOptions => ({}) },\n },\n\n data() {\n return {\n /**\n * 内核实例。\n *\n * **必须 `markRaw`**:Vue 2 的 `observe()` 用 `Object.prototype.toString` 判\n * 「是不是普通对象」,类实例会被判成普通对象而遭深度遍历 ——\n * 那会把整个编辑器(含 ProseMirror 视图)塞满 getter/setter。\n */\n editor: null as MtCoreEditor | null,\n }\n },\n\n computed: {\n /**\n * 实际生效的受控值。\n *\n * 两条 `v-model` 协议共用一个入口:`modelValue` 优先于 `value`,\n * 而 `null` / `undefined` 都算「没给」(Vue 2 的宿主习惯用 `null` 表示「还没加载」)。\n * 有了它,下面只需要**一个** watcher,「两个 prop 谁说了算」也就只有一处答案。\n */\n boundValue(): MtDocument | null | undefined {\n return this.modelValue !== undefined && this.modelValue !== null\n ? this.modelValue\n : this.value\n },\n },\n\n watch: {\n // 「编辑器 → 宿主」由 onChange 完成;这里只做「宿主 → 编辑器」。\n // 内核的结构等价短路保证回灌同一个文档时不会重置光标。\n boundValue(next: MtDocument | null | undefined) {\n if (next === null || next === undefined || this.editor === null) return\n this.editor.setJSON(next)\n },\n\n // 选项变化:只同步能在运行时就地改的那几个(结构性选项挂载时读取一次)\n options: {\n deep: true,\n handler(next: MtAdapterOptions) {\n if (this.editor === null) return\n applyRuntimeOptions(this.editor, next)\n },\n },\n },\n\n mounted() {\n const element = hostFrom(this.$refs)\n if (element === null) return\n\n // `options.content` 语义是「初始内容」;受控值一旦给出就优先于它。\n // 必须先摘出来再展开,否则 `...options` 会把 `content` 覆盖回旧值。\n const { content: initialContent, ...restOptions } = this.options\n\n const editor = new MtCoreEditor({\n ...restOptions,\n element,\n content: this.boundValue ?? initialContent,\n onChange: (payload: MtChangePayload) => {\n // 两条 v-model 协议同时派发,宿主用哪种写法都能收到\n this.$emit('input', payload.json)\n this.$emit('update:modelValue', payload.json)\n this.$emit('change', payload)\n },\n // `ready` 在构造期就已派发,因此它走构造选项;其余事件走总线订阅\n onReady: (payload) => this.$emit('ready', payload),\n onError: (payload: MtErrorPayload) => this.$emit('error', payload),\n })\n\n teardown.set(this, [\n editor.on('focus', (payload) => this.$emit('focus', payload)),\n editor.on('blur', (payload) => this.$emit('blur', payload)),\n editor.on('selectionChange', (payload) => this.$emit('selectionChange', payload)),\n editor.on('destroy', (payload) => this.$emit('destroy', payload)),\n ])\n\n this.editor = markRaw(editor)\n },\n\n // Vue 2 的生命周期名(Vue 3 里叫 `beforeUnmount`)\n beforeDestroy() {\n const editor = this.editor\n this.editor = null\n if (editor === null) return\n // 先销毁再退订:`destroy` 事件本身要透给宿主\n editor.destroy()\n for (const off of teardown.get(this) ?? []) off()\n teardown.delete(this)\n },\n\n render(h) {\n // 无子节点:内核自己往这个 div 里建 DOM,Vue 因此不会去碰它。\n // 用 `ref: 'host'` 字符串引用(Vue 2 的写法),由 `hostFrom()` 取回。\n return h('div', {\n ref: 'host',\n staticClass: 'mt-editor-host',\n attrs: { 'data-mt-adapter': 'vue2' },\n })\n },\n})\n\n/**\n * `<MtEditor>` 的 props,**由组件定义推断而来**。\n *\n * Vue 2 的 props 与 data 都直接挂在实例上,因此这里从实例类型上摘出 props 对应的三个字段。\n * 刻意不在 `types.ts` 里手写一份 interface:手写的那份会与运行时的 props 定义漂移。\n */\nexport type MtEditorVue2Props = Pick<\n InstanceType<typeof MtEditor>,\n 'value' | 'modelValue' | 'options'\n>\n\nexport default MtEditor\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -34,15 +34,15 @@ type MtEditorVue2Props = Pick<InstanceType<typeof MtEditor>, 'value' | 'modelVal
|
|
|
34
34
|
*
|
|
35
35
|
* 这些类型是**给宿主写模板与处理函数用的**,不是内部实现类型。
|
|
36
36
|
* 它们只是 `@mteditor/core` 的再导出与组合 —— 适配层不得自己另立一套文档模型类型,
|
|
37
|
-
*
|
|
37
|
+
* 否则「适配层的类型」与「内核的类型」会漂移成两份。
|
|
38
38
|
*/
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* `<MtEditor>` 派发的事件与载荷。
|
|
42
42
|
*
|
|
43
|
-
*
|
|
43
|
+
* 事件名**原样**沿用内核的命名(`change` / `ready` / `focus` / `blur`
|
|
44
44
|
* `selectionChange` / `error` / `destroy`),不改名也不合并 ——
|
|
45
|
-
*
|
|
45
|
+
* 改名会让「内核文档里的事件名」与「框架里的用法」变成两套说法。
|
|
46
46
|
*
|
|
47
47
|
* 另外两条是 Vue 2 的 `v-model` 协议,**不是**内核事件:
|
|
48
48
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -34,15 +34,15 @@ type MtEditorVue2Props = Pick<InstanceType<typeof MtEditor>, 'value' | 'modelVal
|
|
|
34
34
|
*
|
|
35
35
|
* 这些类型是**给宿主写模板与处理函数用的**,不是内部实现类型。
|
|
36
36
|
* 它们只是 `@mteditor/core` 的再导出与组合 —— 适配层不得自己另立一套文档模型类型,
|
|
37
|
-
*
|
|
37
|
+
* 否则「适配层的类型」与「内核的类型」会漂移成两份。
|
|
38
38
|
*/
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* `<MtEditor>` 派发的事件与载荷。
|
|
42
42
|
*
|
|
43
|
-
*
|
|
43
|
+
* 事件名**原样**沿用内核的命名(`change` / `ready` / `focus` / `blur`
|
|
44
44
|
* `selectionChange` / `error` / `destroy`),不改名也不合并 ——
|
|
45
|
-
*
|
|
45
|
+
* 改名会让「内核文档里的事件名」与「框架里的用法」变成两套说法。
|
|
46
46
|
*
|
|
47
47
|
* 另外两条是 Vue 2 的 `v-model` 协议,**不是**内核事件:
|
|
48
48
|
*
|
package/dist/index.js
CHANGED
|
@@ -53,7 +53,7 @@ var MtEditor = Vue.extend({
|
|
|
53
53
|
},
|
|
54
54
|
watch: {
|
|
55
55
|
// 「编辑器 → 宿主」由 onChange 完成;这里只做「宿主 → 编辑器」。
|
|
56
|
-
//
|
|
56
|
+
// 内核的结构等价短路保证回灌同一个文档时不会重置光标。
|
|
57
57
|
boundValue(next) {
|
|
58
58
|
if (next === null || next === void 0 || this.editor === null) return;
|
|
59
59
|
this.editor.setJSON(next);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/component.ts"],"names":["MtCoreEditor"],"mappings":";;;;AAuDA,IAAM,mBAAA,GAAsB,CAAC,QAAA,EAAwB,OAAA,KAAoC;AACvF,EAAA,IAAI,QAAQ,KAAA,KAAU,MAAA,EAAW,QAAA,CAAS,QAAA,CAAS,QAAQ,KAAK,CAAA;AAChE,EAAA,IAAI,QAAQ,MAAA,KAAW,MAAA,EAAW,QAAA,CAAS,SAAA,CAAU,QAAQ,MAAM,CAAA;AACnE,EAAA,IAAI,QAAQ,QAAA,KAAa,MAAA,EAAW,QAAA,CAAS,WAAA,CAAY,QAAQ,QAAQ,CAAA;AAC3E,CAAA;AASA,IAAM,QAAA,uBAAe,OAAA,EAAgC;AAUrD,IAAM,QAAA,GAAW,CAAC,IAAA,KAAsC;AACtD,EAAA,MAAM,GAAA,GAAO,KAAiC,MAAM,CAAA;AACpD,EAAA,OAAO,GAAA,YAAe,cAAc,GAAA,GAAM,IAAA;AAC5C,CAAA;AAGO,IAAM,QAAA,GAAW,IAAI,MAAA,CAAO;AAAA,EACjC,IAAA,EAAM,UAAA;AAAA,EAEN,KAAA,EAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOL,KAAA,EAAO,EAAE,IAAA,EAAM,MAAA,EAA+C,SAAS,MAAA,EAAU;AAAA;AAAA,IAEjF,UAAA,EAAY,EAAE,IAAA,EAAM,MAAA,EAA+C,SAAS,MAAA,EAAU;AAAA;AAAA,IAEtF,SAAS,EAAE,IAAA,EAAM,QAAkC,OAAA,EAAS,OAAyB,EAAC,CAAA;AAAG,GAC3F;AAAA,EAEA,IAAA,GAAO;AACL,IAAA,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQL,MAAA,EAAQ;AAAA,KACV;AAAA,EACF,CAAA;AAAA,EAEA,QAAA,EAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQR,UAAA,GAA4C;AAC1C,MAAA,OAAO,IAAA,CAAK,eAAe,MAAA,IAAa,IAAA,CAAK,eAAe,IAAA,GACxD,IAAA,CAAK,aACL,IAAA,CAAK,KAAA;AAAA,IACX;AAAA,GACF;AAAA,EAEA,KAAA,EAAO;AAAA;AAAA;AAAA,IAGL,WAAW,IAAA,EAAqC;AAC9C,MAAA,IAAI,SAAS,IAAA,IAAQ,IAAA,KAAS,MAAA,IAAa,IAAA,CAAK,WAAW,IAAA,EAAM;AACjE,MAAA,IAAA,CAAK,MAAA,CAAO,QAAQ,IAAI,CAAA;AAAA,IAC1B,CAAA;AAAA;AAAA,IAGA,OAAA,EAAS;AAAA,MACP,IAAA,EAAM,IAAA;AAAA,MACN,QAAQ,IAAA,EAAwB;AAC9B,QAAA,IAAI,IAAA,CAAK,WAAW,IAAA,EAAM;AAC1B,QAAA,mBAAA,CAAoB,IAAA,CAAK,QAAQ,IAAI,CAAA;AAAA,MACvC;AAAA;AACF,GACF;AAAA,EAEA,OAAA,GAAU;AACR,IAAA,MAAM,OAAA,GAAU,QAAA,CAAS,IAAA,CAAK,KAAK,CAAA;AACnC,IAAA,IAAI,YAAY,IAAA,EAAM;AAItB,IAAA,MAAM,EAAE,OAAA,EAAS,cAAA,EAAgB,GAAG,WAAA,KAAgB,IAAA,CAAK,OAAA;AAEzD,IAAA,MAAM,MAAA,GAAS,IAAIA,UAAA,CAAa;AAAA,MAC9B,GAAG,WAAA;AAAA,MACH,OAAA;AAAA,MACA,OAAA,EAAS,KAAK,UAAA,IAAc,cAAA;AAAA,MAC5B,QAAA,EAAU,CAAC,OAAA,KAA6B;AAEtC,QAAA,IAAA,CAAK,KAAA,CAAM,OAAA,EAAS,OAAA,CAAQ,IAAI,CAAA;AAChC,QAAA,IAAA,CAAK,KAAA,CAAM,mBAAA,EAAqB,OAAA,CAAQ,IAAI,CAAA;AAC5C,QAAA,IAAA,CAAK,KAAA,CAAM,UAAU,OAAO,CAAA;AAAA,MAC9B,CAAA;AAAA;AAAA,MAEA,SAAS,CAAC,OAAA,KAAY,IAAA,CAAK,KAAA,CAAM,SAAS,OAAO,CAAA;AAAA,MACjD,SAAS,CAAC,OAAA,KAA4B,IAAA,CAAK,KAAA,CAAM,SAAS,OAAO;AAAA,KAClE,CAAA;AAED,IAAA,QAAA,CAAS,IAAI,IAAA,EAAM;AAAA,MACjB,MAAA,CAAO,GAAG,OAAA,EAAS,CAAC,YAAY,IAAA,CAAK,KAAA,CAAM,OAAA,EAAS,OAAO,CAAC,CAAA;AAAA,MAC5D,MAAA,CAAO,GAAG,MAAA,EAAQ,CAAC,YAAY,IAAA,CAAK,KAAA,CAAM,MAAA,EAAQ,OAAO,CAAC,CAAA;AAAA,MAC1D,MAAA,CAAO,GAAG,iBAAA,EAAmB,CAAC,YAAY,IAAA,CAAK,KAAA,CAAM,iBAAA,EAAmB,OAAO,CAAC,CAAA;AAAA,MAChF,MAAA,CAAO,GAAG,SAAA,EAAW,CAAC,YAAY,IAAA,CAAK,KAAA,CAAM,SAAA,EAAW,OAAO,CAAC;AAAA,KACjE,CAAA;AAED,IAAA,IAAA,CAAK,MAAA,GAAS,QAAQ,MAAM,CAAA;AAAA,EAC9B,CAAA;AAAA;AAAA,EAGA,aAAA,GAAgB;AACd,IAAA,MAAM,SAAS,IAAA,CAAK,MAAA;AACpB,IAAA,IAAA,CAAK,MAAA,GAAS,IAAA;AACd,IAAA,IAAI,WAAW,IAAA,EAAM;AAErB,IAAA,MAAA,CAAO,OAAA,EAAQ;AACf,IAAA,KAAA,MAAW,OAAO,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA,IAAK,IAAI,GAAA,EAAI;AAChD,IAAA,QAAA,CAAS,OAAO,IAAI,CAAA;AAAA,EACtB,CAAA;AAAA,EAEA,OAAO,CAAA,EAAG;AAGR,IAAA,OAAO,EAAE,KAAA,EAAO;AAAA,MACd,GAAA,EAAK,MAAA;AAAA,MACL,WAAA,EAAa,gBAAA;AAAA,MACb,KAAA,EAAO,EAAE,iBAAA,EAAmB,MAAA;AAAO,KACpC,CAAA;AAAA,EACH;AACF,CAAC;AAaD,IAAO,iBAAA,GAAQ","file":"index.js","sourcesContent":["/**\n * Vue 2.7
|
|
1
|
+
{"version":3,"sources":["../src/component.ts"],"names":["MtCoreEditor"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Vue 2.7 适配组件。\n *\n * 它是**薄壳**:只做挂载 / 卸载、props → 选项映射、增量更新、事件透传与双向绑定。\n * 任何编辑逻辑都写在 `@mteditor/core`,写在这里视为违规。\n *\n * ## 为什么用 `Vue.extend` 而不是 `defineComponent`\n *\n * Vue 2.7 也导出了 `defineComponent`,但它在 Vue 2 里**运行时只是原样返回 options 对象**,\n * 类型上却假装自己是构造器。用 `Vue.extend` 得到的是真正的构造器:既能被 `new`,\n * 也能直接丢给 `h()` / `components:` —— 后者正是宿主要做的事。\n *\n * ## `v-model` 双兼容\n *\n * Vue 2 的 `v-model` 编译产物是 `props.value` + `on.input`;Vue 2.7 起也支持\n * `modelValue` + `update:modelValue`。本组件**两个 prop 都收、两个事件都发**:\n *\n * | 宿主写法 | 走哪条 |\n * |---|---|\n * | `<mt-editor v-model=\"doc\" />` | `value` 进 / `input` 出 |\n * | `<mt-editor :modelValue=\"doc\" @update:modelValue=\"doc = $event\" />` | `modelValue` 进 / `update:modelValue` 出 |\n *\n * 两者同时给出时 `modelValue` 优先(见 `boundValue` 计算属性)。\n *\n * ## 两条关键设计\n *\n * 1. **这里不做回声抑制**。宿主把编辑器刚给出的文档灌回来是 `v-model` 的必然结果,\n * 而「灌回来的是同一份内容就不该碰视图」这条判据写在**内核**\n * (`MtEngine.setDocument()` 的结构等价短路)。适配层再判一次等于两处判据,\n * 且 6 个适配端会各判各的。\n * 2. **结构性选项挂载时读取一次**。内核没有「运行时换档」的能力\n * (`platform` / `ui` / `placeholder` / `historyDepth` 等都没有 setter),\n * 因此本组件不假装支持它。要换档请用 Vue 重挂载机制(`:key`)。\n */\n\nimport Vue, { markRaw } from 'vue'\n\nimport { MtEditor as MtCoreEditor } from '@mteditor/core'\nimport type { MtAdapterOptions, MtChangePayload, MtDocument, MtErrorPayload } from '@mteditor/core'\n\n/**\n * 能就地同步的选项子集。类型取自 `MtAdapterOptions`,不另立一份定义\n * (三者的 setter 分别是 `setTheme` / `setLocale` / `setReadonly`)。\n */\ntype MtRuntimeOptions = Pick<MtAdapterOptions, 'theme' | 'locale' | 'readonly'>\n\n/**\n * 把可在**运行时**就地同步的选项写进已存在的内核实例。\n *\n * 白名单是刻意的:内核将来新增运行时 setter 时,需要**显式**加进这里才会生效 ——\n * 比「默认尝试同步」安全,因为后者会让 `ui` 之类的结构性选项被半途写入而非完整重建。\n *\n * @param instance 内核实例\n * @param options 只含「能就地改」的三项\n */\nconst applyRuntimeOptions = (instance: MtCoreEditor, options: MtRuntimeOptions): void => {\n if (options.theme !== undefined) instance.setTheme(options.theme)\n if (options.locale !== undefined) instance.setLocale(options.locale)\n if (options.readonly !== undefined) instance.setReadonly(options.readonly)\n}\n\n/**\n * 每个组件实例的事件退订函数。\n *\n * 不放进 `data`:Vue 2 会把 `data` **深度 observe**,数组的 `push` 会被改写成\n * 触发重渲染的版本;而这些函数与渲染无关。用 `WeakMap` 挂在实例上,\n * 卸载后随实例一起被回收。\n */\nconst teardown = new WeakMap<object, (() => void)[]>()\n\n/**\n * 从 `$refs` 里取挂载容器。\n *\n * `$refs` 的值可能是组件实例、DOM 元素或它们的数组,因此必须走类型守卫。\n *\n * @param refs 组件实例的 `$refs`\n * @returns 命中且确为 HTMLElement 时返回它,否则 `null`\n */\nconst hostFrom = (refs: unknown): HTMLElement | null => {\n const ref = (refs as Record<string, unknown>)['host']\n return ref instanceof HTMLElement ? ref : null\n}\n\n/** `<MtEditor>` —— Vue 2.7 的 MtEditor 组件 */\nexport const MtEditor = Vue.extend({\n name: 'MtEditor',\n\n props: {\n /**\n * 文档(真相源)。Vue 2 的 `v-model` 默认走这里。\n *\n * 类型里带上 `null`:Vue 2 的宿主习惯写 `data() { return { doc: null } }`,\n * 且在 `null` 上做 `=== null` 判空是必需的分支(`undefined` 覆盖不到它)。\n */\n value: { type: Object as () => MtDocument | null | undefined, default: undefined },\n /** 文档(真相源)。Vue 2.7 的 `v-model` 新写法走这里 */\n modelValue: { type: Object as () => MtDocument | null | undefined, default: undefined },\n /** 其余内核选项 */\n options: { type: Object as () => MtAdapterOptions, default: (): MtAdapterOptions => ({}) },\n },\n\n data() {\n return {\n /**\n * 内核实例。\n *\n * **必须 `markRaw`**:Vue 2 的 `observe()` 用 `Object.prototype.toString` 判\n * 「是不是普通对象」,类实例会被判成普通对象而遭深度遍历 ——\n * 那会把整个编辑器(含 ProseMirror 视图)塞满 getter/setter。\n */\n editor: null as MtCoreEditor | null,\n }\n },\n\n computed: {\n /**\n * 实际生效的受控值。\n *\n * 两条 `v-model` 协议共用一个入口:`modelValue` 优先于 `value`,\n * 而 `null` / `undefined` 都算「没给」(Vue 2 的宿主习惯用 `null` 表示「还没加载」)。\n * 有了它,下面只需要**一个** watcher,「两个 prop 谁说了算」也就只有一处答案。\n */\n boundValue(): MtDocument | null | undefined {\n return this.modelValue !== undefined && this.modelValue !== null\n ? this.modelValue\n : this.value\n },\n },\n\n watch: {\n // 「编辑器 → 宿主」由 onChange 完成;这里只做「宿主 → 编辑器」。\n // 内核的结构等价短路保证回灌同一个文档时不会重置光标。\n boundValue(next: MtDocument | null | undefined) {\n if (next === null || next === undefined || this.editor === null) return\n this.editor.setJSON(next)\n },\n\n // 选项变化:只同步能在运行时就地改的那几个(结构性选项挂载时读取一次)\n options: {\n deep: true,\n handler(next: MtAdapterOptions) {\n if (this.editor === null) return\n applyRuntimeOptions(this.editor, next)\n },\n },\n },\n\n mounted() {\n const element = hostFrom(this.$refs)\n if (element === null) return\n\n // `options.content` 语义是「初始内容」;受控值一旦给出就优先于它。\n // 必须先摘出来再展开,否则 `...options` 会把 `content` 覆盖回旧值。\n const { content: initialContent, ...restOptions } = this.options\n\n const editor = new MtCoreEditor({\n ...restOptions,\n element,\n content: this.boundValue ?? initialContent,\n onChange: (payload: MtChangePayload) => {\n // 两条 v-model 协议同时派发,宿主用哪种写法都能收到\n this.$emit('input', payload.json)\n this.$emit('update:modelValue', payload.json)\n this.$emit('change', payload)\n },\n // `ready` 在构造期就已派发,因此它走构造选项;其余事件走总线订阅\n onReady: (payload) => this.$emit('ready', payload),\n onError: (payload: MtErrorPayload) => this.$emit('error', payload),\n })\n\n teardown.set(this, [\n editor.on('focus', (payload) => this.$emit('focus', payload)),\n editor.on('blur', (payload) => this.$emit('blur', payload)),\n editor.on('selectionChange', (payload) => this.$emit('selectionChange', payload)),\n editor.on('destroy', (payload) => this.$emit('destroy', payload)),\n ])\n\n this.editor = markRaw(editor)\n },\n\n // Vue 2 的生命周期名(Vue 3 里叫 `beforeUnmount`)\n beforeDestroy() {\n const editor = this.editor\n this.editor = null\n if (editor === null) return\n // 先销毁再退订:`destroy` 事件本身要透给宿主\n editor.destroy()\n for (const off of teardown.get(this) ?? []) off()\n teardown.delete(this)\n },\n\n render(h) {\n // 无子节点:内核自己往这个 div 里建 DOM,Vue 因此不会去碰它。\n // 用 `ref: 'host'` 字符串引用(Vue 2 的写法),由 `hostFrom()` 取回。\n return h('div', {\n ref: 'host',\n staticClass: 'mt-editor-host',\n attrs: { 'data-mt-adapter': 'vue2' },\n })\n },\n})\n\n/**\n * `<MtEditor>` 的 props,**由组件定义推断而来**。\n *\n * Vue 2 的 props 与 data 都直接挂在实例上,因此这里从实例类型上摘出 props 对应的三个字段。\n * 刻意不在 `types.ts` 里手写一份 interface:手写的那份会与运行时的 props 定义漂移。\n */\nexport type MtEditorVue2Props = Pick<\n InstanceType<typeof MtEditor>,\n 'value' | 'modelValue' | 'options'\n>\n\nexport default MtEditor\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mteditor/vue2",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "MtEditor 的 Vue 2.7 适配层:Options API 薄壳,兼容 value/input 形式的 v-model",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mteditor",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"access": "public"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@mteditor/core": "0.1.
|
|
50
|
+
"@mteditor/core": "0.1.1"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"vue": ">=2.7.0 <3.0.0"
|