@tiptap/core 2.9.1 → 2.10.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.
Files changed (66) hide show
  1. package/dist/Editor.d.ts.map +1 -1
  2. package/dist/EventEmitter.d.ts +1 -0
  3. package/dist/EventEmitter.d.ts.map +1 -1
  4. package/dist/Extension.d.ts +2 -2
  5. package/dist/Extension.d.ts.map +1 -1
  6. package/dist/InputRule.d.ts.map +1 -1
  7. package/dist/Mark.d.ts +2 -2
  8. package/dist/Mark.d.ts.map +1 -1
  9. package/dist/Node.d.ts +18 -2
  10. package/dist/Node.d.ts.map +1 -1
  11. package/dist/PasteRule.d.ts +1 -1
  12. package/dist/PasteRule.d.ts.map +1 -1
  13. package/dist/commands/insertContent.d.ts +2 -2
  14. package/dist/commands/insertContent.d.ts.map +1 -1
  15. package/dist/commands/insertContentAt.d.ts +2 -2
  16. package/dist/commands/insertContentAt.d.ts.map +1 -1
  17. package/dist/commands/setContent.d.ts +2 -2
  18. package/dist/commands/setContent.d.ts.map +1 -1
  19. package/dist/commands/setNode.d.ts.map +1 -1
  20. package/dist/commands/updateAttributes.d.ts.map +1 -1
  21. package/dist/helpers/createDocument.d.ts +2 -2
  22. package/dist/helpers/createDocument.d.ts.map +1 -1
  23. package/dist/helpers/createNodeFromContent.d.ts +1 -1
  24. package/dist/helpers/createNodeFromContent.d.ts.map +1 -1
  25. package/dist/helpers/getMarkRange.d.ts +17 -1
  26. package/dist/helpers/getMarkRange.d.ts.map +1 -1
  27. package/dist/helpers/getSchemaByResolvedExtensions.d.ts.map +1 -1
  28. package/dist/index.cjs +158 -44
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.js +159 -45
  31. package/dist/index.js.map +1 -1
  32. package/dist/index.umd.js +158 -44
  33. package/dist/index.umd.js.map +1 -1
  34. package/dist/inputRules/markInputRule.d.ts +1 -1
  35. package/dist/inputRules/nodeInputRule.d.ts +1 -1
  36. package/dist/inputRules/textInputRule.d.ts +1 -1
  37. package/dist/inputRules/textblockTypeInputRule.d.ts +1 -1
  38. package/dist/inputRules/wrappingInputRule.d.ts +1 -1
  39. package/dist/pasteRules/markPasteRule.d.ts +1 -1
  40. package/dist/pasteRules/nodePasteRule.d.ts +1 -1
  41. package/dist/pasteRules/textPasteRule.d.ts +1 -1
  42. package/package.json +2 -2
  43. package/src/Editor.ts +5 -8
  44. package/src/EventEmitter.ts +9 -0
  45. package/src/Extension.ts +2 -2
  46. package/src/InputRule.ts +45 -30
  47. package/src/Mark.ts +2 -2
  48. package/src/Node.ts +21 -2
  49. package/src/PasteRule.ts +67 -42
  50. package/src/commands/insertContent.ts +9 -9
  51. package/src/commands/insertContentAt.ts +11 -1
  52. package/src/commands/setContent.ts +10 -14
  53. package/src/commands/setNode.ts +9 -2
  54. package/src/commands/updateAttributes.ts +72 -12
  55. package/src/helpers/createDocument.ts +4 -2
  56. package/src/helpers/createNodeFromContent.ts +4 -1
  57. package/src/helpers/getMarkRange.ts +29 -5
  58. package/src/helpers/getSchemaByResolvedExtensions.ts +1 -0
  59. package/src/inputRules/markInputRule.ts +1 -1
  60. package/src/inputRules/nodeInputRule.ts +1 -1
  61. package/src/inputRules/textInputRule.ts +1 -1
  62. package/src/inputRules/textblockTypeInputRule.ts +1 -1
  63. package/src/inputRules/wrappingInputRule.ts +1 -1
  64. package/src/pasteRules/markPasteRule.ts +1 -1
  65. package/src/pasteRules/nodePasteRule.ts +1 -1
  66. package/src/pasteRules/textPasteRule.ts +1 -1
