@tiptap/core 2.5.0-beta.3 → 2.5.0-beta.5

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 CHANGED
@@ -466,6 +466,7 @@ function getSchemaByResolvedExtensions(extensions, editor) {
466
466
  selectable: callOrReturn(getExtensionField(extension, 'selectable', context)),
467
467
  draggable: callOrReturn(getExtensionField(extension, 'draggable', context)),
468
468
  code: callOrReturn(getExtensionField(extension, 'code', context)),
469
+ whitespace: callOrReturn(getExtensionField(extension, 'whitespace', context)),
469
470
  defining: callOrReturn(getExtensionField(extension, 'defining', context)),
470
471
  isolating: callOrReturn(getExtensionField(extension, 'isolating', context)),
471
472
  attrs: Object.fromEntries(extensionAttributes.map(extensionAttribute => {
@@ -1083,7 +1084,7 @@ class ExtensionManager {
1083
1084
  const addKeyboardShortcuts = getExtensionField(extension, 'addKeyboardShortcuts', context);
1084
1085
  let defaultBindings = {};
1085
1086
  // bind exit handling
1086
- if (extension.type === 'mark' && extension.config.exitable) {
1087
+ if (extension.type === 'mark' && getExtensionField(extension, 'exitable', context)) {
1087
1088
  defaultBindings.ArrowRight = () => Mark.handleExit({ editor, mark: extension });
1088
1089
  }
1089
1090
  if (addKeyboardShortcuts) {
@@ -1289,13 +1290,17 @@ class Extension {
1289
1290
  configure(options = {}) {
1290
1291
  // return a new instance so we can use the same extension
1291
1292
  // with different calls of `configure`
1292
- const extension = this.extend();
1293
+ const extension = this.extend({
1294
+ ...this.config,
1295
+ addOptions() {
1296
+ var _a;
1297
+ return mergeDeep(((_a = this.parent) === null || _a === void 0 ? void 0 : _a.call(this)) || {}, options);
1298
+ },
1299
+ });
1300
+ // Always preserve the current name
1301
+ extension.name = this.name;
1302
+ // Set the parent to be our parent
1293
1303
  extension.parent = this.parent;
1294
- extension.options = mergeDeep(this.options, options);
1295
- extension.storage = callOrReturn(getExtensionField(extension, 'addStorage', {
1296
- name: extension.name,
1297
- options: extension.options,
1298
- }));
1299
1304
  return extension;
1300
1305
  }
1301
1306
  extend(extendedConfig = {}) {
@@ -1303,7 +1308,7 @@ class Extension {
1303
1308
  extension.parent = this;
1304
1309
  this.child = extension;
1305
1310
  extension.name = extendedConfig.name ? extendedConfig.name : extension.parent.name;
1306
- if (extendedConfig.defaultOptions) {
1311
+ if (extendedConfig.defaultOptions && Object.keys(extendedConfig.defaultOptions).length > 0) {
1307
1312
  console.warn(`[tiptap warn]: BREAKING CHANGE: "defaultOptions" is deprecated. Please use "addOptions" instead. Found in extension: "${extension.name}".`);
1308
1313
  }
1309
1314
  extension.options = callOrReturn(getExtensionField(extension, 'addOptions', {
@@ -1777,6 +1782,7 @@ function createNodeFromContent(content, schema, options) {
1777
1782
  if (isTextContent) {
1778
1783
  let schemaToUse = schema;
1779
1784
  let hasInvalidContent = false;
1785
+ let invalidContent = '';
1780
1786
  // Only ever check for invalid content if we're supposed to throw an error
1781
1787
  if (options.errorOnInvalidContent) {
1782
1788
  schemaToUse = new model.Schema({
@@ -1791,9 +1797,11 @@ function createNodeFromContent(content, schema, options) {
1791
1797
  parseDOM: [
1792
1798
  {
1793
1799
  tag: '*',
1794
- getAttrs: () => {
1800
+ getAttrs: e => {
1795
1801
  // If this is ever called, we know that the content has something that we don't know how to handle in the schema
1796
1802
  hasInvalidContent = true;
1803
+ // Try to stringify the element for a more helpful error message
1804
+ invalidContent = typeof e === 'string' ? e : e.outerHTML;
1797
1805
  return null;
1798
1806
  },
1799
1807
  },
@@ -1807,7 +1815,7 @@ function createNodeFromContent(content, schema, options) {
1807
1815
  ? parser.parseSlice(elementFromString(content), options.parseOptions).content
1808
1816
  : parser.parse(elementFromString(content), options.parseOptions);
1809
1817
  if (options.errorOnInvalidContent && hasInvalidContent) {
1810
- throw new Error('[tiptap error]: Invalid HTML content');
1818
+ throw new Error('[tiptap error]: Invalid HTML content', { cause: new Error(`Invalid element found: ${invalidContent}`) });
1811
1819
  }
1812
1820
  return response;
1813
1821
  }
@@ -1860,10 +1868,6 @@ const insertContentAt = (position, value, options) => ({ tr, dispatch, editor })
1860
1868
  catch (e) {
1861
1869
  return false;
1862
1870
  }
1863
- // don’t dispatch an empty fragment because this can lead to strange errors
1864
- if (content.toString() === '<>') {
1865
- return true;
1866
- }
1867
1871
  let { from, to } = typeof position === 'number' ? { from: position, to: position } : { from: position.from, to: position.to };
1868
1872
  let isOnlyTextContent = true;
1869
1873
  let isOnlyBlockContent = true;
@@ -2233,22 +2237,27 @@ function createDocument(content, schema, parseOptions = {}, options = {}) {
2233
2237
  });
2234
2238
  }
2235
2239
 
2236
- const setContent = (content, emitUpdate = false, parseOptions = {}, options = {}) => ({ tr, editor, dispatch }) => {
2237
- var _a;
2240
+ const setContent = (content, emitUpdate = false, parseOptions = {}, options = {}) => ({ editor, tr, dispatch, commands, }) => {
2241
+ var _a, _b;
2238
2242
  const { doc } = tr;
2239
- let document;
2240
- try {
2241
- document = createDocument(content, editor.schema, parseOptions, {
2243
+ // This is to keep backward compatibility with the previous behavior
2244
+ // TODO remove this in the next major version
2245
+ if (parseOptions.preserveWhitespace !== 'full') {
2246
+ const document = createDocument(content, editor.schema, parseOptions, {
2242
2247
  errorOnInvalidContent: (_a = options.errorOnInvalidContent) !== null && _a !== void 0 ? _a : editor.options.enableContentCheck,
2243
2248
  });
2244
- }
2245
- catch (e) {
2246
- return false;
2249
+ if (dispatch) {
2250
+ tr.replaceWith(0, doc.content.size, document).setMeta('preventUpdate', !emitUpdate);
2251
+ }
2252
+ return true;
2247
2253
  }
2248
2254
  if (dispatch) {
2249
- tr.replaceWith(0, doc.content.size, document).setMeta('preventUpdate', !emitUpdate);
2255
+ tr.setMeta('preventUpdate', !emitUpdate);
2250
2256
  }
2251
- return true;
2257
+ return commands.insertContentAt({ from: 0, to: doc.content.size }, content, {
2258
+ parseOptions,
2259
+ errorOnInvalidContent: (_b = options.errorOnInvalidContent) !== null && _b !== void 0 ? _b : editor.options.enableContentCheck,
2260
+ });
2252
2261
  };
2253
2262
 
2254
2263
  function getMarkAttributes(state, typeOrName) {
@@ -3352,40 +3361,30 @@ const updateAttributes = (typeOrName, attributes = {}) => ({ tr, state, dispatch
3352
3361
  markType = getMarkType(typeOrName, state.schema);
3353
3362
  }
3354
3363
  if (dispatch) {
3355
- let lastPos;
3356
- let lastNode;
3357
- let trimmedFrom;
3358
- let trimmedTo;
3359
- tr.selection.ranges.forEach((range) => {
3364
+ tr.selection.ranges.forEach(range => {
3360
3365
  const from = range.$from.pos;
3361
3366
  const to = range.$to.pos;
3362
3367
  state.doc.nodesBetween(from, to, (node, pos) => {
3363
3368
  if (nodeType && nodeType === node.type) {
3364
- trimmedFrom = Math.max(pos, from);
3365
- trimmedTo = Math.min(pos + node.nodeSize, to);
3366
- lastPos = pos;
3367
- lastNode = node;
3369
+ tr.setNodeMarkup(pos, undefined, {
3370
+ ...node.attrs,
3371
+ ...attributes,
3372
+ });
3373
+ }
3374
+ if (markType && node.marks.length) {
3375
+ node.marks.forEach(mark => {
3376
+ if (markType === mark.type) {
3377
+ const trimmedFrom = Math.max(pos, from);
3378
+ const trimmedTo = Math.min(pos + node.nodeSize, to);
3379
+ tr.addMark(trimmedFrom, trimmedTo, markType.create({
3380
+ ...mark.attrs,
3381
+ ...attributes,
3382
+ }));
3383
+ }
3384
+ });
3368
3385
  }
3369
3386
  });
3370
3387
  });
3371
- if (lastNode) {
3372
- if (lastPos !== undefined) {
3373
- tr.setNodeMarkup(lastPos, undefined, {
3374
- ...lastNode.attrs,
3375
- ...attributes,
3376
- });
3377
- }
3378
- if (markType && lastNode.marks.length) {
3379
- lastNode.marks.forEach((mark) => {
3380
- if (markType === mark.type) {
3381
- tr.addMark(trimmedFrom, trimmedTo, markType.create({
3382
- ...mark.attrs,
3383
- ...attributes,
3384
- }));
3385
- }
3386
- });
3387
- }
3388
- }
3389
3388
  }
3390
3389
  return true;
3391
3390
  };
@@ -3641,7 +3640,7 @@ const Tabindex = Extension.create({
3641
3640
  new state.Plugin({
3642
3641
  key: new state.PluginKey('tabindex'),
3643
3642
  props: {
3644
- attributes: this.editor.isEditable ? { tabindex: '0' } : {},
3643
+ attributes: () => (this.editor.isEditable ? { tabindex: '0' } : {}),
3645
3644
  },
3646
3645
  }),
3647
3646
  ];
@@ -4556,20 +4555,25 @@ class Mark {
4556
4555
  configure(options = {}) {
4557
4556
  // return a new instance so we can use the same extension
4558
4557
  // with different calls of `configure`
4559
- const extension = this.extend();
4560
- extension.options = mergeDeep(this.options, options);
4561
- extension.storage = callOrReturn(getExtensionField(extension, 'addStorage', {
4562
- name: extension.name,
4563
- options: extension.options,
4564
- }));
4558
+ const extension = this.extend({
4559
+ ...this.config,
4560
+ addOptions() {
4561
+ var _a;
4562
+ return mergeDeep(((_a = this.parent) === null || _a === void 0 ? void 0 : _a.call(this)) || {}, options);
4563
+ },
4564
+ });
4565
+ // Always preserve the current name
4566
+ extension.name = this.name;
4567
+ // Set the parent to be our parent
4568
+ extension.parent = this.parent;
4565
4569
  return extension;
4566
4570
  }
4567
4571
  extend(extendedConfig = {}) {
4568
- const extension = new Mark({ ...this.config, ...extendedConfig });
4572
+ const extension = new Mark(extendedConfig);
4569
4573
  extension.parent = this;
4570
4574
  this.child = extension;
4571
4575
  extension.name = extendedConfig.name ? extendedConfig.name : extension.parent.name;
4572
- if (extendedConfig.defaultOptions) {
4576
+ if (extendedConfig.defaultOptions && Object.keys(extendedConfig.defaultOptions).length > 0) {
4573
4577
  console.warn(`[tiptap warn]: BREAKING CHANGE: "defaultOptions" is deprecated. Please use "addOptions" instead. Found in extension: "${extension.name}".`);
4574
4578
  }
4575
4579
  extension.options = callOrReturn(getExtensionField(extension, 'addOptions', {
@@ -4643,20 +4647,25 @@ class Node {
4643
4647
  configure(options = {}) {
4644
4648
  // return a new instance so we can use the same extension
4645
4649
  // with different calls of `configure`
4646
- const extension = this.extend();
4647
- extension.options = mergeDeep(this.options, options);
4648
- extension.storage = callOrReturn(getExtensionField(extension, 'addStorage', {
4649
- name: extension.name,
4650
- options: extension.options,
4651
- }));
4650
+ const extension = this.extend({
4651
+ ...this.config,
4652
+ addOptions() {
4653
+ var _a;
4654
+ return mergeDeep(((_a = this.parent) === null || _a === void 0 ? void 0 : _a.call(this)) || {}, options);
4655
+ },
4656
+ });
4657
+ // Always preserve the current name
4658
+ extension.name = this.name;
4659
+ // Set the parent to be our parent
4660
+ extension.parent = this.parent;
4652
4661
  return extension;
4653
4662
  }
4654
4663
  extend(extendedConfig = {}) {
4655
- const extension = new Node({ ...this.config, ...extendedConfig });
4664
+ const extension = new Node(extendedConfig);
4656
4665
  extension.parent = this;
4657
4666
  this.child = extension;
4658
4667
  extension.name = extendedConfig.name ? extendedConfig.name : extension.parent.name;
4659
- if (extendedConfig.defaultOptions) {
4668
+ if (extendedConfig.defaultOptions && Object.keys(extendedConfig.defaultOptions).length > 0) {
4660
4669
  console.warn(`[tiptap warn]: BREAKING CHANGE: "defaultOptions" is deprecated. Please use "addOptions" instead. Found in extension: "${extension.name}".`);
4661
4670
  }
4662
4671
  extension.options = callOrReturn(getExtensionField(extension, 'addOptions', {