@tiptap/vue-2 3.30.2 → 3.30.3
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/dist/index.cjs +402 -488
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +84 -79
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +84 -79
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +371 -449
- package/dist/index.js.map +1 -1
- package/dist/menus/index.cjs +151 -2537
- package/dist/menus/index.cjs.map +1 -1
- package/dist/menus/index.d.cts +39 -222
- package/dist/menus/index.d.cts.map +1 -0
- package/dist/menus/index.d.ts +39 -222
- package/dist/menus/index.d.ts.map +1 -0
- package/dist/menus/index.js +149 -2509
- package/dist/menus/index.js.map +1 -1
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -1,470 +1,392 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { Editor as Editor$1, NodeView, createWidgetDecoration, isNodeViewSelected } from "@tiptap/core";
|
|
2
|
+
import { booleanProp, functionProp, objectProp } from "vue-ts-types";
|
|
3
|
+
import VueDefault from "vue";
|
|
4
|
+
export * from "@tiptap/core";
|
|
5
|
+
//#region src/Editor.ts
|
|
6
|
+
var Editor = class extends Editor$1 {
|
|
7
|
+
constructor(..._args) {
|
|
8
|
+
super(..._args);
|
|
9
|
+
this.contentComponent = null;
|
|
10
|
+
}
|
|
8
11
|
};
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
var _a;
|
|
46
|
-
const { editor } = this;
|
|
47
|
-
if (!editor) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
if (!editor.isDestroyed) {
|
|
51
|
-
editor.view.setProps({
|
|
52
|
-
nodeViews: {}
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
editor.contentComponent = null;
|
|
56
|
-
if (!((_a = editor.view.dom) == null ? void 0 : _a.parentNode)) {
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
const newElement = document.createElement("div");
|
|
60
|
-
newElement.append(...editor.view.dom.parentNode.childNodes);
|
|
61
|
-
editor.setOptions({
|
|
62
|
-
element: newElement
|
|
63
|
-
});
|
|
64
|
-
}
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/EditorContent.ts
|
|
14
|
+
const EditorContent = {
|
|
15
|
+
name: "EditorContent",
|
|
16
|
+
props: { editor: {
|
|
17
|
+
default: null,
|
|
18
|
+
type: Object
|
|
19
|
+
} },
|
|
20
|
+
watch: { editor: {
|
|
21
|
+
immediate: true,
|
|
22
|
+
handler(editor) {
|
|
23
|
+
if (editor && editor.options.element) this.$nextTick(() => {
|
|
24
|
+
var _editor$view$dom;
|
|
25
|
+
const element = this.$el;
|
|
26
|
+
if (!element || !((_editor$view$dom = editor.view.dom) === null || _editor$view$dom === void 0 ? void 0 : _editor$view$dom.parentNode)) return;
|
|
27
|
+
element.append(...editor.view.dom.parentNode.childNodes);
|
|
28
|
+
editor.contentComponent = this;
|
|
29
|
+
editor.setOptions({ element });
|
|
30
|
+
editor.createNodeViews();
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
} },
|
|
34
|
+
render(createElement) {
|
|
35
|
+
return createElement("div");
|
|
36
|
+
},
|
|
37
|
+
beforeDestroy() {
|
|
38
|
+
var _editor$view$dom2;
|
|
39
|
+
const { editor } = this;
|
|
40
|
+
if (!editor) return;
|
|
41
|
+
if (!editor.isDestroyed) editor.view.setProps({ nodeViews: {} });
|
|
42
|
+
editor.contentComponent = null;
|
|
43
|
+
if (!((_editor$view$dom2 = editor.view.dom) === null || _editor$view$dom2 === void 0 ? void 0 : _editor$view$dom2.parentNode)) return;
|
|
44
|
+
const newElement = document.createElement("div");
|
|
45
|
+
newElement.append(...editor.view.dom.parentNode.childNodes);
|
|
46
|
+
editor.setOptions({ element: newElement });
|
|
47
|
+
}
|
|
65
48
|
};
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
},
|
|
88
|
-
render(createElement) {
|
|
89
|
-
return createElement(this.as, {
|
|
90
|
-
style: {
|
|
91
|
-
whiteSpace: "pre-wrap"
|
|
92
|
-
},
|
|
93
|
-
attrs: {
|
|
94
|
-
"data-node-view-content": ""
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
}
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/NodeViewContent.ts
|
|
51
|
+
const NodeViewContent = {
|
|
52
|
+
props: { as: {
|
|
53
|
+
type: String,
|
|
54
|
+
default: "div"
|
|
55
|
+
} },
|
|
56
|
+
inject: { nodeViewContentRef: { default: void 0 } },
|
|
57
|
+
mounted() {
|
|
58
|
+
if (this.nodeViewContentRef && this.$el) this.nodeViewContentRef(this.$el);
|
|
59
|
+
},
|
|
60
|
+
beforeDestroy() {
|
|
61
|
+
if (this.nodeViewContentRef) this.nodeViewContentRef(null);
|
|
62
|
+
},
|
|
63
|
+
render(createElement) {
|
|
64
|
+
return createElement(this.as, {
|
|
65
|
+
style: { whiteSpace: "pre-wrap" },
|
|
66
|
+
attrs: { "data-node-view-content": "" }
|
|
67
|
+
});
|
|
68
|
+
}
|
|
98
69
|
};
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
whiteSpace: "normal"
|
|
116
|
-
},
|
|
117
|
-
attrs: {
|
|
118
|
-
"data-node-view-wrapper": ""
|
|
119
|
-
},
|
|
120
|
-
on: {
|
|
121
|
-
dragstart: this.onDragStart
|
|
122
|
-
}
|
|
123
|
-
},
|
|
124
|
-
this.$slots.default
|
|
125
|
-
);
|
|
126
|
-
}
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/NodeViewWrapper.ts
|
|
72
|
+
const NodeViewWrapper = {
|
|
73
|
+
props: { as: {
|
|
74
|
+
type: String,
|
|
75
|
+
default: "div"
|
|
76
|
+
} },
|
|
77
|
+
inject: ["onDragStart", "decorationClasses"],
|
|
78
|
+
render(createElement) {
|
|
79
|
+
return createElement(this.as, {
|
|
80
|
+
class: this.decorationClasses.value,
|
|
81
|
+
style: { whiteSpace: "normal" },
|
|
82
|
+
attrs: { "data-node-view-wrapper": "" },
|
|
83
|
+
on: { dragstart: this.onDragStart }
|
|
84
|
+
}, this.$slots.default);
|
|
85
|
+
}
|
|
127
86
|
};
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
// src/VueRenderer.ts
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/Vue.ts
|
|
89
|
+
const Vue = VueDefault;
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region src/VueRenderer.ts
|
|
92
|
+
/**
|
|
93
|
+
* The VueRenderer class is responsible for rendering a Vue component as a ProseMirror node view.
|
|
94
|
+
*/
|
|
138
95
|
var VueRenderer = class {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
this.ref.$destroy();
|
|
161
|
-
}
|
|
96
|
+
constructor(component, props) {
|
|
97
|
+
const Component = typeof component === "function" ? component : Vue.extend(component);
|
|
98
|
+
this.ref = new Component(props).$mount();
|
|
99
|
+
}
|
|
100
|
+
get element() {
|
|
101
|
+
return this.ref.$el;
|
|
102
|
+
}
|
|
103
|
+
updateProps(props = {}) {
|
|
104
|
+
var _this$ref$$props$edit, _this$ref$$props$edit2;
|
|
105
|
+
if (!this.ref.$props) return;
|
|
106
|
+
const currentVueConstructor = (_this$ref$$props$edit = (_this$ref$$props$edit2 = this.ref.$props.editor) === null || _this$ref$$props$edit2 === void 0 || (_this$ref$$props$edit2 = _this$ref$$props$edit2.contentComponent) === null || _this$ref$$props$edit2 === void 0 ? void 0 : _this$ref$$props$edit2.$options._base) !== null && _this$ref$$props$edit !== void 0 ? _this$ref$$props$edit : Vue;
|
|
107
|
+
const originalSilent = currentVueConstructor.config.silent;
|
|
108
|
+
currentVueConstructor.config.silent = true;
|
|
109
|
+
Object.entries(props).forEach(([key, value]) => {
|
|
110
|
+
this.ref.$props[key] = value;
|
|
111
|
+
});
|
|
112
|
+
currentVueConstructor.config.silent = originalSilent;
|
|
113
|
+
}
|
|
114
|
+
destroy() {
|
|
115
|
+
this.ref.$destroy();
|
|
116
|
+
}
|
|
162
117
|
};
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
118
|
+
//#endregion
|
|
119
|
+
//#region src/VueNodeViewRenderer.ts
|
|
120
|
+
const nodeViewProps = {
|
|
121
|
+
editor: objectProp().required,
|
|
122
|
+
node: objectProp().required,
|
|
123
|
+
decorations: objectProp().required,
|
|
124
|
+
selected: booleanProp().required,
|
|
125
|
+
extension: objectProp().required,
|
|
126
|
+
getPos: functionProp().required,
|
|
127
|
+
updateAttributes: functionProp().required,
|
|
128
|
+
deleteNode: functionProp().required
|
|
174
129
|
};
|
|
175
130
|
var VueNodeView = class extends NodeView {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
* Select the node.
|
|
347
|
-
* Add the `selected` prop and the `ProseMirror-selectednode` class.
|
|
348
|
-
*/
|
|
349
|
-
selectNode() {
|
|
350
|
-
this.renderer.updateProps({
|
|
351
|
-
selected: true
|
|
352
|
-
});
|
|
353
|
-
this.renderer.element.classList.add("ProseMirror-selectednode");
|
|
354
|
-
}
|
|
355
|
-
/**
|
|
356
|
-
* Deselect the node.
|
|
357
|
-
* Remove the `selected` prop and the `ProseMirror-selectednode` class.
|
|
358
|
-
*/
|
|
359
|
-
deselectNode() {
|
|
360
|
-
this.renderer.updateProps({
|
|
361
|
-
selected: false
|
|
362
|
-
});
|
|
363
|
-
this.renderer.element.classList.remove("ProseMirror-selectednode");
|
|
364
|
-
}
|
|
365
|
-
getDecorationClasses() {
|
|
366
|
-
return this.decorations.flatMap((item) => item.type.attrs.class).join(" ");
|
|
367
|
-
}
|
|
368
|
-
destroy() {
|
|
369
|
-
this.renderer.destroy();
|
|
370
|
-
this.editor.off("selectionUpdate", this.handleSelectionUpdate);
|
|
371
|
-
if (this.options.trackNodeViewPosition) {
|
|
372
|
-
this.editor.off("update", this.handlePositionUpdate);
|
|
373
|
-
}
|
|
374
|
-
this.contentDOMElement = null;
|
|
375
|
-
}
|
|
131
|
+
constructor(component, props, options) {
|
|
132
|
+
super(component, props, options);
|
|
133
|
+
this.handlePositionUpdate = () => {
|
|
134
|
+
const newPos = this.getPos();
|
|
135
|
+
if (typeof newPos !== "number" || newPos === this.currentPos) return;
|
|
136
|
+
this.currentPos = newPos;
|
|
137
|
+
this.renderer.updateProps({ getPos: () => this.getPos() });
|
|
138
|
+
};
|
|
139
|
+
if (this.options.trackNodeViewPosition) this.editor.on("update", this.handlePositionUpdate);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Called when the node view is mounted.
|
|
143
|
+
*/
|
|
144
|
+
mount() {
|
|
145
|
+
var _this$editor$contentC, _this$editor$contentC2;
|
|
146
|
+
const props = {
|
|
147
|
+
editor: this.editor,
|
|
148
|
+
node: this.node,
|
|
149
|
+
decorations: this.decorations,
|
|
150
|
+
innerDecorations: this.innerDecorations,
|
|
151
|
+
view: this.view,
|
|
152
|
+
selected: false,
|
|
153
|
+
extension: this.extension,
|
|
154
|
+
HTMLAttributes: this.HTMLAttributes,
|
|
155
|
+
getPos: () => this.getPos(),
|
|
156
|
+
updateAttributes: (attributes = {}) => this.updateAttributes(attributes),
|
|
157
|
+
deleteNode: () => this.deleteNode()
|
|
158
|
+
};
|
|
159
|
+
const mountProps = props;
|
|
160
|
+
const onDragStart = this.onDragStart.bind(this);
|
|
161
|
+
this.decorationClasses = Vue.observable({ value: this.getDecorationClasses() });
|
|
162
|
+
const Component = ((_this$editor$contentC = (_this$editor$contentC2 = this.editor.contentComponent) === null || _this$editor$contentC2 === void 0 ? void 0 : _this$editor$contentC2.$options._base) !== null && _this$editor$contentC !== void 0 ? _this$editor$contentC : Vue).extend(this.component).extend({
|
|
163
|
+
props: Object.keys(props),
|
|
164
|
+
provide: () => {
|
|
165
|
+
return {
|
|
166
|
+
onDragStart,
|
|
167
|
+
decorationClasses: this.decorationClasses,
|
|
168
|
+
nodeViewContentRef: (el) => {
|
|
169
|
+
if (!this.contentDOMElement) return;
|
|
170
|
+
if (el && el.firstChild !== this.contentDOMElement) el.appendChild(this.contentDOMElement);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
this.handleSelectionUpdate = this.handleSelectionUpdate.bind(this);
|
|
176
|
+
this.editor.on("selectionUpdate", this.handleSelectionUpdate);
|
|
177
|
+
this.currentPos = this.getPos();
|
|
178
|
+
if (!this.node.isLeaf) {
|
|
179
|
+
if (this.options.contentDOMElementTag) this.contentDOMElement = document.createElement(this.options.contentDOMElementTag);
|
|
180
|
+
else this.contentDOMElement = document.createElement(this.node.isInline ? "span" : "div");
|
|
181
|
+
this.contentDOMElement.style.whiteSpace = "inherit";
|
|
182
|
+
this.contentDOMElement.dataset.nodeViewContentVue = "";
|
|
183
|
+
}
|
|
184
|
+
this.renderer = new VueRenderer(Component, {
|
|
185
|
+
parent: this.editor.contentComponent,
|
|
186
|
+
propsData: mountProps
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Return the DOM element.
|
|
191
|
+
* This is the element that will be used to display the node view.
|
|
192
|
+
*/
|
|
193
|
+
get dom() {
|
|
194
|
+
if (!this.renderer.element.hasAttribute("data-node-view-wrapper")) throw Error("Please use the NodeViewWrapper component for your node view.");
|
|
195
|
+
return this.renderer.element;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Return the content DOM element.
|
|
199
|
+
* This is the element that will be used to display the rich-text content of the node.
|
|
200
|
+
*/
|
|
201
|
+
get contentDOM() {
|
|
202
|
+
if (this.node.isLeaf) return null;
|
|
203
|
+
return this.contentDOMElement;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* On editor selection update, check if the node is selected.
|
|
207
|
+
* If it is, call `selectNode`, otherwise call `deselectNode`.
|
|
208
|
+
*/
|
|
209
|
+
handleSelectionUpdate() {
|
|
210
|
+
const pos = this.getPos();
|
|
211
|
+
if (typeof pos !== "number") return;
|
|
212
|
+
if (isNodeViewSelected({
|
|
213
|
+
selection: this.editor.state.selection,
|
|
214
|
+
pos,
|
|
215
|
+
nodeSize: this.node.nodeSize,
|
|
216
|
+
selectedOnTextSelection: this.options.selectedOnTextSelection
|
|
217
|
+
})) {
|
|
218
|
+
if (this.renderer.ref.$props.selected) return;
|
|
219
|
+
this.selectNode();
|
|
220
|
+
} else {
|
|
221
|
+
if (!this.renderer.ref.$props.selected) return;
|
|
222
|
+
this.deselectNode();
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* On update, update the React component.
|
|
227
|
+
* To prevent unnecessary updates, the `update` option can be used.
|
|
228
|
+
*/
|
|
229
|
+
update(node, decorations, innerDecorations) {
|
|
230
|
+
const rerenderComponent = (props) => {
|
|
231
|
+
this.decorationClasses.value = this.getDecorationClasses();
|
|
232
|
+
this.renderer.updateProps(props);
|
|
233
|
+
};
|
|
234
|
+
if (typeof this.options.update === "function") {
|
|
235
|
+
const oldNode = this.node;
|
|
236
|
+
const oldDecorations = this.decorations;
|
|
237
|
+
const oldInnerDecorations = this.innerDecorations;
|
|
238
|
+
this.node = node;
|
|
239
|
+
this.decorations = decorations;
|
|
240
|
+
this.innerDecorations = innerDecorations;
|
|
241
|
+
return this.options.update({
|
|
242
|
+
oldNode,
|
|
243
|
+
oldDecorations,
|
|
244
|
+
newNode: node,
|
|
245
|
+
newDecorations: decorations,
|
|
246
|
+
oldInnerDecorations,
|
|
247
|
+
innerDecorations,
|
|
248
|
+
updateProps: () => rerenderComponent({
|
|
249
|
+
node,
|
|
250
|
+
decorations,
|
|
251
|
+
innerDecorations
|
|
252
|
+
})
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
if (node.type !== this.node.type) return false;
|
|
256
|
+
if (!(node !== this.node)) {
|
|
257
|
+
this.node = node;
|
|
258
|
+
this.decorations = decorations;
|
|
259
|
+
this.innerDecorations = innerDecorations;
|
|
260
|
+
this.decorationClasses.value = this.getDecorationClasses();
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
this.node = node;
|
|
264
|
+
this.decorations = decorations;
|
|
265
|
+
this.innerDecorations = innerDecorations;
|
|
266
|
+
this.currentPos = this.getPos();
|
|
267
|
+
const extraProps = {
|
|
268
|
+
node,
|
|
269
|
+
decorations,
|
|
270
|
+
innerDecorations
|
|
271
|
+
};
|
|
272
|
+
if (this.options.trackNodeViewPosition) extraProps.getPos = () => this.getPos();
|
|
273
|
+
rerenderComponent(extraProps);
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Select the node.
|
|
278
|
+
* Add the `selected` prop and the `ProseMirror-selectednode` class.
|
|
279
|
+
*/
|
|
280
|
+
selectNode() {
|
|
281
|
+
this.renderer.updateProps({ selected: true });
|
|
282
|
+
this.renderer.element.classList.add("ProseMirror-selectednode");
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Deselect the node.
|
|
286
|
+
* Remove the `selected` prop and the `ProseMirror-selectednode` class.
|
|
287
|
+
*/
|
|
288
|
+
deselectNode() {
|
|
289
|
+
this.renderer.updateProps({ selected: false });
|
|
290
|
+
this.renderer.element.classList.remove("ProseMirror-selectednode");
|
|
291
|
+
}
|
|
292
|
+
getDecorationClasses() {
|
|
293
|
+
return this.decorations.flatMap((item) => item.type.attrs.class).join(" ");
|
|
294
|
+
}
|
|
295
|
+
destroy() {
|
|
296
|
+
this.renderer.destroy();
|
|
297
|
+
this.editor.off("selectionUpdate", this.handleSelectionUpdate);
|
|
298
|
+
if (this.options.trackNodeViewPosition) this.editor.off("update", this.handlePositionUpdate);
|
|
299
|
+
this.contentDOMElement = null;
|
|
300
|
+
}
|
|
376
301
|
};
|
|
377
302
|
function VueNodeViewRenderer(component, options) {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
return new VueNodeView(component, props, options);
|
|
383
|
-
};
|
|
303
|
+
return (props) => {
|
|
304
|
+
if (!props.editor.contentComponent) return {};
|
|
305
|
+
return new VueNodeView(component, props, options);
|
|
306
|
+
};
|
|
384
307
|
}
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
308
|
+
//#endregion
|
|
309
|
+
//#region src/utils/createWidgetConstructor.ts
|
|
310
|
+
/**
|
|
311
|
+
* Builds the Vue 2 constructor for a widget component.
|
|
312
|
+
*
|
|
313
|
+
* Extends the editor's own Vue constructor so the widget shares its context,
|
|
314
|
+
* then auto-declares every passed prop the component does not declare itself.
|
|
315
|
+
* Vue 2 fixes the prop list at construction, so undeclared keys would be
|
|
316
|
+
* dropped. Existing declarations keep their type, default and validator.
|
|
317
|
+
*
|
|
318
|
+
* @param base The editor's Vue constructor, or undefined to fall back to `Vue`.
|
|
319
|
+
* @param component The widget component.
|
|
320
|
+
* @param props The props the widget is mounted with.
|
|
321
|
+
* @returns A constructor that accepts every key in `props`.
|
|
322
|
+
* @example
|
|
323
|
+
* createWidgetConstructor(undefined, MyWidget, { editor, getPos, label: 'a' })
|
|
324
|
+
*/
|
|
390
325
|
function createWidgetConstructor(base, component, props) {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
};
|
|
396
|
-
for (const name of Object.keys(props)) {
|
|
397
|
-
if (!Object.prototype.hasOwnProperty.call(declaredProps, name)) {
|
|
398
|
-
declaredProps[name] = null;
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
return Extended.extend({ props: declaredProps });
|
|
326
|
+
const Extended = (base !== null && base !== void 0 ? base : Vue).extend(component);
|
|
327
|
+
const declaredProps = { ...Extended.options.props };
|
|
328
|
+
for (const name of Object.keys(props)) if (!Object.prototype.hasOwnProperty.call(declaredProps, name)) declaredProps[name] = null;
|
|
329
|
+
return Extended.extend({ props: declaredProps });
|
|
402
330
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
331
|
+
//#endregion
|
|
332
|
+
//#region src/VueWidgetRenderer.ts
|
|
333
|
+
const WIDGET_CACHE = Symbol("tiptapVue2WidgetCache");
|
|
334
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
407
335
|
function warnUndeclaredProps(renderer, props, key) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
const declared = (_a = renderer.ref.$props) != null ? _a : {};
|
|
413
|
-
for (const name of Object.keys(props)) {
|
|
414
|
-
if (!(name in declared)) {
|
|
415
|
-
console.warn(
|
|
416
|
-
`[tiptap warn]: VueWidgetRenderer prop "${name}" was not passed on first mount for widget "${key}".`,
|
|
417
|
-
"Vue 2 cannot declare new props after mount, so this value is ignored."
|
|
418
|
-
);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
336
|
+
var _renderer$ref$$props;
|
|
337
|
+
if (!isDev) return;
|
|
338
|
+
const declared = (_renderer$ref$$props = renderer.ref.$props) !== null && _renderer$ref$$props !== void 0 ? _renderer$ref$$props : {};
|
|
339
|
+
for (const name of Object.keys(props)) if (!(name in declared)) console.warn(`[tiptap warn]: VueWidgetRenderer prop "${name}" was not passed on first mount for widget "${key}".`, "Vue 2 cannot declare new props after mount, so this value is ignored.");
|
|
421
340
|
}
|
|
422
341
|
function withPropWarnings(renderer, key) {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
342
|
+
return {
|
|
343
|
+
renderer,
|
|
344
|
+
updateProps: (props) => {
|
|
345
|
+
warnUndeclaredProps(renderer, props, key);
|
|
346
|
+
renderer.updateProps(props);
|
|
347
|
+
},
|
|
348
|
+
destroy: () => renderer.destroy()
|
|
349
|
+
};
|
|
431
350
|
}
|
|
351
|
+
/**
|
|
352
|
+
* Renders a Vue 2 component into a ProseMirror widget decoration.
|
|
353
|
+
* Reuses Tiptap's `VueRenderer` so the component is mounted under the editor's
|
|
354
|
+
* content component (inject/provide works as usual). Use a stable `key` for
|
|
355
|
+
* stateful widgets. The component must render a single root element.
|
|
356
|
+
* @example
|
|
357
|
+
* addDecorations() {
|
|
358
|
+
* return {
|
|
359
|
+
* create: ({ editor, state }) =>
|
|
360
|
+
* findMatches(state.doc).map(match =>
|
|
361
|
+
* VueWidgetRenderer(MyWidget, {
|
|
362
|
+
* editor, pos: match.pos, key: `match-${match.id}`,
|
|
363
|
+
* props: { label: match.label },
|
|
364
|
+
* }),
|
|
365
|
+
* ),
|
|
366
|
+
* }
|
|
367
|
+
* }
|
|
368
|
+
*/
|
|
432
369
|
function VueWidgetRenderer(component, options) {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
key
|
|
452
|
-
);
|
|
453
|
-
},
|
|
454
|
-
materialize: (entry) => entry.renderer.element
|
|
455
|
-
});
|
|
370
|
+
const { editor, key, props = {} } = options;
|
|
371
|
+
return createWidgetDecoration({
|
|
372
|
+
...options,
|
|
373
|
+
props,
|
|
374
|
+
cacheKey: WIDGET_CACHE,
|
|
375
|
+
context: (getPos) => ({
|
|
376
|
+
editor,
|
|
377
|
+
getPos
|
|
378
|
+
}),
|
|
379
|
+
create: (renderProps) => {
|
|
380
|
+
var _editor$contentCompon;
|
|
381
|
+
return withPropWarnings(new VueRenderer(createWidgetConstructor((_editor$contentCompon = editor.contentComponent) === null || _editor$contentCompon === void 0 || (_editor$contentCompon = _editor$contentCompon.$options) === null || _editor$contentCompon === void 0 ? void 0 : _editor$contentCompon._base, component, renderProps), {
|
|
382
|
+
parent: editor.contentComponent,
|
|
383
|
+
propsData: renderProps
|
|
384
|
+
}), key);
|
|
385
|
+
},
|
|
386
|
+
materialize: (entry) => entry.renderer.element
|
|
387
|
+
});
|
|
456
388
|
}
|
|
389
|
+
//#endregion
|
|
390
|
+
export { Editor, EditorContent, NodeViewContent, NodeViewWrapper, VueNodeViewRenderer, VueRenderer, VueWidgetRenderer, nodeViewProps };
|
|
457
391
|
|
|
458
|
-
// src/index.ts
|
|
459
|
-
export * from "@tiptap/core";
|
|
460
|
-
export {
|
|
461
|
-
Editor,
|
|
462
|
-
EditorContent,
|
|
463
|
-
NodeViewContent,
|
|
464
|
-
NodeViewWrapper,
|
|
465
|
-
VueNodeViewRenderer,
|
|
466
|
-
VueRenderer,
|
|
467
|
-
VueWidgetRenderer,
|
|
468
|
-
nodeViewProps
|
|
469
|
-
};
|
|
470
392
|
//# sourceMappingURL=index.js.map
|