@handlewithcare/react-prosemirror 3.1.0-tiptap.29 → 3.1.0-tiptap.31

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.
@@ -12,6 +12,7 @@ const _prosemirrormodel = require("prosemirror-model");
12
12
  const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
13
13
  const _reactdom = require("react-dom");
14
14
  const _ChildDescriptionsContext = require("../../contexts/ChildDescriptionsContext.js");
15
+ const _useForceUpdate = require("../../hooks/useForceUpdate.js");
15
16
  const _useMarkViewDescription = require("../../hooks/useMarkViewDescription.js");
16
17
  function _getRequireWildcardCache(nodeInterop) {
17
18
  if (typeof WeakMap !== "function") return null;
@@ -58,6 +59,7 @@ const MarkViewConstructorView = /*#__PURE__*/ (0, _react.memo)(function MarkView
58
59
  let { constructor, mark, inline, getPos, children } = param;
59
60
  const ref = (0, _react.useRef)(null);
60
61
  const innerRef = (0, _react.useRef)(null);
62
+ const forceUpdate = (0, _useForceUpdate.useForceUpdate)();
61
63
  const markProps = (0, _react.useMemo)(()=>({
62
64
  mark,
63
65
  inline,
@@ -84,13 +86,17 @@ const MarkViewConstructorView = /*#__PURE__*/ (0, _react.memo)(function MarkView
84
86
  }
85
87
  return markView;
86
88
  };
87
- const { childContextValue, contentDOM } = (0, _useMarkViewDescription.useMarkViewDescription)(ref, function() {
89
+ const { childContextValue, contentDOM } = (0, _useMarkViewDescription.useMarkViewDescription)(()=>ref.current, (markView)=>markView?.contentDOM ?? null, function() {
88
90
  for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
89
91
  args[_key] = arguments[_key];
90
92
  }
91
93
  const markView = createMarkView(...args);
92
94
  const dom = markView.dom;
93
95
  const wrapperDOM = innerRef.current ?? ref.current;
96
+ wrapperDOM.appendChild(dom);
97
+ // Force a re-render so that we properly create
98
+ // a portal into the contentDOM/dom
99
+ forceUpdate();
94
100
  return {
95
101
  ...markView,
96
102
  destroy () {
@@ -99,7 +105,7 @@ const MarkViewConstructorView = /*#__PURE__*/ (0, _react.memo)(function MarkView
99
105
  },
100
106
  ignoreMutation: markView.ignoreMutation
101
107
  };
102
- }, (markView)=>markView?.contentDOM ?? null, markProps);
108
+ }, markProps);
103
109
  const Component = inline ? "span" : "div";
104
110
  const props = {
105
111
  ref: innerRef
@@ -67,17 +67,16 @@ const ReactMarkView = /*#__PURE__*/ (0, _react.memo)(function ReactMarkView(para
67
67
  };
68
68
  };
69
69
  }, []);
70
- const markProps = (0, _react.useMemo)(()=>({
70
+ const markViewDescProps = (0, _react.useMemo)(()=>({
71
71
  mark,
72
72
  getPos,
73
- inline,
74
- contentDOMRef
73
+ inline
75
74
  }), [
76
75
  getPos,
77
76
  inline,
78
77
  mark
79
78
  ]);
80
- const { childContextValue } = (0, _useMarkViewDescription.useMarkViewDescription)(ref, ()=>({
79
+ const { childContextValue, refUpdated } = (0, _useMarkViewDescription.useMarkViewDescription)(()=>ref.current, ()=>contentDOMRef.current ?? ref.current, ()=>({
81
80
  dom: ref.current,
82
81
  ignoreMutation (mutation) {
83
82
  const ignoreMutation = ignoreMutationRef.current;
@@ -86,10 +85,29 @@ const ReactMarkView = /*#__PURE__*/ (0, _react.memo)(function ReactMarkView(para
86
85
  }
87
86
  return false;
88
87
  }
89
- }), ()=>contentDOMRef.current ?? ref.current, markProps);
88
+ }), markViewDescProps);
89
+ const setDOM = (0, _react.useCallback)((el)=>{
90
+ ref.current = el;
91
+ refUpdated();
92
+ }, [
93
+ refUpdated
94
+ ]);
95
+ const setContentDOM = (0, _react.useCallback)((el)=>{
96
+ contentDOMRef.current = el;
97
+ refUpdated();
98
+ }, [
99
+ refUpdated
100
+ ]);
101
+ const markProps = (0, _react.useMemo)(()=>({
102
+ ...markViewDescProps,
103
+ contentDOMRef: setContentDOM
104
+ }), [
105
+ markViewDescProps,
106
+ setContentDOM
107
+ ]);
90
108
  const props = {
91
109
  markProps,
92
- ref
110
+ ref: setDOM
93
111
  };
94
112
  return /*#__PURE__*/ _react.default.createElement(_IgnoreMutationContext.IgnoreMutationContext.Provider, {
95
113
  value: setIgnoreMutation
@@ -15,18 +15,17 @@ const _EditorContext = require("../contexts/EditorContext.js");
15
15
  const _viewdesc = require("../viewdesc.js");
16
16
  const _useClientLayoutEffect = require("./useClientLayoutEffect.js");
17
17
  const _useEffectEvent = require("./useEffectEvent.js");
18
- function useMarkViewDescription(ref, constructor, getContentDOM, props) {
18
+ function useMarkViewDescription(getDOM, getContentDOM, constructor, props) {
19
19
  const { view } = (0, _react.useContext)(_EditorContext.EditorContext);
20
20
  const { parentRef, siblingsRef } = (0, _react.useContext)(_ChildDescriptionsContext.ChildDescriptionsContext);
21
- const [dom, setDOM] = (0, _react.useState)(null);
22
- const [contentDOM, setContentDOM] = (0, _react.useState)(null);
21
+ const contentDOMRef = (0, _react.useRef)(null);
23
22
  const viewDescRef = (0, _react.useRef)();
24
23
  const childrenRef = (0, _react.useRef)([]);
25
24
  const create = (0, _useEffectEvent.useEffectEvent)(()=>{
26
25
  if (!(view instanceof _ReactEditorView.ReactEditorView)) {
27
26
  return;
28
27
  }
29
- const dom = ref.current;
28
+ const dom = getDOM();
30
29
  if (!dom) {
31
30
  return;
32
31
  }
@@ -38,9 +37,8 @@ function useMarkViewDescription(ref, constructor, getContentDOM, props) {
38
37
  const parent = parentRef.current;
39
38
  const children = childrenRef.current;
40
39
  const contentDOM = getContentDOM(markView);
41
- const viewDesc = new _viewdesc.MarkViewDesc(parent, children, getPos, mark, dom, contentDOM ?? dom, markView);
42
- setDOM(dom);
43
- setContentDOM(contentDOM);
40
+ const viewDesc = new _viewdesc.ReactMarkViewDesc(parent, children, getPos, mark, dom, contentDOM ?? markView.dom, markView);
41
+ contentDOMRef.current = contentDOM;
44
42
  return viewDesc;
45
43
  });
46
44
  const update = (0, _useEffectEvent.useEffectEvent)(()=>{
@@ -51,7 +49,7 @@ function useMarkViewDescription(ref, constructor, getContentDOM, props) {
51
49
  if (!viewDesc) {
52
50
  return false;
53
51
  }
54
- const dom = ref.current;
52
+ const dom = getDOM();
55
53
  if (!dom || dom !== viewDesc.dom) {
56
54
  return false;
57
55
  }
@@ -73,8 +71,7 @@ function useMarkViewDescription(ref, constructor, getContentDOM, props) {
73
71
  const index = siblings.indexOf(viewDesc);
74
72
  siblings.splice(index, 1);
75
73
  }
76
- setDOM(null);
77
- setContentDOM(null);
74
+ contentDOMRef.current = null;
78
75
  });
79
76
  (0, _useClientLayoutEffect.useClientLayoutEffect)(()=>{
80
77
  viewDescRef.current = create();
@@ -85,6 +82,16 @@ function useMarkViewDescription(ref, constructor, getContentDOM, props) {
85
82
  create,
86
83
  destroy
87
84
  ]);
85
+ const refUpdated = (0, _react.useCallback)(()=>{
86
+ if (!update()) {
87
+ destroy();
88
+ viewDescRef.current = create();
89
+ }
90
+ }, [
91
+ create,
92
+ destroy,
93
+ update
94
+ ]);
88
95
  (0, _useClientLayoutEffect.useClientLayoutEffect)(()=>{
89
96
  if (!update()) {
90
97
  destroy();
@@ -115,8 +122,7 @@ function useMarkViewDescription(ref, constructor, getContentDOM, props) {
115
122
  ]);
116
123
  return {
117
124
  childContextValue,
118
- dom,
119
- contentDOM,
120
- ref
125
+ contentDOM: contentDOMRef.current ?? viewDescRef.current?.dom,
126
+ refUpdated
121
127
  };
122
128
  }
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "ReactProseMirrorCommands", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return ReactProseMirrorCommands;
9
+ }
10
+ });
11
+ const _core = require("@tiptap/core");
12
+ const _updateAttributes = require("./commands/updateAttributes.js");
13
+ const ReactProseMirrorCommands = _core.Extension.create({
14
+ name: "reactProseMirrorCommands",
15
+ addCommands () {
16
+ return {
17
+ ..._core.commands,
18
+ updateAttributes: _updateAttributes.updateAttributes
19
+ };
20
+ }
21
+ });
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "updateAttributes", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return updateAttributes;
9
+ }
10
+ });
11
+ const _core = require("@tiptap/core");
12
+ const updateAttributes = function(typeOrName) {
13
+ let attributes = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
14
+ return (param)=>{
15
+ let { tr, state, dispatch } = param;
16
+ let nodeType = null;
17
+ let markType = null;
18
+ const schemaType = (0, _core.getSchemaTypeNameByName)(typeof typeOrName === "string" ? typeOrName : typeOrName.name, state.schema);
19
+ if (!schemaType) {
20
+ return false;
21
+ }
22
+ if (schemaType === "node") {
23
+ nodeType = (0, _core.getNodeType)(typeOrName, state.schema);
24
+ }
25
+ if (schemaType === "mark") {
26
+ markType = (0, _core.getMarkType)(typeOrName, state.schema);
27
+ }
28
+ let canUpdate = false;
29
+ tr.selection.ranges.forEach((range)=>{
30
+ const from = range.$from.pos;
31
+ const to = range.$to.pos;
32
+ let lastPos;
33
+ let lastNode;
34
+ let trimmedFrom;
35
+ let trimmedTo;
36
+ if (tr.selection.empty) {
37
+ state.doc.nodesBetween(from, to, (node, pos)=>{
38
+ if (nodeType && nodeType === node.type) {
39
+ canUpdate = true;
40
+ trimmedFrom = Math.max(pos, from);
41
+ trimmedTo = Math.min(pos + node.nodeSize, to);
42
+ lastPos = pos;
43
+ lastNode = node;
44
+ }
45
+ });
46
+ } else {
47
+ state.doc.nodesBetween(from, to, (node, pos)=>{
48
+ if (pos < from && nodeType && nodeType === node.type) {
49
+ canUpdate = true;
50
+ trimmedFrom = Math.max(pos, from);
51
+ trimmedTo = Math.min(pos + node.nodeSize, to);
52
+ lastPos = pos;
53
+ lastNode = node;
54
+ }
55
+ if (pos >= from && pos <= to) {
56
+ if (nodeType && nodeType === node.type) {
57
+ canUpdate = true;
58
+ if (dispatch) {
59
+ Object.entries(attributes).forEach((param)=>{
60
+ let [key, value] = param;
61
+ tr.setNodeAttribute(pos, key, value);
62
+ });
63
+ }
64
+ }
65
+ if (markType && node.marks.length) {
66
+ node.marks.forEach((mark)=>{
67
+ if (markType === mark.type) {
68
+ canUpdate = true;
69
+ if (dispatch) {
70
+ const trimmedFrom2 = Math.max(pos, from);
71
+ const trimmedTo2 = Math.min(pos + node.nodeSize, to);
72
+ tr.addMark(trimmedFrom2, trimmedTo2, markType.create({
73
+ ...mark.attrs,
74
+ ...attributes
75
+ }));
76
+ }
77
+ }
78
+ });
79
+ }
80
+ }
81
+ });
82
+ }
83
+ if (lastNode) {
84
+ if (dispatch) {
85
+ Object.entries(attributes).forEach((param)=>{
86
+ let [key, value] = param;
87
+ if (lastPos !== undefined) tr.setNodeAttribute(lastPos, key, value);
88
+ });
89
+ }
90
+ if (markType && lastNode.marks.length) {
91
+ lastNode.marks.forEach((mark)=>{
92
+ if (markType === mark.type && dispatch) {
93
+ tr.addMark(trimmedFrom, trimmedTo, markType.create({
94
+ ...mark.attrs,
95
+ ...attributes
96
+ }));
97
+ }
98
+ });
99
+ }
100
+ }
101
+ });
102
+ return canUpdate;
103
+ };
104
+ };
@@ -10,9 +10,27 @@ Object.defineProperty(exports, "useTiptapEditor", {
10
10
  });
11
11
  const _react = require("@tiptap/react");
12
12
  const _StaticEditorView = require("../../StaticEditorView.js");
13
+ const _ReactProseMirror = require("../extensions/ReactProseMirror.js");
14
+ const _ReactProseMirrorCommands = require("../extensions/ReactProseMirrorCommands.js");
13
15
  function useTiptapEditor(options, deps) {
16
+ const extensions = [
17
+ _ReactProseMirror.ReactProseMirror,
18
+ ...options.extensions ?? []
19
+ ];
20
+ // If a consumer explicitly disables core extensions (or the Commands core extension)
21
+ // do not re-add our custom Commands
22
+ if (options.enableCoreExtensions === false || typeof options.enableCoreExtensions === "object" && options?.enableCoreExtensions?.commands === false) {
23
+ // Do nothing
24
+ } else {
25
+ options.enableCoreExtensions = {
26
+ ...typeof options.enableCoreExtensions === "object" ? options.enableCoreExtensions : {},
27
+ commands: false
28
+ };
29
+ extensions.push(_ReactProseMirrorCommands.ReactProseMirrorCommands);
30
+ }
14
31
  const editor = (0, _react.useEditor)({
15
32
  ...options,
33
+ extensions,
16
34
  element: null
17
35
  }, deps);
18
36
  // @ts-expect-error private property
@@ -18,6 +18,9 @@ _export(exports, {
18
18
  NodeViewDesc: function() {
19
19
  return NodeViewDesc;
20
20
  },
21
+ ReactMarkViewDesc: function() {
22
+ return ReactMarkViewDesc;
23
+ },
21
24
  ReactNodeViewDesc: function() {
22
25
  return ReactNodeViewDesc;
23
26
  },
@@ -743,6 +746,13 @@ let CustomNodeViewDesc = class CustomNodeViewDesc extends NodeViewDesc {
743
746
  return this.spec.ignoreMutation ? this.spec.ignoreMutation.call(this, mutation) : super.ignoreMutation(mutation);
744
747
  }
745
748
  };
749
+ let ReactMarkViewDesc = class ReactMarkViewDesc extends MarkViewDesc {
750
+ destroy() {
751
+ // React has already destroyed the children (if needed).
752
+ this.children = [];
753
+ super.destroy();
754
+ }
755
+ };
746
756
  let ReactNodeViewDesc = class ReactNodeViewDesc extends CustomNodeViewDesc {
747
757
  updateChildren(_view, _pos) {
748
758
  // React has already updated the children.
@@ -2,11 +2,13 @@ import { DOMSerializer } from "prosemirror-model";
2
2
  import React, { memo, useMemo, useRef } from "react";
3
3
  import { createPortal } from "react-dom";
4
4
  import { ChildDescriptionsContext } from "../../contexts/ChildDescriptionsContext.js";
5
+ import { useForceUpdate } from "../../hooks/useForceUpdate.js";
5
6
  import { useMarkViewDescription } from "../../hooks/useMarkViewDescription.js";
6
7
  export const MarkViewConstructorView = /*#__PURE__*/ memo(function MarkViewConstructorView(param) {
7
8
  let { constructor, mark, inline, getPos, children } = param;
8
9
  const ref = useRef(null);
9
10
  const innerRef = useRef(null);
11
+ const forceUpdate = useForceUpdate();
10
12
  const markProps = useMemo(()=>({
11
13
  mark,
12
14
  inline,
@@ -33,13 +35,17 @@ export const MarkViewConstructorView = /*#__PURE__*/ memo(function MarkViewConst
33
35
  }
34
36
  return markView;
35
37
  };
36
- const { childContextValue, contentDOM } = useMarkViewDescription(ref, function() {
38
+ const { childContextValue, contentDOM } = useMarkViewDescription(()=>ref.current, (markView)=>markView?.contentDOM ?? null, function() {
37
39
  for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
38
40
  args[_key] = arguments[_key];
39
41
  }
40
42
  const markView = createMarkView(...args);
41
43
  const dom = markView.dom;
42
44
  const wrapperDOM = innerRef.current ?? ref.current;
45
+ wrapperDOM.appendChild(dom);
46
+ // Force a re-render so that we properly create
47
+ // a portal into the contentDOM/dom
48
+ forceUpdate();
43
49
  return {
44
50
  ...markView,
45
51
  destroy () {
@@ -48,7 +54,7 @@ export const MarkViewConstructorView = /*#__PURE__*/ memo(function MarkViewConst
48
54
  },
49
55
  ignoreMutation: markView.ignoreMutation
50
56
  };
51
- }, (markView)=>markView?.contentDOM ?? null, markProps);
57
+ }, markProps);
52
58
  const Component = inline ? "span" : "div";
53
59
  const props = {
54
60
  ref: innerRef
@@ -16,17 +16,16 @@ export const ReactMarkView = /*#__PURE__*/ memo(function ReactMarkView(param) {
16
16
  };
17
17
  };
18
18
  }, []);
19
- const markProps = useMemo(()=>({
19
+ const markViewDescProps = useMemo(()=>({
20
20
  mark,
21
21
  getPos,
22
- inline,
23
- contentDOMRef
22
+ inline
24
23
  }), [
25
24
  getPos,
26
25
  inline,
27
26
  mark
28
27
  ]);
29
- const { childContextValue } = useMarkViewDescription(ref, ()=>({
28
+ const { childContextValue, refUpdated } = useMarkViewDescription(()=>ref.current, ()=>contentDOMRef.current ?? ref.current, ()=>({
30
29
  dom: ref.current,
31
30
  ignoreMutation (mutation) {
32
31
  const ignoreMutation = ignoreMutationRef.current;
@@ -35,10 +34,29 @@ export const ReactMarkView = /*#__PURE__*/ memo(function ReactMarkView(param) {
35
34
  }
36
35
  return false;
37
36
  }
38
- }), ()=>contentDOMRef.current ?? ref.current, markProps);
37
+ }), markViewDescProps);
38
+ const setDOM = useCallback((el)=>{
39
+ ref.current = el;
40
+ refUpdated();
41
+ }, [
42
+ refUpdated
43
+ ]);
44
+ const setContentDOM = useCallback((el)=>{
45
+ contentDOMRef.current = el;
46
+ refUpdated();
47
+ }, [
48
+ refUpdated
49
+ ]);
50
+ const markProps = useMemo(()=>({
51
+ ...markViewDescProps,
52
+ contentDOMRef: setContentDOM
53
+ }), [
54
+ markViewDescProps,
55
+ setContentDOM
56
+ ]);
39
57
  const props = {
40
58
  markProps,
41
- ref
59
+ ref: setDOM
42
60
  };
43
61
  return /*#__PURE__*/ React.createElement(IgnoreMutationContext.Provider, {
44
62
  value: setIgnoreMutation
@@ -1,22 +1,21 @@
1
- import { useContext, useMemo, useRef, useState } from "react";
1
+ import { useCallback, useContext, useMemo, useRef } from "react";
2
2
  import { ReactEditorView } from "../ReactEditorView.js";
3
3
  import { ChildDescriptionsContext } from "../contexts/ChildDescriptionsContext.js";
4
4
  import { EditorContext } from "../contexts/EditorContext.js";
5
- import { MarkViewDesc, sortViewDescs } from "../viewdesc.js";
5
+ import { ReactMarkViewDesc, sortViewDescs } from "../viewdesc.js";
6
6
  import { useClientLayoutEffect } from "./useClientLayoutEffect.js";
7
7
  import { useEffectEvent } from "./useEffectEvent.js";
8
- export function useMarkViewDescription(ref, constructor, getContentDOM, props) {
8
+ export function useMarkViewDescription(getDOM, getContentDOM, constructor, props) {
9
9
  const { view } = useContext(EditorContext);
10
10
  const { parentRef, siblingsRef } = useContext(ChildDescriptionsContext);
11
- const [dom, setDOM] = useState(null);
12
- const [contentDOM, setContentDOM] = useState(null);
11
+ const contentDOMRef = useRef(null);
13
12
  const viewDescRef = useRef();
14
13
  const childrenRef = useRef([]);
15
14
  const create = useEffectEvent(()=>{
16
15
  if (!(view instanceof ReactEditorView)) {
17
16
  return;
18
17
  }
19
- const dom = ref.current;
18
+ const dom = getDOM();
20
19
  if (!dom) {
21
20
  return;
22
21
  }
@@ -28,9 +27,8 @@ export function useMarkViewDescription(ref, constructor, getContentDOM, props) {
28
27
  const parent = parentRef.current;
29
28
  const children = childrenRef.current;
30
29
  const contentDOM = getContentDOM(markView);
31
- const viewDesc = new MarkViewDesc(parent, children, getPos, mark, dom, contentDOM ?? dom, markView);
32
- setDOM(dom);
33
- setContentDOM(contentDOM);
30
+ const viewDesc = new ReactMarkViewDesc(parent, children, getPos, mark, dom, contentDOM ?? markView.dom, markView);
31
+ contentDOMRef.current = contentDOM;
34
32
  return viewDesc;
35
33
  });
36
34
  const update = useEffectEvent(()=>{
@@ -41,7 +39,7 @@ export function useMarkViewDescription(ref, constructor, getContentDOM, props) {
41
39
  if (!viewDesc) {
42
40
  return false;
43
41
  }
44
- const dom = ref.current;
42
+ const dom = getDOM();
45
43
  if (!dom || dom !== viewDesc.dom) {
46
44
  return false;
47
45
  }
@@ -63,8 +61,7 @@ export function useMarkViewDescription(ref, constructor, getContentDOM, props) {
63
61
  const index = siblings.indexOf(viewDesc);
64
62
  siblings.splice(index, 1);
65
63
  }
66
- setDOM(null);
67
- setContentDOM(null);
64
+ contentDOMRef.current = null;
68
65
  });
69
66
  useClientLayoutEffect(()=>{
70
67
  viewDescRef.current = create();
@@ -75,6 +72,16 @@ export function useMarkViewDescription(ref, constructor, getContentDOM, props) {
75
72
  create,
76
73
  destroy
77
74
  ]);
75
+ const refUpdated = useCallback(()=>{
76
+ if (!update()) {
77
+ destroy();
78
+ viewDescRef.current = create();
79
+ }
80
+ }, [
81
+ create,
82
+ destroy,
83
+ update
84
+ ]);
78
85
  useClientLayoutEffect(()=>{
79
86
  if (!update()) {
80
87
  destroy();
@@ -105,8 +112,7 @@ export function useMarkViewDescription(ref, constructor, getContentDOM, props) {
105
112
  ]);
106
113
  return {
107
114
  childContextValue,
108
- dom,
109
- contentDOM,
110
- ref
115
+ contentDOM: contentDOMRef.current ?? viewDescRef.current?.dom,
116
+ refUpdated
111
117
  };
112
118
  }
@@ -0,0 +1,11 @@
1
+ import { Extension, commands as coreCommands } from "@tiptap/core";
2
+ import { updateAttributes } from "./commands/updateAttributes.js";
3
+ export const ReactProseMirrorCommands = Extension.create({
4
+ name: "reactProseMirrorCommands",
5
+ addCommands () {
6
+ return {
7
+ ...coreCommands,
8
+ updateAttributes
9
+ };
10
+ }
11
+ });
@@ -0,0 +1,96 @@
1
+ import { getMarkType, getNodeType, getSchemaTypeNameByName } from "@tiptap/core";
2
+ // Tiptap's updateAttributes command, but using setNodeAttribute instead of
3
+ // setNodeMarkup to avoid replacing entire leaf nodes
4
+ export const updateAttributes = function(typeOrName) {
5
+ let attributes = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
6
+ return (param)=>{
7
+ let { tr, state, dispatch } = param;
8
+ let nodeType = null;
9
+ let markType = null;
10
+ const schemaType = getSchemaTypeNameByName(typeof typeOrName === "string" ? typeOrName : typeOrName.name, state.schema);
11
+ if (!schemaType) {
12
+ return false;
13
+ }
14
+ if (schemaType === "node") {
15
+ nodeType = getNodeType(typeOrName, state.schema);
16
+ }
17
+ if (schemaType === "mark") {
18
+ markType = getMarkType(typeOrName, state.schema);
19
+ }
20
+ let canUpdate = false;
21
+ tr.selection.ranges.forEach((range)=>{
22
+ const from = range.$from.pos;
23
+ const to = range.$to.pos;
24
+ let lastPos;
25
+ let lastNode;
26
+ let trimmedFrom;
27
+ let trimmedTo;
28
+ if (tr.selection.empty) {
29
+ state.doc.nodesBetween(from, to, (node, pos)=>{
30
+ if (nodeType && nodeType === node.type) {
31
+ canUpdate = true;
32
+ trimmedFrom = Math.max(pos, from);
33
+ trimmedTo = Math.min(pos + node.nodeSize, to);
34
+ lastPos = pos;
35
+ lastNode = node;
36
+ }
37
+ });
38
+ } else {
39
+ state.doc.nodesBetween(from, to, (node, pos)=>{
40
+ if (pos < from && nodeType && nodeType === node.type) {
41
+ canUpdate = true;
42
+ trimmedFrom = Math.max(pos, from);
43
+ trimmedTo = Math.min(pos + node.nodeSize, to);
44
+ lastPos = pos;
45
+ lastNode = node;
46
+ }
47
+ if (pos >= from && pos <= to) {
48
+ if (nodeType && nodeType === node.type) {
49
+ canUpdate = true;
50
+ if (dispatch) {
51
+ Object.entries(attributes).forEach((param)=>{
52
+ let [key, value] = param;
53
+ tr.setNodeAttribute(pos, key, value);
54
+ });
55
+ }
56
+ }
57
+ if (markType && node.marks.length) {
58
+ node.marks.forEach((mark)=>{
59
+ if (markType === mark.type) {
60
+ canUpdate = true;
61
+ if (dispatch) {
62
+ const trimmedFrom2 = Math.max(pos, from);
63
+ const trimmedTo2 = Math.min(pos + node.nodeSize, to);
64
+ tr.addMark(trimmedFrom2, trimmedTo2, markType.create({
65
+ ...mark.attrs,
66
+ ...attributes
67
+ }));
68
+ }
69
+ }
70
+ });
71
+ }
72
+ }
73
+ });
74
+ }
75
+ if (lastNode) {
76
+ if (dispatch) {
77
+ Object.entries(attributes).forEach((param)=>{
78
+ let [key, value] = param;
79
+ if (lastPos !== undefined) tr.setNodeAttribute(lastPos, key, value);
80
+ });
81
+ }
82
+ if (markType && lastNode.marks.length) {
83
+ lastNode.marks.forEach((mark)=>{
84
+ if (markType === mark.type && dispatch) {
85
+ tr.addMark(trimmedFrom, trimmedTo, markType.create({
86
+ ...mark.attrs,
87
+ ...attributes
88
+ }));
89
+ }
90
+ });
91
+ }
92
+ }
93
+ });
94
+ return canUpdate;
95
+ };
96
+ };
@@ -1,8 +1,26 @@
1
1
  import { useEditor } from "@tiptap/react";
2
2
  import { StaticEditorView } from "../../StaticEditorView.js";
3
+ import { ReactProseMirror } from "../extensions/ReactProseMirror.js";
4
+ import { ReactProseMirrorCommands } from "../extensions/ReactProseMirrorCommands.js";
3
5
  export function useTiptapEditor(options, deps) {
6
+ const extensions = [
7
+ ReactProseMirror,
8
+ ...options.extensions ?? []
9
+ ];
10
+ // If a consumer explicitly disables core extensions (or the Commands core extension)
11
+ // do not re-add our custom Commands
12
+ if (options.enableCoreExtensions === false || typeof options.enableCoreExtensions === "object" && options?.enableCoreExtensions?.commands === false) {
13
+ // Do nothing
14
+ } else {
15
+ options.enableCoreExtensions = {
16
+ ...typeof options.enableCoreExtensions === "object" ? options.enableCoreExtensions : {},
17
+ commands: false
18
+ };
19
+ extensions.push(ReactProseMirrorCommands);
20
+ }
4
21
  const editor = useEditor({
5
22
  ...options,
23
+ extensions,
6
24
  element: null
7
25
  }, deps);
8
26
  // @ts-expect-error private property