@tiptap/core 2.6.6 → 2.7.0-pre.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.js CHANGED
@@ -319,7 +319,18 @@ function mergeAttributes(...objects) {
319
319
  mergedAttributes[key] = [...existingClasses, ...insertClasses].join(' ');
320
320
  }
321
321
  else if (key === 'style') {
322
- mergedAttributes[key] = [mergedAttributes[key], value].join('; ');
322
+ const newStyles = value ? value.split(';').map((style) => style.trim()).filter(Boolean) : [];
323
+ const existingStyles = mergedAttributes[key] ? mergedAttributes[key].split(';').map((style) => style.trim()).filter(Boolean) : [];
324
+ const styleMap = new Map();
325
+ existingStyles.forEach(style => {
326
+ const [property, val] = style.split(':').map(part => part.trim());
327
+ styleMap.set(property, val);
328
+ });
329
+ newStyles.forEach(style => {
330
+ const [property, val] = style.split(':').map(part => part.trim());
331
+ styleMap.set(property, val);
332
+ });
333
+ mergedAttributes[key] = Array.from(styleMap.entries()).map(([property, val]) => `${property}: ${val}`).join('; ');
323
334
  }
324
335
  else {
325
336
  mergedAttributes[key] = value;
@@ -713,16 +724,6 @@ function inputRulesPlugin(props) {
713
724
  },
714
725
  },
