@liveblocks/node-prosemirror 0.0.1 → 2.11.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/dist/index.d.mts +53 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.js +3228 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3228 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +72 -2
package/dist/index.js
ADDED
|
@@ -0,0 +1,3228 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }// src/index.ts
|
|
2
|
+
var _core = require('@liveblocks/core');
|
|
3
|
+
|
|
4
|
+
// src/version.ts
|
|
5
|
+
var PKG_NAME = "@liveblocks/node-prosemirror";
|
|
6
|
+
var PKG_VERSION = "2.11.1";
|
|
7
|
+
var PKG_FORMAT = "cjs";
|
|
8
|
+
|
|
9
|
+
// ../../node_modules/@tiptap/core/dist/index.js
|
|
10
|
+
var _state = require('@tiptap/pm/state');
|
|
11
|
+
var _view2 = require('@tiptap/pm/view');
|
|
12
|
+
var _keymap = require('@tiptap/pm/keymap');
|
|
13
|
+
var _model = require('@tiptap/pm/model');
|
|
14
|
+
var _transform = require('@tiptap/pm/transform');
|
|
15
|
+
var _commands = require('@tiptap/pm/commands');
|
|
16
|
+
var _schemalist = require('@tiptap/pm/schema-list');
|
|
17
|
+
function createChainableState(config) {
|
|
18
|
+
const { state, transaction } = config;
|
|
19
|
+
let { selection } = transaction;
|
|
20
|
+
let { doc } = transaction;
|
|
21
|
+
let { storedMarks } = transaction;
|
|
22
|
+
return {
|
|
23
|
+
...state,
|
|
24
|
+
apply: state.apply.bind(state),
|
|
25
|
+
applyTransaction: state.applyTransaction.bind(state),
|
|
26
|
+
plugins: state.plugins,
|
|
27
|
+
schema: state.schema,
|
|
28
|
+
reconfigure: state.reconfigure.bind(state),
|
|
29
|
+
toJSON: state.toJSON.bind(state),
|
|
30
|
+
get storedMarks() {
|
|
31
|
+
return storedMarks;
|
|
32
|
+
},
|
|
33
|
+
get selection() {
|
|
34
|
+
return selection;
|
|
35
|
+
},
|
|
36
|
+
get doc() {
|
|
37
|
+
return doc;
|
|
38
|
+
},
|
|
39
|
+
get tr() {
|
|
40
|
+
selection = transaction.selection;
|
|
41
|
+
doc = transaction.doc;
|
|
42
|
+
storedMarks = transaction.storedMarks;
|
|
43
|
+
return transaction;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
var CommandManager = class {
|
|
48
|
+
constructor(props) {
|
|
49
|
+
this.editor = props.editor;
|
|
50
|
+
this.rawCommands = this.editor.extensionManager.commands;
|
|
51
|
+
this.customState = props.state;
|
|
52
|
+
}
|
|
53
|
+
get hasCustomState() {
|
|
54
|
+
return !!this.customState;
|
|
55
|
+
}
|
|
56
|
+
get state() {
|
|
57
|
+
return this.customState || this.editor.state;
|
|
58
|
+
}
|
|
59
|
+
get commands() {
|
|
60
|
+
const { rawCommands, editor, state } = this;
|
|
61
|
+
const { view } = editor;
|
|
62
|
+
const { tr } = state;
|
|
63
|
+
const props = this.buildProps(tr);
|
|
64
|
+
return Object.fromEntries(Object.entries(rawCommands).map(([name, command2]) => {
|
|
65
|
+
const method = (...args) => {
|
|
66
|
+
const callback = command2(...args)(props);
|
|
67
|
+
if (!tr.getMeta("preventDispatch") && !this.hasCustomState) {
|
|
68
|
+
view.dispatch(tr);
|
|
69
|
+
}
|
|
70
|
+
return callback;
|
|
71
|
+
};
|
|
72
|
+
return [name, method];
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
get chain() {
|
|
76
|
+
return () => this.createChain();
|
|
77
|
+
}
|
|
78
|
+
get can() {
|
|
79
|
+
return () => this.createCan();
|
|
80
|
+
}
|
|
81
|
+
createChain(startTr, shouldDispatch = true) {
|
|
82
|
+
const { rawCommands, editor, state } = this;
|
|
83
|
+
const { view } = editor;
|
|
84
|
+
const callbacks = [];
|
|
85
|
+
const hasStartTransaction = !!startTr;
|
|
86
|
+
const tr = startTr || state.tr;
|
|
87
|
+
const run2 = () => {
|
|
88
|
+
if (!hasStartTransaction && shouldDispatch && !tr.getMeta("preventDispatch") && !this.hasCustomState) {
|
|
89
|
+
view.dispatch(tr);
|
|
90
|
+
}
|
|
91
|
+
return callbacks.every((callback) => callback === true);
|
|
92
|
+
};
|
|
93
|
+
const chain = {
|
|
94
|
+
...Object.fromEntries(Object.entries(rawCommands).map(([name, command2]) => {
|
|
95
|
+
const chainedCommand = (...args) => {
|
|
96
|
+
const props = this.buildProps(tr, shouldDispatch);
|
|
97
|
+
const callback = command2(...args)(props);
|
|
98
|
+
callbacks.push(callback);
|
|
99
|
+
return chain;
|
|
100
|
+
};
|
|
101
|
+
return [name, chainedCommand];
|
|
102
|
+
})),
|
|
103
|
+
run: run2
|
|
104
|
+
};
|
|
105
|
+
return chain;
|
|
106
|
+
}
|
|
107
|
+
createCan(startTr) {
|
|
108
|
+
const { rawCommands, state } = this;
|
|
109
|
+
const dispatch = false;
|
|
110
|
+
const tr = startTr || state.tr;
|
|
111
|
+
const props = this.buildProps(tr, dispatch);
|
|
112
|
+
const formattedCommands = Object.fromEntries(Object.entries(rawCommands).map(([name, command2]) => {
|
|
113
|
+
return [name, (...args) => command2(...args)({ ...props, dispatch: void 0 })];
|
|
114
|
+
}));
|
|
115
|
+
return {
|
|
116
|
+
...formattedCommands,
|
|
117
|
+
chain: () => this.createChain(tr, dispatch)
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
buildProps(tr, shouldDispatch = true) {
|
|
121
|
+
const { rawCommands, editor, state } = this;
|
|
122
|
+
const { view } = editor;
|
|
123
|
+
const props = {
|
|
124
|
+
tr,
|
|
125
|
+
editor,
|
|
126
|
+
view,
|
|
127
|
+
state: createChainableState({
|
|
128
|
+
state,
|
|
129
|
+
transaction: tr
|
|
130
|
+
}),
|
|
131
|
+
dispatch: shouldDispatch ? () => void 0 : void 0,
|
|
132
|
+
chain: () => this.createChain(tr, shouldDispatch),
|
|
133
|
+
can: () => this.createCan(tr),
|
|
134
|
+
get commands() {
|
|
135
|
+
return Object.fromEntries(Object.entries(rawCommands).map(([name, command2]) => {
|
|
136
|
+
return [name, (...args) => command2(...args)(props)];
|
|
137
|
+
}));
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
return props;
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
function getExtensionField(extension, field, context) {
|
|
144
|
+
if (extension.config[field] === void 0 && extension.parent) {
|
|
145
|
+
return getExtensionField(extension.parent, field, context);
|
|
146
|
+
}
|
|
147
|
+
if (typeof extension.config[field] === "function") {
|
|
148
|
+
const value = extension.config[field].bind({
|
|
149
|
+
...context,
|
|
150
|
+
parent: extension.parent ? getExtensionField(extension.parent, field, context) : null
|
|
151
|
+
});
|
|
152
|
+
return value;
|
|
153
|
+
}
|
|
154
|
+
return extension.config[field];
|
|
155
|
+
}
|
|
156
|
+
function splitExtensions(extensions) {
|
|
157
|
+
const baseExtensions = extensions.filter((extension) => extension.type === "extension");
|
|
158
|
+
const nodeExtensions = extensions.filter((extension) => extension.type === "node");
|
|
159
|
+
const markExtensions = extensions.filter((extension) => extension.type === "mark");
|
|
160
|
+
return {
|
|
161
|
+
baseExtensions,
|
|
162
|
+
nodeExtensions,
|
|
163
|
+
markExtensions
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function getAttributesFromExtensions(extensions) {
|
|
167
|
+
const extensionAttributes = [];
|
|
168
|
+
const { nodeExtensions, markExtensions } = splitExtensions(extensions);
|
|
169
|
+
const nodeAndMarkExtensions = [...nodeExtensions, ...markExtensions];
|
|
170
|
+
const defaultAttribute = {
|
|
171
|
+
default: null,
|
|
172
|
+
rendered: true,
|
|
173
|
+
renderHTML: null,
|
|
174
|
+
parseHTML: null,
|
|
175
|
+
keepOnSplit: true,
|
|
176
|
+
isRequired: false
|
|
177
|
+
};
|
|
178
|
+
extensions.forEach((extension) => {
|
|
179
|
+
const context = {
|
|
180
|
+
name: extension.name,
|
|
181
|
+
options: extension.options,
|
|
182
|
+
storage: extension.storage,
|
|
183
|
+
extensions: nodeAndMarkExtensions
|
|
184
|
+
};
|
|
185
|
+
const addGlobalAttributes = getExtensionField(extension, "addGlobalAttributes", context);
|
|
186
|
+
if (!addGlobalAttributes) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const globalAttributes = addGlobalAttributes();
|
|
190
|
+
globalAttributes.forEach((globalAttribute) => {
|
|
191
|
+
globalAttribute.types.forEach((type) => {
|
|
192
|
+
Object.entries(globalAttribute.attributes).forEach(([name, attribute]) => {
|
|
193
|
+
extensionAttributes.push({
|
|
194
|
+
type,
|
|
195
|
+
name,
|
|
196
|
+
attribute: {
|
|
197
|
+
...defaultAttribute,
|
|
198
|
+
...attribute
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
nodeAndMarkExtensions.forEach((extension) => {
|
|
206
|
+
const context = {
|
|
207
|
+
name: extension.name,
|
|
208
|
+
options: extension.options,
|
|
209
|
+
storage: extension.storage
|
|
210
|
+
};
|
|
211
|
+
const addAttributes = getExtensionField(extension, "addAttributes", context);
|
|
212
|
+
if (!addAttributes) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const attributes = addAttributes();
|
|
216
|
+
Object.entries(attributes).forEach(([name, attribute]) => {
|
|
217
|
+
const mergedAttr = {
|
|
218
|
+
...defaultAttribute,
|
|
219
|
+
...attribute
|
|
220
|
+
};
|
|
221
|
+
if (typeof (mergedAttr === null || mergedAttr === void 0 ? void 0 : mergedAttr.default) === "function") {
|
|
222
|
+
mergedAttr.default = mergedAttr.default();
|
|
223
|
+
}
|
|
224
|
+
if ((mergedAttr === null || mergedAttr === void 0 ? void 0 : mergedAttr.isRequired) && (mergedAttr === null || mergedAttr === void 0 ? void 0 : mergedAttr.default) === void 0) {
|
|
225
|
+
delete mergedAttr.default;
|
|
226
|
+
}
|
|
227
|
+
extensionAttributes.push({
|
|
228
|
+
type: extension.name,
|
|
229
|
+
name,
|
|
230
|
+
attribute: mergedAttr
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
return extensionAttributes;
|
|
235
|
+
}
|
|
236
|
+
function getNodeType(nameOrType, schema) {
|
|
237
|
+
if (typeof nameOrType === "string") {
|
|
238
|
+
if (!schema.nodes[nameOrType]) {
|
|
239
|
+
throw Error(`There is no node type named '${nameOrType}'. Maybe you forgot to add the extension?`);
|
|
240
|
+
}
|
|
241
|
+
return schema.nodes[nameOrType];
|
|
242
|
+
}
|
|
243
|
+
return nameOrType;
|
|
244
|
+
}
|
|
245
|
+
function mergeAttributes(...objects) {
|
|
246
|
+
return objects.filter((item) => !!item).reduce((items, item) => {
|
|
247
|
+
const mergedAttributes = { ...items };
|
|
248
|
+
Object.entries(item).forEach(([key, value]) => {
|
|
249
|
+
const exists = mergedAttributes[key];
|
|
250
|
+
if (!exists) {
|
|
251
|
+
mergedAttributes[key] = value;
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (key === "class") {
|
|
255
|
+
const valueClasses = value ? value.split(" ") : [];
|
|
256
|
+
const existingClasses = mergedAttributes[key] ? mergedAttributes[key].split(" ") : [];
|
|
257
|
+
const insertClasses = valueClasses.filter((valueClass) => !existingClasses.includes(valueClass));
|
|
258
|
+
mergedAttributes[key] = [...existingClasses, ...insertClasses].join(" ");
|
|
259
|
+
} else if (key === "style") {
|
|
260
|
+
const newStyles = value ? value.split(";").map((style) => style.trim()).filter(Boolean) : [];
|
|
261
|
+
const existingStyles = mergedAttributes[key] ? mergedAttributes[key].split(";").map((style) => style.trim()).filter(Boolean) : [];
|
|
262
|
+
const styleMap = /* @__PURE__ */ new Map();
|
|
263
|
+
existingStyles.forEach((style) => {
|
|
264
|
+
const [property, val] = style.split(":").map((part) => part.trim());
|
|
265
|
+
styleMap.set(property, val);
|
|
266
|
+
});
|
|
267
|
+
newStyles.forEach((style) => {
|
|
268
|
+
const [property, val] = style.split(":").map((part) => part.trim());
|
|
269
|
+
styleMap.set(property, val);
|
|
270
|
+
});
|
|
271
|
+
mergedAttributes[key] = Array.from(styleMap.entries()).map(([property, val]) => `${property}: ${val}`).join("; ");
|
|
272
|
+
} else {
|
|
273
|
+
mergedAttributes[key] = value;
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
return mergedAttributes;
|
|
277
|
+
}, {});
|
|
278
|
+
}
|
|
279
|
+
function getRenderedAttributes(nodeOrMark, extensionAttributes) {
|
|
280
|
+
return extensionAttributes.filter((attribute) => attribute.type === nodeOrMark.type.name).filter((item) => item.attribute.rendered).map((item) => {
|
|
281
|
+
if (!item.attribute.renderHTML) {
|
|
282
|
+
return {
|
|
283
|
+
[item.name]: nodeOrMark.attrs[item.name]
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
return item.attribute.renderHTML(nodeOrMark.attrs) || {};
|
|
287
|
+
}).reduce((attributes, attribute) => mergeAttributes(attributes, attribute), {});
|
|
288
|
+
}
|
|
289
|
+
function isFunction(value) {
|
|
290
|
+
return typeof value === "function";
|
|
291
|
+
}
|
|
292
|
+
function callOrReturn(value, context = void 0, ...props) {
|
|
293
|
+
if (isFunction(value)) {
|
|
294
|
+
if (context) {
|
|
295
|
+
return value.bind(context)(...props);
|
|
296
|
+
}
|
|
297
|
+
return value(...props);
|
|
298
|
+
}
|
|
299
|
+
return value;
|
|
300
|
+
}
|
|
301
|
+
function isEmptyObject(value = {}) {
|
|
302
|
+
return Object.keys(value).length === 0 && value.constructor === Object;
|
|
303
|
+
}
|
|
304
|
+
function fromString(value) {
|
|
305
|
+
if (typeof value !== "string") {
|
|
306
|
+
return value;
|
|
307
|
+
}
|
|
308
|
+
if (value.match(/^[+-]?(?:\d*\.)?\d+$/)) {
|
|
309
|
+
return Number(value);
|
|
310
|
+
}
|
|
311
|
+
if (value === "true") {
|
|
312
|
+
return true;
|
|
313
|
+
}
|
|
314
|
+
if (value === "false") {
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
return value;
|
|
318
|
+
}
|
|
319
|
+
function injectExtensionAttributesToParseRule(parseRule, extensionAttributes) {
|
|
320
|
+
if ("style" in parseRule) {
|
|
321
|
+
return parseRule;
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
...parseRule,
|
|
325
|
+
getAttrs: (node) => {
|
|
326
|
+
const oldAttributes = parseRule.getAttrs ? parseRule.getAttrs(node) : parseRule.attrs;
|
|
327
|
+
if (oldAttributes === false) {
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
const newAttributes = extensionAttributes.reduce((items, item) => {
|
|
331
|
+
const value = item.attribute.parseHTML ? item.attribute.parseHTML(node) : fromString(node.getAttribute(item.name));
|
|
332
|
+
if (value === null || value === void 0) {
|
|
333
|
+
return items;
|
|
334
|
+
}
|
|
335
|
+
return {
|
|
336
|
+
...items,
|
|
337
|
+
[item.name]: value
|
|
338
|
+
};
|
|
339
|
+
}, {});
|
|
340
|
+
return { ...oldAttributes, ...newAttributes };
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
function cleanUpSchemaItem(data) {
|
|
345
|
+
return Object.fromEntries(
|
|
346
|
+
// @ts-ignore
|
|
347
|
+
Object.entries(data).filter(([key, value]) => {
|
|
348
|
+
if (key === "attrs" && isEmptyObject(value)) {
|
|
349
|
+
return false;
|
|
350
|
+
}
|
|
351
|
+
return value !== null && value !== void 0;
|
|
352
|
+
})
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
function getSchemaByResolvedExtensions(extensions, editor) {
|
|
356
|
+
var _a;
|
|
357
|
+
const allAttributes = getAttributesFromExtensions(extensions);
|
|
358
|
+
const { nodeExtensions, markExtensions } = splitExtensions(extensions);
|
|
359
|
+
const topNode = (_a = nodeExtensions.find((extension) => getExtensionField(extension, "topNode"))) === null || _a === void 0 ? void 0 : _a.name;
|
|
360
|
+
const nodes = Object.fromEntries(nodeExtensions.map((extension) => {
|
|
361
|
+
const extensionAttributes = allAttributes.filter((attribute) => attribute.type === extension.name);
|
|
362
|
+
const context = {
|
|
363
|
+
name: extension.name,
|
|
364
|
+
options: extension.options,
|
|
365
|
+
storage: extension.storage,
|
|
366
|
+
editor
|
|
367
|
+
};
|
|
368
|
+
const extraNodeFields = extensions.reduce((fields, e) => {
|
|
369
|
+
const extendNodeSchema = getExtensionField(e, "extendNodeSchema", context);
|
|
370
|
+
return {
|
|
371
|
+
...fields,
|
|
372
|
+
...extendNodeSchema ? extendNodeSchema(extension) : {}
|
|
373
|
+
};
|
|
374
|
+
}, {});
|
|
375
|
+
const schema = cleanUpSchemaItem({
|
|
376
|
+
...extraNodeFields,
|
|
377
|
+
content: callOrReturn(getExtensionField(extension, "content", context)),
|
|
378
|
+
marks: callOrReturn(getExtensionField(extension, "marks", context)),
|
|
379
|
+
group: callOrReturn(getExtensionField(extension, "group", context)),
|
|
380
|
+
inline: callOrReturn(getExtensionField(extension, "inline", context)),
|
|
381
|
+
atom: callOrReturn(getExtensionField(extension, "atom", context)),
|
|
382
|
+
selectable: callOrReturn(getExtensionField(extension, "selectable", context)),
|
|
383
|
+
draggable: callOrReturn(getExtensionField(extension, "draggable", context)),
|
|
384
|
+
code: callOrReturn(getExtensionField(extension, "code", context)),
|
|
385
|
+
whitespace: callOrReturn(getExtensionField(extension, "whitespace", context)),
|
|
386
|
+
defining: callOrReturn(getExtensionField(extension, "defining", context)),
|
|
387
|
+
isolating: callOrReturn(getExtensionField(extension, "isolating", context)),
|
|
388
|
+
attrs: Object.fromEntries(extensionAttributes.map((extensionAttribute) => {
|
|
389
|
+
var _a2;
|
|
390
|
+
return [extensionAttribute.name, { default: (_a2 = extensionAttribute === null || extensionAttribute === void 0 ? void 0 : extensionAttribute.attribute) === null || _a2 === void 0 ? void 0 : _a2.default }];
|
|
391
|
+
}))
|
|
392
|
+
});
|
|
393
|
+
const parseHTML = callOrReturn(getExtensionField(extension, "parseHTML", context));
|
|
394
|
+
if (parseHTML) {
|
|
395
|
+
schema.parseDOM = parseHTML.map((parseRule) => injectExtensionAttributesToParseRule(parseRule, extensionAttributes));
|
|
396
|
+
}
|
|
397
|
+
const renderHTML = getExtensionField(extension, "renderHTML", context);
|
|
398
|
+
if (renderHTML) {
|
|
399
|
+
schema.toDOM = (node) => renderHTML({
|
|
400
|
+
node,
|
|
401
|
+
HTMLAttributes: getRenderedAttributes(node, extensionAttributes)
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
const renderText = getExtensionField(extension, "renderText", context);
|
|
405
|
+
if (renderText) {
|
|
406
|
+
schema.toText = renderText;
|
|
407
|
+
}
|
|
408
|
+
return [extension.name, schema];
|
|
409
|
+
}));
|
|
410
|
+
const marks = Object.fromEntries(markExtensions.map((extension) => {
|
|
411
|
+
const extensionAttributes = allAttributes.filter((attribute) => attribute.type === extension.name);
|
|
412
|
+
const context = {
|
|
413
|
+
name: extension.name,
|
|
414
|
+
options: extension.options,
|
|
415
|
+
storage: extension.storage,
|
|
416
|
+
editor
|
|
417
|
+
};
|
|
418
|
+
const extraMarkFields = extensions.reduce((fields, e) => {
|
|
419
|
+
const extendMarkSchema = getExtensionField(e, "extendMarkSchema", context);
|
|
420
|
+
return {
|
|
421
|
+
...fields,
|
|
422
|
+
...extendMarkSchema ? extendMarkSchema(extension) : {}
|
|
423
|
+
};
|
|
424
|
+
}, {});
|
|
425
|
+
const schema = cleanUpSchemaItem({
|
|
426
|
+
...extraMarkFields,
|
|
427
|
+
inclusive: callOrReturn(getExtensionField(extension, "inclusive", context)),
|
|
428
|
+
excludes: callOrReturn(getExtensionField(extension, "excludes", context)),
|
|
429
|
+
group: callOrReturn(getExtensionField(extension, "group", context)),
|
|
430
|
+
spanning: callOrReturn(getExtensionField(extension, "spanning", context)),
|
|
431
|
+
code: callOrReturn(getExtensionField(extension, "code", context)),
|
|
432
|
+
attrs: Object.fromEntries(extensionAttributes.map((extensionAttribute) => {
|
|
433
|
+
var _a2;
|
|
434
|
+
return [extensionAttribute.name, { default: (_a2 = extensionAttribute === null || extensionAttribute === void 0 ? void 0 : extensionAttribute.attribute) === null || _a2 === void 0 ? void 0 : _a2.default }];
|
|
435
|
+
}))
|
|
436
|
+
});
|
|
437
|
+
const parseHTML = callOrReturn(getExtensionField(extension, "parseHTML", context));
|
|
438
|
+
if (parseHTML) {
|
|
439
|
+
schema.parseDOM = parseHTML.map((parseRule) => injectExtensionAttributesToParseRule(parseRule, extensionAttributes));
|
|
440
|
+
}
|
|
441
|
+
const renderHTML = getExtensionField(extension, "renderHTML", context);
|
|
442
|
+
if (renderHTML) {
|
|
443
|
+
schema.toDOM = (mark) => renderHTML({
|
|
444
|
+
mark,
|
|
445
|
+
HTMLAttributes: getRenderedAttributes(mark, extensionAttributes)
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
return [extension.name, schema];
|
|
449
|
+
}));
|
|
450
|
+
return new (0, _model.Schema)({
|
|
451
|
+
topNode,
|
|
452
|
+
nodes,
|
|
453
|
+
marks
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
function getSchemaTypeByName(name, schema) {
|
|
457
|
+
return schema.nodes[name] || schema.marks[name] || null;
|
|
458
|
+
}
|
|
459
|
+
function isExtensionRulesEnabled(extension, enabled) {
|
|
460
|
+
if (Array.isArray(enabled)) {
|
|
461
|
+
return enabled.some((enabledExtension) => {
|
|
462
|
+
const name = typeof enabledExtension === "string" ? enabledExtension : enabledExtension.name;
|
|
463
|
+
return name === extension.name;
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
return enabled;
|
|
467
|
+
}
|
|
468
|
+
var getTextContentFromNodes = ($from, maxMatch = 500) => {
|
|
469
|
+
let textBefore = "";
|
|
470
|
+
const sliceEndPos = $from.parentOffset;
|
|
471
|
+
$from.parent.nodesBetween(Math.max(0, sliceEndPos - maxMatch), sliceEndPos, (node, pos, parent, index) => {
|
|
472
|
+
var _a, _b;
|
|
473
|
+
const chunk = ((_b = (_a = node.type.spec).toText) === null || _b === void 0 ? void 0 : _b.call(_a, {
|
|
474
|
+
node,
|
|
475
|
+
pos,
|
|
476
|
+
parent,
|
|
477
|
+
index
|
|
478
|
+
})) || node.textContent || "%leaf%";
|
|
479
|
+
textBefore += node.isAtom && !node.isText ? chunk : chunk.slice(0, Math.max(0, sliceEndPos - pos));
|
|
480
|
+
});
|
|
481
|
+
return textBefore;
|
|
482
|
+
};
|
|
483
|
+
function isRegExp(value) {
|
|
484
|
+
return Object.prototype.toString.call(value) === "[object RegExp]";
|
|
485
|
+
}
|
|
486
|
+
var inputRuleMatcherHandler = (text, find) => {
|
|
487
|
+
if (isRegExp(find)) {
|
|
488
|
+
return find.exec(text);
|
|
489
|
+
}
|
|
490
|
+
const inputRuleMatch = find(text);
|
|
491
|
+
if (!inputRuleMatch) {
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
const result = [inputRuleMatch.text];
|
|
495
|
+
result.index = inputRuleMatch.index;
|
|
496
|
+
result.input = text;
|
|
497
|
+
result.data = inputRuleMatch.data;
|
|
498
|
+
if (inputRuleMatch.replaceWith) {
|
|
499
|
+
if (!inputRuleMatch.text.includes(inputRuleMatch.replaceWith)) {
|
|
500
|
+
console.warn('[tiptap warn]: "inputRuleMatch.replaceWith" must be part of "inputRuleMatch.text".');
|
|
501
|
+
}
|
|
502
|
+
result.push(inputRuleMatch.replaceWith);
|
|
503
|
+
}
|
|
504
|
+
return result;
|
|
505
|
+
};
|
|
506
|
+
function run$1(config) {
|
|
507
|
+
var _a;
|
|
508
|
+
const { editor, from, to, text, rules, plugin } = config;
|
|
509
|
+
const { view } = editor;
|
|
510
|
+
if (view.composing) {
|
|
511
|
+
return false;
|
|
512
|
+
}
|
|
513
|
+
const $from = view.state.doc.resolve(from);
|
|
514
|
+
if (
|
|
515
|
+
// check for code node
|
|
516
|
+
$from.parent.type.spec.code || !!((_a = $from.nodeBefore || $from.nodeAfter) === null || _a === void 0 ? void 0 : _a.marks.find((mark) => mark.type.spec.code))
|
|
517
|
+
) {
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
520
|
+
let matched = false;
|
|
521
|
+
const textBefore = getTextContentFromNodes($from) + text;
|
|
522
|
+
rules.forEach((rule) => {
|
|
523
|
+
if (matched) {
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
const match = inputRuleMatcherHandler(textBefore, rule.find);
|
|
527
|
+
if (!match) {
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
const tr = view.state.tr;
|
|
531
|
+
const state = createChainableState({
|
|
532
|
+
state: view.state,
|
|
533
|
+
transaction: tr
|
|
534
|
+
});
|
|
535
|
+
const range = {
|
|
536
|
+
from: from - (match[0].length - text.length),
|
|
537
|
+
to
|
|
538
|
+
};
|
|
539
|
+
const { commands: commands2, chain, can } = new CommandManager({
|
|
540
|
+
editor,
|
|
541
|
+
state
|
|
542
|
+
});
|
|
543
|
+
const handler = rule.handler({
|
|
544
|
+
state,
|
|
545
|
+
range,
|
|
546
|
+
match,
|
|
547
|
+
commands: commands2,
|
|
548
|
+
chain,
|
|
549
|
+
can
|
|
550
|
+
});
|
|
551
|
+
if (handler === null || !tr.steps.length) {
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
tr.setMeta(plugin, {
|
|
555
|
+
transform: tr,
|
|
556
|
+
from,
|
|
557
|
+
to,
|
|
558
|
+
text
|
|
559
|
+
});
|
|
560
|
+
view.dispatch(tr);
|
|
561
|
+
matched = true;
|
|
562
|
+
});
|
|
563
|
+
return matched;
|
|
564
|
+
}
|
|
565
|
+
function inputRulesPlugin(props) {
|
|
566
|
+
const { editor, rules } = props;
|
|
567
|
+
const plugin = new (0, _state.Plugin)({
|
|
568
|
+
state: {
|
|
569
|
+
init() {
|
|
570
|
+
return null;
|
|
571
|
+
},
|
|
572
|
+
apply(tr, prev) {
|
|
573
|
+
const stored = tr.getMeta(plugin);
|
|
574
|
+
if (stored) {
|
|
575
|
+
return stored;
|
|
576
|
+
}
|
|
577
|
+
const simulatedInputMeta = tr.getMeta("applyInputRules");
|
|
578
|
+
const isSimulatedInput = !!simulatedInputMeta;
|
|
579
|
+
if (isSimulatedInput) {
|
|
580
|
+
setTimeout(() => {
|
|
581
|
+
const { from, text } = simulatedInputMeta;
|
|
582
|
+
const to = from + text.length;
|
|
583
|
+
run$1({
|
|
584
|
+
editor,
|
|
585
|
+
from,
|
|
586
|
+
to,
|
|
587
|
+
text,
|
|
588
|
+
rules,
|
|
589
|
+
plugin
|
|
590
|
+
});
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
return tr.selectionSet || tr.docChanged ? null : prev;
|
|
594
|
+
}
|
|
595
|
+
},
|
|
596
|
+
props: {
|
|
597
|
+
handleTextInput(view, from, to, text) {
|
|
598
|
+
return run$1({
|
|
599
|
+
editor,
|
|
600
|
+
from,
|
|
601
|
+
to,
|
|
602
|
+
text,
|
|
603
|
+
rules,
|
|
604
|
+
plugin
|
|
605
|
+
});
|
|
606
|
+
},
|
|
607
|
+
handleDOMEvents: {
|
|
608
|
+
compositionend: (view) => {
|
|
609
|
+
setTimeout(() => {
|
|
610
|
+
const { $cursor } = view.state.selection;
|
|
611
|
+
if ($cursor) {
|
|
612
|
+
run$1({
|
|
613
|
+
editor,
|
|
614
|
+
from: $cursor.pos,
|
|
615
|
+
to: $cursor.pos,
|
|
616
|
+
text: "",
|
|
617
|
+
rules,
|
|
618
|
+
plugin
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
});
|
|
622
|
+
return false;
|
|
623
|
+
}
|
|
624
|
+
},
|
|
625
|
+
// add support for input rules to trigger on enter
|
|
626
|
+
// this is useful for example for code blocks
|
|
627
|
+
handleKeyDown(view, event) {
|
|
628
|
+
if (event.key !== "Enter") {
|
|
629
|
+
return false;
|
|
630
|
+
}
|
|
631
|
+
const { $cursor } = view.state.selection;
|
|
632
|
+
if ($cursor) {
|
|
633
|
+
return run$1({
|
|
634
|
+
editor,
|
|
635
|
+
from: $cursor.pos,
|
|
636
|
+
to: $cursor.pos,
|
|
637
|
+
text: "\n",
|
|
638
|
+
rules,
|
|
639
|
+
plugin
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
return false;
|
|
643
|
+
}
|
|
644
|
+
},
|
|
645
|
+
// @ts-ignore
|
|
646
|
+
isInputRules: true
|
|
647
|
+
});
|
|
648
|
+
return plugin;
|
|
649
|
+
}
|
|
650
|
+
function getType(value) {
|
|
651
|
+
return Object.prototype.toString.call(value).slice(8, -1);
|
|
652
|
+
}
|
|
653
|
+
function isPlainObject(value) {
|
|
654
|
+
if (getType(value) !== "Object") {
|
|
655
|
+
return false;
|
|
656
|
+
}
|
|
657
|
+
return value.constructor === Object && Object.getPrototypeOf(value) === Object.prototype;
|
|
658
|
+
}
|
|
659
|
+
function mergeDeep(target, source) {
|
|
660
|
+
const output = { ...target };
|
|
661
|
+
if (isPlainObject(target) && isPlainObject(source)) {
|
|
662
|
+
Object.keys(source).forEach((key) => {
|
|
663
|
+
if (isPlainObject(source[key]) && isPlainObject(target[key])) {
|
|
664
|
+
output[key] = mergeDeep(target[key], source[key]);
|
|
665
|
+
} else {
|
|
666
|
+
output[key] = source[key];
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
return output;
|
|
671
|
+
}
|
|
672
|
+
var Mark = class _Mark {
|
|
673
|
+
constructor(config = {}) {
|
|
674
|
+
this.type = "mark";
|
|
675
|
+
this.name = "mark";
|
|
676
|
+
this.parent = null;
|
|
677
|
+
this.child = null;
|
|
678
|
+
this.config = {
|
|
679
|
+
name: this.name,
|
|
680
|
+
defaultOptions: {}
|
|
681
|
+
};
|
|
682
|
+
this.config = {
|
|
683
|
+
...this.config,
|
|
684
|
+
...config
|
|
685
|
+
};
|
|
686
|
+
this.name = this.config.name;
|
|
687
|
+
if (config.defaultOptions && Object.keys(config.defaultOptions).length > 0) {
|
|
688
|
+
console.warn(`[tiptap warn]: BREAKING CHANGE: "defaultOptions" is deprecated. Please use "addOptions" instead. Found in extension: "${this.name}".`);
|
|
689
|
+
}
|
|
690
|
+
this.options = this.config.defaultOptions;
|
|
691
|
+
if (this.config.addOptions) {
|
|
692
|
+
this.options = callOrReturn(getExtensionField(this, "addOptions", {
|
|
693
|
+
name: this.name
|
|
694
|
+
}));
|
|
695
|
+
}
|
|
696
|
+
this.storage = callOrReturn(getExtensionField(this, "addStorage", {
|
|
697
|
+
name: this.name,
|
|
698
|
+
options: this.options
|
|
699
|
+
})) || {};
|
|
700
|
+
}
|
|
701
|
+
static create(config = {}) {
|
|
702
|
+
return new _Mark(config);
|
|
703
|
+
}
|
|
704
|
+
configure(options = {}) {
|
|
705
|
+
const extension = this.extend({
|
|
706
|
+
...this.config,
|
|
707
|
+
addOptions: () => {
|
|
708
|
+
return mergeDeep(this.options, options);
|
|
709
|
+
}
|
|
710
|
+
});
|
|
711
|
+
extension.name = this.name;
|
|
712
|
+
extension.parent = this.parent;
|
|
713
|
+
return extension;
|
|
714
|
+
}
|
|
715
|
+
extend(extendedConfig = {}) {
|
|
716
|
+
const extension = new _Mark(extendedConfig);
|
|
717
|
+
extension.parent = this;
|
|
718
|
+
this.child = extension;
|
|
719
|
+
extension.name = extendedConfig.name ? extendedConfig.name : extension.parent.name;
|
|
720
|
+
if (extendedConfig.defaultOptions && Object.keys(extendedConfig.defaultOptions).length > 0) {
|
|
721
|
+
console.warn(`[tiptap warn]: BREAKING CHANGE: "defaultOptions" is deprecated. Please use "addOptions" instead. Found in extension: "${extension.name}".`);
|
|
722
|
+
}
|
|
723
|
+
extension.options = callOrReturn(getExtensionField(extension, "addOptions", {
|
|
724
|
+
name: extension.name
|
|
725
|
+
}));
|
|
726
|
+
extension.storage = callOrReturn(getExtensionField(extension, "addStorage", {
|
|
727
|
+
name: extension.name,
|
|
728
|
+
options: extension.options
|
|
729
|
+
}));
|
|
730
|
+
return extension;
|
|
731
|
+
}
|
|
732
|
+
static handleExit({ editor, mark }) {
|
|
733
|
+
const { tr } = editor.state;
|
|
734
|
+
const currentPos = editor.state.selection.$from;
|
|
735
|
+
const isAtEnd = currentPos.pos === currentPos.end();
|
|
736
|
+
if (isAtEnd) {
|
|
737
|
+
const currentMarks = currentPos.marks();
|
|
738
|
+
const isInMark = !!currentMarks.find((m) => (m === null || m === void 0 ? void 0 : m.type.name) === mark.name);
|
|
739
|
+
if (!isInMark) {
|
|
740
|
+
return false;
|
|
741
|
+
}
|
|
742
|
+
const removeMark = currentMarks.find((m) => (m === null || m === void 0 ? void 0 : m.type.name) === mark.name);
|
|
743
|
+
if (removeMark) {
|
|
744
|
+
tr.removeStoredMark(removeMark);
|
|
745
|
+
}
|
|
746
|
+
tr.insertText(" ", currentPos.pos);
|
|
747
|
+
editor.view.dispatch(tr);
|
|
748
|
+
return true;
|
|
749
|
+
}
|
|
750
|
+
return false;
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
function isNumber(value) {
|
|
754
|
+
return typeof value === "number";
|
|
755
|
+
}
|
|
756
|
+
var pasteRuleMatcherHandler = (text, find, event) => {
|
|
757
|
+
if (isRegExp(find)) {
|
|
758
|
+
return [...text.matchAll(find)];
|
|
759
|
+
}
|
|
760
|
+
const matches = find(text, event);
|
|
761
|
+
if (!matches) {
|
|
762
|
+
return [];
|
|
763
|
+
}
|
|
764
|
+
return matches.map((pasteRuleMatch) => {
|
|
765
|
+
const result = [pasteRuleMatch.text];
|
|
766
|
+
result.index = pasteRuleMatch.index;
|
|
767
|
+
result.input = text;
|
|
768
|
+
result.data = pasteRuleMatch.data;
|
|
769
|
+
if (pasteRuleMatch.replaceWith) {
|
|
770
|
+
if (!pasteRuleMatch.text.includes(pasteRuleMatch.replaceWith)) {
|
|
771
|
+
console.warn('[tiptap warn]: "pasteRuleMatch.replaceWith" must be part of "pasteRuleMatch.text".');
|
|
772
|
+
}
|
|
773
|
+
result.push(pasteRuleMatch.replaceWith);
|
|
774
|
+
}
|
|
775
|
+
return result;
|
|
776
|
+
});
|
|
777
|
+
};
|
|
778
|
+
function run(config) {
|
|
779
|
+
const { editor, state, from, to, rule, pasteEvent, dropEvent } = config;
|
|
780
|
+
const { commands: commands2, chain, can } = new CommandManager({
|
|
781
|
+
editor,
|
|
782
|
+
state
|
|
783
|
+
});
|
|
784
|
+
const handlers = [];
|
|
785
|
+
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
786
|
+
if (!node.isTextblock || node.type.spec.code) {
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
const resolvedFrom = Math.max(from, pos);
|
|
790
|
+
const resolvedTo = Math.min(to, pos + node.content.size);
|
|
791
|
+
const textToMatch = node.textBetween(resolvedFrom - pos, resolvedTo - pos, void 0, "\uFFFC");
|
|
792
|
+
const matches = pasteRuleMatcherHandler(textToMatch, rule.find, pasteEvent);
|
|
793
|
+
matches.forEach((match) => {
|
|
794
|
+
if (match.index === void 0) {
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
const start = resolvedFrom + match.index + 1;
|
|
798
|
+
const end = start + match[0].length;
|
|
799
|
+
const range = {
|
|
800
|
+
from: state.tr.mapping.map(start),
|
|
801
|
+
to: state.tr.mapping.map(end)
|
|
802
|
+
};
|
|
803
|
+
const handler = rule.handler({
|
|
804
|
+
state,
|
|
805
|
+
range,
|
|
806
|
+
match,
|
|
807
|
+
commands: commands2,
|
|
808
|
+
chain,
|
|
809
|
+
can,
|
|
810
|
+
pasteEvent,
|
|
811
|
+
dropEvent
|
|
812
|
+
});
|
|
813
|
+
handlers.push(handler);
|
|
814
|
+
});
|
|
815
|
+
});
|
|
816
|
+
const success = handlers.every((handler) => handler !== null);
|
|
817
|
+
return success;
|
|
818
|
+
}
|
|
819
|
+
var createClipboardPasteEvent = (text) => {
|
|
820
|
+
var _a;
|
|
821
|
+
const event = new ClipboardEvent("paste", {
|
|
822
|
+
clipboardData: new DataTransfer()
|
|
823
|
+
});
|
|
824
|
+
(_a = event.clipboardData) === null || _a === void 0 ? void 0 : _a.setData("text/html", text);
|
|
825
|
+
return event;
|
|
826
|
+
};
|
|
827
|
+
function pasteRulesPlugin(props) {
|
|
828
|
+
const { editor, rules } = props;
|
|
829
|
+
let dragSourceElement = null;
|
|
830
|
+
let isPastedFromProseMirror = false;
|
|
831
|
+
let isDroppedFromProseMirror = false;
|
|
832
|
+
let pasteEvent = typeof ClipboardEvent !== "undefined" ? new ClipboardEvent("paste") : null;
|
|
833
|
+
let dropEvent = typeof DragEvent !== "undefined" ? new DragEvent("drop") : null;
|
|
834
|
+
const processEvent = ({ state, from, to, rule, pasteEvt }) => {
|
|
835
|
+
const tr = state.tr;
|
|
836
|
+
const chainableState = createChainableState({
|
|
837
|
+
state,
|
|
838
|
+
transaction: tr
|
|
839
|
+
});
|
|
840
|
+
const handler = run({
|
|
841
|
+
editor,
|
|
842
|
+
state: chainableState,
|
|
843
|
+
from: Math.max(from - 1, 0),
|
|
844
|
+
to: to.b - 1,
|
|
845
|
+
rule,
|
|
846
|
+
pasteEvent: pasteEvt,
|
|
847
|
+
dropEvent
|
|
848
|
+
});
|
|
849
|
+
if (!handler || !tr.steps.length) {
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
dropEvent = typeof DragEvent !== "undefined" ? new DragEvent("drop") : null;
|
|
853
|
+
pasteEvent = typeof ClipboardEvent !== "undefined" ? new ClipboardEvent("paste") : null;
|
|
854
|
+
return tr;
|
|
855
|
+
};
|
|
856
|
+
const plugins = rules.map((rule) => {
|
|
857
|
+
return new (0, _state.Plugin)({
|
|
858
|
+
// we register a global drag handler to track the current drag source element
|
|
859
|
+
view(view) {
|
|
860
|
+
const handleDragstart = (event) => {
|
|
861
|
+
var _a;
|
|
862
|
+
dragSourceElement = ((_a = view.dom.parentElement) === null || _a === void 0 ? void 0 : _a.contains(event.target)) ? view.dom.parentElement : null;
|
|
863
|
+
};
|
|
864
|
+
window.addEventListener("dragstart", handleDragstart);
|
|
865
|
+
return {
|
|
866
|
+
destroy() {
|
|
867
|
+
window.removeEventListener("dragstart", handleDragstart);
|
|
868
|
+
}
|
|
869
|
+
};
|
|
870
|
+
},
|
|
871
|
+
props: {
|
|
872
|
+
handleDOMEvents: {
|
|
873
|
+
drop: (view, event) => {
|
|
874
|
+
isDroppedFromProseMirror = dragSourceElement === view.dom.parentElement;
|
|
875
|
+
dropEvent = event;
|
|
876
|
+
return false;
|
|
877
|
+
},
|
|
878
|
+
paste: (_view, event) => {
|
|
879
|
+
var _a;
|
|
880
|
+
const html = (_a = event.clipboardData) === null || _a === void 0 ? void 0 : _a.getData("text/html");
|
|
881
|
+
pasteEvent = event;
|
|
882
|
+
isPastedFromProseMirror = !!(html === null || html === void 0 ? void 0 : html.includes("data-pm-slice"));
|
|
883
|
+
return false;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
},
|
|
887
|
+
appendTransaction: (transactions, oldState, state) => {
|
|
888
|
+
const transaction = transactions[0];
|
|
889
|
+
const isPaste = transaction.getMeta("uiEvent") === "paste" && !isPastedFromProseMirror;
|
|
890
|
+
const isDrop = transaction.getMeta("uiEvent") === "drop" && !isDroppedFromProseMirror;
|
|
891
|
+
const simulatedPasteMeta = transaction.getMeta("applyPasteRules");
|
|
892
|
+
const isSimulatedPaste = !!simulatedPasteMeta;
|
|
893
|
+
if (!isPaste && !isDrop && !isSimulatedPaste) {
|
|
894
|
+
return;
|
|
895
|
+
}
|
|
896
|
+
if (isSimulatedPaste) {
|
|
897
|
+
const { from: from2, text } = simulatedPasteMeta;
|
|
898
|
+
const to2 = from2 + text.length;
|
|
899
|
+
const pasteEvt = createClipboardPasteEvent(text);
|
|
900
|
+
return processEvent({
|
|
901
|
+
rule,
|
|
902
|
+
state,
|
|
903
|
+
from: from2,
|
|
904
|
+
to: { b: to2 },
|
|
905
|
+
pasteEvt
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
const from = oldState.doc.content.findDiffStart(state.doc.content);
|
|
909
|
+
const to = oldState.doc.content.findDiffEnd(state.doc.content);
|
|
910
|
+
if (!isNumber(from) || !to || from === to.b) {
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
return processEvent({
|
|
914
|
+
rule,
|
|
915
|
+
state,
|
|
916
|
+
from,
|
|
917
|
+
to,
|
|
918
|
+
pasteEvt: pasteEvent
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
});
|
|
922
|
+
});
|
|
923
|
+
return plugins;
|
|
924
|
+
}
|
|
925
|
+
function findDuplicates(items) {
|
|
926
|
+
const filtered = items.filter((el, index) => items.indexOf(el) !== index);
|
|
927
|
+
return Array.from(new Set(filtered));
|
|
928
|
+
}
|
|
929
|
+
var ExtensionManager = class _ExtensionManager {
|
|
930
|
+
constructor(extensions, editor) {
|
|
931
|
+
this.splittableMarks = [];
|
|
932
|
+
this.editor = editor;
|
|
933
|
+
this.extensions = _ExtensionManager.resolve(extensions);
|
|
934
|
+
this.schema = getSchemaByResolvedExtensions(this.extensions, editor);
|
|
935
|
+
this.setupExtensions();
|
|
936
|
+
}
|
|
937
|
+
/**
|
|
938
|
+
* Returns a flattened and sorted extension list while
|
|
939
|
+
* also checking for duplicated extensions and warns the user.
|
|
940
|
+
* @param extensions An array of Tiptap extensions
|
|
941
|
+
* @returns An flattened and sorted array of Tiptap extensions
|
|
942
|
+
*/
|
|
943
|
+
static resolve(extensions) {
|
|
944
|
+
const resolvedExtensions = _ExtensionManager.sort(_ExtensionManager.flatten(extensions));
|
|
945
|
+
const duplicatedNames = findDuplicates(resolvedExtensions.map((extension) => extension.name));
|
|
946
|
+
if (duplicatedNames.length) {
|
|
947
|
+
console.warn(`[tiptap warn]: Duplicate extension names found: [${duplicatedNames.map((item) => `'${item}'`).join(", ")}]. This can lead to issues.`);
|
|
948
|
+
}
|
|
949
|
+
return resolvedExtensions;
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* Create a flattened array of extensions by traversing the `addExtensions` field.
|
|
953
|
+
* @param extensions An array of Tiptap extensions
|
|
954
|
+
* @returns A flattened array of Tiptap extensions
|
|
955
|
+
*/
|
|
956
|
+
static flatten(extensions) {
|
|
957
|
+
return extensions.map((extension) => {
|
|
958
|
+
const context = {
|
|
959
|
+
name: extension.name,
|
|
960
|
+
options: extension.options,
|
|
961
|
+
storage: extension.storage
|
|
962
|
+
};
|
|
963
|
+
const addExtensions = getExtensionField(extension, "addExtensions", context);
|
|
964
|
+
if (addExtensions) {
|
|
965
|
+
return [extension, ...this.flatten(addExtensions())];
|
|
966
|
+
}
|
|
967
|
+
return extension;
|
|
968
|
+
}).flat(10);
|
|
969
|
+
}
|
|
970
|
+
/**
|
|
971
|
+
* Sort extensions by priority.
|
|
972
|
+
* @param extensions An array of Tiptap extensions
|
|
973
|
+
* @returns A sorted array of Tiptap extensions by priority
|
|
974
|
+
*/
|
|
975
|
+
static sort(extensions) {
|
|
976
|
+
const defaultPriority = 100;
|
|
977
|
+
return extensions.sort((a, b) => {
|
|
978
|
+
const priorityA = getExtensionField(a, "priority") || defaultPriority;
|
|
979
|
+
const priorityB = getExtensionField(b, "priority") || defaultPriority;
|
|
980
|
+
if (priorityA > priorityB) {
|
|
981
|
+
return -1;
|
|
982
|
+
}
|
|
983
|
+
if (priorityA < priorityB) {
|
|
984
|
+
return 1;
|
|
985
|
+
}
|
|
986
|
+
return 0;
|
|
987
|
+
});
|
|
988
|
+
}
|
|
989
|
+
/**
|
|
990
|
+
* Get all commands from the extensions.
|
|
991
|
+
* @returns An object with all commands where the key is the command name and the value is the command function
|
|
992
|
+
*/
|
|
993
|
+
get commands() {
|
|
994
|
+
return this.extensions.reduce((commands2, extension) => {
|
|
995
|
+
const context = {
|
|
996
|
+
name: extension.name,
|
|
997
|
+
options: extension.options,
|
|
998
|
+
storage: extension.storage,
|
|
999
|
+
editor: this.editor,
|
|
1000
|
+
type: getSchemaTypeByName(extension.name, this.schema)
|
|
1001
|
+
};
|
|
1002
|
+
const addCommands = getExtensionField(extension, "addCommands", context);
|
|
1003
|
+
if (!addCommands) {
|
|
1004
|
+
return commands2;
|
|
1005
|
+
}
|
|
1006
|
+
return {
|
|
1007
|
+
...commands2,
|
|
1008
|
+
...addCommands()
|
|
1009
|
+
};
|
|
1010
|
+
}, {});
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Get all registered Prosemirror plugins from the extensions.
|
|
1014
|
+
* @returns An array of Prosemirror plugins
|
|
1015
|
+
*/
|
|
1016
|
+
get plugins() {
|
|
1017
|
+
const { editor } = this;
|
|
1018
|
+
const extensions = _ExtensionManager.sort([...this.extensions].reverse());
|
|
1019
|
+
const inputRules = [];
|
|
1020
|
+
const pasteRules = [];
|
|
1021
|
+
const allPlugins = extensions.map((extension) => {
|
|
1022
|
+
const context = {
|
|
1023
|
+
name: extension.name,
|
|
1024
|
+
options: extension.options,
|
|
1025
|
+
storage: extension.storage,
|
|
1026
|
+
editor,
|
|
1027
|
+
type: getSchemaTypeByName(extension.name, this.schema)
|
|
1028
|
+
};
|
|
1029
|
+
const plugins = [];
|
|
1030
|
+
const addKeyboardShortcuts = getExtensionField(extension, "addKeyboardShortcuts", context);
|
|
1031
|
+
let defaultBindings = {};
|
|
1032
|
+
if (extension.type === "mark" && getExtensionField(extension, "exitable", context)) {
|
|
1033
|
+
defaultBindings.ArrowRight = () => Mark.handleExit({ editor, mark: extension });
|
|
1034
|
+
}
|
|
1035
|
+
if (addKeyboardShortcuts) {
|
|
1036
|
+
const bindings = Object.fromEntries(Object.entries(addKeyboardShortcuts()).map(([shortcut, method]) => {
|
|
1037
|
+
return [shortcut, () => method({ editor })];
|
|
1038
|
+
}));
|
|
1039
|
+
defaultBindings = { ...defaultBindings, ...bindings };
|
|
1040
|
+
}
|
|
1041
|
+
const keyMapPlugin = _keymap.keymap.call(void 0, defaultBindings);
|
|
1042
|
+
plugins.push(keyMapPlugin);
|
|
1043
|
+
const addInputRules = getExtensionField(extension, "addInputRules", context);
|
|
1044
|
+
if (isExtensionRulesEnabled(extension, editor.options.enableInputRules) && addInputRules) {
|
|
1045
|
+
inputRules.push(...addInputRules());
|
|
1046
|
+
}
|
|
1047
|
+
const addPasteRules = getExtensionField(extension, "addPasteRules", context);
|
|
1048
|
+
if (isExtensionRulesEnabled(extension, editor.options.enablePasteRules) && addPasteRules) {
|
|
1049
|
+
pasteRules.push(...addPasteRules());
|
|
1050
|
+
}
|
|
1051
|
+
const addProseMirrorPlugins = getExtensionField(extension, "addProseMirrorPlugins", context);
|
|
1052
|
+
if (addProseMirrorPlugins) {
|
|
1053
|
+
const proseMirrorPlugins = addProseMirrorPlugins();
|
|
1054
|
+
plugins.push(...proseMirrorPlugins);
|
|
1055
|
+
}
|
|
1056
|
+
return plugins;
|
|
1057
|
+
}).flat();
|
|
1058
|
+
return [
|
|
1059
|
+
inputRulesPlugin({
|
|
1060
|
+
editor,
|
|
1061
|
+
rules: inputRules
|
|
1062
|
+
}),
|
|
1063
|
+
...pasteRulesPlugin({
|
|
1064
|
+
editor,
|
|
1065
|
+
rules: pasteRules
|
|
1066
|
+
}),
|
|
1067
|
+
...allPlugins
|
|
1068
|
+
];
|
|
1069
|
+
}
|
|
1070
|
+
/**
|
|
1071
|
+
* Get all attributes from the extensions.
|
|
1072
|
+
* @returns An array of attributes
|
|
1073
|
+
*/
|
|
1074
|
+
get attributes() {
|
|
1075
|
+
return getAttributesFromExtensions(this.extensions);
|
|
1076
|
+
}
|
|
1077
|
+
/**
|
|
1078
|
+
* Get all node views from the extensions.
|
|
1079
|
+
* @returns An object with all node views where the key is the node name and the value is the node view function
|
|
1080
|
+
*/
|
|
1081
|
+
get nodeViews() {
|
|
1082
|
+
const { editor } = this;
|
|
1083
|
+
const { nodeExtensions } = splitExtensions(this.extensions);
|
|
1084
|
+
return Object.fromEntries(nodeExtensions.filter((extension) => !!getExtensionField(extension, "addNodeView")).map((extension) => {
|
|
1085
|
+
const extensionAttributes = this.attributes.filter((attribute) => attribute.type === extension.name);
|
|
1086
|
+
const context = {
|
|
1087
|
+
name: extension.name,
|
|
1088
|
+
options: extension.options,
|
|
1089
|
+
storage: extension.storage,
|
|
1090
|
+
editor,
|
|
1091
|
+
type: getNodeType(extension.name, this.schema)
|
|
1092
|
+
};
|
|
1093
|
+
const addNodeView = getExtensionField(extension, "addNodeView", context);
|
|
1094
|
+
if (!addNodeView) {
|
|
1095
|
+
return [];
|
|
1096
|
+
}
|
|
1097
|
+
const nodeview = (node, view, getPos, decorations, innerDecorations) => {
|
|
1098
|
+
const HTMLAttributes = getRenderedAttributes(node, extensionAttributes);
|
|
1099
|
+
return addNodeView()({
|
|
1100
|
+
// pass-through
|
|
1101
|
+
node,
|
|
1102
|
+
view,
|
|
1103
|
+
getPos,
|
|
1104
|
+
decorations,
|
|
1105
|
+
innerDecorations,
|
|
1106
|
+
// tiptap-specific
|
|
1107
|
+
editor,
|
|
1108
|
+
extension,
|
|
1109
|
+
HTMLAttributes
|
|
1110
|
+
});
|
|
1111
|
+
};
|
|
1112
|
+
return [extension.name, nodeview];
|
|
1113
|
+
}));
|
|
1114
|
+
}
|
|
1115
|
+
/**
|
|
1116
|
+
* Go through all extensions, create extension storages & setup marks
|
|
1117
|
+
* & bind editor event listener.
|
|
1118
|
+
*/
|
|
1119
|
+
setupExtensions() {
|
|
1120
|
+
this.extensions.forEach((extension) => {
|
|
1121
|
+
var _a;
|
|
1122
|
+
this.editor.extensionStorage[extension.name] = extension.storage;
|
|
1123
|
+
const context = {
|
|
1124
|
+
name: extension.name,
|
|
1125
|
+
options: extension.options,
|
|
1126
|
+
storage: extension.storage,
|
|
1127
|
+
editor: this.editor,
|
|
1128
|
+
type: getSchemaTypeByName(extension.name, this.schema)
|
|
1129
|
+
};
|
|
1130
|
+
if (extension.type === "mark") {
|
|
1131
|
+
const keepOnSplit = (_a = callOrReturn(getExtensionField(extension, "keepOnSplit", context))) !== null && _a !== void 0 ? _a : true;
|
|
1132
|
+
if (keepOnSplit) {
|
|
1133
|
+
this.splittableMarks.push(extension.name);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
const onBeforeCreate = getExtensionField(extension, "onBeforeCreate", context);
|
|
1137
|
+
const onCreate = getExtensionField(extension, "onCreate", context);
|
|
1138
|
+
const onUpdate = getExtensionField(extension, "onUpdate", context);
|
|
1139
|
+
const onSelectionUpdate = getExtensionField(extension, "onSelectionUpdate", context);
|
|
1140
|
+
const onTransaction = getExtensionField(extension, "onTransaction", context);
|
|
1141
|
+
const onFocus = getExtensionField(extension, "onFocus", context);
|
|
1142
|
+
const onBlur = getExtensionField(extension, "onBlur", context);
|
|
1143
|
+
const onDestroy = getExtensionField(extension, "onDestroy", context);
|
|
1144
|
+
if (onBeforeCreate) {
|
|
1145
|
+
this.editor.on("beforeCreate", onBeforeCreate);
|
|
1146
|
+
}
|
|
1147
|
+
if (onCreate) {
|
|
1148
|
+
this.editor.on("create", onCreate);
|
|
1149
|
+
}
|
|
1150
|
+
if (onUpdate) {
|
|
1151
|
+
this.editor.on("update", onUpdate);
|
|
1152
|
+
}
|
|
1153
|
+
if (onSelectionUpdate) {
|
|
1154
|
+
this.editor.on("selectionUpdate", onSelectionUpdate);
|
|
1155
|
+
}
|
|
1156
|
+
if (onTransaction) {
|
|
1157
|
+
this.editor.on("transaction", onTransaction);
|
|
1158
|
+
}
|
|
1159
|
+
if (onFocus) {
|
|
1160
|
+
this.editor.on("focus", onFocus);
|
|
1161
|
+
}
|
|
1162
|
+
if (onBlur) {
|
|
1163
|
+
this.editor.on("blur", onBlur);
|
|
1164
|
+
}
|
|
1165
|
+
if (onDestroy) {
|
|
1166
|
+
this.editor.on("destroy", onDestroy);
|
|
1167
|
+
}
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
1170
|
+
};
|
|
1171
|
+
var Extension = class _Extension {
|
|
1172
|
+
constructor(config = {}) {
|
|
1173
|
+
this.type = "extension";
|
|
1174
|
+
this.name = "extension";
|
|
1175
|
+
this.parent = null;
|
|
1176
|
+
this.child = null;
|
|
1177
|
+
this.config = {
|
|
1178
|
+
name: this.name,
|
|
1179
|
+
defaultOptions: {}
|
|
1180
|
+
};
|
|
1181
|
+
this.config = {
|
|
1182
|
+
...this.config,
|
|
1183
|
+
...config
|
|
1184
|
+
};
|
|
1185
|
+
this.name = this.config.name;
|
|
1186
|
+
if (config.defaultOptions && Object.keys(config.defaultOptions).length > 0) {
|
|
1187
|
+
console.warn(`[tiptap warn]: BREAKING CHANGE: "defaultOptions" is deprecated. Please use "addOptions" instead. Found in extension: "${this.name}".`);
|
|
1188
|
+
}
|
|
1189
|
+
this.options = this.config.defaultOptions;
|
|
1190
|
+
if (this.config.addOptions) {
|
|
1191
|
+
this.options = callOrReturn(getExtensionField(this, "addOptions", {
|
|
1192
|
+
name: this.name
|
|
1193
|
+
}));
|
|
1194
|
+
}
|
|
1195
|
+
this.storage = callOrReturn(getExtensionField(this, "addStorage", {
|
|
1196
|
+
name: this.name,
|
|
1197
|
+
options: this.options
|
|
1198
|
+
})) || {};
|
|
1199
|
+
}
|
|
1200
|
+
static create(config = {}) {
|
|
1201
|
+
return new _Extension(config);
|
|
1202
|
+
}
|
|
1203
|
+
configure(options = {}) {
|
|
1204
|
+
const extension = this.extend({
|
|
1205
|
+
...this.config,
|
|
1206
|
+
addOptions: () => {
|
|
1207
|
+
return mergeDeep(this.options, options);
|
|
1208
|
+
}
|
|
1209
|
+
});
|
|
1210
|
+
extension.name = this.name;
|
|
1211
|
+
extension.parent = this.parent;
|
|
1212
|
+
return extension;
|
|
1213
|
+
}
|
|
1214
|
+
extend(extendedConfig = {}) {
|
|
1215
|
+
const extension = new _Extension({ ...this.config, ...extendedConfig });
|
|
1216
|
+
extension.parent = this;
|
|
1217
|
+
this.child = extension;
|
|
1218
|
+
extension.name = extendedConfig.name ? extendedConfig.name : extension.parent.name;
|
|
1219
|
+
if (extendedConfig.defaultOptions && Object.keys(extendedConfig.defaultOptions).length > 0) {
|
|
1220
|
+
console.warn(`[tiptap warn]: BREAKING CHANGE: "defaultOptions" is deprecated. Please use "addOptions" instead. Found in extension: "${extension.name}".`);
|
|
1221
|
+
}
|
|
1222
|
+
extension.options = callOrReturn(getExtensionField(extension, "addOptions", {
|
|
1223
|
+
name: extension.name
|
|
1224
|
+
}));
|
|
1225
|
+
extension.storage = callOrReturn(getExtensionField(extension, "addStorage", {
|
|
1226
|
+
name: extension.name,
|
|
1227
|
+
options: extension.options
|
|
1228
|
+
}));
|
|
1229
|
+
return extension;
|
|
1230
|
+
}
|
|
1231
|
+
};
|
|
1232
|
+
function getTextBetween(startNode, range, options) {
|
|
1233
|
+
const { from, to } = range;
|
|
1234
|
+
const { blockSeparator = "\n\n", textSerializers = {} } = options || {};
|
|
1235
|
+
let text = "";
|
|
1236
|
+
startNode.nodesBetween(from, to, (node, pos, parent, index) => {
|
|
1237
|
+
var _a;
|
|
1238
|
+
if (node.isBlock && pos > from) {
|
|
1239
|
+
text += blockSeparator;
|
|
1240
|
+
}
|
|
1241
|
+
const textSerializer = textSerializers === null || textSerializers === void 0 ? void 0 : textSerializers[node.type.name];
|
|
1242
|
+
if (textSerializer) {
|
|
1243
|
+
if (parent) {
|
|
1244
|
+
text += textSerializer({
|
|
1245
|
+
node,
|
|
1246
|
+
pos,
|
|
1247
|
+
parent,
|
|
1248
|
+
index,
|
|
1249
|
+
range
|
|
1250
|
+
});
|
|
1251
|
+
}
|
|
1252
|
+
return false;
|
|
1253
|
+
}
|
|
1254
|
+
if (node.isText) {
|
|
1255
|
+
text += (_a = node === null || node === void 0 ? void 0 : node.text) === null || _a === void 0 ? void 0 : _a.slice(Math.max(from, pos) - pos, to - pos);
|
|
1256
|
+
}
|
|
1257
|
+
});
|
|
1258
|
+
return text;
|
|
1259
|
+
}
|
|
1260
|
+
function getTextSerializersFromSchema(schema) {
|
|
1261
|
+
return Object.fromEntries(Object.entries(schema.nodes).filter(([, node]) => node.spec.toText).map(([name, node]) => [name, node.spec.toText]));
|
|
1262
|
+
}
|
|
1263
|
+
var ClipboardTextSerializer = Extension.create({
|
|
1264
|
+
name: "clipboardTextSerializer",
|
|
1265
|
+
addOptions() {
|
|
1266
|
+
return {
|
|
1267
|
+
blockSeparator: void 0
|
|
1268
|
+
};
|
|
1269
|
+
},
|
|
1270
|
+
addProseMirrorPlugins() {
|
|
1271
|
+
return [
|
|
1272
|
+
new (0, _state.Plugin)({
|
|
1273
|
+
key: new (0, _state.PluginKey)("clipboardTextSerializer"),
|
|
1274
|
+
props: {
|
|
1275
|
+
clipboardTextSerializer: () => {
|
|
1276
|
+
const { editor } = this;
|
|
1277
|
+
const { state, schema } = editor;
|
|
1278
|
+
const { doc, selection } = state;
|
|
1279
|
+
const { ranges } = selection;
|
|
1280
|
+
const from = Math.min(...ranges.map((range2) => range2.$from.pos));
|
|
1281
|
+
const to = Math.max(...ranges.map((range2) => range2.$to.pos));
|
|
1282
|
+
const textSerializers = getTextSerializersFromSchema(schema);
|
|
1283
|
+
const range = { from, to };
|
|
1284
|
+
return getTextBetween(doc, range, {
|
|
1285
|
+
...this.options.blockSeparator !== void 0 ? { blockSeparator: this.options.blockSeparator } : {},
|
|
1286
|
+
textSerializers
|
|
1287
|
+
});
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
})
|
|
1291
|
+
];
|
|
1292
|
+
}
|
|
1293
|
+
});
|
|
1294
|
+
var blur = () => ({ editor, view }) => {
|
|
1295
|
+
requestAnimationFrame(() => {
|
|
1296
|
+
var _a;
|
|
1297
|
+
if (!editor.isDestroyed) {
|
|
1298
|
+
view.dom.blur();
|
|
1299
|
+
(_a = window === null || window === void 0 ? void 0 : window.getSelection()) === null || _a === void 0 ? void 0 : _a.removeAllRanges();
|
|
1300
|
+
}
|
|
1301
|
+
});
|
|
1302
|
+
return true;
|
|
1303
|
+
};
|
|
1304
|
+
var clearContent = (emitUpdate = false) => ({ commands: commands2 }) => {
|
|
1305
|
+
return commands2.setContent("", emitUpdate);
|
|
1306
|
+
};
|
|
1307
|
+
var clearNodes = () => ({ state, tr, dispatch }) => {
|
|
1308
|
+
const { selection } = tr;
|
|
1309
|
+
const { ranges } = selection;
|
|
1310
|
+
if (!dispatch) {
|
|
1311
|
+
return true;
|
|
1312
|
+
}
|
|
1313
|
+
ranges.forEach(({ $from, $to }) => {
|
|
1314
|
+
state.doc.nodesBetween($from.pos, $to.pos, (node, pos) => {
|
|
1315
|
+
if (node.type.isText) {
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1318
|
+
const { doc, mapping } = tr;
|
|
1319
|
+
const $mappedFrom = doc.resolve(mapping.map(pos));
|
|
1320
|
+
const $mappedTo = doc.resolve(mapping.map(pos + node.nodeSize));
|
|
1321
|
+
const nodeRange = $mappedFrom.blockRange($mappedTo);
|
|
1322
|
+
if (!nodeRange) {
|
|
1323
|
+
return;
|
|
1324
|
+
}
|
|
1325
|
+
const targetLiftDepth = _transform.liftTarget.call(void 0, nodeRange);
|
|
1326
|
+
if (node.type.isTextblock) {
|
|
1327
|
+
const { defaultType } = $mappedFrom.parent.contentMatchAt($mappedFrom.index());
|
|
1328
|
+
tr.setNodeMarkup(nodeRange.start, defaultType);
|
|
1329
|
+
}
|
|
1330
|
+
if (targetLiftDepth || targetLiftDepth === 0) {
|
|
1331
|
+
tr.lift(nodeRange, targetLiftDepth);
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
});
|
|
1335
|
+
return true;
|
|
1336
|
+
};
|
|
1337
|
+
var command = (fn) => (props) => {
|
|
1338
|
+
return fn(props);
|
|
1339
|
+
};
|
|
1340
|
+
var createParagraphNear = () => ({ state, dispatch }) => {
|
|
1341
|
+
return _commands.createParagraphNear.call(void 0, state, dispatch);
|
|
1342
|
+
};
|
|
1343
|
+
var cut = (originRange, targetPos) => ({ editor, tr }) => {
|
|
1344
|
+
const { state } = editor;
|
|
1345
|
+
const contentSlice = state.doc.slice(originRange.from, originRange.to);
|
|
1346
|
+
tr.deleteRange(originRange.from, originRange.to);
|
|
1347
|
+
const newPos = tr.mapping.map(targetPos);
|
|
1348
|
+
tr.insert(newPos, contentSlice.content);
|
|
1349
|
+
tr.setSelection(new (0, _state.TextSelection)(tr.doc.resolve(newPos - 1)));
|
|
1350
|
+
return true;
|
|
1351
|
+
};
|
|
1352
|
+
var deleteCurrentNode = () => ({ tr, dispatch }) => {
|
|
1353
|
+
const { selection } = tr;
|
|
1354
|
+
const currentNode = selection.$anchor.node();
|
|
1355
|
+
if (currentNode.content.size > 0) {
|
|
1356
|
+
return false;
|
|
1357
|
+
}
|
|
1358
|
+
const $pos = tr.selection.$anchor;
|
|
1359
|
+
for (let depth = $pos.depth; depth > 0; depth -= 1) {
|
|
1360
|
+
const node = $pos.node(depth);
|
|
1361
|
+
if (node.type === currentNode.type) {
|
|
1362
|
+
if (dispatch) {
|
|
1363
|
+
const from = $pos.before(depth);
|
|
1364
|
+
const to = $pos.after(depth);
|
|
1365
|
+
tr.delete(from, to).scrollIntoView();
|
|
1366
|
+
}
|
|
1367
|
+
return true;
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
return false;
|
|
1371
|
+
};
|
|
1372
|
+
var deleteNode = (typeOrName) => ({ tr, state, dispatch }) => {
|
|
1373
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
1374
|
+
const $pos = tr.selection.$anchor;
|
|
1375
|
+
for (let depth = $pos.depth; depth > 0; depth -= 1) {
|
|
1376
|
+
const node = $pos.node(depth);
|
|
1377
|
+
if (node.type === type) {
|
|
1378
|
+
if (dispatch) {
|
|
1379
|
+
const from = $pos.before(depth);
|
|
1380
|
+
const to = $pos.after(depth);
|
|
1381
|
+
tr.delete(from, to).scrollIntoView();
|
|
1382
|
+
}
|
|
1383
|
+
return true;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
return false;
|
|
1387
|
+
};
|
|
1388
|
+
var deleteRange = (range) => ({ tr, dispatch }) => {
|
|
1389
|
+
const { from, to } = range;
|
|
1390
|
+
if (dispatch) {
|
|
1391
|
+
tr.delete(from, to);
|
|
1392
|
+
}
|
|
1393
|
+
return true;
|
|
1394
|
+
};
|
|
1395
|
+
var deleteSelection = () => ({ state, dispatch }) => {
|
|
1396
|
+
return _commands.deleteSelection.call(void 0, state, dispatch);
|
|
1397
|
+
};
|
|
1398
|
+
var enter = () => ({ commands: commands2 }) => {
|
|
1399
|
+
return commands2.keyboardShortcut("Enter");
|
|
1400
|
+
};
|
|
1401
|
+
var exitCode = () => ({ state, dispatch }) => {
|
|
1402
|
+
return _commands.exitCode.call(void 0, state, dispatch);
|
|
1403
|
+
};
|
|
1404
|
+
function objectIncludes(object1, object2, options = { strict: true }) {
|
|
1405
|
+
const keys = Object.keys(object2);
|
|
1406
|
+
if (!keys.length) {
|
|
1407
|
+
return true;
|
|
1408
|
+
}
|
|
1409
|
+
return keys.every((key) => {
|
|
1410
|
+
if (options.strict) {
|
|
1411
|
+
return object2[key] === object1[key];
|
|
1412
|
+
}
|
|
1413
|
+
if (isRegExp(object2[key])) {
|
|
1414
|
+
return object2[key].test(object1[key]);
|
|
1415
|
+
}
|
|
1416
|
+
return object2[key] === object1[key];
|
|
1417
|
+
});
|
|
1418
|
+
}
|
|
1419
|
+
function findMarkInSet(marks, type, attributes = {}) {
|
|
1420
|
+
return marks.find((item) => {
|
|
1421
|
+
return item.type === type && objectIncludes(item.attrs, attributes);
|
|
1422
|
+
});
|
|
1423
|
+
}
|
|
1424
|
+
function isMarkInSet(marks, type, attributes = {}) {
|
|
1425
|
+
return !!findMarkInSet(marks, type, attributes);
|
|
1426
|
+
}
|
|
1427
|
+
function getMarkRange($pos, type, attributes = {}) {
|
|
1428
|
+
if (!$pos || !type) {
|
|
1429
|
+
return;
|
|
1430
|
+
}
|
|
1431
|
+
let start = $pos.parent.childAfter($pos.parentOffset);
|
|
1432
|
+
if (!start.node || !start.node.marks.some((mark2) => mark2.type === type)) {
|
|
1433
|
+
start = $pos.parent.childBefore($pos.parentOffset);
|
|
1434
|
+
}
|
|
1435
|
+
if (!start.node || !start.node.marks.some((mark2) => mark2.type === type)) {
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
const mark = findMarkInSet([...start.node.marks], type, attributes);
|
|
1439
|
+
if (!mark) {
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
let startIndex = start.index;
|
|
1443
|
+
let startPos = $pos.start() + start.offset;
|
|
1444
|
+
let endIndex = startIndex + 1;
|
|
1445
|
+
let endPos = startPos + start.node.nodeSize;
|
|
1446
|
+
findMarkInSet([...start.node.marks], type, attributes);
|
|
1447
|
+
while (startIndex > 0 && mark.isInSet($pos.parent.child(startIndex - 1).marks)) {
|
|
1448
|
+
startIndex -= 1;
|
|
1449
|
+
startPos -= $pos.parent.child(startIndex).nodeSize;
|
|
1450
|
+
}
|
|
1451
|
+
while (endIndex < $pos.parent.childCount && isMarkInSet([...$pos.parent.child(endIndex).marks], type, attributes)) {
|
|
1452
|
+
endPos += $pos.parent.child(endIndex).nodeSize;
|
|
1453
|
+
endIndex += 1;
|
|
1454
|
+
}
|
|
1455
|
+
return {
|
|
1456
|
+
from: startPos,
|
|
1457
|
+
to: endPos
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
function getMarkType(nameOrType, schema) {
|
|
1461
|
+
if (typeof nameOrType === "string") {
|
|
1462
|
+
if (!schema.marks[nameOrType]) {
|
|
1463
|
+
throw Error(`There is no mark type named '${nameOrType}'. Maybe you forgot to add the extension?`);
|
|
1464
|
+
}
|
|
1465
|
+
return schema.marks[nameOrType];
|
|
1466
|
+
}
|
|
1467
|
+
return nameOrType;
|
|
1468
|
+
}
|
|
1469
|
+
var extendMarkRange = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => {
|
|
1470
|
+
const type = getMarkType(typeOrName, state.schema);
|
|
1471
|
+
const { doc, selection } = tr;
|
|
1472
|
+
const { $from, from, to } = selection;
|
|
1473
|
+
if (dispatch) {
|
|
1474
|
+
const range = getMarkRange($from, type, attributes);
|
|
1475
|
+
if (range && range.from <= from && range.to >= to) {
|
|
1476
|
+
const newSelection = _state.TextSelection.create(doc, range.from, range.to);
|
|
1477
|
+
tr.setSelection(newSelection);
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
return true;
|
|
1481
|
+
};
|
|
1482
|
+
var first = (commands2) => (props) => {
|
|
1483
|
+
const items = typeof commands2 === "function" ? commands2(props) : commands2;
|
|
1484
|
+
for (let i = 0; i < items.length; i += 1) {
|
|
1485
|
+
if (items[i](props)) {
|
|
1486
|
+
return true;
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
return false;
|
|
1490
|
+
};
|
|
1491
|
+
function isTextSelection(value) {
|
|
1492
|
+
return value instanceof _state.TextSelection;
|
|
1493
|
+
}
|
|
1494
|
+
function minMax(value = 0, min = 0, max = 0) {
|
|
1495
|
+
return Math.min(Math.max(value, min), max);
|
|
1496
|
+
}
|
|
1497
|
+
function resolveFocusPosition(doc, position = null) {
|
|
1498
|
+
if (!position) {
|
|
1499
|
+
return null;
|
|
1500
|
+
}
|
|
1501
|
+
const selectionAtStart = _state.Selection.atStart(doc);
|
|
1502
|
+
const selectionAtEnd = _state.Selection.atEnd(doc);
|
|
1503
|
+
if (position === "start" || position === true) {
|
|
1504
|
+
return selectionAtStart;
|
|
1505
|
+
}
|
|
1506
|
+
if (position === "end") {
|
|
1507
|
+
return selectionAtEnd;
|
|
1508
|
+
}
|
|
1509
|
+
const minPos = selectionAtStart.from;
|
|
1510
|
+
const maxPos = selectionAtEnd.to;
|
|
1511
|
+
if (position === "all") {
|
|
1512
|
+
return _state.TextSelection.create(doc, minMax(0, minPos, maxPos), minMax(doc.content.size, minPos, maxPos));
|
|
1513
|
+
}
|
|
1514
|
+
return _state.TextSelection.create(doc, minMax(position, minPos, maxPos), minMax(position, minPos, maxPos));
|
|
1515
|
+
}
|
|
1516
|
+
function isiOS() {
|
|
1517
|
+
return [
|
|
1518
|
+
"iPad Simulator",
|
|
1519
|
+
"iPhone Simulator",
|
|
1520
|
+
"iPod Simulator",
|
|
1521
|
+
"iPad",
|
|
1522
|
+
"iPhone",
|
|
1523
|
+
"iPod"
|
|
1524
|
+
].includes(navigator.platform) || navigator.userAgent.includes("Mac") && "ontouchend" in document;
|
|
1525
|
+
}
|
|
1526
|
+
var focus = (position = null, options = {}) => ({ editor, view, tr, dispatch }) => {
|
|
1527
|
+
options = {
|
|
1528
|
+
scrollIntoView: true,
|
|
1529
|
+
...options
|
|
1530
|
+
};
|
|
1531
|
+
const delayedFocus = () => {
|
|
1532
|
+
if (isiOS()) {
|
|
1533
|
+
view.dom.focus();
|
|
1534
|
+
}
|
|
1535
|
+
requestAnimationFrame(() => {
|
|
1536
|
+
if (!editor.isDestroyed) {
|
|
1537
|
+
view.focus();
|
|
1538
|
+
if (options === null || options === void 0 ? void 0 : options.scrollIntoView) {
|
|
1539
|
+
editor.commands.scrollIntoView();
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
});
|
|
1543
|
+
};
|
|
1544
|
+
if (view.hasFocus() && position === null || position === false) {
|
|
1545
|
+
return true;
|
|
1546
|
+
}
|
|
1547
|
+
if (dispatch && position === null && !isTextSelection(editor.state.selection)) {
|
|
1548
|
+
delayedFocus();
|
|
1549
|
+
return true;
|
|
1550
|
+
}
|
|
1551
|
+
const selection = resolveFocusPosition(tr.doc, position) || editor.state.selection;
|
|
1552
|
+
const isSameSelection = editor.state.selection.eq(selection);
|
|
1553
|
+
if (dispatch) {
|
|
1554
|
+
if (!isSameSelection) {
|
|
1555
|
+
tr.setSelection(selection);
|
|
1556
|
+
}
|
|
1557
|
+
if (isSameSelection && tr.storedMarks) {
|
|
1558
|
+
tr.setStoredMarks(tr.storedMarks);
|
|
1559
|
+
}
|
|
1560
|
+
delayedFocus();
|
|
1561
|
+
}
|
|
1562
|
+
return true;
|
|
1563
|
+
};
|
|
1564
|
+
var forEach = (items, fn) => (props) => {
|
|
1565
|
+
return items.every((item, index) => fn(item, { ...props, index }));
|
|
1566
|
+
};
|
|
1567
|
+
var insertContent = (value, options) => ({ tr, commands: commands2 }) => {
|
|
1568
|
+
return commands2.insertContentAt({ from: tr.selection.from, to: tr.selection.to }, value, options);
|
|
1569
|
+
};
|
|
1570
|
+
var removeWhitespaces = (node) => {
|
|
1571
|
+
const children = node.childNodes;
|
|
1572
|
+
for (let i = children.length - 1; i >= 0; i -= 1) {
|
|
1573
|
+
const child = children[i];
|
|
1574
|
+
if (child.nodeType === 3 && child.nodeValue && /^(\n\s\s|\n)$/.test(child.nodeValue)) {
|
|
1575
|
+
node.removeChild(child);
|
|
1576
|
+
} else if (child.nodeType === 1) {
|
|
1577
|
+
removeWhitespaces(child);
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
return node;
|
|
1581
|
+
};
|
|
1582
|
+
function elementFromString(value) {
|
|
1583
|
+
const wrappedValue = `<body>${value}</body>`;
|
|
1584
|
+
const html = new window.DOMParser().parseFromString(wrappedValue, "text/html").body;
|
|
1585
|
+
return removeWhitespaces(html);
|
|
1586
|
+
}
|
|
1587
|
+
function createNodeFromContent(content, schema, options) {
|
|
1588
|
+
options = {
|
|
1589
|
+
slice: true,
|
|
1590
|
+
parseOptions: {},
|
|
1591
|
+
...options
|
|
1592
|
+
};
|
|
1593
|
+
const isJSONContent = typeof content === "object" && content !== null;
|
|
1594
|
+
const isTextContent = typeof content === "string";
|
|
1595
|
+
if (isJSONContent) {
|
|
1596
|
+
try {
|
|
1597
|
+
const isArrayContent = Array.isArray(content) && content.length > 0;
|
|
1598
|
+
if (isArrayContent) {
|
|
1599
|
+
return _model.Fragment.fromArray(content.map((item) => schema.nodeFromJSON(item)));
|
|
1600
|
+
}
|
|
1601
|
+
const node = schema.nodeFromJSON(content);
|
|
1602
|
+
if (options.errorOnInvalidContent) {
|
|
1603
|
+
node.check();
|
|
1604
|
+
}
|
|
1605
|
+
return node;
|
|
1606
|
+
} catch (error) {
|
|
1607
|
+
if (options.errorOnInvalidContent) {
|
|
1608
|
+
throw new Error("[tiptap error]: Invalid JSON content", { cause: error });
|
|
1609
|
+
}
|
|
1610
|
+
console.warn("[tiptap warn]: Invalid content.", "Passed value:", content, "Error:", error);
|
|
1611
|
+
return createNodeFromContent("", schema, options);
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
if (isTextContent) {
|
|
1615
|
+
if (options.errorOnInvalidContent) {
|
|
1616
|
+
let hasInvalidContent = false;
|
|
1617
|
+
let invalidContent = "";
|
|
1618
|
+
const contentCheckSchema = new (0, _model.Schema)({
|
|
1619
|
+
topNode: schema.spec.topNode,
|
|
1620
|
+
marks: schema.spec.marks,
|
|
1621
|
+
// Prosemirror's schemas are executed such that: the last to execute, matches last
|
|
1622
|
+
// This means that we can add a catch-all node at the end of the schema to catch any content that we don't know how to handle
|
|
1623
|
+
nodes: schema.spec.nodes.append({
|
|
1624
|
+
__tiptap__private__unknown__catch__all__node: {
|
|
1625
|
+
content: "inline*",
|
|
1626
|
+
group: "block",
|
|
1627
|
+
parseDOM: [
|
|
1628
|
+
{
|
|
1629
|
+
tag: "*",
|
|
1630
|
+
getAttrs: (e) => {
|
|
1631
|
+
hasInvalidContent = true;
|
|
1632
|
+
invalidContent = typeof e === "string" ? e : e.outerHTML;
|
|
1633
|
+
return null;
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
]
|
|
1637
|
+
}
|
|
1638
|
+
})
|
|
1639
|
+
});
|
|
1640
|
+
if (options.slice) {
|
|
1641
|
+
_model.DOMParser.fromSchema(contentCheckSchema).parseSlice(elementFromString(content), options.parseOptions);
|
|
1642
|
+
} else {
|
|
1643
|
+
_model.DOMParser.fromSchema(contentCheckSchema).parse(elementFromString(content), options.parseOptions);
|
|
1644
|
+
}
|
|
1645
|
+
if (options.errorOnInvalidContent && hasInvalidContent) {
|
|
1646
|
+
throw new Error("[tiptap error]: Invalid HTML content", { cause: new Error(`Invalid element found: ${invalidContent}`) });
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
const parser = _model.DOMParser.fromSchema(schema);
|
|
1650
|
+
if (options.slice) {
|
|
1651
|
+
return parser.parseSlice(elementFromString(content), options.parseOptions).content;
|
|
1652
|
+
}
|
|
1653
|
+
return parser.parse(elementFromString(content), options.parseOptions);
|
|
1654
|
+
}
|
|
1655
|
+
return createNodeFromContent("", schema, options);
|
|
1656
|
+
}
|
|
1657
|
+
function selectionToInsertionEnd(tr, startLen, bias) {
|
|
1658
|
+
const last = tr.steps.length - 1;
|
|
1659
|
+
if (last < startLen) {
|
|
1660
|
+
return;
|
|
1661
|
+
}
|
|
1662
|
+
const step = tr.steps[last];
|
|
1663
|
+
if (!(step instanceof _transform.ReplaceStep || step instanceof _transform.ReplaceAroundStep)) {
|
|
1664
|
+
return;
|
|
1665
|
+
}
|
|
1666
|
+
const map = tr.mapping.maps[last];
|
|
1667
|
+
let end = 0;
|
|
1668
|
+
map.forEach((_from, _to, _newFrom, newTo) => {
|
|
1669
|
+
if (end === 0) {
|
|
1670
|
+
end = newTo;
|
|
1671
|
+
}
|
|
1672
|
+
});
|
|
1673
|
+
tr.setSelection(_state.Selection.near(tr.doc.resolve(end), bias));
|
|
1674
|
+
}
|
|
1675
|
+
var isFragment = (nodeOrFragment) => {
|
|
1676
|
+
return !("type" in nodeOrFragment);
|
|
1677
|
+
};
|
|
1678
|
+
var insertContentAt = (position, value, options) => ({ tr, dispatch, editor }) => {
|
|
1679
|
+
var _a;
|
|
1680
|
+
if (dispatch) {
|
|
1681
|
+
options = {
|
|
1682
|
+
parseOptions: editor.options.parseOptions,
|
|
1683
|
+
updateSelection: true,
|
|
1684
|
+
applyInputRules: false,
|
|
1685
|
+
applyPasteRules: false,
|
|
1686
|
+
...options
|
|
1687
|
+
};
|
|
1688
|
+
let content;
|
|
1689
|
+
try {
|
|
1690
|
+
content = createNodeFromContent(value, editor.schema, {
|
|
1691
|
+
parseOptions: {
|
|
1692
|
+
preserveWhitespace: "full",
|
|
1693
|
+
...options.parseOptions
|
|
1694
|
+
},
|
|
1695
|
+
errorOnInvalidContent: (_a = options.errorOnInvalidContent) !== null && _a !== void 0 ? _a : editor.options.enableContentCheck
|
|
1696
|
+
});
|
|
1697
|
+
} catch (e) {
|
|
1698
|
+
editor.emit("contentError", {
|
|
1699
|
+
editor,
|
|
1700
|
+
error: e,
|
|
1701
|
+
disableCollaboration: () => {
|
|
1702
|
+
if (editor.storage.collaboration) {
|
|
1703
|
+
editor.storage.collaboration.isDisabled = true;
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
});
|
|
1707
|
+
return false;
|
|
1708
|
+
}
|
|
1709
|
+
let { from, to } = typeof position === "number" ? { from: position, to: position } : { from: position.from, to: position.to };
|
|
1710
|
+
let isOnlyTextContent = true;
|
|
1711
|
+
let isOnlyBlockContent = true;
|
|
1712
|
+
const nodes = isFragment(content) ? content : [content];
|
|
1713
|
+
nodes.forEach((node) => {
|
|
1714
|
+
node.check();
|
|
1715
|
+
isOnlyTextContent = isOnlyTextContent ? node.isText && node.marks.length === 0 : false;
|
|
1716
|
+
isOnlyBlockContent = isOnlyBlockContent ? node.isBlock : false;
|
|
1717
|
+
});
|
|
1718
|
+
if (from === to && isOnlyBlockContent) {
|
|
1719
|
+
const { parent } = tr.doc.resolve(from);
|
|
1720
|
+
const isEmptyTextBlock = parent.isTextblock && !parent.type.spec.code && !parent.childCount;
|
|
1721
|
+
if (isEmptyTextBlock) {
|
|
1722
|
+
from -= 1;
|
|
1723
|
+
to += 1;
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
let newContent;
|
|
1727
|
+
if (isOnlyTextContent) {
|
|
1728
|
+
if (Array.isArray(value)) {
|
|
1729
|
+
newContent = value.map((v) => v.text || "").join("");
|
|
1730
|
+
} else if (typeof value === "object" && !!value && !!value.text) {
|
|
1731
|
+
newContent = value.text;
|
|
1732
|
+
} else {
|
|
1733
|
+
newContent = value;
|
|
1734
|
+
}
|
|
1735
|
+
tr.insertText(newContent, from, to);
|
|
1736
|
+
} else {
|
|
1737
|
+
newContent = content;
|
|
1738
|
+
tr.replaceWith(from, to, newContent);
|
|
1739
|
+
}
|
|
1740
|
+
if (options.updateSelection) {
|
|
1741
|
+
selectionToInsertionEnd(tr, tr.steps.length - 1, -1);
|
|
1742
|
+
}
|
|
1743
|
+
if (options.applyInputRules) {
|
|
1744
|
+
tr.setMeta("applyInputRules", { from, text: newContent });
|
|
1745
|
+
}
|
|
1746
|
+
if (options.applyPasteRules) {
|
|
1747
|
+
tr.setMeta("applyPasteRules", { from, text: newContent });
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
return true;
|
|
1751
|
+
};
|
|
1752
|
+
var joinUp = () => ({ state, dispatch }) => {
|
|
1753
|
+
return _commands.joinUp.call(void 0, state, dispatch);
|
|
1754
|
+
};
|
|
1755
|
+
var joinDown = () => ({ state, dispatch }) => {
|
|
1756
|
+
return _commands.joinDown.call(void 0, state, dispatch);
|
|
1757
|
+
};
|
|
1758
|
+
var joinBackward = () => ({ state, dispatch }) => {
|
|
1759
|
+
return _commands.joinBackward.call(void 0, state, dispatch);
|
|
1760
|
+
};
|
|
1761
|
+
var joinForward = () => ({ state, dispatch }) => {
|
|
1762
|
+
return _commands.joinForward.call(void 0, state, dispatch);
|
|
1763
|
+
};
|
|
1764
|
+
var joinItemBackward = () => ({ state, dispatch, tr }) => {
|
|
1765
|
+
try {
|
|
1766
|
+
const point = _transform.joinPoint.call(void 0, state.doc, state.selection.$from.pos, -1);
|
|
1767
|
+
if (point === null || point === void 0) {
|
|
1768
|
+
return false;
|
|
1769
|
+
}
|
|
1770
|
+
tr.join(point, 2);
|
|
1771
|
+
if (dispatch) {
|
|
1772
|
+
dispatch(tr);
|
|
1773
|
+
}
|
|
1774
|
+
return true;
|
|
1775
|
+
} catch (e) {
|
|
1776
|
+
return false;
|
|
1777
|
+
}
|
|
1778
|
+
};
|
|
1779
|
+
var joinItemForward = () => ({ state, dispatch, tr }) => {
|
|
1780
|
+
try {
|
|
1781
|
+
const point = _transform.joinPoint.call(void 0, state.doc, state.selection.$from.pos, 1);
|
|
1782
|
+
if (point === null || point === void 0) {
|
|
1783
|
+
return false;
|
|
1784
|
+
}
|
|
1785
|
+
tr.join(point, 2);
|
|
1786
|
+
if (dispatch) {
|
|
1787
|
+
dispatch(tr);
|
|
1788
|
+
}
|
|
1789
|
+
return true;
|
|
1790
|
+
} catch (e) {
|
|
1791
|
+
return false;
|
|
1792
|
+
}
|
|
1793
|
+
};
|
|
1794
|
+
var joinTextblockBackward = () => ({ state, dispatch }) => {
|
|
1795
|
+
return _commands.joinTextblockBackward.call(void 0, state, dispatch);
|
|
1796
|
+
};
|
|
1797
|
+
var joinTextblockForward = () => ({ state, dispatch }) => {
|
|
1798
|
+
return _commands.joinTextblockForward.call(void 0, state, dispatch);
|
|
1799
|
+
};
|
|
1800
|
+
function isMacOS() {
|
|
1801
|
+
return typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) : false;
|
|
1802
|
+
}
|
|
1803
|
+
function normalizeKeyName(name) {
|
|
1804
|
+
const parts = name.split(/-(?!$)/);
|
|
1805
|
+
let result = parts[parts.length - 1];
|
|
1806
|
+
if (result === "Space") {
|
|
1807
|
+
result = " ";
|
|
1808
|
+
}
|
|
1809
|
+
let alt;
|
|
1810
|
+
let ctrl;
|
|
1811
|
+
let shift;
|
|
1812
|
+
let meta;
|
|
1813
|
+
for (let i = 0; i < parts.length - 1; i += 1) {
|
|
1814
|
+
const mod = parts[i];
|
|
1815
|
+
if (/^(cmd|meta|m)$/i.test(mod)) {
|
|
1816
|
+
meta = true;
|
|
1817
|
+
} else if (/^a(lt)?$/i.test(mod)) {
|
|
1818
|
+
alt = true;
|
|
1819
|
+
} else if (/^(c|ctrl|control)$/i.test(mod)) {
|
|
1820
|
+
ctrl = true;
|
|
1821
|
+
} else if (/^s(hift)?$/i.test(mod)) {
|
|
1822
|
+
shift = true;
|
|
1823
|
+
} else if (/^mod$/i.test(mod)) {
|
|
1824
|
+
if (isiOS() || isMacOS()) {
|
|
1825
|
+
meta = true;
|
|
1826
|
+
} else {
|
|
1827
|
+
ctrl = true;
|
|
1828
|
+
}
|
|
1829
|
+
} else {
|
|
1830
|
+
throw new Error(`Unrecognized modifier name: ${mod}`);
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
if (alt) {
|
|
1834
|
+
result = `Alt-${result}`;
|
|
1835
|
+
}
|
|
1836
|
+
if (ctrl) {
|
|
1837
|
+
result = `Ctrl-${result}`;
|
|
1838
|
+
}
|
|
1839
|
+
if (meta) {
|
|
1840
|
+
result = `Meta-${result}`;
|
|
1841
|
+
}
|
|
1842
|
+
if (shift) {
|
|
1843
|
+
result = `Shift-${result}`;
|
|
1844
|
+
}
|
|
1845
|
+
return result;
|
|
1846
|
+
}
|
|
1847
|
+
var keyboardShortcut = (name) => ({ editor, view, tr, dispatch }) => {
|
|
1848
|
+
const keys = normalizeKeyName(name).split(/-(?!$)/);
|
|
1849
|
+
const key = keys.find((item) => !["Alt", "Ctrl", "Meta", "Shift"].includes(item));
|
|
1850
|
+
const event = new KeyboardEvent("keydown", {
|
|
1851
|
+
key: key === "Space" ? " " : key,
|
|
1852
|
+
altKey: keys.includes("Alt"),
|
|
1853
|
+
ctrlKey: keys.includes("Ctrl"),
|
|
1854
|
+
metaKey: keys.includes("Meta"),
|
|
1855
|
+
shiftKey: keys.includes("Shift"),
|
|
1856
|
+
bubbles: true,
|
|
1857
|
+
cancelable: true
|
|
1858
|
+
});
|
|
1859
|
+
const capturedTransaction = editor.captureTransaction(() => {
|
|
1860
|
+
view.someProp("handleKeyDown", (f) => f(view, event));
|
|
1861
|
+
});
|
|
1862
|
+
capturedTransaction === null || capturedTransaction === void 0 ? void 0 : capturedTransaction.steps.forEach((step) => {
|
|
1863
|
+
const newStep = step.map(tr.mapping);
|
|
1864
|
+
if (newStep && dispatch) {
|
|
1865
|
+
tr.maybeStep(newStep);
|
|
1866
|
+
}
|
|
1867
|
+
});
|
|
1868
|
+
return true;
|
|
1869
|
+
};
|
|
1870
|
+
function isNodeActive(state, typeOrName, attributes = {}) {
|
|
1871
|
+
const { from, to, empty } = state.selection;
|
|
1872
|
+
const type = typeOrName ? getNodeType(typeOrName, state.schema) : null;
|
|
1873
|
+
const nodeRanges = [];
|
|
1874
|
+
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
1875
|
+
if (node.isText) {
|
|
1876
|
+
return;
|
|
1877
|
+
}
|
|
1878
|
+
const relativeFrom = Math.max(from, pos);
|
|
1879
|
+
const relativeTo = Math.min(to, pos + node.nodeSize);
|
|
1880
|
+
nodeRanges.push({
|
|
1881
|
+
node,
|
|
1882
|
+
from: relativeFrom,
|
|
1883
|
+
to: relativeTo
|
|
1884
|
+
});
|
|
1885
|
+
});
|
|
1886
|
+
const selectionRange = to - from;
|
|
1887
|
+
const matchedNodeRanges = nodeRanges.filter((nodeRange) => {
|
|
1888
|
+
if (!type) {
|
|
1889
|
+
return true;
|
|
1890
|
+
}
|
|
1891
|
+
return type.name === nodeRange.node.type.name;
|
|
1892
|
+
}).filter((nodeRange) => objectIncludes(nodeRange.node.attrs, attributes, { strict: false }));
|
|
1893
|
+
if (empty) {
|
|
1894
|
+
return !!matchedNodeRanges.length;
|
|
1895
|
+
}
|
|
1896
|
+
const range = matchedNodeRanges.reduce((sum, nodeRange) => sum + nodeRange.to - nodeRange.from, 0);
|
|
1897
|
+
return range >= selectionRange;
|
|
1898
|
+
}
|
|
1899
|
+
var lift = (typeOrName, attributes = {}) => ({ state, dispatch }) => {
|
|
1900
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
1901
|
+
const isActive = isNodeActive(state, type, attributes);
|
|
1902
|
+
if (!isActive) {
|
|
1903
|
+
return false;
|
|
1904
|
+
}
|
|
1905
|
+
return _commands.lift.call(void 0, state, dispatch);
|
|
1906
|
+
};
|
|
1907
|
+
var liftEmptyBlock = () => ({ state, dispatch }) => {
|
|
1908
|
+
return _commands.liftEmptyBlock.call(void 0, state, dispatch);
|
|
1909
|
+
};
|
|
1910
|
+
var liftListItem = (typeOrName) => ({ state, dispatch }) => {
|
|
1911
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
1912
|
+
return _schemalist.liftListItem.call(void 0, type)(state, dispatch);
|
|
1913
|
+
};
|
|
1914
|
+
var newlineInCode = () => ({ state, dispatch }) => {
|
|
1915
|
+
return _commands.newlineInCode.call(void 0, state, dispatch);
|
|
1916
|
+
};
|
|
1917
|
+
function getSchemaTypeNameByName(name, schema) {
|
|
1918
|
+
if (schema.nodes[name]) {
|
|
1919
|
+
return "node";
|
|
1920
|
+
}
|
|
1921
|
+
if (schema.marks[name]) {
|
|
1922
|
+
return "mark";
|
|
1923
|
+
}
|
|
1924
|
+
return null;
|
|
1925
|
+
}
|
|
1926
|
+
function deleteProps(obj, propOrProps) {
|
|
1927
|
+
const props = typeof propOrProps === "string" ? [propOrProps] : propOrProps;
|
|
1928
|
+
return Object.keys(obj).reduce((newObj, prop) => {
|
|
1929
|
+
if (!props.includes(prop)) {
|
|
1930
|
+
newObj[prop] = obj[prop];
|
|
1931
|
+
}
|
|
1932
|
+
return newObj;
|
|
1933
|
+
}, {});
|
|
1934
|
+
}
|
|
1935
|
+
var resetAttributes = (typeOrName, attributes) => ({ tr, state, dispatch }) => {
|
|
1936
|
+
let nodeType = null;
|
|
1937
|
+
let markType = null;
|
|
1938
|
+
const schemaType = getSchemaTypeNameByName(typeof typeOrName === "string" ? typeOrName : typeOrName.name, state.schema);
|
|
1939
|
+
if (!schemaType) {
|
|
1940
|
+
return false;
|
|
1941
|
+
}
|
|
1942
|
+
if (schemaType === "node") {
|
|
1943
|
+
nodeType = getNodeType(typeOrName, state.schema);
|
|
1944
|
+
}
|
|
1945
|
+
if (schemaType === "mark") {
|
|
1946
|
+
markType = getMarkType(typeOrName, state.schema);
|
|
1947
|
+
}
|
|
1948
|
+
if (dispatch) {
|
|
1949
|
+
tr.selection.ranges.forEach((range) => {
|
|
1950
|
+
state.doc.nodesBetween(range.$from.pos, range.$to.pos, (node, pos) => {
|
|
1951
|
+
if (nodeType && nodeType === node.type) {
|
|
1952
|
+
tr.setNodeMarkup(pos, void 0, deleteProps(node.attrs, attributes));
|
|
1953
|
+
}
|
|
1954
|
+
if (markType && node.marks.length) {
|
|
1955
|
+
node.marks.forEach((mark) => {
|
|
1956
|
+
if (markType === mark.type) {
|
|
1957
|
+
tr.addMark(pos, pos + node.nodeSize, markType.create(deleteProps(mark.attrs, attributes)));
|
|
1958
|
+
}
|
|
1959
|
+
});
|
|
1960
|
+
}
|
|
1961
|
+
});
|
|
1962
|
+
});
|
|
1963
|
+
}
|
|
1964
|
+
return true;
|
|
1965
|
+
};
|
|
1966
|
+
var scrollIntoView = () => ({ tr, dispatch }) => {
|
|
1967
|
+
if (dispatch) {
|
|
1968
|
+
tr.scrollIntoView();
|
|
1969
|
+
}
|
|
1970
|
+
return true;
|
|
1971
|
+
};
|
|
1972
|
+
var selectAll = () => ({ tr, commands: commands2 }) => {
|
|
1973
|
+
return commands2.setTextSelection({
|
|
1974
|
+
from: 0,
|
|
1975
|
+
to: tr.doc.content.size
|
|
1976
|
+
});
|
|
1977
|
+
};
|
|
1978
|
+
var selectNodeBackward = () => ({ state, dispatch }) => {
|
|
1979
|
+
return _commands.selectNodeBackward.call(void 0, state, dispatch);
|
|
1980
|
+
};
|
|
1981
|
+
var selectNodeForward = () => ({ state, dispatch }) => {
|
|
1982
|
+
return _commands.selectNodeForward.call(void 0, state, dispatch);
|
|
1983
|
+
};
|
|
1984
|
+
var selectParentNode = () => ({ state, dispatch }) => {
|
|
1985
|
+
return _commands.selectParentNode.call(void 0, state, dispatch);
|
|
1986
|
+
};
|
|
1987
|
+
var selectTextblockEnd = () => ({ state, dispatch }) => {
|
|
1988
|
+
return _commands.selectTextblockEnd.call(void 0, state, dispatch);
|
|
1989
|
+
};
|
|
1990
|
+
var selectTextblockStart = () => ({ state, dispatch }) => {
|
|
1991
|
+
return _commands.selectTextblockStart.call(void 0, state, dispatch);
|
|
1992
|
+
};
|
|
1993
|
+
function createDocument(content, schema, parseOptions = {}, options = {}) {
|
|
1994
|
+
return createNodeFromContent(content, schema, {
|
|
1995
|
+
slice: false,
|
|
1996
|
+
parseOptions,
|
|
1997
|
+
errorOnInvalidContent: options.errorOnInvalidContent
|
|
1998
|
+
});
|
|
1999
|
+
}
|
|
2000
|
+
var setContent = (content, emitUpdate = false, parseOptions = {}, options = {}) => ({ editor, tr, dispatch, commands: commands2 }) => {
|
|
2001
|
+
var _a, _b;
|
|
2002
|
+
const { doc } = tr;
|
|
2003
|
+
if (parseOptions.preserveWhitespace !== "full") {
|
|
2004
|
+
const document2 = createDocument(content, editor.schema, parseOptions, {
|
|
2005
|
+
errorOnInvalidContent: (_a = options.errorOnInvalidContent) !== null && _a !== void 0 ? _a : editor.options.enableContentCheck
|
|
2006
|
+
});
|
|
2007
|
+
if (dispatch) {
|
|
2008
|
+
tr.replaceWith(0, doc.content.size, document2).setMeta("preventUpdate", !emitUpdate);
|
|
2009
|
+
}
|
|
2010
|
+
return true;
|
|
2011
|
+
}
|
|
2012
|
+
if (dispatch) {
|
|
2013
|
+
tr.setMeta("preventUpdate", !emitUpdate);
|
|
2014
|
+
}
|
|
2015
|
+
return commands2.insertContentAt({ from: 0, to: doc.content.size }, content, {
|
|
2016
|
+
parseOptions,
|
|
2017
|
+
errorOnInvalidContent: (_b = options.errorOnInvalidContent) !== null && _b !== void 0 ? _b : editor.options.enableContentCheck
|
|
2018
|
+
});
|
|
2019
|
+
};
|
|
2020
|
+
function getMarkAttributes(state, typeOrName) {
|
|
2021
|
+
const type = getMarkType(typeOrName, state.schema);
|
|
2022
|
+
const { from, to, empty } = state.selection;
|
|
2023
|
+
const marks = [];
|
|
2024
|
+
if (empty) {
|
|
2025
|
+
if (state.storedMarks) {
|
|
2026
|
+
marks.push(...state.storedMarks);
|
|
2027
|
+
}
|
|
2028
|
+
marks.push(...state.selection.$head.marks());
|
|
2029
|
+
} else {
|
|
2030
|
+
state.doc.nodesBetween(from, to, (node) => {
|
|
2031
|
+
marks.push(...node.marks);
|
|
2032
|
+
});
|
|
2033
|
+
}
|
|
2034
|
+
const mark = marks.find((markItem) => markItem.type.name === type.name);
|
|
2035
|
+
if (!mark) {
|
|
2036
|
+
return {};
|
|
2037
|
+
}
|
|
2038
|
+
return { ...mark.attrs };
|
|
2039
|
+
}
|
|
2040
|
+
function defaultBlockAt(match) {
|
|
2041
|
+
for (let i = 0; i < match.edgeCount; i += 1) {
|
|
2042
|
+
const { type } = match.edge(i);
|
|
2043
|
+
if (type.isTextblock && !type.hasRequiredAttrs()) {
|
|
2044
|
+
return type;
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
return null;
|
|
2048
|
+
}
|
|
2049
|
+
function findParentNodeClosestToPos($pos, predicate) {
|
|
2050
|
+
for (let i = $pos.depth; i > 0; i -= 1) {
|
|
2051
|
+
const node = $pos.node(i);
|
|
2052
|
+
if (predicate(node)) {
|
|
2053
|
+
return {
|
|
2054
|
+
pos: i > 0 ? $pos.before(i) : 0,
|
|
2055
|
+
start: $pos.start(i),
|
|
2056
|
+
depth: i,
|
|
2057
|
+
node
|
|
2058
|
+
};
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
function findParentNode(predicate) {
|
|
2063
|
+
return (selection) => findParentNodeClosestToPos(selection.$from, predicate);
|
|
2064
|
+
}
|
|
2065
|
+
function getSchema(extensions, editor) {
|
|
2066
|
+
const resolvedExtensions = ExtensionManager.resolve(extensions);
|
|
2067
|
+
return getSchemaByResolvedExtensions(resolvedExtensions, editor);
|
|
2068
|
+
}
|
|
2069
|
+
function getText(node, options) {
|
|
2070
|
+
const range = {
|
|
2071
|
+
from: 0,
|
|
2072
|
+
to: node.content.size
|
|
2073
|
+
};
|
|
2074
|
+
return getTextBetween(node, range, options);
|
|
2075
|
+
}
|
|
2076
|
+
function getSplittedAttributes(extensionAttributes, typeName, attributes) {
|
|
2077
|
+
return Object.fromEntries(Object.entries(attributes).filter(([name]) => {
|
|
2078
|
+
const extensionAttribute = extensionAttributes.find((item) => {
|
|
2079
|
+
return item.type === typeName && item.name === name;
|
|
2080
|
+
});
|
|
2081
|
+
if (!extensionAttribute) {
|
|
2082
|
+
return false;
|
|
2083
|
+
}
|
|
2084
|
+
return extensionAttribute.attribute.keepOnSplit;
|
|
2085
|
+
}));
|
|
2086
|
+
}
|
|
2087
|
+
function isMarkActive(state, typeOrName, attributes = {}) {
|
|
2088
|
+
const { empty, ranges } = state.selection;
|
|
2089
|
+
const type = typeOrName ? getMarkType(typeOrName, state.schema) : null;
|
|
2090
|
+
if (empty) {
|
|
2091
|
+
return !!(state.storedMarks || state.selection.$from.marks()).filter((mark) => {
|
|
2092
|
+
if (!type) {
|
|
2093
|
+
return true;
|
|
2094
|
+
}
|
|
2095
|
+
return type.name === mark.type.name;
|
|
2096
|
+
}).find((mark) => objectIncludes(mark.attrs, attributes, { strict: false }));
|
|
2097
|
+
}
|
|
2098
|
+
let selectionRange = 0;
|
|
2099
|
+
const markRanges = [];
|
|
2100
|
+
ranges.forEach(({ $from, $to }) => {
|
|
2101
|
+
const from = $from.pos;
|
|
2102
|
+
const to = $to.pos;
|
|
2103
|
+
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
2104
|
+
if (!node.isText && !node.marks.length) {
|
|
2105
|
+
return;
|
|
2106
|
+
}
|
|
2107
|
+
const relativeFrom = Math.max(from, pos);
|
|
2108
|
+
const relativeTo = Math.min(to, pos + node.nodeSize);
|
|
2109
|
+
const range2 = relativeTo - relativeFrom;
|
|
2110
|
+
selectionRange += range2;
|
|
2111
|
+
markRanges.push(...node.marks.map((mark) => ({
|
|
2112
|
+
mark,
|
|
2113
|
+
from: relativeFrom,
|
|
2114
|
+
to: relativeTo
|
|
2115
|
+
})));
|
|
2116
|
+
});
|
|
2117
|
+
});
|
|
2118
|
+
if (selectionRange === 0) {
|
|
2119
|
+
return false;
|
|
2120
|
+
}
|
|
2121
|
+
const matchedRange = markRanges.filter((markRange) => {
|
|
2122
|
+
if (!type) {
|
|
2123
|
+
return true;
|
|
2124
|
+
}
|
|
2125
|
+
return type.name === markRange.mark.type.name;
|
|
2126
|
+
}).filter((markRange) => objectIncludes(markRange.mark.attrs, attributes, { strict: false })).reduce((sum, markRange) => sum + markRange.to - markRange.from, 0);
|
|
2127
|
+
const excludedRange = markRanges.filter((markRange) => {
|
|
2128
|
+
if (!type) {
|
|
2129
|
+
return true;
|
|
2130
|
+
}
|
|
2131
|
+
return markRange.mark.type !== type && markRange.mark.type.excludes(type);
|
|
2132
|
+
}).reduce((sum, markRange) => sum + markRange.to - markRange.from, 0);
|
|
2133
|
+
const range = matchedRange > 0 ? matchedRange + excludedRange : matchedRange;
|
|
2134
|
+
return range >= selectionRange;
|
|
2135
|
+
}
|
|
2136
|
+
function isList(name, extensions) {
|
|
2137
|
+
const { nodeExtensions } = splitExtensions(extensions);
|
|
2138
|
+
const extension = nodeExtensions.find((item) => item.name === name);
|
|
2139
|
+
if (!extension) {
|
|
2140
|
+
return false;
|
|
2141
|
+
}
|
|
2142
|
+
const context = {
|
|
2143
|
+
name: extension.name,
|
|
2144
|
+
options: extension.options,
|
|
2145
|
+
storage: extension.storage
|
|
2146
|
+
};
|
|
2147
|
+
const group = callOrReturn(getExtensionField(extension, "group", context));
|
|
2148
|
+
if (typeof group !== "string") {
|
|
2149
|
+
return false;
|
|
2150
|
+
}
|
|
2151
|
+
return group.split(" ").includes("list");
|
|
2152
|
+
}
|
|
2153
|
+
function isNodeEmpty(node, { checkChildren = true, ignoreWhitespace = false } = {}) {
|
|
2154
|
+
var _a;
|
|
2155
|
+
if (ignoreWhitespace) {
|
|
2156
|
+
if (node.type.name === "hardBreak") {
|
|
2157
|
+
return true;
|
|
2158
|
+
}
|
|
2159
|
+
if (node.isText) {
|
|
2160
|
+
return /^\s*$/m.test((_a = node.text) !== null && _a !== void 0 ? _a : "");
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
if (node.isText) {
|
|
2164
|
+
return !node.text;
|
|
2165
|
+
}
|
|
2166
|
+
if (node.isAtom || node.isLeaf) {
|
|
2167
|
+
return false;
|
|
2168
|
+
}
|
|
2169
|
+
if (node.content.childCount === 0) {
|
|
2170
|
+
return true;
|
|
2171
|
+
}
|
|
2172
|
+
if (checkChildren) {
|
|
2173
|
+
let isContentEmpty = true;
|
|
2174
|
+
node.content.forEach((childNode) => {
|
|
2175
|
+
if (isContentEmpty === false) {
|
|
2176
|
+
return;
|
|
2177
|
+
}
|
|
2178
|
+
if (!isNodeEmpty(childNode, { ignoreWhitespace, checkChildren })) {
|
|
2179
|
+
isContentEmpty = false;
|
|
2180
|
+
}
|
|
2181
|
+
});
|
|
2182
|
+
return isContentEmpty;
|
|
2183
|
+
}
|
|
2184
|
+
return false;
|
|
2185
|
+
}
|
|
2186
|
+
function canSetMark(state, tr, newMarkType) {
|
|
2187
|
+
var _a;
|
|
2188
|
+
const { selection } = tr;
|
|
2189
|
+
let cursor = null;
|
|
2190
|
+
if (isTextSelection(selection)) {
|
|
2191
|
+
cursor = selection.$cursor;
|
|
2192
|
+
}
|
|
2193
|
+
if (cursor) {
|
|
2194
|
+
const currentMarks = (_a = state.storedMarks) !== null && _a !== void 0 ? _a : cursor.marks();
|
|
2195
|
+
return !!newMarkType.isInSet(currentMarks) || !currentMarks.some((mark) => mark.type.excludes(newMarkType));
|
|
2196
|
+
}
|
|
2197
|
+
const { ranges } = selection;
|
|
2198
|
+
return ranges.some(({ $from, $to }) => {
|
|
2199
|
+
let someNodeSupportsMark = $from.depth === 0 ? state.doc.inlineContent && state.doc.type.allowsMarkType(newMarkType) : false;
|
|
2200
|
+
state.doc.nodesBetween($from.pos, $to.pos, (node, _pos, parent) => {
|
|
2201
|
+
if (someNodeSupportsMark) {
|
|
2202
|
+
return false;
|
|
2203
|
+
}
|
|
2204
|
+
if (node.isInline) {
|
|
2205
|
+
const parentAllowsMarkType = !parent || parent.type.allowsMarkType(newMarkType);
|
|
2206
|
+
const currentMarksAllowMarkType = !!newMarkType.isInSet(node.marks) || !node.marks.some((otherMark) => otherMark.type.excludes(newMarkType));
|
|
2207
|
+
someNodeSupportsMark = parentAllowsMarkType && currentMarksAllowMarkType;
|
|
2208
|
+
}
|
|
2209
|
+
return !someNodeSupportsMark;
|
|
2210
|
+
});
|
|
2211
|
+
return someNodeSupportsMark;
|
|
2212
|
+
});
|
|
2213
|
+
}
|
|
2214
|
+
var setMark = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => {
|
|
2215
|
+
const { selection } = tr;
|
|
2216
|
+
const { empty, ranges } = selection;
|
|
2217
|
+
const type = getMarkType(typeOrName, state.schema);
|
|
2218
|
+
if (dispatch) {
|
|
2219
|
+
if (empty) {
|
|
2220
|
+
const oldAttributes = getMarkAttributes(state, type);
|
|
2221
|
+
tr.addStoredMark(type.create({
|
|
2222
|
+
...oldAttributes,
|
|
2223
|
+
...attributes
|
|
2224
|
+
}));
|
|
2225
|
+
} else {
|
|
2226
|
+
ranges.forEach((range) => {
|
|
2227
|
+
const from = range.$from.pos;
|
|
2228
|
+
const to = range.$to.pos;
|
|
2229
|
+
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
2230
|
+
const trimmedFrom = Math.max(pos, from);
|
|
2231
|
+
const trimmedTo = Math.min(pos + node.nodeSize, to);
|
|
2232
|
+
const someHasMark = node.marks.find((mark) => mark.type === type);
|
|
2233
|
+
if (someHasMark) {
|
|
2234
|
+
node.marks.forEach((mark) => {
|
|
2235
|
+
if (type === mark.type) {
|
|
2236
|
+
tr.addMark(trimmedFrom, trimmedTo, type.create({
|
|
2237
|
+
...mark.attrs,
|
|
2238
|
+
...attributes
|
|
2239
|
+
}));
|
|
2240
|
+
}
|
|
2241
|
+
});
|
|
2242
|
+
} else {
|
|
2243
|
+
tr.addMark(trimmedFrom, trimmedTo, type.create(attributes));
|
|
2244
|
+
}
|
|
2245
|
+
});
|
|
2246
|
+
});
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
return canSetMark(state, tr, type);
|
|
2250
|
+
};
|
|
2251
|
+
var setMeta = (key, value) => ({ tr }) => {
|
|
2252
|
+
tr.setMeta(key, value);
|
|
2253
|
+
return true;
|
|
2254
|
+
};
|
|
2255
|
+
var setNode = (typeOrName, attributes = {}) => ({ state, dispatch, chain }) => {
|
|
2256
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
2257
|
+
if (!type.isTextblock) {
|
|
2258
|
+
console.warn('[tiptap warn]: Currently "setNode()" only supports text block nodes.');
|
|
2259
|
+
return false;
|
|
2260
|
+
}
|
|
2261
|
+
return chain().command(({ commands: commands2 }) => {
|
|
2262
|
+
const canSetBlock = _commands.setBlockType.call(void 0, type, attributes)(state);
|
|
2263
|
+
if (canSetBlock) {
|
|
2264
|
+
return true;
|
|
2265
|
+
}
|
|
2266
|
+
return commands2.clearNodes();
|
|
2267
|
+
}).command(({ state: updatedState }) => {
|
|
2268
|
+
return _commands.setBlockType.call(void 0, type, attributes)(updatedState, dispatch);
|
|
2269
|
+
}).run();
|
|
2270
|
+
};
|
|
2271
|
+
var setNodeSelection = (position) => ({ tr, dispatch }) => {
|
|
2272
|
+
if (dispatch) {
|
|
2273
|
+
const { doc } = tr;
|
|
2274
|
+
const from = minMax(position, 0, doc.content.size);
|
|
2275
|
+
const selection = _state.NodeSelection.create(doc, from);
|
|
2276
|
+
tr.setSelection(selection);
|
|
2277
|
+
}
|
|
2278
|
+
return true;
|
|
2279
|
+
};
|
|
2280
|
+
var setTextSelection = (position) => ({ tr, dispatch }) => {
|
|
2281
|
+
if (dispatch) {
|
|
2282
|
+
const { doc } = tr;
|
|
2283
|
+
const { from, to } = typeof position === "number" ? { from: position, to: position } : position;
|
|
2284
|
+
const minPos = _state.TextSelection.atStart(doc).from;
|
|
2285
|
+
const maxPos = _state.TextSelection.atEnd(doc).to;
|
|
2286
|
+
const resolvedFrom = minMax(from, minPos, maxPos);
|
|
2287
|
+
const resolvedEnd = minMax(to, minPos, maxPos);
|
|
2288
|
+
const selection = _state.TextSelection.create(doc, resolvedFrom, resolvedEnd);
|
|
2289
|
+
tr.setSelection(selection);
|
|
2290
|
+
}
|
|
2291
|
+
return true;
|
|
2292
|
+
};
|
|
2293
|
+
var sinkListItem = (typeOrName) => ({ state, dispatch }) => {
|
|
2294
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
2295
|
+
return _schemalist.sinkListItem.call(void 0, type)(state, dispatch);
|
|
2296
|
+
};
|
|
2297
|
+
function ensureMarks(state, splittableMarks) {
|
|
2298
|
+
const marks = state.storedMarks || state.selection.$to.parentOffset && state.selection.$from.marks();
|
|
2299
|
+
if (marks) {
|
|
2300
|
+
const filteredMarks = marks.filter((mark) => splittableMarks === null || splittableMarks === void 0 ? void 0 : splittableMarks.includes(mark.type.name));
|
|
2301
|
+
state.tr.ensureMarks(filteredMarks);
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
var splitBlock = ({ keepMarks = true } = {}) => ({ tr, state, dispatch, editor }) => {
|
|
2305
|
+
const { selection, doc } = tr;
|
|
2306
|
+
const { $from, $to } = selection;
|
|
2307
|
+
const extensionAttributes = editor.extensionManager.attributes;
|
|
2308
|
+
const newAttributes = getSplittedAttributes(extensionAttributes, $from.node().type.name, $from.node().attrs);
|
|
2309
|
+
if (selection instanceof _state.NodeSelection && selection.node.isBlock) {
|
|
2310
|
+
if (!$from.parentOffset || !_transform.canSplit.call(void 0, doc, $from.pos)) {
|
|
2311
|
+
return false;
|
|
2312
|
+
}
|
|
2313
|
+
if (dispatch) {
|
|
2314
|
+
if (keepMarks) {
|
|
2315
|
+
ensureMarks(state, editor.extensionManager.splittableMarks);
|
|
2316
|
+
}
|
|
2317
|
+
tr.split($from.pos).scrollIntoView();
|
|
2318
|
+
}
|
|
2319
|
+
return true;
|
|
2320
|
+
}
|
|
2321
|
+
if (!$from.parent.isBlock) {
|
|
2322
|
+
return false;
|
|
2323
|
+
}
|
|
2324
|
+
const atEnd = $to.parentOffset === $to.parent.content.size;
|
|
2325
|
+
const deflt = $from.depth === 0 ? void 0 : defaultBlockAt($from.node(-1).contentMatchAt($from.indexAfter(-1)));
|
|
2326
|
+
let types = atEnd && deflt ? [
|
|
2327
|
+
{
|
|
2328
|
+
type: deflt,
|
|
2329
|
+
attrs: newAttributes
|
|
2330
|
+
}
|
|
2331
|
+
] : void 0;
|
|
2332
|
+
let can = _transform.canSplit.call(void 0, tr.doc, tr.mapping.map($from.pos), 1, types);
|
|
2333
|
+
if (!types && !can && _transform.canSplit.call(void 0, tr.doc, tr.mapping.map($from.pos), 1, deflt ? [{ type: deflt }] : void 0)) {
|
|
2334
|
+
can = true;
|
|
2335
|
+
types = deflt ? [
|
|
2336
|
+
{
|
|
2337
|
+
type: deflt,
|
|
2338
|
+
attrs: newAttributes
|
|
2339
|
+
}
|
|
2340
|
+
] : void 0;
|
|
2341
|
+
}
|
|
2342
|
+
if (dispatch) {
|
|
2343
|
+
if (can) {
|
|
2344
|
+
if (selection instanceof _state.TextSelection) {
|
|
2345
|
+
tr.deleteSelection();
|
|
2346
|
+
}
|
|
2347
|
+
tr.split(tr.mapping.map($from.pos), 1, types);
|
|
2348
|
+
if (deflt && !atEnd && !$from.parentOffset && $from.parent.type !== deflt) {
|
|
2349
|
+
const first2 = tr.mapping.map($from.before());
|
|
2350
|
+
const $first = tr.doc.resolve(first2);
|
|
2351
|
+
if ($from.node(-1).canReplaceWith($first.index(), $first.index() + 1, deflt)) {
|
|
2352
|
+
tr.setNodeMarkup(tr.mapping.map($from.before()), deflt);
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
if (keepMarks) {
|
|
2357
|
+
ensureMarks(state, editor.extensionManager.splittableMarks);
|
|
2358
|
+
}
|
|
2359
|
+
tr.scrollIntoView();
|
|
2360
|
+
}
|
|
2361
|
+
return can;
|
|
2362
|
+
};
|
|
2363
|
+
var splitListItem = (typeOrName, overrideAttrs = {}) => ({ tr, state, dispatch, editor }) => {
|
|
2364
|
+
var _a;
|
|
2365
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
2366
|
+
const { $from, $to } = state.selection;
|
|
2367
|
+
const node = state.selection.node;
|
|
2368
|
+
if (node && node.isBlock || $from.depth < 2 || !$from.sameParent($to)) {
|
|
2369
|
+
return false;
|
|
2370
|
+
}
|
|
2371
|
+
const grandParent = $from.node(-1);
|
|
2372
|
+
if (grandParent.type !== type) {
|
|
2373
|
+
return false;
|
|
2374
|
+
}
|
|
2375
|
+
const extensionAttributes = editor.extensionManager.attributes;
|
|
2376
|
+
if ($from.parent.content.size === 0 && $from.node(-1).childCount === $from.indexAfter(-1)) {
|
|
2377
|
+
if ($from.depth === 2 || $from.node(-3).type !== type || $from.index(-2) !== $from.node(-2).childCount - 1) {
|
|
2378
|
+
return false;
|
|
2379
|
+
}
|
|
2380
|
+
if (dispatch) {
|
|
2381
|
+
let wrap = _model.Fragment.empty;
|
|
2382
|
+
const depthBefore = $from.index(-1) ? 1 : $from.index(-2) ? 2 : 3;
|
|
2383
|
+
for (let d = $from.depth - depthBefore; d >= $from.depth - 3; d -= 1) {
|
|
2384
|
+
wrap = _model.Fragment.from($from.node(d).copy(wrap));
|
|
2385
|
+
}
|
|
2386
|
+
const depthAfter = $from.indexAfter(-1) < $from.node(-2).childCount ? 1 : $from.indexAfter(-2) < $from.node(-3).childCount ? 2 : 3;
|
|
2387
|
+
const newNextTypeAttributes2 = {
|
|
2388
|
+
...getSplittedAttributes(extensionAttributes, $from.node().type.name, $from.node().attrs),
|
|
2389
|
+
...overrideAttrs
|
|
2390
|
+
};
|
|
2391
|
+
const nextType2 = ((_a = type.contentMatch.defaultType) === null || _a === void 0 ? void 0 : _a.createAndFill(newNextTypeAttributes2)) || void 0;
|
|
2392
|
+
wrap = wrap.append(_model.Fragment.from(type.createAndFill(null, nextType2) || void 0));
|
|
2393
|
+
const start = $from.before($from.depth - (depthBefore - 1));
|
|
2394
|
+
tr.replace(start, $from.after(-depthAfter), new (0, _model.Slice)(wrap, 4 - depthBefore, 0));
|
|
2395
|
+
let sel = -1;
|
|
2396
|
+
tr.doc.nodesBetween(start, tr.doc.content.size, (n, pos) => {
|
|
2397
|
+
if (sel > -1) {
|
|
2398
|
+
return false;
|
|
2399
|
+
}
|
|
2400
|
+
if (n.isTextblock && n.content.size === 0) {
|
|
2401
|
+
sel = pos + 1;
|
|
2402
|
+
}
|
|
2403
|
+
});
|
|
2404
|
+
if (sel > -1) {
|
|
2405
|
+
tr.setSelection(_state.TextSelection.near(tr.doc.resolve(sel)));
|
|
2406
|
+
}
|
|
2407
|
+
tr.scrollIntoView();
|
|
2408
|
+
}
|
|
2409
|
+
return true;
|
|
2410
|
+
}
|
|
2411
|
+
const nextType = $to.pos === $from.end() ? grandParent.contentMatchAt(0).defaultType : null;
|
|
2412
|
+
const newTypeAttributes = {
|
|
2413
|
+
...getSplittedAttributes(extensionAttributes, grandParent.type.name, grandParent.attrs),
|
|
2414
|
+
...overrideAttrs
|
|
2415
|
+
};
|
|
2416
|
+
const newNextTypeAttributes = {
|
|
2417
|
+
...getSplittedAttributes(extensionAttributes, $from.node().type.name, $from.node().attrs),
|
|
2418
|
+
...overrideAttrs
|
|
2419
|
+
};
|
|
2420
|
+
tr.delete($from.pos, $to.pos);
|
|
2421
|
+
const types = nextType ? [
|
|
2422
|
+
{ type, attrs: newTypeAttributes },
|
|
2423
|
+
{ type: nextType, attrs: newNextTypeAttributes }
|
|
2424
|
+
] : [{ type, attrs: newTypeAttributes }];
|
|
2425
|
+
if (!_transform.canSplit.call(void 0, tr.doc, $from.pos, 2)) {
|
|
2426
|
+
return false;
|
|
2427
|
+
}
|
|
2428
|
+
if (dispatch) {
|
|
2429
|
+
const { selection, storedMarks } = state;
|
|
2430
|
+
const { splittableMarks } = editor.extensionManager;
|
|
2431
|
+
const marks = storedMarks || selection.$to.parentOffset && selection.$from.marks();
|
|
2432
|
+
tr.split($from.pos, 2, types).scrollIntoView();
|
|
2433
|
+
if (!marks || !dispatch) {
|
|
2434
|
+
return true;
|
|
2435
|
+
}
|
|
2436
|
+
const filteredMarks = marks.filter((mark) => splittableMarks.includes(mark.type.name));
|
|
2437
|
+
tr.ensureMarks(filteredMarks);
|
|
2438
|
+
}
|
|
2439
|
+
return true;
|
|
2440
|
+
};
|
|
2441
|
+
var joinListBackwards = (tr, listType) => {
|
|
2442
|
+
const list = findParentNode((node) => node.type === listType)(tr.selection);
|
|
2443
|
+
if (!list) {
|
|
2444
|
+
return true;
|
|
2445
|
+
}
|
|
2446
|
+
const before = tr.doc.resolve(Math.max(0, list.pos - 1)).before(list.depth);
|
|
2447
|
+
if (before === void 0) {
|
|
2448
|
+
return true;
|
|
2449
|
+
}
|
|
2450
|
+
const nodeBefore = tr.doc.nodeAt(before);
|
|
2451
|
+
const canJoinBackwards = list.node.type === (nodeBefore === null || nodeBefore === void 0 ? void 0 : nodeBefore.type) && _transform.canJoin.call(void 0, tr.doc, list.pos);
|
|
2452
|
+
if (!canJoinBackwards) {
|
|
2453
|
+
return true;
|
|
2454
|
+
}
|
|
2455
|
+
tr.join(list.pos);
|
|
2456
|
+
return true;
|
|
2457
|
+
};
|
|
2458
|
+
var joinListForwards = (tr, listType) => {
|
|
2459
|
+
const list = findParentNode((node) => node.type === listType)(tr.selection);
|
|
2460
|
+
if (!list) {
|
|
2461
|
+
return true;
|
|
2462
|
+
}
|
|
2463
|
+
const after = tr.doc.resolve(list.start).after(list.depth);
|
|
2464
|
+
if (after === void 0) {
|
|
2465
|
+
return true;
|
|
2466
|
+
}
|
|
2467
|
+
const nodeAfter = tr.doc.nodeAt(after);
|
|
2468
|
+
const canJoinForwards = list.node.type === (nodeAfter === null || nodeAfter === void 0 ? void 0 : nodeAfter.type) && _transform.canJoin.call(void 0, tr.doc, after);
|
|
2469
|
+
if (!canJoinForwards) {
|
|
2470
|
+
return true;
|
|
2471
|
+
}
|
|
2472
|
+
tr.join(after);
|
|
2473
|
+
return true;
|
|
2474
|
+
};
|
|
2475
|
+
var toggleList = (listTypeOrName, itemTypeOrName, keepMarks, attributes = {}) => ({ editor, tr, state, dispatch, chain, commands: commands2, can }) => {
|
|
2476
|
+
const { extensions, splittableMarks } = editor.extensionManager;
|
|
2477
|
+
const listType = getNodeType(listTypeOrName, state.schema);
|
|
2478
|
+
const itemType = getNodeType(itemTypeOrName, state.schema);
|
|
2479
|
+
const { selection, storedMarks } = state;
|
|
2480
|
+
const { $from, $to } = selection;
|
|
2481
|
+
const range = $from.blockRange($to);
|
|
2482
|
+
const marks = storedMarks || selection.$to.parentOffset && selection.$from.marks();
|
|
2483
|
+
if (!range) {
|
|
2484
|
+
return false;
|
|
2485
|
+
}
|
|
2486
|
+
const parentList = findParentNode((node) => isList(node.type.name, extensions))(selection);
|
|
2487
|
+
if (range.depth >= 1 && parentList && range.depth - parentList.depth <= 1) {
|
|
2488
|
+
if (parentList.node.type === listType) {
|
|
2489
|
+
return commands2.liftListItem(itemType);
|
|
2490
|
+
}
|
|
2491
|
+
if (isList(parentList.node.type.name, extensions) && listType.validContent(parentList.node.content) && dispatch) {
|
|
2492
|
+
return chain().command(() => {
|
|
2493
|
+
tr.setNodeMarkup(parentList.pos, listType);
|
|
2494
|
+
return true;
|
|
2495
|
+
}).command(() => joinListBackwards(tr, listType)).command(() => joinListForwards(tr, listType)).run();
|
|
2496
|
+
}
|
|
2497
|
+
}
|
|
2498
|
+
if (!keepMarks || !marks || !dispatch) {
|
|
2499
|
+
return chain().command(() => {
|
|
2500
|
+
const canWrapInList = can().wrapInList(listType, attributes);
|
|
2501
|
+
if (canWrapInList) {
|
|
2502
|
+
return true;
|
|
2503
|
+
}
|
|
2504
|
+
return commands2.clearNodes();
|
|
2505
|
+
}).wrapInList(listType, attributes).command(() => joinListBackwards(tr, listType)).command(() => joinListForwards(tr, listType)).run();
|
|
2506
|
+
}
|
|
2507
|
+
return chain().command(() => {
|
|
2508
|
+
const canWrapInList = can().wrapInList(listType, attributes);
|
|
2509
|
+
const filteredMarks = marks.filter((mark) => splittableMarks.includes(mark.type.name));
|
|
2510
|
+
tr.ensureMarks(filteredMarks);
|
|
2511
|
+
if (canWrapInList) {
|
|
2512
|
+
return true;
|
|
2513
|
+
}
|
|
2514
|
+
return commands2.clearNodes();
|
|
2515
|
+
}).wrapInList(listType, attributes).command(() => joinListBackwards(tr, listType)).command(() => joinListForwards(tr, listType)).run();
|
|
2516
|
+
};
|
|
2517
|
+
var toggleMark = (typeOrName, attributes = {}, options = {}) => ({ state, commands: commands2 }) => {
|
|
2518
|
+
const { extendEmptyMarkRange = false } = options;
|
|
2519
|
+
const type = getMarkType(typeOrName, state.schema);
|
|
2520
|
+
const isActive = isMarkActive(state, type, attributes);
|
|
2521
|
+
if (isActive) {
|
|
2522
|
+
return commands2.unsetMark(type, { extendEmptyMarkRange });
|
|
2523
|
+
}
|
|
2524
|
+
return commands2.setMark(type, attributes);
|
|
2525
|
+
};
|
|
2526
|
+
var toggleNode = (typeOrName, toggleTypeOrName, attributes = {}) => ({ state, commands: commands2 }) => {
|
|
2527
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
2528
|
+
const toggleType = getNodeType(toggleTypeOrName, state.schema);
|
|
2529
|
+
const isActive = isNodeActive(state, type, attributes);
|
|
2530
|
+
let attributesToCopy;
|
|
2531
|
+
if (state.selection.$anchor.sameParent(state.selection.$head)) {
|
|
2532
|
+
attributesToCopy = state.selection.$anchor.parent.attrs;
|
|
2533
|
+
}
|
|
2534
|
+
if (isActive) {
|
|
2535
|
+
return commands2.setNode(toggleType, attributesToCopy);
|
|
2536
|
+
}
|
|
2537
|
+
return commands2.setNode(type, { ...attributesToCopy, ...attributes });
|
|
2538
|
+
};
|
|
2539
|
+
var toggleWrap = (typeOrName, attributes = {}) => ({ state, commands: commands2 }) => {
|
|
2540
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
2541
|
+
const isActive = isNodeActive(state, type, attributes);
|
|
2542
|
+
if (isActive) {
|
|
2543
|
+
return commands2.lift(type);
|
|
2544
|
+
}
|
|
2545
|
+
return commands2.wrapIn(type, attributes);
|
|
2546
|
+
};
|
|
2547
|
+
var undoInputRule = () => ({ state, dispatch }) => {
|
|
2548
|
+
const plugins = state.plugins;
|
|
2549
|
+
for (let i = 0; i < plugins.length; i += 1) {
|
|
2550
|
+
const plugin = plugins[i];
|
|
2551
|
+
let undoable;
|
|
2552
|
+
if (plugin.spec.isInputRules && (undoable = plugin.getState(state))) {
|
|
2553
|
+
if (dispatch) {
|
|
2554
|
+
const tr = state.tr;
|
|
2555
|
+
const toUndo = undoable.transform;
|
|
2556
|
+
for (let j = toUndo.steps.length - 1; j >= 0; j -= 1) {
|
|
2557
|
+
tr.step(toUndo.steps[j].invert(toUndo.docs[j]));
|
|
2558
|
+
}
|
|
2559
|
+
if (undoable.text) {
|
|
2560
|
+
const marks = tr.doc.resolve(undoable.from).marks();
|
|
2561
|
+
tr.replaceWith(undoable.from, undoable.to, state.schema.text(undoable.text, marks));
|
|
2562
|
+
} else {
|
|
2563
|
+
tr.delete(undoable.from, undoable.to);
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
return true;
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
return false;
|
|
2570
|
+
};
|
|
2571
|
+
var unsetAllMarks = () => ({ tr, dispatch }) => {
|
|
2572
|
+
const { selection } = tr;
|
|
2573
|
+
const { empty, ranges } = selection;
|
|
2574
|
+
if (empty) {
|
|
2575
|
+
return true;
|
|
2576
|
+
}
|
|
2577
|
+
if (dispatch) {
|
|
2578
|
+
ranges.forEach((range) => {
|
|
2579
|
+
tr.removeMark(range.$from.pos, range.$to.pos);
|
|
2580
|
+
});
|
|
2581
|
+
}
|
|
2582
|
+
return true;
|
|
2583
|
+
};
|
|
2584
|
+
var unsetMark = (typeOrName, options = {}) => ({ tr, state, dispatch }) => {
|
|
2585
|
+
var _a;
|
|
2586
|
+
const { extendEmptyMarkRange = false } = options;
|
|
2587
|
+
const { selection } = tr;
|
|
2588
|
+
const type = getMarkType(typeOrName, state.schema);
|
|
2589
|
+
const { $from, empty, ranges } = selection;
|
|
2590
|
+
if (!dispatch) {
|
|
2591
|
+
return true;
|
|
2592
|
+
}
|
|
2593
|
+
if (empty && extendEmptyMarkRange) {
|
|
2594
|
+
let { from, to } = selection;
|
|
2595
|
+
const attrs = (_a = $from.marks().find((mark) => mark.type === type)) === null || _a === void 0 ? void 0 : _a.attrs;
|
|
2596
|
+
const range = getMarkRange($from, type, attrs);
|
|
2597
|
+
if (range) {
|
|
2598
|
+
from = range.from;
|
|
2599
|
+
to = range.to;
|
|
2600
|
+
}
|
|
2601
|
+
tr.removeMark(from, to, type);
|
|
2602
|
+
} else {
|
|
2603
|
+
ranges.forEach((range) => {
|
|
2604
|
+
tr.removeMark(range.$from.pos, range.$to.pos, type);
|
|
2605
|
+
});
|
|
2606
|
+
}
|
|
2607
|
+
tr.removeStoredMark(type);
|
|
2608
|
+
return true;
|
|
2609
|
+
};
|
|
2610
|
+
var updateAttributes = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => {
|
|
2611
|
+
let nodeType = null;
|
|
2612
|
+
let markType = null;
|
|
2613
|
+
const schemaType = getSchemaTypeNameByName(typeof typeOrName === "string" ? typeOrName : typeOrName.name, state.schema);
|
|
2614
|
+
if (!schemaType) {
|
|
2615
|
+
return false;
|
|
2616
|
+
}
|
|
2617
|
+
if (schemaType === "node") {
|
|
2618
|
+
nodeType = getNodeType(typeOrName, state.schema);
|
|
2619
|
+
}
|
|
2620
|
+
if (schemaType === "mark") {
|
|
2621
|
+
markType = getMarkType(typeOrName, state.schema);
|
|
2622
|
+
}
|
|
2623
|
+
if (dispatch) {
|
|
2624
|
+
tr.selection.ranges.forEach((range) => {
|
|
2625
|
+
const from = range.$from.pos;
|
|
2626
|
+
const to = range.$to.pos;
|
|
2627
|
+
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
2628
|
+
if (nodeType && nodeType === node.type) {
|
|
2629
|
+
tr.setNodeMarkup(pos, void 0, {
|
|
2630
|
+
...node.attrs,
|
|
2631
|
+
...attributes
|
|
2632
|
+
});
|
|
2633
|
+
}
|
|
2634
|
+
if (markType && node.marks.length) {
|
|
2635
|
+
node.marks.forEach((mark) => {
|
|
2636
|
+
if (markType === mark.type) {
|
|
2637
|
+
const trimmedFrom = Math.max(pos, from);
|
|
2638
|
+
const trimmedTo = Math.min(pos + node.nodeSize, to);
|
|
2639
|
+
tr.addMark(trimmedFrom, trimmedTo, markType.create({
|
|
2640
|
+
...mark.attrs,
|
|
2641
|
+
...attributes
|
|
2642
|
+
}));
|
|
2643
|
+
}
|
|
2644
|
+
});
|
|
2645
|
+
}
|
|
2646
|
+
});
|
|
2647
|
+
});
|
|
2648
|
+
}
|
|
2649
|
+
return true;
|
|
2650
|
+
};
|
|
2651
|
+
var wrapIn = (typeOrName, attributes = {}) => ({ state, dispatch }) => {
|
|
2652
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
2653
|
+
return _commands.wrapIn.call(void 0, type, attributes)(state, dispatch);
|
|
2654
|
+
};
|
|
2655
|
+
var wrapInList = (typeOrName, attributes = {}) => ({ state, dispatch }) => {
|
|
2656
|
+
const type = getNodeType(typeOrName, state.schema);
|
|
2657
|
+
return _schemalist.wrapInList.call(void 0, type, attributes)(state, dispatch);
|
|
2658
|
+
};
|
|
2659
|
+
var commands = /* @__PURE__ */ Object.freeze({
|
|
2660
|
+
__proto__: null,
|
|
2661
|
+
blur,
|
|
2662
|
+
clearContent,
|
|
2663
|
+
clearNodes,
|
|
2664
|
+
command,
|
|
2665
|
+
createParagraphNear,
|
|
2666
|
+
cut,
|
|
2667
|
+
deleteCurrentNode,
|
|
2668
|
+
deleteNode,
|
|
2669
|
+
deleteRange,
|
|
2670
|
+
deleteSelection,
|
|
2671
|
+
enter,
|
|
2672
|
+
exitCode,
|
|
2673
|
+
extendMarkRange,
|
|
2674
|
+
first,
|
|
2675
|
+
focus,
|
|
2676
|
+
forEach,
|
|
2677
|
+
insertContent,
|
|
2678
|
+
insertContentAt,
|
|
2679
|
+
joinBackward,
|
|
2680
|
+
joinDown,
|
|
2681
|
+
joinForward,
|
|
2682
|
+
joinItemBackward,
|
|
2683
|
+
joinItemForward,
|
|
2684
|
+
joinTextblockBackward,
|
|
2685
|
+
joinTextblockForward,
|
|
2686
|
+
joinUp,
|
|
2687
|
+
keyboardShortcut,
|
|
2688
|
+
lift,
|
|
2689
|
+
liftEmptyBlock,
|
|
2690
|
+
liftListItem,
|
|
2691
|
+
newlineInCode,
|
|
2692
|
+
resetAttributes,
|
|
2693
|
+
scrollIntoView,
|
|
2694
|
+
selectAll,
|
|
2695
|
+
selectNodeBackward,
|
|
2696
|
+
selectNodeForward,
|
|
2697
|
+
selectParentNode,
|
|
2698
|
+
selectTextblockEnd,
|
|
2699
|
+
selectTextblockStart,
|
|
2700
|
+
setContent,
|
|
2701
|
+
setMark,
|
|
2702
|
+
setMeta,
|
|
2703
|
+
setNode,
|
|
2704
|
+
setNodeSelection,
|
|
2705
|
+
setTextSelection,
|
|
2706
|
+
sinkListItem,
|
|
2707
|
+
splitBlock,
|
|
2708
|
+
splitListItem,
|
|
2709
|
+
toggleList,
|
|
2710
|
+
toggleMark,
|
|
2711
|
+
toggleNode,
|
|
2712
|
+
toggleWrap,
|
|
2713
|
+
undoInputRule,
|
|
2714
|
+
unsetAllMarks,
|
|
2715
|
+
unsetMark,
|
|
2716
|
+
updateAttributes,
|
|
2717
|
+
wrapIn,
|
|
2718
|
+
wrapInList
|
|
2719
|
+
});
|
|
2720
|
+
var Commands = Extension.create({
|
|
2721
|
+
name: "commands",
|
|
2722
|
+
addCommands() {
|
|
2723
|
+
return {
|
|
2724
|
+
...commands
|
|
2725
|
+
};
|
|
2726
|
+
}
|
|
2727
|
+
});
|
|
2728
|
+
var Drop = Extension.create({
|
|
2729
|
+
name: "drop",
|
|
2730
|
+
addProseMirrorPlugins() {
|
|
2731
|
+
return [
|
|
2732
|
+
new (0, _state.Plugin)({
|
|
2733
|
+
key: new (0, _state.PluginKey)("tiptapDrop"),
|
|
2734
|
+
props: {
|
|
2735
|
+
handleDrop: (_, e, slice, moved) => {
|
|
2736
|
+
this.editor.emit("drop", {
|
|
2737
|
+
editor: this.editor,
|
|
2738
|
+
event: e,
|
|
2739
|
+
slice,
|
|
2740
|
+
moved
|
|
2741
|
+
});
|
|
2742
|
+
}
|
|
2743
|
+
}
|
|
2744
|
+
})
|
|
2745
|
+
];
|
|
2746
|
+
}
|
|
2747
|
+
});
|
|
2748
|
+
var Editable = Extension.create({
|
|
2749
|
+
name: "editable",
|
|
2750
|
+
addProseMirrorPlugins() {
|
|
2751
|
+
return [
|
|
2752
|
+
new (0, _state.Plugin)({
|
|
2753
|
+
key: new (0, _state.PluginKey)("editable"),
|
|
2754
|
+
props: {
|
|
2755
|
+
editable: () => this.editor.options.editable
|
|
2756
|
+
}
|
|
2757
|
+
})
|
|
2758
|
+
];
|
|
2759
|
+
}
|
|
2760
|
+
});
|
|
2761
|
+
var FocusEvents = Extension.create({
|
|
2762
|
+
name: "focusEvents",
|
|
2763
|
+
addProseMirrorPlugins() {
|
|
2764
|
+
const { editor } = this;
|
|
2765
|
+
return [
|
|
2766
|
+
new (0, _state.Plugin)({
|
|
2767
|
+
key: new (0, _state.PluginKey)("focusEvents"),
|
|
2768
|
+
props: {
|
|
2769
|
+
handleDOMEvents: {
|
|
2770
|
+
focus: (view, event) => {
|
|
2771
|
+
editor.isFocused = true;
|
|
2772
|
+
const transaction = editor.state.tr.setMeta("focus", { event }).setMeta("addToHistory", false);
|
|
2773
|
+
view.dispatch(transaction);
|
|
2774
|
+
return false;
|
|
2775
|
+
},
|
|
2776
|
+
blur: (view, event) => {
|
|
2777
|
+
editor.isFocused = false;
|
|
2778
|
+
const transaction = editor.state.tr.setMeta("blur", { event }).setMeta("addToHistory", false);
|
|
2779
|
+
view.dispatch(transaction);
|
|
2780
|
+
return false;
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
})
|
|
2785
|
+
];
|
|
2786
|
+
}
|
|
2787
|
+
});
|
|
2788
|
+
var Keymap = Extension.create({
|
|
2789
|
+
name: "keymap",
|
|
2790
|
+
addKeyboardShortcuts() {
|
|
2791
|
+
const handleBackspace = () => this.editor.commands.first(({ commands: commands2 }) => [
|
|
2792
|
+
() => commands2.undoInputRule(),
|
|
2793
|
+
// maybe convert first text block node to default node
|
|
2794
|
+
() => commands2.command(({ tr }) => {
|
|
2795
|
+
const { selection, doc } = tr;
|
|
2796
|
+
const { empty, $anchor } = selection;
|
|
2797
|
+
const { pos, parent } = $anchor;
|
|
2798
|
+
const $parentPos = $anchor.parent.isTextblock && pos > 0 ? tr.doc.resolve(pos - 1) : $anchor;
|
|
2799
|
+
const parentIsIsolating = $parentPos.parent.type.spec.isolating;
|
|
2800
|
+
const parentPos = $anchor.pos - $anchor.parentOffset;
|
|
2801
|
+
const isAtStart = parentIsIsolating && $parentPos.parent.childCount === 1 ? parentPos === $anchor.pos : _state.Selection.atStart(doc).from === pos;
|
|
2802
|
+
if (!empty || !parent.type.isTextblock || parent.textContent.length || !isAtStart || isAtStart && $anchor.parent.type.name === "paragraph") {
|
|
2803
|
+
return false;
|
|
2804
|
+
}
|
|
2805
|
+
return commands2.clearNodes();
|
|
2806
|
+
}),
|
|
2807
|
+
() => commands2.deleteSelection(),
|
|
2808
|
+
() => commands2.joinBackward(),
|
|
2809
|
+
() => commands2.selectNodeBackward()
|
|
2810
|
+
]);
|
|
2811
|
+
const handleDelete = () => this.editor.commands.first(({ commands: commands2 }) => [
|
|
2812
|
+
() => commands2.deleteSelection(),
|
|
2813
|
+
() => commands2.deleteCurrentNode(),
|
|
2814
|
+
() => commands2.joinForward(),
|
|
2815
|
+
() => commands2.selectNodeForward()
|
|
2816
|
+
]);
|
|
2817
|
+
const handleEnter = () => this.editor.commands.first(({ commands: commands2 }) => [
|
|
2818
|
+
() => commands2.newlineInCode(),
|
|
2819
|
+
() => commands2.createParagraphNear(),
|
|
2820
|
+
() => commands2.liftEmptyBlock(),
|
|
2821
|
+
() => commands2.splitBlock()
|
|
2822
|
+
]);
|
|
2823
|
+
const baseKeymap = {
|
|
2824
|
+
Enter: handleEnter,
|
|
2825
|
+
"Mod-Enter": () => this.editor.commands.exitCode(),
|
|
2826
|
+
Backspace: handleBackspace,
|
|
2827
|
+
"Mod-Backspace": handleBackspace,
|
|
2828
|
+
"Shift-Backspace": handleBackspace,
|
|
2829
|
+
Delete: handleDelete,
|
|
2830
|
+
"Mod-Delete": handleDelete,
|
|
2831
|
+
"Mod-a": () => this.editor.commands.selectAll()
|
|
2832
|
+
};
|
|
2833
|
+
const pcKeymap = {
|
|
2834
|
+
...baseKeymap
|
|
2835
|
+
};
|
|
2836
|
+
const macKeymap = {
|
|
2837
|
+
...baseKeymap,
|
|
2838
|
+
"Ctrl-h": handleBackspace,
|
|
2839
|
+
"Alt-Backspace": handleBackspace,
|
|
2840
|
+
"Ctrl-d": handleDelete,
|
|
2841
|
+
"Ctrl-Alt-Backspace": handleDelete,
|
|
2842
|
+
"Alt-Delete": handleDelete,
|
|
2843
|
+
"Alt-d": handleDelete,
|
|
2844
|
+
"Ctrl-a": () => this.editor.commands.selectTextblockStart(),
|
|
2845
|
+
"Ctrl-e": () => this.editor.commands.selectTextblockEnd()
|
|
2846
|
+
};
|
|
2847
|
+
if (isiOS() || isMacOS()) {
|
|
2848
|
+
return macKeymap;
|
|
2849
|
+
}
|
|
2850
|
+
return pcKeymap;
|
|
2851
|
+
},
|
|
2852
|
+
addProseMirrorPlugins() {
|
|
2853
|
+
return [
|
|
2854
|
+
// With this plugin we check if the whole document was selected and deleted.
|
|
2855
|
+
// In this case we will additionally call `clearNodes()` to convert e.g. a heading
|
|
2856
|
+
// to a paragraph if necessary.
|
|
2857
|
+
// This is an alternative to ProseMirror's `AllSelection`, which doesn’t work well
|
|
2858
|
+
// with many other commands.
|
|
2859
|
+
new (0, _state.Plugin)({
|
|
2860
|
+
key: new (0, _state.PluginKey)("clearDocument"),
|
|
2861
|
+
appendTransaction: (transactions, oldState, newState) => {
|
|
2862
|
+
const docChanges = transactions.some((transaction) => transaction.docChanged) && !oldState.doc.eq(newState.doc);
|
|
2863
|
+
const ignoreTr = transactions.some((transaction) => transaction.getMeta("preventClearDocument"));
|
|
2864
|
+
if (!docChanges || ignoreTr) {
|
|
2865
|
+
return;
|
|
2866
|
+
}
|
|
2867
|
+
const { empty, from, to } = oldState.selection;
|
|
2868
|
+
const allFrom = _state.Selection.atStart(oldState.doc).from;
|
|
2869
|
+
const allEnd = _state.Selection.atEnd(oldState.doc).to;
|
|
2870
|
+
const allWasSelected = from === allFrom && to === allEnd;
|
|
2871
|
+
if (empty || !allWasSelected) {
|
|
2872
|
+
return;
|
|
2873
|
+
}
|
|
2874
|
+
const isEmpty = isNodeEmpty(newState.doc);
|
|
2875
|
+
if (!isEmpty) {
|
|
2876
|
+
return;
|
|
2877
|
+
}
|
|
2878
|
+
const tr = newState.tr;
|
|
2879
|
+
const state = createChainableState({
|
|
2880
|
+
state: newState,
|
|
2881
|
+
transaction: tr
|
|
2882
|
+
});
|
|
2883
|
+
const { commands: commands2 } = new CommandManager({
|
|
2884
|
+
editor: this.editor,
|
|
2885
|
+
state
|
|
2886
|
+
});
|
|
2887
|
+
commands2.clearNodes();
|
|
2888
|
+
if (!tr.steps.length) {
|
|
2889
|
+
return;
|
|
2890
|
+
}
|
|
2891
|
+
return tr;
|
|
2892
|
+
}
|
|
2893
|
+
})
|
|
2894
|
+
];
|
|
2895
|
+
}
|
|
2896
|
+
});
|
|
2897
|
+
var Paste = Extension.create({
|
|
2898
|
+
name: "paste",
|
|
2899
|
+
addProseMirrorPlugins() {
|
|
2900
|
+
return [
|
|
2901
|
+
new (0, _state.Plugin)({
|
|
2902
|
+
key: new (0, _state.PluginKey)("tiptapPaste"),
|
|
2903
|
+
props: {
|
|
2904
|
+
handlePaste: (_view, e, slice) => {
|
|
2905
|
+
this.editor.emit("paste", {
|
|
2906
|
+
editor: this.editor,
|
|
2907
|
+
event: e,
|
|
2908
|
+
slice
|
|
2909
|
+
});
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
})
|
|
2913
|
+
];
|
|
2914
|
+
}
|
|
2915
|
+
});
|
|
2916
|
+
var Tabindex = Extension.create({
|
|
2917
|
+
name: "tabindex",
|
|
2918
|
+
addProseMirrorPlugins() {
|
|
2919
|
+
return [
|
|
2920
|
+
new (0, _state.Plugin)({
|
|
2921
|
+
key: new (0, _state.PluginKey)("tabindex"),
|
|
2922
|
+
props: {
|
|
2923
|
+
attributes: () => this.editor.isEditable ? { tabindex: "0" } : {}
|
|
2924
|
+
}
|
|
2925
|
+
})
|
|
2926
|
+
];
|
|
2927
|
+
}
|
|
2928
|
+
});
|
|
2929
|
+
var Node = class _Node {
|
|
2930
|
+
constructor(config = {}) {
|
|
2931
|
+
this.type = "node";
|
|
2932
|
+
this.name = "node";
|
|
2933
|
+
this.parent = null;
|
|
2934
|
+
this.child = null;
|
|
2935
|
+
this.config = {
|
|
2936
|
+
name: this.name,
|
|
2937
|
+
defaultOptions: {}
|
|
2938
|
+
};
|
|
2939
|
+
this.config = {
|
|
2940
|
+
...this.config,
|
|
2941
|
+
...config
|
|
2942
|
+
};
|
|
2943
|
+
this.name = this.config.name;
|
|
2944
|
+
if (config.defaultOptions && Object.keys(config.defaultOptions).length > 0) {
|
|
2945
|
+
console.warn(`[tiptap warn]: BREAKING CHANGE: "defaultOptions" is deprecated. Please use "addOptions" instead. Found in extension: "${this.name}".`);
|
|
2946
|
+
}
|
|
2947
|
+
this.options = this.config.defaultOptions;
|
|
2948
|
+
if (this.config.addOptions) {
|
|
2949
|
+
this.options = callOrReturn(getExtensionField(this, "addOptions", {
|
|
2950
|
+
name: this.name
|
|
2951
|
+
}));
|
|
2952
|
+
}
|
|
2953
|
+
this.storage = callOrReturn(getExtensionField(this, "addStorage", {
|
|
2954
|
+
name: this.name,
|
|
2955
|
+
options: this.options
|
|
2956
|
+
})) || {};
|
|
2957
|
+
}
|
|
2958
|
+
static create(config = {}) {
|
|
2959
|
+
return new _Node(config);
|
|
2960
|
+
}
|
|
2961
|
+
configure(options = {}) {
|
|
2962
|
+
const extension = this.extend({
|
|
2963
|
+
...this.config,
|
|
2964
|
+
addOptions: () => {
|
|
2965
|
+
return mergeDeep(this.options, options);
|
|
2966
|
+
}
|
|
2967
|
+
});
|
|
2968
|
+
extension.name = this.name;
|
|
2969
|
+
extension.parent = this.parent;
|
|
2970
|
+
return extension;
|
|
2971
|
+
}
|
|
2972
|
+
extend(extendedConfig = {}) {
|
|
2973
|
+
const extension = new _Node(extendedConfig);
|
|
2974
|
+
extension.parent = this;
|
|
2975
|
+
this.child = extension;
|
|
2976
|
+
extension.name = extendedConfig.name ? extendedConfig.name : extension.parent.name;
|
|
2977
|
+
if (extendedConfig.defaultOptions && Object.keys(extendedConfig.defaultOptions).length > 0) {
|
|
2978
|
+
console.warn(`[tiptap warn]: BREAKING CHANGE: "defaultOptions" is deprecated. Please use "addOptions" instead. Found in extension: "${extension.name}".`);
|
|
2979
|
+
}
|
|
2980
|
+
extension.options = callOrReturn(getExtensionField(extension, "addOptions", {
|
|
2981
|
+
name: extension.name
|
|
2982
|
+
}));
|
|
2983
|
+
extension.storage = callOrReturn(getExtensionField(extension, "addStorage", {
|
|
2984
|
+
name: extension.name,
|
|
2985
|
+
options: extension.options
|
|
2986
|
+
}));
|
|
2987
|
+
return extension;
|
|
2988
|
+
}
|
|
2989
|
+
};
|
|
2990
|
+
|
|
2991
|
+
// src/document.ts
|
|
2992
|
+
|
|
2993
|
+
var _starterkit = require('@tiptap/starter-kit'); var _starterkit2 = _interopRequireDefault(_starterkit);
|
|
2994
|
+
var _prosemirrormarkdown = require('prosemirror-markdown');
|
|
2995
|
+
var _yprosemirror = require('y-prosemirror');
|
|
2996
|
+
var _yjs = require('yjs');
|
|
2997
|
+
|
|
2998
|
+
// src/comment.ts
|
|
2999
|
+
var LIVEBLOCKS_COMMENT_MARK_TYPE = "liveblocksCommentMark";
|
|
3000
|
+
var CommentExtension = Mark.create({
|
|
3001
|
+
name: LIVEBLOCKS_COMMENT_MARK_TYPE,
|
|
3002
|
+
excludes: "",
|
|
3003
|
+
inclusive: false,
|
|
3004
|
+
keepOnSplit: true,
|
|
3005
|
+
addAttributes() {
|
|
3006
|
+
return {
|
|
3007
|
+
orphan: {
|
|
3008
|
+
parseHTML: (element) => !!element.getAttribute("data-orphan"),
|
|
3009
|
+
renderHTML: (attributes) => {
|
|
3010
|
+
return attributes.orphan ? {
|
|
3011
|
+
"data-orphan": "true"
|
|
3012
|
+
} : {};
|
|
3013
|
+
},
|
|
3014
|
+
default: false
|
|
3015
|
+
},
|
|
3016
|
+
threadId: {
|
|
3017
|
+
parseHTML: (element) => element.getAttribute("data-lb-thread-id"),
|
|
3018
|
+
renderHTML: (attributes) => {
|
|
3019
|
+
return {
|
|
3020
|
+
"data-lb-thread-id": attributes.threadId
|
|
3021
|
+
};
|
|
3022
|
+
},
|
|
3023
|
+
default: ""
|
|
3024
|
+
}
|
|
3025
|
+
};
|
|
3026
|
+
},
|
|
3027
|
+
renderHTML({ HTMLAttributes }) {
|
|
3028
|
+
return [
|
|
3029
|
+
"span",
|
|
3030
|
+
mergeAttributes(HTMLAttributes, {
|
|
3031
|
+
class: "lb-root lb-tiptap-thread-mark"
|
|
3032
|
+
})
|
|
3033
|
+
];
|
|
3034
|
+
}
|
|
3035
|
+
});
|
|
3036
|
+
|
|
3037
|
+
// src/mention.ts
|
|
3038
|
+
var LIVEBLOCKS_MENTION_TYPE = "liveblocksMention";
|
|
3039
|
+
var MentionExtension = Node.create({
|
|
3040
|
+
name: LIVEBLOCKS_MENTION_TYPE,
|
|
3041
|
+
group: "inline",
|
|
3042
|
+
inline: true,
|
|
3043
|
+
selectable: true,
|
|
3044
|
+
atom: true,
|
|
3045
|
+
priority: 101,
|
|
3046
|
+
parseHTML() {
|
|
3047
|
+
return [
|
|
3048
|
+
{
|
|
3049
|
+
tag: "liveblocks-mention"
|
|
3050
|
+
}
|
|
3051
|
+
];
|
|
3052
|
+
},
|
|
3053
|
+
renderHTML({ HTMLAttributes }) {
|
|
3054
|
+
return ["liveblocks-mention", mergeAttributes(HTMLAttributes)];
|
|
3055
|
+
},
|
|
3056
|
+
addAttributes() {
|
|
3057
|
+
return {
|
|
3058
|
+
id: {
|
|
3059
|
+
default: null,
|
|
3060
|
+
parseHTML: (element) => element.getAttribute("data-id"),
|
|
3061
|
+
renderHTML: (attributes) => {
|
|
3062
|
+
if (!attributes.id) {
|
|
3063
|
+
return {};
|
|
3064
|
+
}
|
|
3065
|
+
return {
|
|
3066
|
+
"data-id": attributes.id
|
|
3067
|
+
// "as" typing because TipTap doesn't have a way to type attributes
|
|
3068
|
+
};
|
|
3069
|
+
}
|
|
3070
|
+
},
|
|
3071
|
+
notificationId: {
|
|
3072
|
+
default: null,
|
|
3073
|
+
parseHTML: (element) => element.getAttribute("data-notification-id"),
|
|
3074
|
+
renderHTML: (attributes) => {
|
|
3075
|
+
if (!attributes.notificationId) {
|
|
3076
|
+
return {};
|
|
3077
|
+
}
|
|
3078
|
+
return {
|
|
3079
|
+
"data-notification-id": attributes.notificationId
|
|
3080
|
+
// "as" typing because TipTap doesn't have a way to type attributes
|
|
3081
|
+
};
|
|
3082
|
+
}
|
|
3083
|
+
}
|
|
3084
|
+
};
|
|
3085
|
+
}
|
|
3086
|
+
});
|
|
3087
|
+
|
|
3088
|
+
// src/document.ts
|
|
3089
|
+
var DEFAULT_SCHEMA = getSchema([
|
|
3090
|
+
_starterkit2.default,
|
|
3091
|
+
CommentExtension,
|
|
3092
|
+
MentionExtension
|
|
3093
|
+
]);
|
|
3094
|
+
var getLiveblocksDocumentState = async (roomId, client, schema, field) => {
|
|
3095
|
+
const update = new Uint8Array(
|
|
3096
|
+
await client.getYjsDocumentAsBinaryUpdate(roomId)
|
|
3097
|
+
);
|
|
3098
|
+
const ydoc = new (0, _yjs.Doc)();
|
|
3099
|
+
_yjs.applyUpdate.call(void 0, ydoc, update);
|
|
3100
|
+
const fragment = ydoc.getXmlFragment(_nullishCoalesce(field, () => ( "default")));
|
|
3101
|
+
const { mapping, doc } = _yprosemirror.initProseMirrorDoc.call(void 0, fragment, schema);
|
|
3102
|
+
const state = _state.EditorState.create({
|
|
3103
|
+
schema,
|
|
3104
|
+
doc
|
|
3105
|
+
});
|
|
3106
|
+
return {
|
|
3107
|
+
fragment,
|
|
3108
|
+
state,
|
|
3109
|
+
ydoc,
|
|
3110
|
+
mapping
|
|
3111
|
+
};
|
|
3112
|
+
};
|
|
3113
|
+
var createDocumentFromContent = (content, schema) => {
|
|
3114
|
+
try {
|
|
3115
|
+
return schema.nodeFromJSON(content);
|
|
3116
|
+
} catch (error) {
|
|
3117
|
+
console.warn(
|
|
3118
|
+
"[warn]: Invalid content.",
|
|
3119
|
+
"Passed value:",
|
|
3120
|
+
content,
|
|
3121
|
+
"Error:",
|
|
3122
|
+
error
|
|
3123
|
+
);
|
|
3124
|
+
return false;
|
|
3125
|
+
}
|
|
3126
|
+
};
|
|
3127
|
+
async function withProsemirrorDocument({ roomId, schema: maybeSchema, client, field }, callback) {
|
|
3128
|
+
const schema = _nullishCoalesce(maybeSchema, () => ( DEFAULT_SCHEMA));
|
|
3129
|
+
let liveblocksState = await getLiveblocksDocumentState(
|
|
3130
|
+
roomId,
|
|
3131
|
+
client,
|
|
3132
|
+
schema,
|
|
3133
|
+
_nullishCoalesce(field, () => ( "default"))
|
|
3134
|
+
);
|
|
3135
|
+
const val = await callback({
|
|
3136
|
+
/**
|
|
3137
|
+
* Fetches and resyncs the latest document with Liveblocks
|
|
3138
|
+
*/
|
|
3139
|
+
async refresh() {
|
|
3140
|
+
liveblocksState = await getLiveblocksDocumentState(
|
|
3141
|
+
roomId,
|
|
3142
|
+
client,
|
|
3143
|
+
schema,
|
|
3144
|
+
_nullishCoalesce(field, () => ( "default"))
|
|
3145
|
+
);
|
|
3146
|
+
},
|
|
3147
|
+
/**
|
|
3148
|
+
* Provide a callback to modify documetns with Lexical's standard api. All calls are discrete.
|
|
3149
|
+
*/
|
|
3150
|
+
async update(modifyFn) {
|
|
3151
|
+
const { ydoc, fragment, state, mapping } = liveblocksState;
|
|
3152
|
+
const beforeVector = _yjs.encodeStateVector.call(void 0, ydoc);
|
|
3153
|
+
const afterState = state.apply(modifyFn(state.doc, state.tr));
|
|
3154
|
+
ydoc.transact(() => {
|
|
3155
|
+
_yprosemirror.updateYFragment.call(void 0, ydoc, fragment, afterState.doc, mapping);
|
|
3156
|
+
});
|
|
3157
|
+
const diffUpdate = _yjs.encodeStateAsUpdate.call(void 0, ydoc, beforeVector);
|
|
3158
|
+
await client.sendYjsBinaryUpdate(roomId, diffUpdate);
|
|
3159
|
+
await this.refresh();
|
|
3160
|
+
},
|
|
3161
|
+
/**
|
|
3162
|
+
* allows you to set content similar to TipTap's setcontent. Only accepts nulls, objects or strings.
|
|
3163
|
+
* Unlike TipTap, strings won't be parsed with DOMParser
|
|
3164
|
+
* */
|
|
3165
|
+
async setContent(content) {
|
|
3166
|
+
if (typeof content === "string") {
|
|
3167
|
+
return this.update((doc, tr) => {
|
|
3168
|
+
tr.delete(0, doc.content.size);
|
|
3169
|
+
tr.insertText(content);
|
|
3170
|
+
return tr;
|
|
3171
|
+
});
|
|
3172
|
+
}
|
|
3173
|
+
if (content === null) {
|
|
3174
|
+
return this.clearContent();
|
|
3175
|
+
}
|
|
3176
|
+
const node = createDocumentFromContent(content, schema);
|
|
3177
|
+
if (!node) {
|
|
3178
|
+
throw "Invalid content";
|
|
3179
|
+
}
|
|
3180
|
+
return this.update((doc, tr) => {
|
|
3181
|
+
tr.delete(0, doc.content.size);
|
|
3182
|
+
tr.insert(0, node);
|
|
3183
|
+
return tr;
|
|
3184
|
+
});
|
|
3185
|
+
},
|
|
3186
|
+
async clearContent() {
|
|
3187
|
+
await this.update((doc, tr) => {
|
|
3188
|
+
tr.delete(0, doc.content.size);
|
|
3189
|
+
return tr;
|
|
3190
|
+
});
|
|
3191
|
+
},
|
|
3192
|
+
/**
|
|
3193
|
+
* Uses TipTap's getText function, which allows passing a custom text serializer
|
|
3194
|
+
*/
|
|
3195
|
+
getText(options) {
|
|
3196
|
+
const { state } = liveblocksState;
|
|
3197
|
+
return getText(state.doc, options);
|
|
3198
|
+
},
|
|
3199
|
+
/**
|
|
3200
|
+
* Helper function to return prosemirror document in JSON form
|
|
3201
|
+
*/
|
|
3202
|
+
toJSON() {
|
|
3203
|
+
return liveblocksState.state.doc.toJSON();
|
|
3204
|
+
},
|
|
3205
|
+
/**
|
|
3206
|
+
* Helper function to return editor state as Markdown. By default it uses the defaultMarkdownSerializer from prosemirror-markdown, but you may pass your own
|
|
3207
|
+
*/
|
|
3208
|
+
toMarkdown(serializer) {
|
|
3209
|
+
return (_nullishCoalesce(serializer, () => ( _prosemirrormarkdown.defaultMarkdownSerializer))).serialize(
|
|
3210
|
+
liveblocksState.state.doc
|
|
3211
|
+
);
|
|
3212
|
+
},
|
|
3213
|
+
/**
|
|
3214
|
+
* Helper function to return the editor's current prosemirror state
|
|
3215
|
+
*/
|
|
3216
|
+
getEditorState() {
|
|
3217
|
+
return liveblocksState.state;
|
|
3218
|
+
}
|
|
3219
|
+
});
|
|
3220
|
+
return val;
|
|
3221
|
+
}
|
|
3222
|
+
|
|
3223
|
+
// src/index.ts
|
|
3224
|
+
_core.detectDupes.call(void 0, PKG_NAME, PKG_VERSION, PKG_FORMAT);
|
|
3225
|
+
|
|
3226
|
+
|
|
3227
|
+
exports.withProsemirrorDocument = withProsemirrorDocument;
|
|
3228
|
+
//# sourceMappingURL=index.js.map
|