@handlewithcare/react-prosemirror 3.1.0-tiptap.43 → 3.1.0-tiptap.44

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.
@@ -244,7 +244,9 @@ function adjustWidgetMarksBack(widgetChildren, nodeChild) {
244
244
  const child = widgetChildren[i];
245
245
  if (// Using internal Decoration property, "type"
246
246
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
247
- child.widget.type.side < 0) {
247
+ child.widget.type.side < 0 || // Using internal Decoration property, "type"
248
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
249
+ child.widget.type.spec.marks) {
248
250
  continue;
249
251
  }
250
252
  child.marks = child.marks.reduce((acc, mark)=>mark.addToSet(acc), marksToSpread);
@@ -54,7 +54,6 @@ function _interop_require_wildcard(obj, nodeInterop) {
54
54
  }
55
55
  const CursorWrapper = /*#__PURE__*/ (0, _react.forwardRef)(function CursorWrapper(param, ref) {
56
56
  let { widget, getPos, ...props } = param;
57
- const [shouldRender, setShouldRender] = (0, _react.useState)(true);
58
57
  const innerRef = (0, _react.useRef)(null);
59
58
  (0, _react.useImperativeHandle)(ref, ()=>{
60
59
  return innerRef.current;
@@ -65,27 +64,23 @@ const CursorWrapper = /*#__PURE__*/ (0, _react.forwardRef)(function CursorWrappe
65
64
  view.domObserver.disconnectSelection();
66
65
  // @ts-expect-error Internal property - domSelection
67
66
  const domSel = view.domSelection();
68
- const range = document.createRange();
69
67
  const node = innerRef.current;
70
68
  const img = node.nodeName == "IMG";
71
- if (img && node.parentNode) {
72
- range.setEnd(node.parentNode, (0, _dom.domIndex)(node) + 1);
69
+ if (img) {
70
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
71
+ domSel.collapse(node.parentNode, (0, _dom.domIndex)(node) + 1);
73
72
  } else {
74
- range.setEnd(node, 0);
73
+ domSel.collapse(node, 0);
75
74
  }
76
- range.collapse(false);
77
- domSel.removeAllRanges();
78
- domSel.addRange(range);
79
- setShouldRender(false);
80
75
  // @ts-expect-error Internal property - domObserver
81
76
  view.domObserver.connectSelection();
82
77
  }, []);
83
- return shouldRender ? /*#__PURE__*/ _react.default.createElement("img", {
78
+ return /*#__PURE__*/ _react.default.createElement("img", {
84
79
  ref: innerRef,
85
80
  className: "ProseMirror-separator",
86
81
  // eslint-disable-next-line react/no-unknown-property
87
82
  "mark-placeholder": "true",
88
83
  alt: "",
89
84
  ...props
90
- }) : null;
85
+ });
91
86
  });
@@ -73,7 +73,7 @@ const rootChildDescriptionsContextValue = {
73
73
  function ProseMirrorInner(param) {
74
74
  let { children, nodeViewComponents, markViewComponents, ...props } = param;
75
75
  const [mount, setMount] = (0, _react.useState)(null);
76
- const { editor, state } = (0, _useEditor.useEditor)(mount, props);
76
+ const { editor, cursorWrapper, state } = (0, _useEditor.useEditor)(mount, props);
77
77
  const nodeViewConstructors = editor.view.nodeViews;
78
78
  const nodeViewContextValue = (0, _react.useMemo)(()=>{
79
79
  return {
@@ -90,7 +90,7 @@ function ProseMirrorInner(param) {
90
90
  ]);
91
91
  const node = state.doc;
92
92
  const decorations = (0, _computeDocDeco.computeDocDeco)(editor.view);
93
- const innerDecorations = (0, _viewDecorations.viewDecorations)(editor.view, editor.cursorWrapper);
93
+ const innerDecorations = (0, _viewDecorations.viewDecorations)(editor.view, cursorWrapper);
94
94
  const docNodeViewContextValue = (0, _react.useMemo)(()=>({
95
95
  setMount,
96
96
  node,
@@ -113,13 +113,11 @@ function useEditor(mount, options) {
113
113
  view.update(directEditorProps);
114
114
  const editor = (0, _react.useMemo)(()=>({
115
115
  view,
116
- cursorWrapper,
117
116
  flushSyncRef,
118
117
  registerEventListener,
119
118
  unregisterEventListener,
120
119
  isStatic: options.static ?? false
121
120
  }), [
122
- cursorWrapper,
123
121
  options.static,
124
122
  registerEventListener,
125
123
  unregisterEventListener,
@@ -127,6 +125,7 @@ function useEditor(mount, options) {
127
125
  ]);
128
126
  return {
129
127
  editor,
128
+ cursorWrapper,
130
129
  state
131
130
  };
132
131
  }
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "beforeInputPlugin", {
8
8
  return beforeInputPlugin;
9
9
  }
10
10
  });
11
+ const _prosemirrormodel = require("prosemirror-model");
11
12
  const _prosemirrorstate = require("prosemirror-state");
12
13
  const _CursorWrapper = require("../components/CursorWrapper.js");
13
14
  const _ReactWidgetType = require("../decorations/ReactWidgetType.js");
@@ -25,6 +26,34 @@ function insertText(view, eventData) {
25
26
  view.dispatch(tr);
26
27
  return true;
27
28
  }
29
+ // Taken from https://github.com/ProseMirror/prosemirror-gapcursor/blob/master/src/index.ts#L67-L84
30
+ // This is a hack that, when a composition starts while a gap cursor
31
+ // is active, quickly creates an inline context for the composition to
32
+ // happen in, to avoid it being aborted by the DOM selection being
33
+ // moved into a valid position.
34
+ //
35
+ // We can't rely on the actual hack from prosemirror-gapcursor, because
36
+ // it happens too late. We snapshot the DOM during compositionstart, but
37
+ // the gapcursor hack runs in beforeinput (after compositionstart).
38
+ function handleGapCursorComposition(view) {
39
+ // @ts-expect-error Internal property - jsonID
40
+ if (!(view.state.selection.jsonID === "gapcursor")) {
41
+ return;
42
+ }
43
+ const { $from } = view.state.selection;
44
+ const insert = $from.parent.contentMatchAt($from.index())// All schemas _must_ have a text node type
45
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
46
+ .findWrapping(view.state.schema.nodes.text);
47
+ if (!insert) return;
48
+ let fragment = _prosemirrormodel.Fragment.empty;
49
+ for(let i = insert.length - 1; i >= 0; i--){
50
+ fragment = _prosemirrormodel.Fragment.from(// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
51
+ insert[i].createAndFill(null, fragment));
52
+ }
53
+ const tr = view.state.tr.replace($from.pos, $from.pos, new _prosemirrormodel.Slice(fragment, 0, 0));
54
+ tr.setSelection(_prosemirrorstate.TextSelection.near(tr.doc.resolve($from.pos + 1)));
55
+ view.dispatch(tr);
56
+ }
28
57
  function beforeInputPlugin(setCursorWrapper) {
29
58
  let compositionMarks = null;
30
59
  let precompositionSnapshot = null;
@@ -32,10 +61,11 @@ function beforeInputPlugin(setCursorWrapper) {
32
61
  props: {
33
62
  handleDOMEvents: {
34
63
  compositionstart (view) {
64
+ compositionMarks = view.state.storedMarks ?? view.state.selection.$from.marks();
65
+ view.dispatch(view.state.tr.deleteSelection());
66
+ handleGapCursorComposition(view);
35
67
  const { state } = view;
36
- view.dispatch(state.tr.deleteSelection());
37
68
  const $pos = state.selection.$from;
38
- compositionMarks = state.storedMarks ?? $pos.marks();
39
69
  if (compositionMarks) {
40
70
  setCursorWrapper((0, _ReactWidgetType.widget)(state.selection.from, _CursorWrapper.CursorWrapper, {
41
71
  key: "cursor-wrapper",
@@ -51,7 +51,7 @@ function tempEditor(param) {
51
51
  const state = _prosemirrorstate.EditorState.create({
52
52
  doc: startDoc,
53
53
  schema: _prosemirrortestbuilder.schema,
54
- selection: selection ?? startDoc.tag?.a ? _prosemirrorstate.TextSelection.create(startDoc, startDoc.tag.a, startDoc.tag?.b) : undefined,
54
+ selection: selection ?? (startDoc.tag?.a ? _prosemirrorstate.TextSelection.create(startDoc, startDoc.tag.a, startDoc.tag?.b) : undefined),
55
55
  plugins: [
56
56
  ...plugins ?? [],
57
57
  (0, _reactKeys.reactKeys)()
@@ -185,7 +185,9 @@ function adjustWidgetMarksBack(widgetChildren, nodeChild) {
185
185
  const child = widgetChildren[i];
186
186
  if (// Using internal Decoration property, "type"
187
187
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
188
- child.widget.type.side < 0) {
188
+ child.widget.type.side < 0 || // Using internal Decoration property, "type"
189
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
190
+ child.widget.type.spec.marks) {
189
191
  continue;
190
192
  }
191
193
  child.marks = child.marks.reduce((acc, mark)=>mark.addToSet(acc), marksToSpread);
@@ -1,9 +1,8 @@
1
- import React, { forwardRef, useImperativeHandle, useRef, useState } from "react";
1
+ import React, { forwardRef, useImperativeHandle, useRef } from "react";
2
2
  import { domIndex } from "../dom.js";
3
3
  import { useEditorEffect } from "../hooks/useEditorEffect.js";
4
4
  export const CursorWrapper = /*#__PURE__*/ forwardRef(function CursorWrapper(param, ref) {
5
5
  let { widget, getPos, ...props } = param;
6
- const [shouldRender, setShouldRender] = useState(true);
7
6
  const innerRef = useRef(null);
8
7
  useImperativeHandle(ref, ()=>{
9
8
  return innerRef.current;
@@ -14,27 +13,23 @@ export const CursorWrapper = /*#__PURE__*/ forwardRef(function CursorWrapper(par
14
13
  view.domObserver.disconnectSelection();
15
14
  // @ts-expect-error Internal property - domSelection
16
15
  const domSel = view.domSelection();
17
- const range = document.createRange();
18
16
  const node = innerRef.current;
19
17
  const img = node.nodeName == "IMG";
20
- if (img && node.parentNode) {
21
- range.setEnd(node.parentNode, domIndex(node) + 1);
18
+ if (img) {
19
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
20
+ domSel.collapse(node.parentNode, domIndex(node) + 1);
22
21
  } else {
23
- range.setEnd(node, 0);
22
+ domSel.collapse(node, 0);
24
23
  }
25
- range.collapse(false);
26
- domSel.removeAllRanges();
27
- domSel.addRange(range);
28
- setShouldRender(false);
29
24
  // @ts-expect-error Internal property - domObserver
30
25
  view.domObserver.connectSelection();
31
26
  }, []);
32
- return shouldRender ? /*#__PURE__*/ React.createElement("img", {
27
+ return /*#__PURE__*/ React.createElement("img", {
33
28
  ref: innerRef,
34
29
  className: "ProseMirror-separator",
35
30
  // eslint-disable-next-line react/no-unknown-property
36
31
  "mark-placeholder": "true",
37
32
  alt: "",
38
33
  ...props
39
- }) : null;
34
+ });
40
35
  });
@@ -22,7 +22,7 @@ const rootChildDescriptionsContextValue = {
22
22
  function ProseMirrorInner(param) {
23
23
  let { children, nodeViewComponents, markViewComponents, ...props } = param;
24
24
  const [mount, setMount] = useState(null);
25
- const { editor, state } = useEditor(mount, props);
25
+ const { editor, cursorWrapper, state } = useEditor(mount, props);
26
26
  const nodeViewConstructors = editor.view.nodeViews;
27
27
  const nodeViewContextValue = useMemo(()=>{
28
28
  return {
@@ -39,7 +39,7 @@ function ProseMirrorInner(param) {
39
39
  ]);
40
40
  const node = state.doc;
41
41
  const decorations = computeDocDeco(editor.view);
42
- const innerDecorations = viewDecorations(editor.view, editor.cursorWrapper);
42
+ const innerDecorations = viewDecorations(editor.view, cursorWrapper);
43
43
  const docNodeViewContextValue = useMemo(()=>({
44
44
  setMount,
45
45
  node,
@@ -111,13 +111,11 @@ let didWarnValueDefaultValue = false;
111
111
  view.update(directEditorProps);
112
112
  const editor = useMemo(()=>({
113
113
  view,
114
- cursorWrapper,
115
114
  flushSyncRef,
116
115
  registerEventListener,
117
116
  unregisterEventListener,
118
117
  isStatic: options.static ?? false
119
118
  }), [
120
- cursorWrapper,
121
119
  options.static,
122
120
  registerEventListener,
123
121
  unregisterEventListener,
@@ -125,6 +123,7 @@ let didWarnValueDefaultValue = false;
125
123
  ]);
126
124
  return {
127
125
  editor,
126
+ cursorWrapper,
128
127
  state
129
128
  };
130
129
  }
@@ -1,4 +1,5 @@
1
- import { Plugin } from "prosemirror-state";
1
+ import { Fragment, Slice } from "prosemirror-model";
2
+ import { Plugin, TextSelection } from "prosemirror-state";
2
3
  import { CursorWrapper } from "../components/CursorWrapper.js";
3
4
  import { widget } from "../decorations/ReactWidgetType.js";
4
5
  function insertText(view, eventData) {
@@ -15,6 +16,34 @@ function insertText(view, eventData) {
15
16
  view.dispatch(tr);
16
17
  return true;
17
18
  }
19
+ // Taken from https://github.com/ProseMirror/prosemirror-gapcursor/blob/master/src/index.ts#L67-L84
20
+ // This is a hack that, when a composition starts while a gap cursor
21
+ // is active, quickly creates an inline context for the composition to
22
+ // happen in, to avoid it being aborted by the DOM selection being
23
+ // moved into a valid position.
24
+ //
25
+ // We can't rely on the actual hack from prosemirror-gapcursor, because
26
+ // it happens too late. We snapshot the DOM during compositionstart, but
27
+ // the gapcursor hack runs in beforeinput (after compositionstart).
28
+ function handleGapCursorComposition(view) {
29
+ // @ts-expect-error Internal property - jsonID
30
+ if (!(view.state.selection.jsonID === "gapcursor")) {
31
+ return;
32
+ }
33
+ const { $from } = view.state.selection;
34
+ const insert = $from.parent.contentMatchAt($from.index())// All schemas _must_ have a text node type
35
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
36
+ .findWrapping(view.state.schema.nodes.text);
37
+ if (!insert) return;
38
+ let fragment = Fragment.empty;
39
+ for(let i = insert.length - 1; i >= 0; i--){
40
+ fragment = Fragment.from(// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
41
+ insert[i].createAndFill(null, fragment));
42
+ }
43
+ const tr = view.state.tr.replace($from.pos, $from.pos, new Slice(fragment, 0, 0));
44
+ tr.setSelection(TextSelection.near(tr.doc.resolve($from.pos + 1)));
45
+ view.dispatch(tr);
46
+ }
18
47
  export function beforeInputPlugin(setCursorWrapper) {
19
48
  let compositionMarks = null;
20
49
  let precompositionSnapshot = null;
@@ -22,10 +51,11 @@ export function beforeInputPlugin(setCursorWrapper) {
22
51
  props: {
23
52
  handleDOMEvents: {
24
53
  compositionstart (view) {
54
+ compositionMarks = view.state.storedMarks ?? view.state.selection.$from.marks();
55
+ view.dispatch(view.state.tr.deleteSelection());
56
+ handleGapCursorComposition(view);
25
57
  const { state } = view;
26
- view.dispatch(state.tr.deleteSelection());
27
58
  const $pos = state.selection.$from;
28
- compositionMarks = state.storedMarks ?? $pos.marks();
29
59
  if (compositionMarks) {
30
60
  setCursorWrapper(widget(state.selection.from, CursorWrapper, {
31
61
  key: "cursor-wrapper",
@@ -28,7 +28,7 @@ export function tempEditor(param) {
28
28
  const state = EditorState.create({
29
29
  doc: startDoc,
30
30
  schema,
31
- selection: selection ?? startDoc.tag?.a ? TextSelection.create(startDoc, startDoc.tag.a, startDoc.tag?.b) : undefined,
31
+ selection: selection ?? (startDoc.tag?.a ? TextSelection.create(startDoc, startDoc.tag.a, startDoc.tag?.b) : undefined),
32
32
  plugins: [
33
33
  ...plugins ?? [],
34
34
  reactKeys()