@tiptap/core 2.4.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 +96 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +96 -16
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +96 -16
- package/dist/index.umd.js.map +1 -1
- package/dist/packages/core/src/Editor.d.ts +4 -2
- package/dist/packages/core/src/EventEmitter.d.ts +2 -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/EventEmitter.ts +2 -2
- package/src/commands/insertContentAt.ts +26 -6
- package/src/commands/joinItemBackward.ts +4 -2
- package/src/commands/setContent.ts +21 -3
- package/src/helpers/createDocument.ts +6 -1
- package/src/helpers/createNodeFromContent.ts +42 -2
- package/src/inputRules/nodeInputRule.ts +3 -1
- package/src/types.ts +21 -0
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;
|
|
@@ -1894,7 +1936,7 @@
|
|
|
1894
1936
|
return commands$1.joinForward(state, dispatch);
|
|
1895
1937
|
};
|
|
1896
1938
|
|
|
1897
|
-
const joinItemBackward = () => ({
|
|
1939
|
+
const joinItemBackward = () => ({ state, dispatch, tr, }) => {
|
|
1898
1940
|
try {
|
|
1899
1941
|
const point = transform.joinPoint(state.doc, state.selection.$from.pos, -1);
|
|
1900
1942
|
if (point === null || point === undefined) {
|
|
@@ -1906,7 +1948,7 @@
|
|
|
1906
1948
|
}
|
|
1907
1949
|
return true;
|
|
1908
1950
|
}
|
|
1909
|
-
catch {
|
|
1951
|
+
catch (e) {
|
|
1910
1952
|
return false;
|
|
1911
1953
|
}
|
|
1912
1954
|
};
|
|
@@ -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
|
}
|
|
@@ -3877,6 +3932,7 @@ img.ProseMirror-separator {
|
|
|
3877
3932
|
enableInputRules: true,
|
|
3878
3933
|
enablePasteRules: true,
|
|
3879
3934
|
enableCoreExtensions: true,
|
|
3935
|
+
enableContentCheck: false,
|
|
3880
3936
|
onBeforeCreate: () => null,
|
|
3881
3937
|
onCreate: () => null,
|
|
3882
3938
|
onUpdate: () => null,
|
|
@@ -3885,6 +3941,7 @@ img.ProseMirror-separator {
|
|
|
3885
3941
|
onFocus: () => null,
|
|
3886
3942
|
onBlur: () => null,
|
|
3887
3943
|
onDestroy: () => null,
|
|
3944
|
+
onContentError: ({ error }) => { throw error; },
|
|
3888
3945
|
};
|
|
3889
3946
|
this.isCapturingTransaction = false;
|
|
3890
3947
|
this.capturedTransaction = null;
|
|
@@ -3894,6 +3951,7 @@ img.ProseMirror-separator {
|
|
|
3894
3951
|
this.createSchema();
|
|
3895
3952
|
this.on('beforeCreate', this.options.onBeforeCreate);
|
|
3896
3953
|
this.emit('beforeCreate', { editor: this });
|
|
3954
|
+
this.on('contentError', this.options.onContentError);
|
|
3897
3955
|
this.createView();
|
|
3898
3956
|
this.injectCSS();
|
|
3899
3957
|
this.on('create', this.options.onCreate);
|
|
@@ -4053,7 +4111,28 @@ img.ProseMirror-separator {
|
|
|
4053
4111
|
* Creates a ProseMirror view.
|
|
4054
4112
|
*/
|
|
4055
4113
|
createView() {
|
|
4056
|
-
|
|
4114
|
+
let doc;
|
|
4115
|
+
try {
|
|
4116
|
+
doc = createDocument(this.options.content, this.schema, this.options.parseOptions, { errorOnInvalidContent: this.options.enableContentCheck });
|
|
4117
|
+
}
|
|
4118
|
+
catch (e) {
|
|
4119
|
+
if (!(e instanceof Error) || !['[tiptap error]: Invalid JSON content', '[tiptap error]: Invalid HTML content'].includes(e.message)) {
|
|
4120
|
+
// Not the content error we were expecting
|
|
4121
|
+
throw e;
|
|
4122
|
+
}
|
|
4123
|
+
this.emit('contentError', {
|
|
4124
|
+
editor: this,
|
|
4125
|
+
error: e,
|
|
4126
|
+
disableCollaboration: () => {
|
|
4127
|
+
// To avoid syncing back invalid content, reinitialize the extensions without the collaboration extension
|
|
4128
|
+
this.options.extensions = this.options.extensions.filter(extension => extension.name !== 'collaboration');
|
|
4129
|
+
// Restart the initialization process by recreating the extension manager with the new set of extensions
|
|
4130
|
+
this.createExtensionManager();
|
|
4131
|
+
},
|
|
4132
|
+
});
|
|
4133
|
+
// Content is invalid, but attempt to create it anyway, stripping out the invalid parts
|
|
4134
|
+
doc = createDocument(this.options.content, this.schema, this.options.parseOptions, { errorOnInvalidContent: false });
|
|
4135
|
+
}
|
|
4057
4136
|
const selection = resolveFocusPosition(doc, this.options.autofocus);
|
|
4058
4137
|
this.view = new view.EditorView(this.options.element, {
|
|
4059
4138
|
...this.options.editorProps,
|
|
@@ -4314,7 +4393,8 @@ img.ProseMirror-separator {
|
|
|
4314
4393
|
tr.replaceWith(matchStart, end, newNode);
|
|
4315
4394
|
}
|
|
4316
4395
|
else if (match[0]) {
|
|
4317
|
-
|
|
4396
|
+
const insertionStart = config.type.isInline ? start : start - 1;
|
|
4397
|
+
tr.insert(insertionStart, config.type.create(attributes)).delete(tr.mapping.map(start), tr.mapping.map(end));
|
|
4318
4398
|
}
|
|
4319
4399
|
tr.scrollIntoView();
|
|
4320
4400
|
},
|