@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.cjs CHANGED
@@ -321,7 +321,18 @@ function mergeAttributes(...objects) {
321
321
  mergedAttributes[key] = [...existingClasses, ...insertClasses].join(' ');
322
322
  }
323
323
  else if (key === 'style') {
324
- mergedAttributes[key] = [mergedAttributes[key], value].join('; ');
324
+ const newStyles = value ? value.split(';').map((style) => style.trim()).filter(Boolean) : [];
325
+ const existingStyles = mergedAttributes[key] ? mergedAttributes[key].split(';').map((style) => style.trim()).filter(Boolean) : [];
326
+ const styleMap = new Map();
327
+ existingStyles.forEach(style => {
328
+ const [property, val] = style.split(':').map(part => part.trim());
329
+ styleMap.set(property, val);
330
+ });
331
+ newStyles.forEach(style => {
332
+ const [property, val] = style.split(':').map(part => part.trim());
333
+ styleMap.set(property, val);
334
+ });
335
+ mergedAttributes[key] = Array.from(styleMap.entries()).map(([property, val]) => `${property}: ${val}`).join('; ');
325
336
  }
326
337
  else {
327
338
  mergedAttributes[key] = value;
@@ -1152,15 +1163,19 @@ class ExtensionManager {
1152
1163
  if (!addNodeView) {
1153
1164
  return [];
1154
1165
  }
1155
- const nodeview = (node, view, getPos, decorations) => {
1166
+ const nodeview = (node, view, getPos, decorations, innerDecorations) => {
1156
1167
  const HTMLAttributes = getRenderedAttributes(node, extensionAttributes);
1157
1168
  return addNodeView()({
1158
- editor,
1169
+ // pass-through
1159
1170
  node,
1160
- getPos,
1171
+ view,
1172
+ getPos: getPos,
1161
1173
  decorations,
1162
- HTMLAttributes,
1174
+ innerDecorations,
1175
+ // tiptap-specific
1176
+ editor,
1163
1177
  extension,
1178
+ HTMLAttributes,
1164
1179
  });
1165
1180
  };
1166
1181
  return [extension.name, nodeview];
@@ -3318,10 +3333,17 @@ const toggleNode = (typeOrName, toggleTypeOrName, attributes = {}) => ({ state,
3318
3333
  const type = getNodeType(typeOrName, state.schema);
3319
3334
  const toggleType = getNodeType(toggleTypeOrName, state.schema);
3320
3335
  const isActive = isNodeActive(state, type, attributes);
3336
+ let attributesToCopy;
3337
+ if (state.selection.$anchor.sameParent(state.selection.$head)) {
3338
+ // only copy attributes if the selection is pointing to a node of the same type
3339
+ attributesToCopy = state.selection.$anchor.parent.attrs;
3340
+ }
3321
3341
  if (isActive) {
3322
- return commands.setNode(toggleType);
3342
+ return commands.setNode(toggleType, attributesToCopy);
3323
3343
  }
3324
- return commands.setNode(type, attributes);
3344
+ // If the node is not active, we want to set the new node type with the given attributes
3345
+ // Copying over the attributes from the current node if the selection is pointing to a node of the same type
3346
+ return commands.setNode(type, { ...attributesToCopy, ...attributes });
3325
3347
  };
3326
3348
 
3327
3349
  const toggleWrap = (typeOrName, attributes = {}) => ({ state, commands }) => {
@@ -3655,7 +3677,8 @@ const Keymap = Extension.create({
3655
3677
  appendTransaction: (transactions, oldState, newState) => {
3656
3678
  const docChanges = transactions.some(transaction => transaction.docChanged)
3657
3679
  && !oldState.doc.eq(newState.doc);
3658
- if (!docChanges) {
3680
+ const ignoreTr = transactions.some(transaction => transaction.getMeta('preventClearDocument'));
3681
+ if (!docChanges || ignoreTr) {
3659
3682
  return;
3660
3683
  }
3661
3684
  const { empty, from, to } = oldState.selection;
@@ -3665,7 +3688,7 @@ const Keymap = Extension.create({
3665
3688
  if (empty || !allWasSelected) {
3666
3689
  return;
3667
3690
  }
3668
- const isEmpty = newState.doc.textBetween(0, newState.doc.content.size, ' ', ' ').length === 0;
3691
+ const isEmpty = isNodeEmpty(newState.doc);
3669
3692
  if (!isEmpty) {
3670
3693
  return;
3671
3694
  }
@@ -3889,6 +3912,28 @@ class NodePos {
3889
3912
  }
3890
3913
  }
3891
3914
 
3915
+ const DropPlugin = (onDrop) => {
3916
+ return new state.Plugin({
3917
+ key: new state.PluginKey('tiptapDrop'),
3918
+ props: {
3919
+ handleDrop: (_, e, slice, moved) => {
3920
+ onDrop(e, slice, moved);
3921
+ },
3922
+ },
3923
+ });
3924
+ };
3925
+
3926
+ const PastePlugin = (onPaste) => {
3927
+ return new state.Plugin({
3928
+ key: new state.PluginKey('tiptapPaste'),
3929
+ props: {
3930
+ handlePaste: (_view, e, slice) => {
3931
+ onPaste(e, slice);
3932
+ },
3933
+ },
3934
+ });
3935
+ };
3936
+
3892
3937
  const style = `.ProseMirror {
3893
3938
  position: relative;
3894
3939
  }
@@ -4013,6 +4058,8 @@ class Editor extends EventEmitter {
4013
4058
  onBlur: () => null,
4014
4059
  onDestroy: () => null,
4015
4060
  onContentError: ({ error }) => { throw error; },
4061
+ onPaste: () => null,
4062
+ onDrop: () => null,
4016
4063
  };
4017
4064
  this.isCapturingTransaction = false;
4018
4065
  this.capturedTransaction = null;
@@ -4032,6 +4079,12 @@ class Editor extends EventEmitter {
4032
4079
  this.on('focus', this.options.onFocus);
4033
4080
  this.on('blur', this.options.onBlur);
4034
4081
  this.on('destroy', this.options.onDestroy);
4082
+ if (this.options.onPaste) {
4083
+ this.registerPlugin(PastePlugin(this.options.onPaste));
4084
+ }
4085
+ if (this.options.onDrop) {
4086
+ this.registerPlugin(DropPlugin(this.options.onDrop));
4087
+ }
4035
4088
  window.setTimeout(() => {
4036
4089
  if (this.isDestroyed) {
4037
4090
  return;
@@ -4159,7 +4212,12 @@ class Editor extends EventEmitter {
4159
4212
  FocusEvents,
4160
4213
  Keymap,
4161
4214
  Tabindex,
4162
- ] : [];
4215
+ ].filter(ext => {
4216
+ if (typeof this.options.enableCoreExtensions === 'object') {
4217
+ return this.options.enableCoreExtensions[ext.name] !== false;
4218
+ }
4219
+ return true;
4220
+ }) : [];
4163
4221
  const allExtensions = [...coreExtensions, ...this.options.extensions].filter(extension => {
4164
4222
  return ['extension', 'node', 'mark'].includes(extension === null || extension === void 0 ? void 0 : extension.type);
4165
4223
  });
@@ -4768,6 +4826,9 @@ class NodeView {
4768
4826
  this.extension = props.extension;
4769
4827
  this.node = props.node;
4770
4828
  this.decorations = props.decorations;
4829
+ this.innerDecorations = props.innerDecorations;
4830
+ this.view = props.view;
4831
+ this.HTMLAttributes = props.HTMLAttributes;
4771
4832
  this.getPos = props.getPos;
4772
4833
  this.mount();
4773
4834
  }
@@ -4806,9 +4867,13 @@ class NodeView {
4806
4867
  y = handleBox.y - domBox.y + offsetY;
4807
4868
  }
4808
4869
  (_g = event.dataTransfer) === null || _g === void 0 ? void 0 : _g.setDragImage(this.dom, x, y);
4870
+ const pos = this.getPos();
4871
+ if (typeof pos !== 'number') {
4872
+ return;
4873
+ }
4809
4874
  // we need to tell ProseMirror that we want to move the whole node
4810
4875
  // so we create a NodeSelection
4811
- const selection = state.NodeSelection.create(view.state.doc, this.getPos());
4876
+ const selection = state.NodeSelection.create(view.state.doc, pos);
4812
4877
  const transaction = view.state.tr.setSelection(selection);
4813
4878
  view.dispatch(transaction);
4814
4879
  }
@@ -4879,6 +4944,11 @@ class NodeView {
4879
4944
  }
4880
4945
  return true;
4881
4946
  }
4947
+ /**
4948
+ * Called when a DOM [mutation](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) or a selection change happens within the view.
4949
+ * @return `false` if the editor should re-read the selection or re-parse the range around the mutation
4950
+ * @return `true` if it can safely be ignored.
4951
+ */
4882
4952
  ignoreMutation(mutation) {
4883
4953
  if (!this.dom || !this.contentDOM) {
4884
4954
  return true;
@@ -4925,9 +4995,15 @@ class NodeView {
4925
4995
  }
4926
4996
  return true;
4927
4997
  }
4998
+ /**
4999
+ * Update the attributes of the prosemirror node.
5000
+ */
4928
5001
  updateAttributes(attributes) {
4929
5002
  this.editor.commands.command(({ tr }) => {
4930
5003
  const pos = this.getPos();
5004
+ if (typeof pos !== 'number') {
5005
+ return false;
5006
+ }
4931
5007
  tr.setNodeMarkup(pos, undefined, {
4932
5008
  ...this.node.attrs,
4933
5009
  ...attributes,
@@ -4935,8 +5011,14 @@ class NodeView {
4935
5011
  return true;
4936
5012
  });
4937
5013
  }
5014
+ /**
5015
+ * Delete the node.
5016
+ */
4938
5017
  deleteNode() {
4939
5018
  const from = this.getPos();
5019
+ if (typeof from !== 'number') {
5020
+ return;
5021
+ }
4940
5022
  const to = from + this.node.nodeSize;
4941
5023
  this.editor.commands.deleteRange({ from, to });
4942
5024
  }
@@ -5072,6 +5154,7 @@ class Tracker {
5072
5154
  }
5073
5155
 
5074
5156
  exports.CommandManager = CommandManager;
5157
+ exports.DropPlugin = DropPlugin;
5075
5158
  exports.Editor = Editor;
5076
5159
  exports.Extension = Extension;
5077
5160
  exports.InputRule = InputRule;
@@ -5079,6 +5162,7 @@ exports.Mark = Mark;
5079
5162
  exports.Node = Node;
5080
5163
  exports.NodePos = NodePos;
5081
5164
  exports.NodeView = NodeView;
5165
+ exports.PastePlugin = PastePlugin;
5082
5166
  exports.PasteRule = PasteRule;
5083
5167
  exports.Tracker = Tracker;
5084
5168
  exports.callOrReturn = callOrReturn;