@handlewithcare/react-prosemirror 3.1.0-tiptap.49 → 3.1.0-tiptap.51

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 (35) hide show
  1. package/dist/cjs/ReactEditorView.js +2 -0
  2. package/dist/cjs/components/ChildNodeViews.js +14 -9
  3. package/dist/cjs/components/CursorWrapper.js +6 -9
  4. package/dist/cjs/components/TextNodeView.js +109 -38
  5. package/dist/cjs/components/TrailingHackView.js +29 -0
  6. package/dist/cjs/hooks/useComponentEventListeners.js +46 -5
  7. package/dist/cjs/hooks/useEditor.js +3 -6
  8. package/dist/cjs/hooks/useNodeViewDescription.js +37 -16
  9. package/dist/cjs/plugins/beforeInputPlugin.js +41 -43
  10. package/dist/cjs/viewdesc.js +10 -3
  11. package/dist/esm/ReactEditorView.js +2 -0
  12. package/dist/esm/components/ChildNodeViews.js +14 -9
  13. package/dist/esm/components/CursorWrapper.js +7 -10
  14. package/dist/esm/components/TextNodeView.js +109 -38
  15. package/dist/esm/components/TrailingHackView.js +30 -1
  16. package/dist/esm/hooks/useComponentEventListeners.js +53 -12
  17. package/dist/esm/hooks/useEditor.js +3 -6
  18. package/dist/esm/hooks/useNodeViewDescription.js +38 -17
  19. package/dist/esm/plugins/beforeInputPlugin.js +41 -43
  20. package/dist/esm/viewdesc.js +10 -3
  21. package/dist/tsconfig.tsbuildinfo +1 -1
  22. package/dist/types/ReactEditorView.d.ts +4 -0
  23. package/dist/types/components/TextNodeView.d.ts +14 -4
  24. package/dist/types/components/TrailingHackView.d.ts +1 -1
  25. package/dist/types/constants.d.ts +1 -1
  26. package/dist/types/contexts/EditorContext.d.ts +1 -1
  27. package/dist/types/hooks/useComponentEventListeners.d.ts +11 -10
  28. package/dist/types/hooks/useEditor.d.ts +2 -2
  29. package/dist/types/hooks/useEditorEventListener.d.ts +1 -1
  30. package/dist/types/props.d.ts +26 -26
  31. package/dist/types/viewdesc.d.ts +2 -2
  32. package/package.json +2 -1
  33. package/dist/cjs/tiptap/utils/ssrJSDOMPatch.js +0 -59
  34. package/dist/esm/tiptap/utils/ssrJSDOMPatch.js +0 -56
  35. package/dist/types/tiptap/utils/ssrJSDOMPatch.d.ts +0 -1
@@ -1,5 +1,6 @@
1
1
  import { Fragment, Slice } from "prosemirror-model";
2
2
  import { Plugin, TextSelection } from "prosemirror-state";
3
+ import { ReactEditorView } from "../ReactEditorView.js";
3
4
  import { CursorWrapper } from "../components/CursorWrapper.js";
4
5
  import { widget } from "../decorations/ReactWidgetType.js";
