@tiptap/core 2.6.5 → 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];
@@ -1766,7 +1784,11 @@ function createNodeFromContent(content, schema, options) {
1766
1784
  if (isArrayContent) {
1767
1785
  return Fragment.fromArray(content.map(item => schema.nodeFromJSON(item)));
1768
1786
  }
1769
- return schema.nodeFromJSON(content);
1787
+ const node = schema.nodeFromJSON(content);
1788
+ if (options.errorOnInvalidContent) {
1789
+ node.check();
1790
+ }
1791
+ return node;
1770
1792
  }
1771
1793
  catch (error) {
1772
1794
  if (options.errorOnInvalidContent) {
@@ -3312,10 +3334,17 @@ const toggleNode = (typeOrName, toggleTypeOrName, attributes = {}) => ({ state,
3312
3334
  const type = getNodeType(typeOrName, state.schema);
3313
3335
  const toggleType = getNodeType(toggleTypeOrName, state.schema);
3314
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
+ }
3315
3342
  if (isActive) {
3316
- return commands.setNode(toggleType);
3343
+ return commands.setNode(toggleType, attributesToCopy);
3317
3344
  }
3318
- 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 });
3319
3348
  };
3320
3349
 
3321
3350
  const toggleWrap = (typeOrName, attributes = {}) => ({ state, commands }) => {
@@ -3649,7 +3678,8 @@ const Keymap = Extension.create({
3649
3678
  appendTransaction: (transactions, oldState, newState) => {
3650
3679
  const docChanges = transactions.some(transaction => transaction.docChanged)
3651
3680
  && !oldState.doc.eq(newState.doc);
3652
- if (!docChanges) {
3681
+ const ignoreTr = transactions.some(transaction => transaction.getMeta('preventClearDocument'));
3682
+ if (!docChanges || ignoreTr) {
3653
3683
  return;
3654
3684
  }
3655
3685
  const { empty, from, to } = oldState.selection;
@@ -3659,7 +3689,7 @@ const Keymap = Extension.create({
3659
3689
  if (empty || !allWasSelected) {
3660
3690
  return;
3661
3691
  }
3662
- const isEmpty = newState.doc.textBetween(0, newState.doc.content.size, ' ', ' ').length === 0;
3692
+ const isEmpty = isNodeEmpty(newState.doc);
3663
3693
  if (!isEmpty) {
3664
3694
  return;
3665
3695
  }
@@ -3883,6 +3913,28 @@ class NodePos {
3883
3913
  }
3884
3914
  }
3885
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
+
3886
3938
  const style = `.ProseMirror {
3887
3939
  position: relative;
3888
3940
  }
@@ -4007,6 +4059,8 @@ class Editor extends EventEmitter {
4007
4059
  onBlur: () => null,
4008
4060
  onDestroy: () => null,
4009
4061
  onContentError: ({ error }) => { throw error; },
4062
+ onPaste: () => null,
4063
+ onDrop: () => null,
4010
4064
  };
4011
4065
  this.isCapturingTransaction = false;
4012
4066
  this.capturedTransaction = null;
@@ -4026,6 +4080,12 @@ class Editor extends EventEmitter {
4026
4080
  this.on('focus', this.options.onFocus);
4027
4081
  this.on('blur', this.options.onBlur);
4028
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
+ }
4029
4089
  window.setTimeout(() => {
4030
4090
  if (this.isDestroyed) {
4031
4091
  return;
@@ -4153,7 +4213,12 @@ class Editor extends EventEmitter {
4153
4213
  FocusEvents,
4154
4214
  Keymap,
4155
4215
  Tabindex,
4156
- ] : [];
4216
+ ].filter(ext => {
4217
+ if (typeof this.options.enableCoreExtensions === 'object') {
4218
+ return this.options.enableCoreExtensions[ext.name] !== false;
4219
+ }
4220
+ return true;
4221
+ }) : [];
4157
4222
  const allExtensions = [...coreExtensions, ...this.options.extensions].filter(extension => {
4158
4223
  return ['extension', 'node', 'mark'].includes(extension === null || extension === void 0 ? void 0 : extension.type);
4159
4224
  });
@@ -4762,6 +4827,9 @@ class NodeView {
4762
4827
  this.extension = props.extension;
4763
4828
  this.node = props.node;
4764
4829
  this.decorations = props.decorations;
4830
+ this.innerDecorations = props.innerDecorations;
4831
+ this.view = props.view;
4832
+ this.HTMLAttributes = props.HTMLAttributes;
4765
4833
  this.getPos = props.getPos;
4766
4834
  this.mount();
4767
4835
  }
@@ -4800,9 +4868,13 @@ class NodeView {
4800
4868
  y = handleBox.y - domBox.y + offsetY;
4801
4869
  }
4802
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
+ }
4803
4875
  // we need to tell ProseMirror that we want to move the whole node
4804
4876
  // so we create a NodeSelection
4805
- const selection = NodeSelection.create(view.state.doc, this.getPos());
4877
+ const selection = NodeSelection.create(view.state.doc, pos);
4806
4878
  const transaction = view.state.tr.setSelection(selection);
4807
4879
  view.dispatch(transaction);
4808
4880
  }
@@ -4873,6 +4945,11 @@ class NodeView {
4873
4945
  }
4874
4946
  return true;
4875
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
+ */
4876
4953
  ignoreMutation(mutation) {
4877
4954
  if (!this.dom || !this.contentDOM) {
4878
4955
  return true;
@@ -4919,9 +4996,15 @@ class NodeView {
4919
4996
  }
4920
4997
  return true;
4921
4998
  }
4999
+ /**
5000
+ * Update the attributes of the prosemirror node.
5001
+ */
4922
5002
  updateAttributes(attributes) {
4923
5003
  this.editor.commands.command(({ tr }) => {
4924
5004
  const pos = this.getPos();
5005
+ if (typeof pos !== 'number') {
5006
+ return false;
5007
+ }
4925
5008
  tr.setNodeMarkup(pos, undefined, {
4926
5009
  ...this.node.attrs,
4927
5010
  ...attributes,
@@ -4929,8 +5012,14 @@ class NodeView {
4929
5012
  return true;
4930
5013
  });
4931
5014
  }
5015
+ /**
5016
+ * Delete the node.
5017
+ */
4932
5018
  deleteNode() {
4933
5019
  const from = this.getPos();
5020
+ if (typeof from !== 'number') {
5021
+ return;
5022
+ }
4934
5023
  const to = from + this.node.nodeSize;
4935
5024
  this.editor.commands.deleteRange({ from, to });
4936
5025
  }
@@ -5065,5 +5154,5 @@ class Tracker {
5065
5154
  }
5066
5155
  }
5067
5156
 
5068
- 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 };
5069
5158
  //# sourceMappingURL=index.js.map