715
726
  props: {
716
- handleTextInput(view, from, to, text) {
717
- return run$1({
718
- editor,
719
- from,
720
- to,
721
- text,
722
- rules,
723
- plugin,
724
- });
725
- },
726
727
  handleDOMEvents: {
727
728
  compositionend: view => {
728
729
  setTimeout(() => {
@@ -740,6 +741,19 @@ function inputRulesPlugin(props) {
740
741
  });
741
742
  return false;
742
743
  },
744
+ keyup(view, event) {
745
+ if (event.key.length === 1) {
746
+ return run$1({
747
+ editor,
748
+ from: view.state.selection.from,
749
+ to: view.state.selection.from,
750
+ text: '',
751
+ rules,
752
+ plugin,
753
+ });
754
+ }
755
+ return false;
756
+ },
743
757
  },
744
758
  // add support for input rules to trigger on enter
745
759
  // this is useful for example for code blocks
@@ -1150,15 +1164,19 @@ class ExtensionManager {
1150
1164
  if (!addNodeView) {
1151
1165
  return [];
1152
1166
  }
1153
- const nodeview = (node, view, getPos, decorations) => {
1167
+ const nodeview = (node, view, getPos, decorations, innerDecorations) => {
1154
1168
  const HTMLAttributes = getRenderedAttributes(node, extensionAttributes);
1155
1169
  return addNodeView()({
1156
- editor,
1170
+ // pass-through
1157
1171
  node,
1158
- getPos,
1172
+ view,
1173
+ getPos: getPos,
1159
1174
  decorations,
1160
- HTMLAttributes,
1175
+ innerDecorations,
1176
+ // tiptap-specific
1177
+ editor,
1161
1178
  extension,
1179
+ HTMLAttributes,
1162
1180
  });
1163
1181
  };
1164
1182
  return [extension.name, nodeview];
@@ -3316,10 +3334,17 @@ const toggleNode = (typeOrName, toggleTypeOrName, attributes = {}) => ({ state,
3316
3334
  const type = getNodeType(typeOrName, state.schema);
3317
3335
  const toggleType = getNodeType(toggleTypeOrName, state.schema);
3318
3336
  const isActive = isNodeActive(state, type, attributes);
3337
+ let attributesToCopy;
3338
+ if (state.selection.$anchor.sameParent(state.selection.$head)) {
3339
+ // only copy attributes if the selection is pointing to a node of the same type
3340
+ attributesToCopy = state.selection.$anchor.parent.attrs;
3341
+ }
3319
3342
  if (isActive) {
3320
- return commands.setNode(toggleType);
3343
+ return commands.setNode(toggleType, attributesToCopy);
3321
3344
  }
3322
- return commands.setNode(type, attributes);
3345
+ // If the node is not active, we want to set the new node type with the given attributes
3346
+ // Copying over the attributes from the current node if the selection is pointing to a node of the same type
3347
+ return commands.setNode(type, { ...attributesToCopy, ...attributes });
3323
3348
  };
3324
3349
 
3325
3350
  const toggleWrap = (typeOrName, attributes = {}) => ({ state, commands }) => {
@@ -3653,7 +3678,8 @@ const Keymap = Extension.create({
3653
3678
  appendTransaction: (transactions, oldState, newState) => {
3654
3679
  const docChanges = transactions.some(transaction => transaction.docChanged)
3655
3680
  && !oldState.doc.eq(newState.doc);
3656
- if (!docChanges) {
3681
+ const ignoreTr = transactions.some(transaction => transaction.getMeta('preventClearDocument'));
3682
+ if (!docChanges || ignoreTr) {
3657
3683
  return;
3658
3684
  }
3659
3685
  const { empty, from, to } = oldState.selection;
@@ -3663,7 +3689,7 @@ const Keymap = Extension.create({
3663
3689
  if (empty || !allWasSelected) {
3664
3690
  return;
3665
3691
  }
3666
- const isEmpty = newState.doc.textBetween(0, newState.doc.content.size, ' ', ' ').length === 0;
3692
+ const isEmpty = isNodeEmpty(newState.doc);
3667
3693
  if (!isEmpty) {
3668
3694
  return;
3669
3695
  }
@@ -3887,6 +3913,28 @@ class NodePos {
3887
3913
  }
3888
3914
  }
3889
3915
 
3916
+ const DropPlugin = (onDrop) => {
3917
+ return new Plugin({
3918
+ key: new PluginKey('tiptapDrop'),
3919
+ props: {
3920
+ handleDrop: (_, e, slice, moved) => {
3921
+ onDrop(e, slice, moved);
3922
+ },
3923
+ },
3924
+ });
3925
+ };
3926
+
3927
+ const PastePlugin = (onPaste) => {
3928
+ return new Plugin({
3929
+ key: new PluginKey('tiptapPaste'),
3930
+ props: {
3931
+ handlePaste: (_view, e, slice) => {
3932
+ onPaste(e, slice);
3933
+ },
3934
+ },
3935
+ });
3936
+ };
3937
+
3890
3938
  const style = `.ProseMirror {
3891
3939
  position: relative;
3892
3940
  }
@@ -4011,6 +4059,8 @@ class Editor extends EventEmitter {
4011
4059
  onBlur: () => null,
4012
4060
  onDestroy: () => null,
4013
4061
  onContentError: ({ error }) => { throw error; },
4062
+ onPaste: () => null,
4063
+ onDrop: () => null,
4014
4064
  };
4015
4065
  this.isCapturingTransaction = false;
4016
4066
  this.capturedTransaction = null;
@@ -4030,6 +4080,12 @@ class Editor extends EventEmitter {
4030
4080
  this.on('focus', this.options.onFocus);
4031
4081
  this.on('blur', this.options.onBlur);
4032
4082
  this.on('destroy', this.options.onDestroy);
4083
+ if (this.options.onPaste) {
4084
+ this.registerPlugin(PastePlugin(this.options.onPaste));
4085
+ }
4086
+ if (this.options.onDrop) {
4087
+ this.registerPlugin(DropPlugin(this.options.onDrop));
4088
+ }
4033
4089
  window.setTimeout(() => {
4034
4090
  if (this.isDestroyed) {
4035
4091
  return;
@@ -4157,7 +4213,12 @@ class Editor extends EventEmitter {
4157
4213
  FocusEvents,
4158
4214
  Keymap,
4159
4215
  Tabindex,
4160
- ] : [];
4216
+ ].filter(ext => {
4217
+ if (typeof this.options.enableCoreExtensions === 'object') {
4218
+ return this.options.enableCoreExtensions[ext.name] !== false;
4219
+ }
4220
+ return true;
4221
+ }) : [];
4161
4222
  const allExtensions = [...coreExtensions, ...this.options.extensions].filter(extension => {
4162
4223
  return ['extension', 'node', 'mark'].includes(extension === null || extension === void 0 ? void 0 : extension.type);
4163
4224
  });
@@ -4766,6 +4827,9 @@ class NodeView {
4766
4827
  this.extension = props.extension;
4767
4828
  this.node = props.node;
4768
4829
  this.decorations = props.decorations;
4830
+ this.innerDecorations = props.innerDecorations;
4831
+ this.view = props.view;
4832
+ this.HTMLAttributes = props.HTMLAttributes;
4769
4833
  this.getPos = props.getPos;
4770
4834
  this.mount();
4771
4835
  }
@@ -4804,9 +4868,13 @@ class NodeView {
4804
4868
  y = handleBox.y - domBox.y + offsetY;
4805
4869
  }
4806
4870
  (_g = event.dataTransfer) === null || _g === void 0 ? void 0 : _g.setDragImage(this.dom, x, y);
4871
+ const pos = this.getPos();
4872
+ if (typeof pos !== 'number') {
4873
+ return;
4874
+ }
4807
4875
  // we need to tell ProseMirror that we want to move the whole node
4808
4876
  // so we create a NodeSelection
4809
- const selection = NodeSelection.create(view.state.doc, this.getPos());
4877
+ const selection = NodeSelection.create(view.state.doc, pos);
4810
4878
  const transaction = view.state.tr.setSelection(selection);
4811
4879
  view.dispatch(transaction);
4812
4880
  }
@@ -4877,6 +4945,11 @@ class NodeView {
4877
4945
  }
4878
4946
  return true;
4879
4947
  }
4948
+ /**
4949
+ * Called when a DOM [mutation](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) or a selection change happens within the view.
4950
+ * @return `false` if the editor should re-read the selection or re-parse the range around the mutation
4951
+ * @return `true` if it can safely be ignored.
4952
+ */
4880
4953
  ignoreMutation(mutation) {
4881
4954
  if (!this.dom || !this.contentDOM) {
4882
4955
  return true;
@@ -4923,9 +4996,15 @@ class NodeView {
4923
4996
  }
4924
4997
  return true;
4925
4998
  }
4999
+ /**
5000
+ * Update the attributes of the prosemirror node.
5001
+ */
4926
5002
  updateAttributes(attributes) {
4927
5003
  this.editor.commands.command(({ tr }) => {
4928
5004
  const pos = this.getPos();
5005
+ if (typeof pos !== 'number') {
5006
+ return false;
5007
+ }
4929
5008
  tr.setNodeMarkup(pos, undefined, {
4930
5009
  ...this.node.attrs,
4931
5010
  ...attributes,
@@ -4933,8 +5012,14 @@ class NodeView {
4933
5012
  return true;
4934
5013
  });
4935
5014
  }
5015
+ /**
5016
+ * Delete the node.
5017
+ */
4936
5018
  deleteNode() {
4937
5019
  const from = this.getPos();
5020
+ if (typeof from !== 'number') {
5021
+ return;
5022
+ }
4938
5023
  const to = from + this.node.nodeSize;
4939
5024
  this.editor.commands.deleteRange({ from, to });
4940
5025
  }
@@ -5069,5 +5154,5 @@ class Tracker {
5069
5154
  }
5070
5155
  }
5071
5156
 
5072
- export { CommandManager, Editor, Extension, InputRule, Mark, Node, NodePos, NodeView, PasteRule, Tracker, callOrReturn, combineTransactionSteps, createChainableState, createDocument, createNodeFromContent, createStyleTag, defaultBlockAt, deleteProps, elementFromString, escapeForRegEx, index as extensions, findChildren, findChildrenInRange, findDuplicates, findParentNode, findParentNodeClosestToPos, fromString, generateHTML, generateJSON, generateText, getAttributes, getAttributesFromExtensions, getChangedRanges, getDebugJSON, getExtensionField, getHTMLFromFragment, getMarkAttributes, getMarkRange, getMarkType, getMarksBetween, getNodeAtPosition, getNodeAttributes, getNodeType, getRenderedAttributes, getSchema, getSchemaByResolvedExtensions, getSchemaTypeByName, getSchemaTypeNameByName, getSplittedAttributes, getText, getTextBetween, getTextContentFromNodes, getTextSerializersFromSchema, injectExtensionAttributesToParseRule, inputRulesPlugin, isActive, isAtEndOfNode, isAtStartOfNode, isEmptyObject, isExtensionRulesEnabled, isFunction, isList, isMacOS, isMarkActive, isNodeActive, isNodeEmpty, isNodeSelection, isNumber, isPlainObject, isRegExp, isString, isTextSelection, isiOS, markInputRule, markPasteRule, mergeAttributes, mergeDeep, minMax, nodeInputRule, nodePasteRule, objectIncludes, pasteRulesPlugin, posToDOMRect, removeDuplicates, resolveFocusPosition, selectionToInsertionEnd, splitExtensions, textInputRule, textPasteRule, textblockTypeInputRule, wrappingInputRule };
5157
+ export { CommandManager, DropPlugin, Editor, Extension, InputRule, Mark, Node, NodePos, NodeView, PastePlugin, PasteRule, Tracker, callOrReturn, combineTransactionSteps, createChainableState, createDocument, createNodeFromContent, createStyleTag, defaultBlockAt, deleteProps, elementFromString, escapeForRegEx, index as extensions, findChildren, findChildrenInRange, findDuplicates, findParentNode, findParentNodeClosestToPos, fromString, generateHTML, generateJSON, generateText, getAttributes, getAttributesFromExtensions, getChangedRanges, getDebugJSON, getExtensionField, getHTMLFromFragment, getMarkAttributes, getMarkRange, getMarkType, getMarksBetween, getNodeAtPosition, getNodeAttributes, getNodeType, getRenderedAttributes, getSchema, getSchemaByResolvedExtensions, getSchemaTypeByName, getSchemaTypeNameByName, getSplittedAttributes, getText, getTextBetween, getTextContentFromNodes, getTextSerializersFromSchema, injectExtensionAttributesToParseRule, inputRulesPlugin, isActive, isAtEndOfNode, isAtStartOfNode, isEmptyObject, isExtensionRulesEnabled, isFunction, isList, isMacOS, isMarkActive, isNodeActive, isNodeEmpty, isNodeSelection, isNumber, isPlainObject, isRegExp, isString, isTextSelection, isiOS, markInputRule, markPasteRule, mergeAttributes, mergeDeep, minMax, nodeInputRule, nodePasteRule, objectIncludes, pasteRulesPlugin, posToDOMRect, removeDuplicates, resolveFocusPosition, selectionToInsertionEnd, splitExtensions, textInputRule, textPasteRule, textblockTypeInputRule, wrappingInputRule };
5073
5158
  //# sourceMappingURL=index.js.map