package/dist/index.cjs CHANGED
@@ -174,6 +174,13 @@ class EventEmitter {
174
174
  }
175
175
  return this;
176
176
  }
177
+ once(event, fn) {
178
+ const onceFn = (...args) => {
179
+ this.off(event, onceFn);
180
+ fn.apply(this, args);
181
+ };
182
+ return this.on(event, onceFn);
183
+ }
177
184
  removeAllListeners() {
178
185
  this.callbacks = {};
179
186
  }
@@ -479,6 +486,7 @@ function getSchemaByResolvedExtensions(extensions, editor) {
479
486
  draggable: callOrReturn(getExtensionField(extension, 'draggable', context)),
480
487
  code: callOrReturn(getExtensionField(extension, 'code', context)),
481
488
  whitespace: callOrReturn(getExtensionField(extension, 'whitespace', context)),
489
+ linebreakReplacement: callOrReturn(getExtensionField(extension, 'linebreakReplacement', context)),
482
490
  defining: callOrReturn(getExtensionField(extension, 'defining', context)),
483
491
  isolating: callOrReturn(getExtensionField(extension, 'isolating', context)),
484
492
  attrs: Object.fromEntries(extensionAttributes.map(extensionAttribute => {
@@ -572,6 +580,14 @@ function isExtensionRulesEnabled(extension, enabled) {
572
580
  return enabled;
573
581
  }
574
582
 
583
+ function getHTMLFromFragment(fragment, schema) {
584
+ const documentFragment = model.DOMSerializer.fromSchema(schema).serializeFragment(fragment);
585
+ const temporaryDocument = document.implementation.createHTMLDocument();
586
+ const container = temporaryDocument.createElement('div');
587
+ container.appendChild(documentFragment);
588
+ return container.innerHTML;
589
+ }
590
+
575
591
  /**
576
592
  * Returns the text content of a resolved prosemirror position
577
593
  * @param $from The resolved position to get the text content from
@@ -701,7 +717,7 @@ function inputRulesPlugin(props) {
701
717
  init() {
702
718
  return null;
703
719
  },
704
- apply(tr, prev) {
720
+ apply(tr, prev, state) {
705
721
  const stored = tr.getMeta(plugin);
706
722
  if (stored) {
707
723
  return stored;
@@ -711,7 +727,14 @@ function inputRulesPlugin(props) {
711
727
  const isSimulatedInput = !!simulatedInputMeta;
712
728
  if (isSimulatedInput) {
713
729
  setTimeout(() => {
714
- const { from, text } = simulatedInputMeta;
730
+ let { text } = simulatedInputMeta;
731
+ if (typeof text === 'string') {
732
+ text = text;
733
+ }
734
+ else {
735
+ text = getHTMLFromFragment(model.Fragment.from(text), state.schema);
736
+ }
737
+ const { from } = simulatedInputMeta;
715
738
  const to = from + text.length;
716
739
  run$1({
717
740
  editor,
@@ -904,7 +927,7 @@ function isNumber(value) {
904
927
 
905
928
  /**
906
929
  * Paste rules are used to react to pasted content.
907
- * @see https://tiptap.dev/guide/custom-extensions/#paste-rules
930
+ * @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#paste-rules
908
931
  */
909
932
  class PasteRule {
910
933
  constructor(config) {
@@ -994,7 +1017,13 @@ function pasteRulesPlugin(props) {
994
1017
  let isPastedFromProseMirror = false;
995
1018
  let isDroppedFromProseMirror = false;
996
1019
  let pasteEvent = typeof ClipboardEvent !== 'undefined' ? new ClipboardEvent('paste') : null;
997
- let dropEvent = typeof DragEvent !== 'undefined' ? new DragEvent('drop') : null;
1020
+ let dropEvent;
1021
+ try {
1022
+ dropEvent = typeof DragEvent !== 'undefined' ? new DragEvent('drop') : null;
1023
+ }
1024
+ catch (e) {
1025
+ dropEvent = null;
1026
+ }
998
1027
  const processEvent = ({ state, from, to, rule, pasteEvt, }) => {
999
1028
  const tr = state.tr;
1000
1029
  const chainableState = createChainableState({
@@ -1013,7 +1042,12 @@ function pasteRulesPlugin(props) {
1013
1042
  if (!handler || !tr.steps.length) {
1014
1043
  return;
1015
1044
  }
1016
- dropEvent = typeof DragEvent !== 'undefined' ? new DragEvent('drop') : null;
1045
+ try {
1046
+ dropEvent = typeof DragEvent !== 'undefined' ? new DragEvent('drop') : null;
1047
+ }
1048
+ catch (e) {
1049
+ dropEvent = null;
1050
+ }
1017
1051
  pasteEvent = typeof ClipboardEvent !== 'undefined' ? new ClipboardEvent('paste') : null;
1018
1052
  return tr;
1019
1053
  };
@@ -1062,7 +1096,14 @@ function pasteRulesPlugin(props) {
1062
1096
  }
1063
1097
  // Handle simulated paste
1064
1098
  if (isSimulatedPaste) {
1065
- const { from, text } = simulatedPasteMeta;
1099
+ let { text } = simulatedPasteMeta;
1100
+ if (typeof text === 'string') {
1101
+ text = text;
1102
+ }
1103
+ else {
1104
+ text = getHTMLFromFragment(model.Fragment.from(text), state.schema);
1105
+ }
1106
+ const { from } = simulatedPasteMeta;
1066
1107
  const to = from + text.length;
1067
1108
  const pasteEvt = createClipboardPasteEvent(text);
1068
1109
  return processEvent({
@@ -1659,13 +1700,33 @@ function objectIncludes(object1, object2, options = { strict: true }) {
1659
1700
 
1660
1701
  function findMarkInSet(marks, type, attributes = {}) {
1661
1702
  return marks.find(item => {
1662
- return item.type === type && objectIncludes(item.attrs, attributes);
1703
+ return (item.type === type
1704
+ && objectIncludes(
1705
+ // Only check equality for the attributes that are provided
1706
+ Object.fromEntries(Object.keys(attributes).map(k => [k, item.attrs[k]])), attributes));
1663
1707
  });
1664
1708
  }
1665
1709
  function isMarkInSet(marks, type, attributes = {}) {
1666
1710
  return !!findMarkInSet(marks, type, attributes);
1667
1711
  }
1668
- function getMarkRange($pos, type, attributes = {}) {
1712
+ /**
1713
+ * Get the range of a mark at a resolved position.
1714
+ */
1715
+ function getMarkRange(
1716
+ /**
1717
+ * The position to get the mark range for.
1718
+ */
1719
+ $pos,
1720
+ /**
1721
+ * The mark type to get the range for.
1722
+ */
1723
+ type,
1724
+ /**
1725
+ * The attributes to match against.
1726
+ * If not provided, only the first mark at the position will be matched.
1727
+ */
1728
+ attributes) {
1729
+ var _a;
1669
1730
  if (!$pos || !type) {
1670
1731
  return;
1671
1732
  }
@@ -1678,6 +1739,8 @@ function getMarkRange($pos, type, attributes = {}) {
1678
1739
  if (!start.node || !start.node.marks.some(mark => mark.type === type)) {
1679
1740
  return;
1680
1741
  }
1742
+ // Default to only matching against the first mark's attributes
1743
+ attributes = attributes || ((_a = start.node.marks[0]) === null || _a === void 0 ? void 0 : _a.attrs);
1681
1744
  // We now know that the cursor is either at the start, middle or end of a text node with the specified mark
1682
1745
  // so we can look it up on the targeted mark
1683
1746
  const mark = findMarkInSet([...start.node.marks], type, attributes);
@@ -1688,8 +1751,8 @@ function getMarkRange($pos, type, attributes = {}) {
1688
1751
  let startPos = $pos.start() + start.offset;
1689
1752
  let endIndex = startIndex + 1;
1690
1753
  let endPos = startPos + start.node.nodeSize;
1691
- findMarkInSet([...start.node.marks], type, attributes);
1692
- while (startIndex > 0 && mark.isInSet($pos.parent.child(startIndex - 1).marks)) {
1754
+ while (startIndex > 0
1755
+ && isMarkInSet([...$pos.parent.child(startIndex - 1).marks], type, attributes)) {
1693
1756
  startIndex -= 1;
1694
1757
  startPos -= $pos.parent.child(startIndex).nodeSize;
1695
1758
  }
@@ -1865,6 +1928,9 @@ function elementFromString(value) {
1865
1928
  * @returns The created Prosemirror node or fragment
1866
1929
  */
1867
1930
  function createNodeFromContent(content, schema, options) {
1931
+ if (content instanceof model.Node || content instanceof model.Fragment) {
1932
+ return content;
1933
+ }
1868
1934
  options = {
1869
1935
  slice: true,
1870
1936
  parseOptions: {},
@@ -2029,6 +2095,15 @@ const insertContentAt = (position, value, options) => ({ tr, dispatch, editor })
2029
2095
  if (Array.isArray(value)) {
2030
2096
  newContent = value.map(v => v.text || '').join('');
2031
2097
  }
2098
+ else if (value instanceof model.Fragment) {
2099
+ let text = '';
2100
+ value.forEach(node => {
2101
+ if (node.text) {
2102
+ text += node.text;
2103
+ }
2104
+ });
2105
+ newContent = text;
2106
+ }
2032
2107
  else if (typeof value === 'object' && !!value && !!value.text) {
2033
2108
  newContent = value.text;
2034
2109
  }
@@ -2525,14 +2600,6 @@ function findParentNode(predicate) {
2525
2600
  return (selection) => findParentNodeClosestToPos(selection.$from, predicate);
2526
2601
  }
2527
2602
 
2528
- function getHTMLFromFragment(fragment, schema) {
2529
- const documentFragment = model.DOMSerializer.fromSchema(schema).serializeFragment(fragment);
2530
- const temporaryDocument = document.implementation.createHTMLDocument();
2531
- const container = temporaryDocument.createElement('div');
2532
- container.appendChild(documentFragment);
2533
- return container.innerHTML;
2534
- }
2535
-
2536
2603
  function getSchema(extensions, editor) {
2537
2604
  const resolvedExtensions = ExtensionManager.resolve(extensions);
2538
2605
  return getSchemaByResolvedExtensions(resolvedExtensions, editor);
@@ -3103,6 +3170,11 @@ const setMeta = (key, value) => ({ tr }) => {
3103
3170
 
3104
3171
  const setNode = (typeOrName, attributes = {}) => ({ state, dispatch, chain }) => {
3105
3172
  const type = getNodeType(typeOrName, state.schema);
3173
+ let attributesToCopy;
3174
+ if (state.selection.$anchor.sameParent(state.selection.$head)) {
3175
+ // only copy attributes if the selection is pointing to a node of the same type
3176
+ attributesToCopy = state.selection.$anchor.parent.attrs;
3177
+ }
3106
3178
  // TODO: use a fallback like insertContent?
3107
3179
  if (!type.isTextblock) {
3108
3180
  console.warn('[tiptap warn]: Currently "setNode()" only supports text block nodes.');
@@ -3111,14 +3183,14 @@ const setNode = (typeOrName, attributes = {}) => ({ state, dispatch, chain }) =>
3111
3183
  return (chain()
3112
3184
  // try to convert node to default node if needed
3113
3185
  .command(({ commands }) => {
3114
- const canSetBlock = commands$1.setBlockType(type, attributes)(state);
3186
+ const canSetBlock = commands$1.setBlockType(type, { ...attributesToCopy, ...attributes })(state);
3115
3187
  if (canSetBlock) {
3116
3188
  return true;
3117
3189
  }
3118
3190
  return commands.clearNodes();
3119
3191
  })
3120
3192
  .command(({ state: updatedState }) => {
3121
- return commands$1.setBlockType(type, attributes)(updatedState, dispatch);
3193
+ return commands$1.setBlockType(type, { ...attributesToCopy, ...attributes })(updatedState, dispatch);
3122
3194
  })
3123
3195
  .run());
3124
3196
  };
@@ -3537,21 +3609,63 @@ const updateAttributes = (typeOrName, attributes = {}) => ({ tr, state, dispatch
3537
3609
  markType = getMarkType(typeOrName, state.schema);
3538
3610
  }
3539
3611
  if (dispatch) {
3540
- tr.selection.ranges.forEach(range => {
3612
+ tr.selection.ranges.forEach((range) => {
3541
3613
  const from = range.$from.pos;
3542
3614
  const to = range.$to.pos;
3543
- state.doc.nodesBetween(from, to, (node, pos) => {
3544
- if (nodeType && nodeType === node.type) {
3545
- tr.setNodeMarkup(pos, undefined, {
3546
- ...node.attrs,
3615
+ let lastPos;
3616
+ let lastNode;
3617
+ let trimmedFrom;
3618
+ let trimmedTo;
3619
+ if (tr.selection.empty) {
3620
+ state.doc.nodesBetween(from, to, (node, pos) => {
3621
+ if (nodeType && nodeType === node.type) {
3622
+ trimmedFrom = Math.max(pos, from);
3623
+ trimmedTo = Math.min(pos + node.nodeSize, to);
3624
+ lastPos = pos;
3625
+ lastNode = node;
3626
+ }
3627
+ });
3628
+ }
3629
+ else {
3630
+ state.doc.nodesBetween(from, to, (node, pos) => {
3631
+ if (pos < from && nodeType && nodeType === node.type) {
3632
+ trimmedFrom = Math.max(pos, from);
3633
+ trimmedTo = Math.min(pos + node.nodeSize, to);
3634
+ lastPos = pos;
3635
+ lastNode = node;
3636
+ }
3637
+ if (pos >= from && pos <= to) {
3638
+ if (nodeType && nodeType === node.type) {
3639
+ tr.setNodeMarkup(pos, undefined, {
3640
+ ...node.attrs,
3641
+ ...attributes,
3642
+ });
3643
+ }
3644
+ if (markType && node.marks.length) {
3645
+ node.marks.forEach((mark) => {
3646
+ if (markType === mark.type) {
3647
+ const trimmedFrom2 = Math.max(pos, from);
3648
+ const trimmedTo2 = Math.min(pos + node.nodeSize, to);
3649
+ tr.addMark(trimmedFrom2, trimmedTo2, markType.create({
3650
+ ...mark.attrs,
3651
+ ...attributes,
3652
+ }));
3653
+ }
3654
+ });
3655
+ }
3656
+ }
3657
+ });
3658
+ }
3659
+ if (lastNode) {
3660
+ if (lastPos !== undefined) {
3661
+ tr.setNodeMarkup(lastPos, undefined, {
3662
+ ...lastNode.attrs,
3547
3663
  ...attributes,
3548
3664
  });
3549
3665
  }
3550
- if (markType && node.marks.length) {
3551
- node.marks.forEach(mark => {
3666
+ if (markType && lastNode.marks.length) {
3667
+ lastNode.marks.forEach((mark) => {
3552
3668
  if (markType === mark.type) {
3553
- const trimmedFrom = Math.max(pos, from);
3554
- const trimmedTo = Math.min(pos + node.nodeSize, to);
3555
3669
  tr.addMark(trimmedFrom, trimmedTo, markType.create({
3556
3670
  ...mark.attrs,
3557
3671
  ...attributes,
@@ -3559,7 +3673,7 @@ const updateAttributes = (typeOrName, attributes = {}) => ({ tr, state, dispatch
3559
3673
  }
3560
3674
  });
3561
3675
  }
3562
- });
3676
+ }
3563
3677
  });
3564
3678
  }
3565
3679
  return true;
@@ -4375,6 +4489,7 @@ class Editor extends EventEmitter {
4375
4489
  * Creates a ProseMirror view.
4376
4490
  */
4377
4491
  createView() {
4492
+ var _a;
4378
4493
  let doc;
4379
4494
  try {
4380
4495
  doc = createDocument(this.options.content, this.schema, this.options.parseOptions, { errorOnInvalidContent: this.options.enableContentCheck });
@@ -4403,18 +4518,17 @@ class Editor extends EventEmitter {
4403
4518
  const selection = resolveFocusPosition(doc, this.options.autofocus);
4404
4519
  this.view = new view.EditorView(this.options.element, {
4405
4520
  ...this.options.editorProps,
4521
+ attributes: {
4522
+ // add `role="textbox"` to the editor element
4523
+ role: 'textbox',
4524
+ ...(_a = this.options.editorProps) === null || _a === void 0 ? void 0 : _a.attributes,
4525
+ },
4406
4526
  dispatchTransaction: this.dispatchTransaction.bind(this),
4407
4527
  state: state.EditorState.create({
4408
4528
  doc,
4409
4529
  selection: selection || undefined,
4410
4530
  }),
4411
4531
  });
4412
- // add `role="textbox"` to the editor element
4413
- this.view.dom.setAttribute('role', 'textbox');
4414
- // add aria-label to the editor element
4415
- if (!this.view.dom.getAttribute('aria-label')) {
4416
- this.view.dom.setAttribute('aria-label', 'Rich-Text Editor');
4417
- }
4418
4532
  // `editor.view` is not yet available at this time.
4419
4533
  // Therefore we will add all plugins and node views directly afterwards.
4420
4534
  const newState = this.state.reconfigure({
@@ -4610,7 +4724,7 @@ class Editor extends EventEmitter {
4610
4724
  /**
4611
4725
  * Build an input rule that adds a mark when the
4612
4726
  * matched text is typed into it.
4613
- * @see https://tiptap.dev/guide/custom-extensions/#input-rules
4727
+ * @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules
4614
4728
  */
4615
4729
  function markInputRule(config) {
4616
4730
  return new InputRule({
@@ -4654,7 +4768,7 @@ function markInputRule(config) {
4654
4768
  /**
4655
4769
  * Build an input rule that adds a node when the
4656
4770
  * matched text is typed into it.
4657
- * @see https://tiptap.dev/guide/custom-extensions/#input-rules
4771
+ * @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules
4658
4772
  */
4659
4773
  function nodeInputRule(config) {
4660
4774
  return new InputRule({
@@ -4694,7 +4808,7 @@ function nodeInputRule(config) {
4694
4808
  * matched text is typed into it. When using a regular expresion you’ll
4695
4809
  * probably want the regexp to start with `^`, so that the pattern can
4696
4810
  * only occur at the start of a textblock.
4697
- * @see https://tiptap.dev/guide/custom-extensions/#input-rules
4811
+ * @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules
4698
4812
  */
4699
4813
  function textblockTypeInputRule(config) {
4700
4814
  return new InputRule({
@@ -4715,7 +4829,7 @@ function textblockTypeInputRule(config) {
4715
4829
  /**
4716
4830
  * Build an input rule that replaces text when the
4717
4831
  * matched text is typed into it.
4718
- * @see https://tiptap.dev/guide/custom-extensions/#input-rules
4832
+ * @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules
4719
4833
  */
4720
4834
  function textInputRule(config) {
4721
4835
  return new InputRule({
@@ -4752,7 +4866,7 @@ function textInputRule(config) {
4752
4866
  * two nodes. You can pass a join predicate, which takes a regular
4753
4867
  * expression match and the node before the wrapped node, and can
4754
4868
  * return a boolean to indicate whether a join should happen.
4755
- * @see https://tiptap.dev/guide/custom-extensions/#input-rules
4869
+ * @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules
4756
4870
  */
4757
4871
  function wrappingInputRule(config) {
4758
4872
  return new InputRule({
@@ -5085,7 +5199,7 @@ class NodeView {
5085
5199
  /**
5086
5200
  * Build an paste rule that adds a mark when the
5087
5201
  * matched text is pasted into it.
5088
- * @see https://tiptap.dev/guide/custom-extensions/#paste-rules
5202
+ * @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#paste-rules
5089
5203
  */
5090
5204
  function markPasteRule(config) {
5091
5205
  return new PasteRule({
@@ -5139,7 +5253,7 @@ function isString(value) {
5139
5253
  /**
5140
5254
  * Build an paste rule that adds a node when the
5141
5255
  * matched text is pasted into it.
5142
- * @see https://tiptap.dev/guide/custom-extensions/#paste-rules
5256
+ * @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#paste-rules
5143
5257
  */
5144
5258
  function nodePasteRule(config) {
5145
5259
  return new PasteRule({
@@ -5164,7 +5278,7 @@ function nodePasteRule(config) {
5164
5278
  /**
5165
5279
  * Build an paste rule that replaces text when the
5166
5280
  * matched text is pasted into it.
5167
- * @see https://tiptap.dev/guide/custom-extensions/#paste-rules
5281
+ * @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#paste-rules
5168
5282
  */
5169
5283
  function textPasteRule(config) {
5170
5284
  return new PasteRule({