5
6
  function insertText(view, eventData) {
@@ -46,68 +47,41 @@ function handleGapCursorComposition(view) {
46
47
  }
47
48
  export function beforeInputPlugin(setCursorWrapper) {
48
49
  let compositionMarks = null;
49
- let precompositionSnapshot = null;
50
50
  return new Plugin({
51
51
  props: {
52
52
  handleDOMEvents: {
53
53
  compositionstart (view) {
54
- compositionMarks = view.state.storedMarks ?? view.state.selection.$from.marks();
55
- view.dispatch(view.state.tr.deleteSelection());
54
+ if (!(view instanceof ReactEditorView)) return false;
55
+ view.input.composing = true;
56
+ compositionMarks = view.state.storedMarks;
57
+ const tr = view.state.tr.deleteSelection().setStoredMarks(null);
58
+ view.dispatch(tr);
56
59
  handleGapCursorComposition(view);
57
60
  const { state } = view;
58
- const $pos = state.selection.$from;
59
- if (compositionMarks) {
61
+ if (compositionMarks?.length) {
60
62
  setCursorWrapper(widget(state.selection.from, CursorWrapper, {
61
63
  key: "cursor-wrapper",
62
- marks: compositionMarks
64
+ marks: compositionMarks,
65
+ side: 1
63
66
  }));
64
67
  }
65
- // Snapshot the siblings of the node that contains the
66
- // current cursor. We'll restore this later, so that React
67
- // doesn't panic about unknown DOM nodes.
68
- const { node: parent } = view.domAtPos($pos.pos);
69
- precompositionSnapshot = [];
70
- for (const node of parent.childNodes){
71
- precompositionSnapshot.push(node);
72
- }
73
- // @ts-expect-error Internal property - input
74
- view.input.composing = true;
75
68
  return true;
76
69
  },
77
70
  compositionupdate () {
78
71
  return true;
79
72
  },
80
73
  compositionend (view, event) {
81
- // @ts-expect-error Internal property - input
74
+ if (!(view instanceof ReactEditorView)) return false;
75
+ if (!view.composing) return false;
82
76
  view.input.composing = false;
83
- const { state } = view;
84
- const { node: parent } = view.domAtPos(state.selection.from);
85
- if (precompositionSnapshot) {
86
- // Restore the snapshot of the parent node's children
87
- // from before the composition started. This gives us a
88
- // clean slate from which to dispatch our transaction
89
- // and trigger a React update.
90
- precompositionSnapshot.forEach((prevNode, i)=>{
91
- if (parent.childNodes.length <= i) {
92
- parent.appendChild(prevNode);
93
- return;
94
- }
95
- parent.replaceChild(prevNode, parent.childNodes.item(i));
96
- });
97
- if (parent.childNodes.length > precompositionSnapshot.length) {
98
- for(let i = precompositionSnapshot.length; i < parent.childNodes.length; i++){
99
- parent.removeChild(parent.childNodes.item(i));
100
- }
101
- }
102
- }
103
- if (event.data) {
104
- insertText(view, event.data, {
105
- marks: compositionMarks
106
- });
107
- }
108
77
  compositionMarks = null;
109
- precompositionSnapshot = null;
110
78
  setCursorWrapper(null);
79
+ if (view.input.compositionNode && !view.input.compositionNode.pmViewDesc) {
80
+ view.input.compositionNode.remove();
81
+ }
82
+ view.input.compositionEndedAt = event.timeStamp;
83
+ view.input.compositionNode = null;
84
+ view.input.compositionID++;
111
85
  return true;
112
86
  },
113
87
  beforeinput (view, event) {
@@ -156,6 +130,30 @@ export function beforeInputPlugin(setCursorWrapper) {
156
130
  insertText(view, event.data);
157
131
  break;
158
132
  }
133
+ case "insertCompositionText":
134
+ {
135
+ const { tr } = view.state;
136
+ // There's always a range on insertCompositionText beforeinput events
137
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
138
+ const range = event.getTargetRanges()[0];
139
+ const start = view.posAtDOM(range.startContainer, range.startOffset);
140
+ const end = view.posAtDOM(range.endContainer, range.endOffset, 1);
141
+ if (view.state.doc.textBetween(start, end, "**", "*") === event.data) {
142
+ return;
143
+ }
144
+ if (event.data) {
145
+ if (compositionMarks) tr.ensureMarks(compositionMarks);
146
+ tr.insertText(event.data, start, end);
147
+ } else {
148
+ tr.delete(start, end);
149
+ }
150
+ view.dom.addEventListener("input", ()=>{
151
+ view.dispatch(tr);
152
+ }, {
153
+ once: true
154
+ });
155
+ break;
156
+ }
159
157
  case "deleteWordBackward":
160
158
  case "deleteHardLineBackward":
161
159
  case "deleteSoftLineBackward":
@@ -235,7 +235,9 @@ export class ViewDesc {
235
235
  prev = i ? this.children[i - 1] : null;
236
236
  if (!prev || prev.dom.parentNode == this.contentDOM) break;
237
237
  }
238
- if (prev && side && enter && !prev.border && !prev.domAtom) return prev.domFromPos(prev.size, side);
238
+ if (prev && side && enter && !prev.border && !prev.domAtom) {
239
+ return prev.domFromPos(prev.size, side);
240
+ }
239
241
  return {
240
242
  node: this.contentDOM,
241
243
  offset: prev ? domIndex(prev.dom) + 1 : 0
@@ -370,7 +372,9 @@ export class ViewDesc {
370
372
  const after = selRange.focusNode.childNodes[selRange.focusOffset];
371
373
  if (after && after.contentEditable == "false") force = true;
372
374
  }
373
- if (!(force || brKludge && browser.safari) && isEquivalentPosition(anchorDOM.node, anchorDOM.offset, selRange.anchorNode, selRange.anchorOffset) && isEquivalentPosition(headDOM.node, headDOM.offset, selRange.focusNode, selRange.focusOffset)) return;
375
+ if (!(force || brKludge && browser.safari) && isEquivalentPosition(anchorDOM.node, anchorDOM.offset, selRange.anchorNode, selRange.anchorOffset) && isEquivalentPosition(headDOM.node, headDOM.offset, selRange.focusNode, selRange.focusOffset)) {
376
+ return;
377
+ }
374
378
  // Selection.extend can be used to create an 'inverted' selection
375
379
  // (one where the focus is before the anchor), but not all
376
380
  // browsers support it yet.
@@ -645,7 +649,10 @@ export class TextViewDesc extends NodeViewDesc {
645
649
  skip: skip || true
646
650
  };
647
651
  }
648
- update(_node, _outerDeco, _innerDeco, _view) {
652
+ update(node, outerDeco, _innerDeco, _view) {
653
+ if (this.dirty == NODE_DIRTY || this.dirty != NOT_DIRTY && !this.inParent() || !node.sameMarkup(this.node)) return false;
654
+ this.updateOuterDeco(outerDeco);
655
+ this.node = node;
649
656
  this.dirty = NOT_DIRTY;
650
657
  return true;
651
658
  }