@tiptap/core 2.6.6 → 2.7.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;
@@ -1150,15 +1161,19 @@ class ExtensionManager {
1150
1161
  if (!addNodeView) {
1151
1162
  return [];
1152
1163
  }
1153
- const nodeview = (node, view, getPos, decorations) => {
1164
+ const nodeview = (node, view, getPos, decorations, innerDecorations) => {
1154
1165
  const HTMLAttributes = getRenderedAttributes(node, extensionAttributes);
1155
1166
  return addNodeView()({
1156
- editor,
1167
+ // pass-through
1157
1168
  node,
1158
- getPos,
1169
+ view,
1170
+ getPos: getPos,
1159
1171
  decorations,
1160
- HTMLAttributes,
1172
+ innerDecorations,
1173
+ // tiptap-specific
1174
+ editor,
1161
1175
  extension,
1176
+ HTMLAttributes,
1162
1177
  });
1163
1178
  };
1164
1179
  return [extension.name, nodeview];
@@ -3316,10 +3331,17 @@ const toggleNode = (typeOrName, toggleTypeOrName, attributes = {}) => ({ state,
3316
3331
  const type = getNodeType(typeOrName, state.schema);
3317
3332
  const toggleType = getNodeType(toggleTypeOrName, state.schema);
3318
3333
  const isActive = isNodeActive(state, type, attributes);
3334
+ let attributesToCopy;
3335
+ if (state.selection.$anchor.sameParent(state.selection.$head)) {
3336
+ // only copy attributes if the selection is pointing to a node of the same type
3337
+ attributesToCopy = state.selection.$anchor.parent.attrs;
3338
+ }
3319
3339
  if (isActive) {
3320
- return commands.setNode(toggleType);
3340
+ return commands.setNode(toggleType, attributesToCopy);
3321
3341
  }
3322
- return commands.setNode(type, attributes);
3342
+ // If the node is not active, we want to set the new node type with the given attributes
3343
+ // Copying over the attributes from the current node if the selection is pointing to a node of the same type
3344
+ return commands.setNode(type, { ...attributesToCopy, ...attributes });
3323
3345
  };
3324
3346
 
3325
3347
  const toggleWrap = (typeOrName, attributes = {}) => ({ state, commands }) => {
@@ -3653,7 +3675,8 @@ const Keymap = Extension.create({
3653
3675
  appendTransaction: (transactions, oldState, newState) => {
3654
3676
  const docChanges = transactions.some(transaction => transaction.docChanged)
3655
3677
  && !oldState.doc.eq(newState.doc);
3656
- if (!docChanges) {
3678
+ const ignoreTr = transactions.some(transaction => transaction.getMeta('preventClearDocument'));
3679
+ if (!docChanges || ignoreTr) {
3657
3680
  return;
3658
3681
  }
3659
3682
  const { empty, from, to } = oldState.selection;
@@ -3663,7 +3686,7 @@ const Keymap = Extension.create({
3663
3686
  if (empty || !allWasSelected) {
3664
3687
  return;
3665
3688
  }
3666
- const isEmpty = newState.doc.textBetween(0, newState.doc.content.size, ' ', ' ').length === 0;
3689
+ const isEmpty = isNodeEmpty(newState.doc);
3667
3690
  if (!isEmpty) {
3668
3691
  return;
3669
3692
  }
@@ -3887,6 +3910,28 @@ class NodePos {
3887
3910
  }
3888
3911
  }
3889
3912
 
3913
+ const DropPlugin = (onDrop) => {
3914
+ return new Plugin({
3915
+ key: new PluginKey('tiptapDrop'),
3916
+ props: {
3917
+ handleDrop: (_, e, slice, moved) => {
3918
+ onDrop(e, slice, moved);
3919
+ },
3920
+ },
3921
+ });
3922
+ };
3923
+
3924
+ const PastePlugin = (onPaste) => {
3925
+ return new Plugin({
3926
+ key: new PluginKey('tiptapPaste'),
3927
+ props: {
3928
+ handlePaste: (_view, e, slice) => {
3929
+ onPaste(e, slice);
3930
+ },
3931
+ },
3932
+ });
3933
+ };
3934
+
3890
3935
  const style = `.ProseMirror {
3891
3936
  position: relative;
3892
3937
  }
@@ -4011,6 +4056,8 @@ class Editor extends EventEmitter {
4011
4056
  onBlur: () => null,
4012
4057
  onDestroy: () => null,
4013
4058
  onContentError: ({ error }) => { throw error; },
4059
+ onPaste: () => null,
4060
+ onDrop: () => null,
4014
4061
  };
4015
4062
  this.isCapturingTransaction = false;
4016
4063
  this.capturedTransaction = null;
@@ -4030,6 +4077,12 @@ class Editor extends EventEmitter {
4030
4077
  this.on('focus', this.options.onFocus);
4031
4078
  this.on('blur', this.options.onBlur);
4032
4079
  this.on('destroy', this.options.onDestroy);
4080
+ if (this.options.onPaste) {
4081
+ this.registerPlugin(PastePlugin(this.options.onPaste));
4082
+ }
4083
+ if (this.options.onDrop) {
4084
+ this.registerPlugin(DropPlugin(this.options.onDrop));
4085
+ }
4033
4086
  window.setTimeout(() => {
4034
4087
  if (this.isDestroyed) {
4035
4088
  return;
@@ -4157,7 +4210,12 @@ class Editor extends EventEmitter {
4157
4210
  FocusEvents,
4158
4211
  Keymap,
4159
4212
  Tabindex,
4160
- ] : [];
4213
+ ].filter(ext => {
4214
+ if (typeof this.options.enableCoreExtensions === 'object') {
4215
+ return this.options.enableCoreExtensions[ext.name] !== false;
4216
+ }
4217
+ return true;
4218
+ }) : [];
4161
4219
  const allExtensions = [...coreExtensions, ...this.options.extensions].filter(extension => {
4162
4220
  return ['extension', 'node', 'mark'].includes(extension === null || extension === void 0 ? void 0 : extension.type);
4163
4221
  });
@@ -4766,6 +4824,9 @@ class NodeView {
4766
4824
  this.extension = props.extension;
4767
4825
  this.node = props.node;
4768
4826
  this.decorations = props.decorations;
4827
+ this.innerDecorations = props.innerDecorations;
4828
+ this.view = props.view;
4829
+ this.HTMLAttributes = props.HTMLAttributes;
4769
4830
  this.getPos = props.getPos;
4770
4831
  this.mount();
4771
4832
  }
@@ -4804,9 +4865,13 @@ class NodeView {
4804
4865
  y = handleBox.y - domBox.y + offsetY;
4805
4866
  }
4806
4867
  (_g = event.dataTransfer) === null || _g === void 0 ? void 0 : _g.setDragImage(this.dom, x, y);
4868
+ const pos = this.getPos();
4869
+ if (typeof pos !== 'number') {
4870
+ return;
4871
+ }
4807
4872
  // we need to tell ProseMirror that we want to move the whole node
4808
4873
  // so we create a NodeSelection
4809
- const selection = NodeSelection.create(view.state.doc, this.getPos());
4874
+ const selection = NodeSelection.create(view.state.doc, pos);
4810
4875
  const transaction = view.state.tr.setSelection(selection);
4811
4876
  view.dispatch(transaction);
4812
4877
  }
@@ -4877,6 +4942,11 @@ class NodeView {
4877
4942
  }
4878
4943
  return true;
4879
4944
  }
4945
+ /**
4946
+ * Called when a DOM [mutation](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) or a selection change happens within the view.
4947
+ * @return `false` if the editor should re-read the selection or re-parse the range around the mutation
4948
+ * @return `true` if it can safely be ignored.
4949
+ */
4880
4950
  ignoreMutation(mutation) {
4881
4951
  if (!this.dom || !this.contentDOM) {
4882
4952
  return true;
@@ -4923,9 +4993,15 @@ class NodeView {
4923
4993
  }
4924
4994
  return true;
4925
4995
  }
4996
+ /**
4997
+ * Update the attributes of the prosemirror node.
4998
+ */
4926
4999
  updateAttributes(attributes) {
4927
5000
  this.editor.commands.command(({ tr }) => {
4928
5001
  const pos = this.getPos();
5002
+ if (typeof pos !== 'number') {
5003
+ return false;
5004
+ }
4929
5005
  tr.setNodeMarkup(pos, undefined, {
4930
5006
  ...this.node.attrs,
4931
5007
  ...attributes,
@@ -4933,8 +5009,14 @@ class NodeView {
4933
5009
  return true;
4934
5010
  });
4935
5011
  }
5012
+ /**
5013
+ * Delete the node.
5014
+ */
4936
5015
  deleteNode() {
4937
5016
  const from = this.getPos();
5017
+ if (typeof from !== 'number') {
5018
+ return;
5019
+ }
4938
5020
  const to = from + this.node.nodeSize;
4939
5021
  this.editor.commands.deleteRange({ from, to });
4940
5022
  }
@@ -5069,5 +5151,5 @@ class Tracker {
5069
5151
  }
5070
5152
  }
5071
5153
 
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 };
5154
+ 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
5155
  //# sourceMappingURL=index.js.map