@tiptap/core 2.5.0-beta.0 → 2.5.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +119 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +119 -30
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +119 -30
- package/dist/index.umd.js.map +1 -1
- package/dist/packages/core/src/Editor.d.ts +4 -2
- package/dist/packages/core/src/commands/insertContentAt.d.ts +10 -0
- package/dist/packages/core/src/commands/setContent.d.ts +10 -1
- package/dist/packages/core/src/helpers/createDocument.d.ts +3 -1
- package/dist/packages/core/src/helpers/createNodeFromContent.d.ts +1 -0
- package/dist/packages/core/src/types.d.ts +23 -2
- package/package.json +2 -2
- package/src/Editor.ts +45 -4
- package/src/commands/insertContentAt.ts +26 -6
- package/src/commands/setContent.ts +21 -3
- package/src/commands/updateAttributes.ts +40 -25
- package/src/helpers/createDocument.ts +6 -1
- package/src/helpers/createNodeFromContent.ts +42 -2
- package/src/types.ts +23 -2
package/dist/index.umd.js
CHANGED
|
@@ -1768,15 +1768,49 @@
|
|
|
1768
1768
|
return schema.nodeFromJSON(content);
|
|
1769
1769
|
}
|
|
1770
1770
|
catch (error) {
|
|
1771
|
+
if (options.errorOnInvalidContent) {
|
|
1772
|
+
throw new Error('[tiptap error]: Invalid JSON content', { cause: error });
|
|
1773
|
+
}
|
|
1771
1774
|
console.warn('[tiptap warn]: Invalid content.', 'Passed value:', content, 'Error:', error);
|
|
1772
1775
|
return createNodeFromContent('', schema, options);
|
|
1773
1776
|
}
|
|
1774
1777
|
}
|
|
1775
1778
|
if (isTextContent) {
|
|
1776
|
-
|
|
1777
|
-
|
|
1779
|
+
let schemaToUse = schema;
|
|
1780
|
+
let hasInvalidContent = false;
|
|
1781
|
+
// Only ever check for invalid content if we're supposed to throw an error
|
|
1782
|
+
if (options.errorOnInvalidContent) {
|
|
1783
|
+
schemaToUse = new model.Schema({
|
|
1784
|
+
topNode: schema.spec.topNode,
|
|
1785
|
+
marks: schema.spec.marks,
|
|
1786
|
+
// Prosemirror's schemas are executed such that: the last to execute, matches last
|
|
1787
|
+
// 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
|
|
1788
|
+
nodes: schema.spec.nodes.append({
|
|
1789
|
+
__tiptap__private__unknown__catch__all__node: {
|
|
1790
|
+
content: 'inline*',
|
|
1791
|
+
group: 'block',
|
|
1792
|
+
parseDOM: [
|
|
1793
|
+
{
|
|
1794
|
+
tag: '*',
|
|
1795
|
+
getAttrs: () => {
|
|
1796
|
+
// If this is ever called, we know that the content has something that we don't know how to handle in the schema
|
|
1797
|
+
hasInvalidContent = true;
|
|
1798
|
+
return null;
|
|
1799
|
+
},
|
|
1800
|
+
},
|
|
1801
|
+
],
|
|
1802
|
+
},
|
|
1803
|
+
}),
|
|
1804
|
+
});
|
|
1805
|
+
}
|
|
1806
|
+
const parser = model.DOMParser.fromSchema(schemaToUse);
|
|
1807
|
+
const response = options.slice
|
|
1778
1808
|
? parser.parseSlice(elementFromString(content), options.parseOptions).content
|
|
1779
1809
|
: parser.parse(elementFromString(content), options.parseOptions);
|
|
1810
|
+
if (options.errorOnInvalidContent && hasInvalidContent) {
|
|
1811
|
+
throw new Error('[tiptap error]: Invalid HTML content');
|
|
1812
|
+
}
|
|
1813
|
+
return response;
|
|
1780
1814
|
}
|
|
1781
1815
|
return createNodeFromContent('', schema, options);
|
|
1782
1816
|
}
|
|
@@ -1805,6 +1839,7 @@
|
|
|
1805
1839
|
return nodeOrFragment.toString().startsWith('<');
|
|
1806
1840
|
};
|
|
1807
1841
|
const insertContentAt = (position, value, options) => ({ tr, dispatch, editor }) => {
|
|
1842
|
+
var _a;
|
|
1808
1843
|
if (dispatch) {
|
|
1809
1844
|
options = {
|
|
1810
1845
|
parseOptions: {},
|
|
@@ -1813,12 +1848,19 @@
|
|
|
1813
1848
|
applyPasteRules: false,
|
|
1814
1849
|
...options,
|
|
1815
1850
|
};
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1851
|
+
let content;
|
|
1852
|
+
try {
|
|
1853
|
+
content = createNodeFromContent(value, editor.schema, {
|
|
1854
|
+
parseOptions: {
|
|
1855
|
+
preserveWhitespace: 'full',
|
|
1856
|
+
...options.parseOptions,
|
|
1857
|
+
},
|
|
1858
|
+
errorOnInvalidContent: (_a = options.errorOnInvalidContent) !== null && _a !== void 0 ? _a : editor.options.enableContentCheck,
|
|
1859
|
+
});
|
|
1860
|
+
}
|
|
1861
|
+
catch (e) {
|
|
1862
|
+
return false;
|
|
1863
|
+
}
|
|
1822
1864
|
// don’t dispatch an empty fragment because this can lead to strange errors
|
|
1823
1865
|
if (content.toString() === '<>') {
|
|
1824
1866
|
return true;
|
|
@@ -2182,13 +2224,26 @@
|
|
|
2182
2224
|
* @param parseOptions Options for the parser
|
|
2183
2225
|
* @returns The created Prosemirror document node
|
|
2184
2226
|
*/
|
|
2185
|
-
function createDocument(content, schema, parseOptions = {}) {
|
|
2186
|
-
return createNodeFromContent(content, schema, {
|
|
2227
|
+
function createDocument(content, schema, parseOptions = {}, options = {}) {
|
|
2228
|
+
return createNodeFromContent(content, schema, {
|
|
2229
|
+
slice: false,
|
|
2230
|
+
parseOptions,
|
|
2231
|
+
errorOnInvalidContent: options.errorOnInvalidContent,
|
|
2232
|
+
});
|
|
2187
2233
|
}
|
|
2188
2234
|
|
|
2189
|
-
const setContent = (content, emitUpdate = false, parseOptions = {}) => ({ tr, editor, dispatch }) => {
|
|
2235
|
+
const setContent = (content, emitUpdate = false, parseOptions = {}, options = {}) => ({ tr, editor, dispatch }) => {
|
|
2236
|
+
var _a;
|
|
2190
2237
|
const { doc } = tr;
|
|
2191
|
-
|
|
2238
|
+
let document;
|
|
2239
|
+
try {
|
|
2240
|
+
document = createDocument(content, editor.schema, parseOptions, {
|
|
2241
|
+
errorOnInvalidContent: (_a = options.errorOnInvalidContent) !== null && _a !== void 0 ? _a : editor.options.enableContentCheck,
|
|
2242
|
+
});
|
|
2243
|
+
}
|
|
2244
|
+
catch (e) {
|
|
2245
|
+
return false;
|
|
2246
|
+
}
|
|
2192
2247
|
if (dispatch) {
|
|
2193
2248
|
tr.replaceWith(0, doc.content.size, document).setMeta('preventUpdate', !emitUpdate);
|
|
2194
2249
|
}
|
|
@@ -3295,30 +3350,40 @@
|
|
|
3295
3350
|
markType = getMarkType(typeOrName, state.schema);
|
|
3296
3351
|
}
|
|
3297
3352
|
if (dispatch) {
|
|
3298
|
-
|
|
3353
|
+
let lastPos;
|
|
3354
|
+
let lastNode;
|
|
3355
|
+
let trimmedFrom;
|
|
3356
|
+
let trimmedTo;
|
|
3357
|
+
tr.selection.ranges.forEach((range) => {
|
|
3299
3358
|
const from = range.$from.pos;
|
|
3300
3359
|
const to = range.$to.pos;
|
|
3301
3360
|
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
3302
3361
|
if (nodeType && nodeType === node.type) {
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
}
|
|
3308
|
-
if (markType && node.marks.length) {
|
|
3309
|
-
node.marks.forEach(mark => {
|
|
3310
|
-
if (markType === mark.type) {
|
|
3311
|
-
const trimmedFrom = Math.max(pos, from);
|
|
3312
|
-
const trimmedTo = Math.min(pos + node.nodeSize, to);
|
|
3313
|
-
tr.addMark(trimmedFrom, trimmedTo, markType.create({
|
|
3314
|
-
...mark.attrs,
|
|
3315
|
-
...attributes,
|
|
3316
|
-
}));
|
|
3317
|
-
}
|
|
3318
|
-
});
|
|
3362
|
+
trimmedFrom = Math.max(pos, from);
|
|
3363
|
+
trimmedTo = Math.min(pos + node.nodeSize, to);
|
|
3364
|
+
lastPos = pos;
|
|
3365
|
+
lastNode = node;
|
|
3319
3366
|
}
|
|
3320
3367
|
});
|
|
3321
3368
|
});
|
|
3369
|
+
if (lastNode) {
|
|
3370
|
+
if (lastPos !== undefined) {
|
|
3371
|
+
tr.setNodeMarkup(lastPos, undefined, {
|
|
3372
|
+
...lastNode.attrs,
|
|
3373
|
+
...attributes,
|
|
3374
|
+
});
|
|
3375
|
+
}
|
|
3376
|
+
if (markType && lastNode.marks.length) {
|
|
3377
|
+
lastNode.marks.forEach((mark) => {
|
|
3378
|
+
if (markType === mark.type) {
|
|
3379
|
+
tr.addMark(trimmedFrom, trimmedTo, markType.create({
|
|
3380
|
+
...mark.attrs,
|
|
3381
|
+
...attributes,
|
|
3382
|
+
}));
|
|
3383
|
+
}
|
|
3384
|
+
});
|
|
3385
|
+
}
|
|
3386
|
+
}
|
|
3322
3387
|
}
|
|
3323
3388
|
return true;
|
|
3324
3389
|
};
|
|
@@ -3877,6 +3942,7 @@ img.ProseMirror-separator {
|
|
|
3877
3942
|
enableInputRules: true,
|
|
3878
3943
|
enablePasteRules: true,
|
|
3879
3944
|
enableCoreExtensions: true,
|
|
3945
|
+
enableContentCheck: false,
|
|
3880
3946
|
onBeforeCreate: () => null,
|
|
3881
3947
|
onCreate: () => null,
|
|
3882
3948
|
onUpdate: () => null,
|
|
@@ -3885,6 +3951,7 @@ img.ProseMirror-separator {
|
|
|
3885
3951
|
onFocus: () => null,
|
|
3886
3952
|
onBlur: () => null,
|
|
3887
3953
|
onDestroy: () => null,
|
|
3954
|
+
onContentError: ({ error }) => { throw error; },
|
|
3888
3955
|
};
|
|
3889
3956
|
this.isCapturingTransaction = false;
|
|
3890
3957
|
this.capturedTransaction = null;
|
|
@@ -3894,6 +3961,7 @@ img.ProseMirror-separator {
|
|
|
3894
3961
|
this.createSchema();
|
|
3895
3962
|
this.on('beforeCreate', this.options.onBeforeCreate);
|
|
3896
3963
|
this.emit('beforeCreate', { editor: this });
|
|
3964
|
+
this.on('contentError', this.options.onContentError);
|
|
3897
3965
|
this.createView();
|
|
3898
3966
|
this.injectCSS();
|
|
3899
3967
|
this.on('create', this.options.onCreate);
|
|
@@ -4053,7 +4121,28 @@ img.ProseMirror-separator {
|
|
|
4053
4121
|
* Creates a ProseMirror view.
|
|
4054
4122
|
*/
|
|
4055
4123
|
createView() {
|
|
4056
|
-
|
|
4124
|
+
let doc;
|
|
4125
|
+
try {
|
|
4126
|
+
doc = createDocument(this.options.content, this.schema, this.options.parseOptions, { errorOnInvalidContent: this.options.enableContentCheck });
|
|
4127
|
+
}
|
|
4128
|
+
catch (e) {
|
|
4129
|
+
if (!(e instanceof Error) || !['[tiptap error]: Invalid JSON content', '[tiptap error]: Invalid HTML content'].includes(e.message)) {
|
|
4130
|
+
// Not the content error we were expecting
|
|
4131
|
+
throw e;
|
|
4132
|
+
}
|
|
4133
|
+
this.emit('contentError', {
|
|
4134
|
+
editor: this,
|
|
4135
|
+
error: e,
|
|
4136
|
+
disableCollaboration: () => {
|
|
4137
|
+
// To avoid syncing back invalid content, reinitialize the extensions without the collaboration extension
|
|
4138
|
+
this.options.extensions = this.options.extensions.filter(extension => extension.name !== 'collaboration');
|
|
4139
|
+
// Restart the initialization process by recreating the extension manager with the new set of extensions
|
|
4140
|
+
this.createExtensionManager();
|
|
4141
|
+
},
|
|
4142
|
+
});
|
|
4143
|
+
// Content is invalid, but attempt to create it anyway, stripping out the invalid parts
|
|
4144
|
+
doc = createDocument(this.options.content, this.schema, this.options.parseOptions, { errorOnInvalidContent: false });
|
|
4145
|
+
}
|
|
4057
4146
|
const selection = resolveFocusPosition(doc, this.options.autofocus);
|
|
4058
4147
|
this.view = new view.EditorView(this.options.element, {
|
|
4059
4148
|
...this.options.editorProps,
|