@tiptap/core 2.5.0-beta.0 → 2.5.0-beta.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.cjs +92 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +92 -13
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +92 -13
- 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 +21 -0
- 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/helpers/createDocument.ts +6 -1
- package/src/helpers/createNodeFromContent.ts +42 -2
- package/src/types.ts +21 -0
package/dist/index.js
CHANGED
|
@@ -1770,15 +1770,49 @@ function createNodeFromContent(content, schema, options) {
|
|
|
1770
1770
|
return schema.nodeFromJSON(content);
|
|
1771
1771
|
}
|
|
1772
1772
|
catch (error) {
|
|
1773
|
+
if (options.errorOnInvalidContent) {
|
|
1774
|
+
throw new Error('[tiptap error]: Invalid JSON content', { cause: error });
|
|
1775
|
+
}
|
|
1773
1776
|
console.warn('[tiptap warn]: Invalid content.', 'Passed value:', content, 'Error:', error);
|
|
1774
1777
|
return createNodeFromContent('', schema, options);
|
|
1775
1778
|
}
|
|
1776
1779
|
}
|
|
1777
1780
|
if (isTextContent) {
|
|
1778
|
-
|
|
1779
|
-
|
|
1781
|
+
let schemaToUse = schema;
|
|
1782
|
+
let hasInvalidContent = false;
|
|
1783
|
+
// Only ever check for invalid content if we're supposed to throw an error
|
|
1784
|
+
if (options.errorOnInvalidContent) {
|
|
1785
|
+
schemaToUse = new Schema({
|
|
1786
|
+
topNode: schema.spec.topNode,
|
|
1787
|
+
marks: schema.spec.marks,
|
|
1788
|
+
// Prosemirror's schemas are executed such that: the last to execute, matches last
|
|
1789
|
+
// 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
|
|
1790
|
+
nodes: schema.spec.nodes.append({
|
|
1791
|
+
__tiptap__private__unknown__catch__all__node: {
|
|
1792
|
+
content: 'inline*',
|
|
1793
|
+
group: 'block',
|
|
1794
|
+
parseDOM: [
|
|
1795
|
+
{
|
|
1796
|
+
tag: '*',
|
|
1797
|
+
getAttrs: () => {
|
|
1798
|
+
// If this is ever called, we know that the content has something that we don't know how to handle in the schema
|
|
1799
|
+
hasInvalidContent = true;
|
|
1800
|
+
return null;
|
|
1801
|
+
},
|
|
1802
|
+
},
|
|
1803
|
+
],
|
|
1804
|
+
},
|
|
1805
|
+
}),
|
|
1806
|
+
});
|
|
1807
|
+
}
|
|
1808
|
+
const parser = DOMParser.fromSchema(schemaToUse);
|
|
1809
|
+
const response = options.slice
|
|
1780
1810
|
? parser.parseSlice(elementFromString(content), options.parseOptions).content
|
|
1781
1811
|
: parser.parse(elementFromString(content), options.parseOptions);
|
|
1812
|
+
if (options.errorOnInvalidContent && hasInvalidContent) {
|
|
1813
|
+
throw new Error('[tiptap error]: Invalid HTML content');
|
|
1814
|
+
}
|
|
1815
|
+
return response;
|
|
1782
1816
|
}
|
|
1783
1817
|
return createNodeFromContent('', schema, options);
|
|
1784
1818
|
}
|
|
@@ -1807,6 +1841,7 @@ const isFragment = (nodeOrFragment) => {
|
|
|
1807
1841
|
return nodeOrFragment.toString().startsWith('<');
|
|
1808
1842
|
};
|
|
1809
1843
|
const insertContentAt = (position, value, options) => ({ tr, dispatch, editor }) => {
|
|
1844
|
+
var _a;
|
|
1810
1845
|
if (dispatch) {
|
|
1811
1846
|
options = {
|
|
1812
1847
|
parseOptions: {},
|
|
@@ -1815,12 +1850,19 @@ const insertContentAt = (position, value, options) => ({ tr, dispatch, editor })
|
|
|
1815
1850
|
applyPasteRules: false,
|
|
1816
1851
|
...options,
|
|
1817
1852
|
};
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1853
|
+
let content;
|
|
1854
|
+
try {
|
|
1855
|
+
content = createNodeFromContent(value, editor.schema, {
|
|
1856
|
+
parseOptions: {
|
|
1857
|
+
preserveWhitespace: 'full',
|
|
1858
|
+
...options.parseOptions,
|
|
1859
|
+
},
|
|
1860
|
+
errorOnInvalidContent: (_a = options.errorOnInvalidContent) !== null && _a !== void 0 ? _a : editor.options.enableContentCheck,
|
|
1861
|
+
});
|
|
1862
|
+
}
|
|
1863
|
+
catch (e) {
|
|
1864
|
+
return false;
|
|
1865
|
+
}
|
|
1824
1866
|
// don’t dispatch an empty fragment because this can lead to strange errors
|
|
1825
1867
|
if (content.toString() === '<>') {
|
|
1826
1868
|
return true;
|
|
@@ -2184,13 +2226,26 @@ const selectTextblockStart = () => ({ state, dispatch }) => {
|
|
|
2184
2226
|
* @param parseOptions Options for the parser
|
|
2185
2227
|
* @returns The created Prosemirror document node
|
|
2186
2228
|
*/
|
|
2187
|
-
function createDocument(content, schema, parseOptions = {}) {
|
|
2188
|
-
return createNodeFromContent(content, schema, {
|
|
2229
|
+
function createDocument(content, schema, parseOptions = {}, options = {}) {
|
|
2230
|
+
return createNodeFromContent(content, schema, {
|
|
2231
|
+
slice: false,
|
|
2232
|
+
parseOptions,
|
|
2233
|
+
errorOnInvalidContent: options.errorOnInvalidContent,
|
|
2234
|
+
});
|
|
2189
2235
|
}
|
|
2190
2236
|
|
|
2191
|
-
const setContent = (content, emitUpdate = false, parseOptions = {}) => ({ tr, editor, dispatch }) => {
|
|
2237
|
+
const setContent = (content, emitUpdate = false, parseOptions = {}, options = {}) => ({ tr, editor, dispatch }) => {
|
|
2238
|
+
var _a;
|
|
2192
2239
|
const { doc } = tr;
|
|
2193
|
-
|
|
2240
|
+
let document;
|
|
2241
|
+
try {
|
|
2242
|
+
document = createDocument(content, editor.schema, parseOptions, {
|
|
2243
|
+
errorOnInvalidContent: (_a = options.errorOnInvalidContent) !== null && _a !== void 0 ? _a : editor.options.enableContentCheck,
|
|
2244
|
+
});
|
|
2245
|
+
}
|
|
2246
|
+
catch (e) {
|
|
2247
|
+
return false;
|
|
2248
|
+
}
|
|
2194
2249
|
if (dispatch) {
|
|
2195
2250
|
tr.replaceWith(0, doc.content.size, document).setMeta('preventUpdate', !emitUpdate);
|
|
2196
2251
|
}
|
|
@@ -3879,6 +3934,7 @@ class Editor extends EventEmitter {
|
|
|
3879
3934
|
enableInputRules: true,
|
|
3880
3935
|
enablePasteRules: true,
|
|
3881
3936
|
enableCoreExtensions: true,
|
|
3937
|
+
enableContentCheck: false,
|
|
3882
3938
|
onBeforeCreate: () => null,
|
|
3883
3939
|
onCreate: () => null,
|
|
3884
3940
|
onUpdate: () => null,
|
|
@@ -3887,6 +3943,7 @@ class Editor extends EventEmitter {
|
|
|
3887
3943
|
onFocus: () => null,
|
|
3888
3944
|
onBlur: () => null,
|
|
3889
3945
|
onDestroy: () => null,
|
|
3946
|
+
onContentError: ({ error }) => { throw error; },
|
|
3890
3947
|
};
|
|
3891
3948
|
this.isCapturingTransaction = false;
|
|
3892
3949
|
this.capturedTransaction = null;
|
|
@@ -3896,6 +3953,7 @@ class Editor extends EventEmitter {
|
|
|
3896
3953
|
this.createSchema();
|
|
3897
3954
|
this.on('beforeCreate', this.options.onBeforeCreate);
|
|
3898
3955
|
this.emit('beforeCreate', { editor: this });
|
|
3956
|
+
this.on('contentError', this.options.onContentError);
|
|
3899
3957
|
this.createView();
|
|
3900
3958
|
this.injectCSS();
|
|
3901
3959
|
this.on('create', this.options.onCreate);
|
|
@@ -4055,7 +4113,28 @@ class Editor extends EventEmitter {
|
|
|
4055
4113
|
* Creates a ProseMirror view.
|
|
4056
4114
|
*/
|
|
4057
4115
|
createView() {
|
|
4058
|
-
|
|
4116
|
+
let doc;
|
|
4117
|
+
try {
|
|
4118
|
+
doc = createDocument(this.options.content, this.schema, this.options.parseOptions, { errorOnInvalidContent: this.options.enableContentCheck });
|
|
4119
|
+
}
|
|
4120
|
+
catch (e) {
|
|
4121
|
+
if (!(e instanceof Error) || !['[tiptap error]: Invalid JSON content', '[tiptap error]: Invalid HTML content'].includes(e.message)) {
|
|
4122
|
+
// Not the content error we were expecting
|
|
4123
|
+
throw e;
|
|
4124
|
+
}
|
|
4125
|
+
this.emit('contentError', {
|
|
4126
|
+
editor: this,
|
|
4127
|
+
error: e,
|
|
4128
|
+
disableCollaboration: () => {
|
|
4129
|
+
// To avoid syncing back invalid content, reinitialize the extensions without the collaboration extension
|
|
4130
|
+
this.options.extensions = this.options.extensions.filter(extension => extension.name !== 'collaboration');
|
|
4131
|
+
// Restart the initialization process by recreating the extension manager with the new set of extensions
|
|
4132
|
+
this.createExtensionManager();
|
|
4133
|
+
},
|
|
4134
|
+
});
|
|
4135
|
+
// Content is invalid, but attempt to create it anyway, stripping out the invalid parts
|
|
4136
|
+
doc = createDocument(this.options.content, this.schema, this.options.parseOptions, { errorOnInvalidContent: false });
|
|
4137
|
+
}
|
|
4059
4138
|
const selection = resolveFocusPosition(doc, this.options.autofocus);
|
|
4060
4139
|
this.view = new EditorView(this.options.element, {
|
|
4061
4140
|
...this.options.editorProps,
|