@tiptap/core 2.2.5 → 2.3.0

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.umd.js CHANGED
@@ -659,6 +659,23 @@
659
659
  if (stored) {
660
660
  return stored;
661
661
  }
662
+ // if InputRule is triggered by insertContent()
663
+ const simulatedInputMeta = tr.getMeta('applyInputRules');
664
+ const isSimulatedInput = !!simulatedInputMeta;
665
+ if (isSimulatedInput) {
666
+ setTimeout(() => {
667
+ const { from, text } = simulatedInputMeta;
668
+ const to = from + text.length;
669
+ run$1({
670
+ editor,
671
+ from,
672
+ to,
673
+ text,
674
+ rules,
675
+ plugin,
676
+ });
677
+ });
678
+ }
662
679
  return tr.selectionSet || tr.docChanged ? null : prev;
663
680
  },
664
681
  },
@@ -790,6 +807,14 @@
790
807
  const success = handlers.every(handler => handler !== null);
791
808
  return success;
792
809
  }
810
+ const createClipboardPasteEvent = (text) => {
811
+ var _a;
812
+ const event = new ClipboardEvent('paste', {
813
+ clipboardData: new DataTransfer(),
814
+ });
815
+ (_a = event.clipboardData) === null || _a === void 0 ? void 0 : _a.setData('text/html', text);
816
+ return event;
817
+ };
793
818
  /**
794
819
  * Create an paste rules plugin. When enabled, it will cause pasted
795
820
  * text that matches any of the given rules to trigger the rule’s
@@ -802,6 +827,28 @@
802
827
  let isDroppedFromProseMirror = false;
803
828
  let pasteEvent = typeof ClipboardEvent !== 'undefined' ? new ClipboardEvent('paste') : null;
804
829
  let dropEvent = typeof DragEvent !== 'undefined' ? new DragEvent('drop') : null;
830
+ const processEvent = ({ state, from, to, rule, pasteEvt, }) => {
831
+ const tr = state.tr;
832
+ const chainableState = createChainableState({
833
+ state,
834
+ transaction: tr,
835
+ });
836
+ const handler = run({
837
+ editor,
838
+ state: chainableState,
839
+ from: Math.max(from - 1, 0),
840
+ to: to.b - 1,
841
+ rule,
842
+ pasteEvent: pasteEvt,
843
+ dropEvent,
844
+ });
845
+ if (!handler || !tr.steps.length) {
846
+ return;
847
+ }
848
+ dropEvent = typeof DragEvent !== 'undefined' ? new DragEvent('drop') : null;
849
+ pasteEvent = typeof ClipboardEvent !== 'undefined' ? new ClipboardEvent('paste') : null;
850
+ return tr;
851
+ };
805
852
  const plugins = rules.map(rule => {
806
853
  return new state.Plugin({
807
854
  // we register a global drag handler to track the current drag source element
@@ -839,38 +886,39 @@
839
886
  const transaction = transactions[0];
840
887
  const isPaste = transaction.getMeta('uiEvent') === 'paste' && !isPastedFromProseMirror;
841
888
  const isDrop = transaction.getMeta('uiEvent') === 'drop' && !isDroppedFromProseMirror;
842
- if (!isPaste && !isDrop) {
889
+ // if PasteRule is triggered by insertContent()
890
+ const simulatedPasteMeta = transaction.getMeta('applyPasteRules');
891
+ const isSimulatedPaste = !!simulatedPasteMeta;
892
+ if (!isPaste && !isDrop && !isSimulatedPaste) {
843
893
  return;
844
894
  }
845
- // stop if there is no changed range
895
+ // Handle simulated paste
896
+ if (isSimulatedPaste) {
897
+ const { from, text } = simulatedPasteMeta;
898
+ const to = from + text.length;
899
+ const pasteEvt = createClipboardPasteEvent(text);
900
+ return processEvent({
901
+ rule,
902
+ state,
903
+ from,
904
+ to: { b: to },
905
+ pasteEvt,
906
+ });
907
+ }
908
+ // handle actual paste/drop
846
909
  const from = oldState.doc.content.findDiffStart(state.doc.content);
847
910
  const to = oldState.doc.content.findDiffEnd(state.doc.content);
911
+ // stop if there is no changed range
848
912
  if (!isNumber(from) || !to || from === to.b) {
849
913
  return;
850
914
  }
851
- // build a chainable state
852
- // so we can use a single transaction for all paste rules
853
- const tr = state.tr;
854
- const chainableState = createChainableState({
855
- state,
856
- transaction: tr,
857
- });
858
- const handler = run({
859
- editor,
860
- state: chainableState,
861
- from: Math.max(from - 1, 0),
862
- to: to.b - 1,
915
+ return processEvent({
863
916
  rule,
864
- pasteEvent,
865
- dropEvent,
917
+ state,
918
+ from,
919
+ to,
920
+ pasteEvt: pasteEvent,
866
921
  });
867
- // stop if there are no changes
868
- if (!handler || !tr.steps.length) {
869
- return;
870
- }
871
- dropEvent = typeof DragEvent !== 'undefined' ? new DragEvent('drop') : null;
872
- pasteEvent = typeof ClipboardEvent !== 'undefined' ? new ClipboardEvent('paste') : null;
873
- return tr;
874
922
  },
875
923
  });
876
924
  });
@@ -1214,8 +1262,10 @@
1214
1262
  range,
1215
1263
  });
1216
1264
  }
1265
+ // do not descend into child nodes when there exists a serializer
1266
+ return false;
1217
1267
  }
1218
- else if (node.isText) {
1268
+ if (node.isText) {
1219
1269
  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); // eslint-disable-line
1220
1270
  separated = false;
1221
1271
  }
@@ -1235,6 +1285,11 @@
1235
1285
 
1236
1286
  const ClipboardTextSerializer = Extension.create({
1237
1287
  name: 'clipboardTextSerializer',
1288
+ addOptions() {
1289
+ return {
1290
+ blockSeparator: undefined,
1291
+ };
1292
+ },
1238
1293
  addProseMirrorPlugins() {
1239
1294
  return [
1240
1295
  new state.Plugin({
@@ -1250,6 +1305,9 @@
1250
1305
  const textSerializers = getTextSerializersFromSchema(schema);
1251
1306
  const range = { from, to };
1252
1307
  return getTextBetween(doc, range, {
1308
+ ...(this.options.blockSeparator !== undefined
1309
+ ? { blockSeparator: this.options.blockSeparator }
1310
+ : {}),
1253
1311
  textSerializers,
1254
1312
  });
1255
1313
  },
@@ -1656,6 +1714,8 @@
1656
1714
  options = {
1657
1715
  parseOptions: {},
1658
1716
  updateSelection: true,
1717
+ applyInputRules: false,
1718
+ applyPasteRules: false,
1659
1719
  ...options,
1660
1720
  };
1661
1721
  const content = createNodeFromContent(value, editor.schema, {
@@ -1691,28 +1751,37 @@
1691
1751
  to += 1;
1692
1752
  }
1693
1753
  }
1754
+ let newContent;
1694
1755
  // if there is only plain text we have to use `insertText`
1695
1756
  // because this will keep the current marks
1696
1757
  if (isOnlyTextContent) {
1697
1758
  // if value is string, we can use it directly
1698
1759
  // otherwise if it is an array, we have to join it
1699
1760
  if (Array.isArray(value)) {
1700
- tr.insertText(value.map(v => v.text || '').join(''), from, to);
1761
+ newContent = value.map(v => v.text || '').join('');
1701
1762
  }
1702
1763
  else if (typeof value === 'object' && !!value && !!value.text) {
1703
- tr.insertText(value.text, from, to);
1764
+ newContent = value.text;
1704
1765
  }
1705
1766
  else {
1706
- tr.insertText(value, from, to);
1767
+ newContent = value;
1707
1768
  }
1769
+ tr.insertText(newContent, from, to);
1708
1770
  }
1709
1771
  else {
1710
- tr.replaceWith(from, to, content);
1772
+ newContent = content;
1773
+ tr.replaceWith(from, to, newContent);
1711
1774
  }
1712
1775
  // set cursor at end of inserted content
1713
1776
  if (options.updateSelection) {
1714
1777
  selectionToInsertionEnd(tr, tr.steps.length - 1, -1);
1715
1778
  }
1779
+ if (options.applyInputRules) {
1780
+ tr.setMeta('applyInputRules', { from, text: newContent });
1781
+ }
1782
+ if (options.applyPasteRules) {
1783
+ tr.setMeta('applyPasteRules', { from, text: newContent });
1784
+ }
1716
1785
  }
1717
1786
  return true;
1718
1787
  };
@@ -3207,7 +3276,7 @@
3207
3276
  const { selection, doc } = tr;
3208
3277
  const { empty, $anchor } = selection;
3209
3278
  const { pos, parent } = $anchor;
3210
- const $parentPos = $anchor.parent.isTextblock ? tr.doc.resolve(pos - 1) : $anchor;
3279
+ const $parentPos = $anchor.parent.isTextblock && pos > 0 ? tr.doc.resolve(pos - 1) : $anchor;
3211
3280
  const parentIsIsolating = $parentPos.parent.type.spec.isolating;
3212
3281
  const parentPos = $anchor.pos - $anchor.parentOffset;
3213
3282
  const isAtStart = (parentIsIsolating && $parentPos.parent.childCount === 1)
@@ -3323,7 +3392,7 @@
3323
3392
  },
3324
3393
  });
3325
3394
 
3326
- var extensions = /*#__PURE__*/Object.freeze({
3395
+ var index = /*#__PURE__*/Object.freeze({
3327
3396
  __proto__: null,
3328
3397
  ClipboardTextSerializer: ClipboardTextSerializer,
3329
3398
  Commands: Commands,
@@ -3427,7 +3496,7 @@
3427
3496
  const children = [];
3428
3497
  this.node.content.forEach((node, offset) => {
3429
3498
  const isBlock = node.isBlock && !node.isTextblock;
3430
- const targetPos = this.pos + offset + (isBlock ? 0 : 1);
3499
+ const targetPos = this.pos + offset + 1;
3431
3500
  const $pos = this.resolvedPos.doc.resolve(targetPos);
3432
3501
  if (!isBlock && $pos.depth <= this.depth) {
3433
3502
  return;
@@ -3476,7 +3545,7 @@
3476
3545
  querySelectorAll(selector, attributes = {}, firstItemOnly = false) {
3477
3546
  let nodes = [];
3478
3547
  // iterate through children recursively finding all nodes which match the selector with the node name
3479
- if (this.isBlock || !this.children || this.children.length === 0) {
3548
+ if (!this.children || this.children.length === 0) {
3480
3549
  return nodes;
3481
3550
  }
3482
3551
  this.children.forEach(childPos => {
@@ -3613,6 +3682,7 @@ img.ProseMirror-separator {
3613
3682
  editable: true,
3614
3683
  editorProps: {},
3615
3684
  parseOptions: {},
3685
+ coreExtensionOptions: {},
3616
3686
  enableInputRules: true,
3617
3687
  enablePasteRules: true,
3618
3688
  enableCoreExtensions: true,
@@ -3758,7 +3828,17 @@ img.ProseMirror-separator {
3758
3828
  * Creates an extension manager.
3759
3829
  */
3760
3830
  createExtensionManager() {
3761
- const coreExtensions = this.options.enableCoreExtensions ? Object.values(extensions) : [];
3831
+ var _a, _b;
3832
+ const coreExtensions = this.options.enableCoreExtensions ? [
3833
+ Editable,
3834
+ ClipboardTextSerializer.configure({
3835
+ blockSeparator: (_b = (_a = this.options.coreExtensionOptions) === null || _a === void 0 ? void 0 : _a.clipboardTextSerializer) === null || _b === void 0 ? void 0 : _b.blockSeparator,
3836
+ }),
3837
+ Commands,
3838
+ FocusEvents,
3839
+ Keymap,
3840
+ Tabindex,
3841
+ ] : [];
3762
3842
  const allExtensions = [...coreExtensions, ...this.options.extensions].filter(extension => {
3763
3843
  return ['extension', 'node', 'mark'].includes(extension === null || extension === void 0 ? void 0 : extension.type);
3764
3844
  });
@@ -4629,7 +4709,7 @@ img.ProseMirror-separator {
4629
4709
  exports.deleteProps = deleteProps;
4630
4710
  exports.elementFromString = elementFromString;
4631
4711
  exports.escapeForRegEx = escapeForRegEx;
4632
- exports.extensions = extensions;
4712
+ exports.extensions = index;
4633
4713
  exports.findChildren = findChildren;
4634
4714
  exports.findChildrenInRange = findChildrenInRange;
4635
4715
  exports.findDuplicates = findDuplicates;