@tiptap/react 3.0.0-next.3 → 3.0.0-next.5

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
@@ -1,41 +1,30 @@
1
- // src/BubbleMenu.tsx
2
- import { BubbleMenuPlugin } from "@tiptap/extension-bubble-menu";
3
- import React3, { useEffect as useEffect3, useRef as useRef2 } from "react";
4
- import { createPortal } from "react-dom";
5
-
6
1
  // src/Context.tsx
7
- import React2, {
8
- createContext,
9
- useContext,
10
- useMemo
11
- } from "react";
2
+ import { createContext, useContext, useMemo } from "react";
12
3
 
13
4
  // src/EditorContent.tsx
14
- import React, {
15
- forwardRef
16
- } from "react";
5
+ import React, { forwardRef } from "react";
17
6
  import ReactDOM from "react-dom";
18
7
  import { useSyncExternalStore } from "use-sync-external-store/shim";
8
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
19
9
  var mergeRefs = (...refs) => {
20
10
  return (node) => {
21
11
  refs.forEach((ref) => {
22
12
  if (typeof ref === "function") {
23
13
  ref(node);
24
14
  } else if (ref) {
15
+ ;
25
16
  ref.current = node;
26
17
  }
27
18
  });
28
19
  };
29
20
  };
30
- var Portals = ({
31
- contentComponent
32
- }) => {
21
+ var Portals = ({ contentComponent }) => {
33
22
  const renderers = useSyncExternalStore(
34
23
  contentComponent.subscribe,
35
24
  contentComponent.getSnapshot,
36
25
  contentComponent.getServerSnapshot
37
26
  );
38
- return /* @__PURE__ */ React.createElement(React.Fragment, null, Object.values(renderers));
27
+ return /* @__PURE__ */ jsx(Fragment, { children: Object.values(renderers) });
39
28
  };
40
29
  function getInstance() {
41
30
  const subscribers = /* @__PURE__ */ new Set();
@@ -125,6 +114,7 @@ var PureEditorContent = class extends React.Component {
125
114
  }
126
115
  }
127
116
  componentWillUnmount() {
117
+ var _a;
128
118
  const editor = this.props.editor;
129
119
  if (!editor) {
130
120
  return;
@@ -139,7 +129,7 @@ var PureEditorContent = class extends React.Component {
139
129
  this.unsubscribeToContentComponent();
140
130
  }
141
131
  editor.contentComponent = null;
142
- if (!editor.options.element.firstChild) {
132
+ if (!((_a = editor.options.element) == null ? void 0 : _a.firstChild)) {
143
133
  return;
144
134
  }
145
135
  const newElement = document.createElement("div");
@@ -150,7 +140,10 @@ var PureEditorContent = class extends React.Component {
150
140
  }
151
141
  render() {
152
142
  const { editor, innerRef, ...rest } = this.props;
153
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { ref: mergeRefs(innerRef, this.editorContentRef), ...rest }), (editor == null ? void 0 : editor.contentComponent) && /* @__PURE__ */ React.createElement(Portals, { contentComponent: editor.contentComponent }));
143
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
144
+ /* @__PURE__ */ jsx("div", { ref: mergeRefs(innerRef, this.editorContentRef), ...rest }),
145
+ (editor == null ? void 0 : editor.contentComponent) && /* @__PURE__ */ jsx(Portals, { contentComponent: editor.contentComponent })
146
+ ] });
154
147
  }
155
148
  };
156
149
  var EditorContentWithKey = forwardRef(
@@ -169,22 +162,12 @@ var EditorContent = React.memo(EditorContentWithKey);
169
162
 
170
163
  // src/useEditor.ts
171
164
  import { Editor } from "@tiptap/core";
172
- import {
173
- useDebugValue as useDebugValue2,
174
- useEffect as useEffect2,
175
- useRef,
176
- useState as useState2
177
- } from "react";
165
+ import { useDebugValue as useDebugValue2, useEffect as useEffect2, useRef, useState as useState2 } from "react";
178
166
  import { useSyncExternalStore as useSyncExternalStore2 } from "use-sync-external-store/shim";
179
167
 
180
168
  // src/useEditorState.ts
181
169
  import deepEqual from "fast-deep-equal/es6/react";
182
- import {
183
- useDebugValue,
184
- useEffect,
185
- useLayoutEffect,
186
- useState
187
- } from "react";
170
+ import { useDebugValue, useEffect, useLayoutEffect, useState } from "react";
188
171
  import { useSyncExternalStoreWithSelector } from "use-sync-external-store/shim/with-selector";
189
172
  var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
190
173
  var EditorStateManager = class {
@@ -265,7 +248,7 @@ function useEditorState(options) {
265
248
  var isDev = process.env.NODE_ENV !== "production";
266
249
  var isSSR = typeof window === "undefined";
267
250
  var isNext = isSSR || Boolean(typeof window !== "undefined" && window.next);
268
- var EditorInstanceManager = class {
251
+ var EditorInstanceManager = class _EditorInstanceManager {
269
252
  constructor(options) {
270
253
  /**
271
254
  * The current editor instance.
@@ -377,6 +360,10 @@ var EditorInstanceManager = class {
377
360
  onPaste: (...args) => {
378
361
  var _a, _b;
379
362
  return (_b = (_a = this.options.current).onPaste) == null ? void 0 : _b.call(_a, ...args);
363
+ },
364
+ onDelete: (...args) => {
365
+ var _a, _b;
366
+ return (_b = (_a = this.options.current).onDelete) == null ? void 0 : _b.call(_a, ...args);
380
367
  }
381
368
  };
382
369
  const editor = new Editor(optionsToApply);
@@ -403,6 +390,41 @@ var EditorInstanceManager = class {
403
390
  this.subscriptions.delete(onStoreChange);
404
391
  };
405
392
  }
393
+ static compareOptions(a, b) {
394
+ return Object.keys(a).every((key) => {
395
+ if ([
396
+ "onCreate",
397
+ "onBeforeCreate",
398
+ "onDestroy",
399
+ "onUpdate",
400
+ "onTransaction",
401
+ "onFocus",
402
+ "onBlur",
403
+ "onSelectionUpdate",
404
+ "onContentError",
405
+ "onDrop",
406
+ "onPaste"
407
+ ].includes(key)) {
408
+ return true;
409
+ }
410
+ if (key === "extensions" && a.extensions && b.extensions) {
411
+ if (a.extensions.length !== b.extensions.length) {
412
+ return false;
413
+ }
414
+ return a.extensions.every((extension, index) => {
415
+ var _a;
416
+ if (extension !== ((_a = b.extensions) == null ? void 0 : _a[index])) {
417
+ return false;
418
+ }
419
+ return true;
420
+ });
421
+ }
422
+ if (a[key] !== b[key]) {
423
+ return false;
424
+ }
425
+ return true;
426
+ });
427
+ }
406
428
  /**
407
429
  * On each render, we will create, update, or destroy the editor instance.
408
430
  * @param deps The dependencies to watch for changes
@@ -413,10 +435,12 @@ var EditorInstanceManager = class {
413
435
  this.isComponentMounted = true;
414
436
  clearTimeout(this.scheduledDestructionTimeout);
415
437
  if (this.editor && !this.editor.isDestroyed && deps.length === 0) {
416
- this.editor.setOptions({
417
- ...this.options.current,
418
- editable: this.editor.isEditable
419
- });
438
+ if (!_EditorInstanceManager.compareOptions(this.options.current, this.editor.options)) {
439
+ this.editor.setOptions({
440
+ ...this.options.current,
441
+ editable: this.editor.isEditable
442
+ });
443
+ }
420
444
  } else {
421
445
  this.refreshEditorInstance(deps);
422
446
  }
@@ -497,6 +521,7 @@ function useEditor(options = {}, deps = []) {
497
521
  }
498
522
 
499
523
  // src/Context.tsx
524
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
500
525
  var EditorContext = createContext({
501
526
  editor: null
502
527
  });
@@ -514,153 +539,38 @@ function EditorProvider({
514
539
  if (!editor) {
515
540
  return null;
516
541
  }
517
- return /* @__PURE__ */ React2.createElement(EditorContext.Provider, { value: contextValue }, slotBefore, /* @__PURE__ */ React2.createElement(EditorConsumer, null, ({ editor: currentEditor }) => /* @__PURE__ */ React2.createElement(EditorContent, { editor: currentEditor, ...editorContainerProps })), children, slotAfter);
518
- }
519
-
520
- // src/BubbleMenu.tsx
521
- var BubbleMenu = React3.forwardRef(
522
- ({
523
- pluginKey = "bubbleMenu",
524
- editor,
525
- updateDelay,
526
- resizeDelay,
527
- shouldShow = null,
528
- options,
542
+ return /* @__PURE__ */ jsxs2(EditorContext.Provider, { value: contextValue, children: [
543
+ slotBefore,
544
+ /* @__PURE__ */ jsx2(EditorConsumer, { children: ({ editor: currentEditor }) => /* @__PURE__ */ jsx2(EditorContent, { editor: currentEditor, ...editorContainerProps }) }),
529
545
  children,
530
- ...restProps
531
- }, ref) => {
532
- const menuEl = useRef2(document.createElement("div"));
533
- if (typeof ref === "function") {
534
- ref(menuEl.current);
535
- } else if (ref) {
536
- ref.current = menuEl.current;
537
- }
538
- const { editor: currentEditor } = useCurrentEditor();
539
- useEffect3(() => {
540
- const bubbleMenuElement = menuEl.current;
541
- bubbleMenuElement.style.visibility = "hidden";
542
- bubbleMenuElement.style.position = "absolute";
543
- if ((editor == null ? void 0 : editor.isDestroyed) || (currentEditor == null ? void 0 : currentEditor.isDestroyed)) {
544
- return;
545
- }
546
- const attachToEditor = editor || currentEditor;
547
- if (!attachToEditor) {
548
- console.warn(
549
- "BubbleMenu component is not rendered inside of an editor component or does not have editor prop."
550
- );
551
- return;
552
- }
553
- const plugin = BubbleMenuPlugin({
554
- updateDelay,
555
- resizeDelay,
556
- editor: attachToEditor,
557
- element: bubbleMenuElement,
558
- pluginKey,
559
- shouldShow,
560
- options
561
- });
562
- attachToEditor.registerPlugin(plugin);
563
- return () => {
564
- attachToEditor.unregisterPlugin(pluginKey);
565
- window.requestAnimationFrame(() => {
566
- if (bubbleMenuElement.parentNode) {
567
- bubbleMenuElement.parentNode.removeChild(bubbleMenuElement);
568
- }
569
- });
570
- };
571
- }, [editor, currentEditor]);
572
- return createPortal(
573
- /* @__PURE__ */ React3.createElement(
574
- "div",
575
- {
576
- ...restProps
577
- },
578
- children
579
- ),
580
- menuEl.current
581
- );
582
- }
583
- );
584
-
585
- // src/FloatingMenu.tsx
586
- import { FloatingMenuPlugin } from "@tiptap/extension-floating-menu";
587
- import React4, { useEffect as useEffect4, useRef as useRef3 } from "react";
588
- import { createPortal as createPortal2 } from "react-dom";
589
- var FloatingMenu = React4.forwardRef(({
590
- pluginKey = "floatingMenu",
591
- editor,
592
- shouldShow = null,
593
- options,
594
- children,
595
- ...restProps
596
- }, ref) => {
597
- const menuEl = useRef3(document.createElement("div"));
598
- if (typeof ref === "function") {
599
- ref(menuEl.current);
600
- } else if (ref) {
601
- ref.current = menuEl.current;
602
- }
603
- const { editor: currentEditor } = useCurrentEditor();
604
- useEffect4(() => {
605
- const floatingMenuElement = menuEl.current;
606
- floatingMenuElement.style.visibility = "hidden";
607
- floatingMenuElement.style.position = "absolute";
608
- if ((editor == null ? void 0 : editor.isDestroyed) || (currentEditor == null ? void 0 : currentEditor.isDestroyed)) {
609
- return;
610
- }
611
- const attachToEditor = editor || currentEditor;
612
- if (!attachToEditor) {
613
- console.warn(
614
- "FloatingMenu component is not rendered inside of an editor component or does not have editor prop."
615
- );
616
- return;
617
- }
618
- const plugin = FloatingMenuPlugin({
619
- editor: attachToEditor,
620
- element: floatingMenuElement,
621
- pluginKey,
622
- shouldShow,
623
- options
624
- });
625
- attachToEditor.registerPlugin(plugin);
626
- return () => {
627
- attachToEditor.unregisterPlugin(pluginKey);
628
- window.requestAnimationFrame(() => {
629
- if (floatingMenuElement.parentNode) {
630
- floatingMenuElement.parentNode.removeChild(floatingMenuElement);
631
- }
632
- });
633
- };
634
- }, [editor, currentEditor]);
635
- return createPortal2(
636
- /* @__PURE__ */ React4.createElement(
637
- "div",
638
- {
639
- ...restProps
640
- },
641
- children
642
- ),
643
- menuEl.current
644
- );
645
- });
646
-
647
- // src/NodeViewContent.tsx
648
- import React5 from "react";
546
+ slotAfter
547
+ ] });
548
+ }
649
549
 
650
550
  // src/useReactNodeView.ts
651
- import { createContext as createContext2, useContext as useContext2 } from "react";
551
+ import { createContext as createContext2, createElement, useContext as useContext2 } from "react";
652
552
  var ReactNodeViewContext = createContext2({
653
- onDragStart: void 0
553
+ onDragStart: () => {
554
+ },
555
+ nodeViewContentChildren: void 0,
556
+ nodeViewContentRef: () => {
557
+ }
654
558
  });
559
+ var ReactNodeViewContentProvider = ({ children, content }) => {
560
+ return createElement(ReactNodeViewContext.Provider, { value: { nodeViewContentChildren: content } }, children);
561
+ };
655
562
  var useReactNodeView = () => useContext2(ReactNodeViewContext);
656
563
 
657
564
  // src/NodeViewContent.tsx
658
- var NodeViewContent = (props) => {
659
- const Tag = props.as || "div";
660
- const { nodeViewContentRef } = useReactNodeView();
565
+ import { jsx as jsx3 } from "react/jsx-runtime";
566
+ function NodeViewContent({
567
+ as: Tag = "div",
568
+ ...props
569
+ }) {
570
+ const { nodeViewContentRef, nodeViewContentChildren } = useReactNodeView();
661
571
  return (
662
572
  // @ts-ignore
663
- /* @__PURE__ */ React5.createElement(
573
+ /* @__PURE__ */ jsx3(
664
574
  Tag,
665
575
  {
666
576
  ...props,
@@ -669,20 +579,22 @@ var NodeViewContent = (props) => {
669
579
  style: {
670
580
  whiteSpace: "pre-wrap",
671
581
  ...props.style
672
- }
582
+ },
583
+ children: nodeViewContentChildren
673
584
  }
674
585
  )
675
586
  );
676
- };
587
+ }
677
588
 
678
589
  // src/NodeViewWrapper.tsx
679
- import React6 from "react";
680
- var NodeViewWrapper = React6.forwardRef((props, ref) => {
590
+ import React3 from "react";
591
+ import { jsx as jsx4 } from "react/jsx-runtime";
592
+ var NodeViewWrapper = React3.forwardRef((props, ref) => {
681
593
  const { onDragStart } = useReactNodeView();
682
594
  const Tag = props.as || "div";
683
595
  return (
684
596
  // @ts-ignore
685
- /* @__PURE__ */ React6.createElement(
597
+ /* @__PURE__ */ jsx4(
686
598
  Tag,
687
599
  {
688
600
  ...props,
@@ -698,16 +610,13 @@ var NodeViewWrapper = React6.forwardRef((props, ref) => {
698
610
  );
699
611
  });
700
612
 
701
- // src/ReactNodeViewRenderer.tsx
702
- import {
703
- getRenderedAttributes,
704
- NodeView
705
- } from "@tiptap/core";
706
- import React8 from "react";
613
+ // src/ReactMarkViewRenderer.tsx
614
+ import { MarkView } from "@tiptap/core";
615
+ import React4 from "react";
707
616
 
708
617
  // src/ReactRenderer.tsx
709
- import React7 from "react";
710
618
  import { flushSync } from "react-dom";
619
+ import { jsx as jsx5 } from "react/jsx-runtime";
711
620
  function isClassComponent(Component) {
712
621
  return !!(typeof Component === "function" && Component.prototype && Component.prototype.isReactComponent);
713
622
  }
@@ -719,12 +628,7 @@ var ReactRenderer = class {
719
628
  /**
720
629
  * Immediately creates element and renders the provided React component.
721
630
  */
722
- constructor(component, {
723
- editor,
724
- props = {},
725
- as = "div",
726
- className = ""
727
- }) {
631
+ constructor(component, { editor, props = {}, as = "div", className = "" }) {
728
632
  this.ref = null;
729
633
  this.id = Math.floor(Math.random() * 4294967295).toString();
730
634
  this.component = component;
@@ -756,7 +660,7 @@ var ReactRenderer = class {
756
660
  this.ref = ref;
757
661
  };
758
662
  }
759
- this.reactElement = /* @__PURE__ */ React7.createElement(Component, { ...props });
663
+ this.reactElement = /* @__PURE__ */ jsx5(Component, { ...props });
760
664
  (_a = editor == null ? void 0 : editor.contentComponent) == null ? void 0 : _a.setRenderer(this.id, this);
761
665
  }
762
666
  /**
@@ -787,7 +691,71 @@ var ReactRenderer = class {
787
691
  }
788
692
  };
789
693
 
694
+ // src/ReactMarkViewRenderer.tsx
695
+ import { jsx as jsx6 } from "react/jsx-runtime";
696
+ var ReactMarkViewContext = React4.createContext({
697
+ markViewContentRef: () => {
698
+ }
699
+ });
700
+ var MarkViewContent = (props) => {
701
+ const Tag = props.as || "span";
702
+ const { markViewContentRef } = React4.useContext(ReactMarkViewContext);
703
+ return (
704
+ // @ts-ignore
705
+ /* @__PURE__ */ jsx6(Tag, { ...props, ref: markViewContentRef, "data-mark-view-content": "" })
706
+ );
707
+ };
708
+ var ReactMarkView = class extends MarkView {
709
+ constructor(component, props, options) {
710
+ super(component, props, options);
711
+ this.didMountContentDomElement = false;
712
+ const { as = "span", attrs, className = "" } = options || {};
713
+ const componentProps = props;
714
+ this.contentDOMElement = document.createElement("span");
715
+ const markViewContentRef = (el) => {
716
+ if (el && this.contentDOMElement && el.firstChild !== this.contentDOMElement) {
717
+ el.appendChild(this.contentDOMElement);
718
+ this.didMountContentDomElement = true;
719
+ }
720
+ };
721
+ const context = {
722
+ markViewContentRef
723
+ };
724
+ const ReactMarkViewProvider = React4.memo((componentProps2) => {
725
+ return /* @__PURE__ */ jsx6(ReactMarkViewContext.Provider, { value: context, children: React4.createElement(component, componentProps2) });
726
+ });
727
+ ReactMarkViewProvider.displayName = "ReactNodeView";
728
+ this.renderer = new ReactRenderer(ReactMarkViewProvider, {
729
+ editor: props.editor,
730
+ props: componentProps,
731
+ as,
732
+ className: `mark-${props.mark.type.name} ${className}`.trim()
733
+ });
734
+ if (attrs) {
735
+ this.renderer.updateAttributes(attrs);
736
+ }
737
+ }
738
+ get dom() {
739
+ return this.renderer.element;
740
+ }
741
+ get contentDOM() {
742
+ if (!this.didMountContentDomElement) {
743
+ return null;
744
+ }
745
+ return this.contentDOMElement;
746
+ }
747
+ };
748
+ function ReactMarkViewRenderer(component, options = {}) {
749
+ return (props) => new ReactMarkView(component, props, options);
750
+ }
751
+
790
752
  // src/ReactNodeViewRenderer.tsx
753
+ import {
754
+ getRenderedAttributes,
755
+ NodeView
756
+ } from "@tiptap/core";
757
+ import React5 from "react";
758
+ import { jsx as jsx7 } from "react/jsx-runtime";
791
759
  var ReactNodeView = class extends NodeView {
792
760
  /**
793
761
  * Setup the React component.
@@ -821,11 +789,9 @@ var ReactNodeView = class extends NodeView {
821
789
  };
822
790
  const context = { onDragStart, nodeViewContentRef };
823
791
  const Component = this.component;
824
- const ReactNodeViewProvider = React8.memo(
825
- (componentProps) => {
826
- return /* @__PURE__ */ React8.createElement(ReactNodeViewContext.Provider, { value: context }, React8.createElement(Component, componentProps));
827
- }
828
- );
792
+ const ReactNodeViewProvider = React5.memo((componentProps) => {
793
+ return /* @__PURE__ */ jsx7(ReactNodeViewContext.Provider, { value: context, children: React5.createElement(Component, componentProps) });
794
+ });
829
795
  ReactNodeViewProvider.displayName = "ReactNodeView";
830
796
  if (this.node.isLeaf) {
831
797
  this.contentDOMElement = null;
@@ -844,13 +810,13 @@ var ReactNodeView = class extends NodeView {
844
810
  }
845
811
  const { className = "" } = this.options;
846
812
  this.handleSelectionUpdate = this.handleSelectionUpdate.bind(this);
847
- this.editor.on("selectionUpdate", this.handleSelectionUpdate);
848
813
  this.renderer = new ReactRenderer(ReactNodeViewProvider, {
849
814
  editor: this.editor,
850
815
  props,
851
816
  as,
852
817
  className: `node-${this.node.type.name} ${className}`.trim()
853
818
  });
819
+ this.editor.on("selectionUpdate", this.handleSelectionUpdate);
854
820
  this.updateElementAttributes();
855
821
  }
856
822
  /**
@@ -994,16 +960,19 @@ function ReactNodeViewRenderer(component, options) {
994
960
  // src/index.ts
995
961
  export * from "@tiptap/core";
996
962
  export {
997
- BubbleMenu,
998
963
  EditorConsumer,
999
964
  EditorContent,
1000
965
  EditorContext,
1001
966
  EditorProvider,
1002
- FloatingMenu,
967
+ MarkViewContent,
1003
968
  NodeViewContent,
1004
969
  NodeViewWrapper,
1005
970
  PureEditorContent,
971
+ ReactMarkView,
972
+ ReactMarkViewContext,
973
+ ReactMarkViewRenderer,
1006
974
  ReactNodeView,
975
+ ReactNodeViewContentProvider,
1007
976
  ReactNodeViewContext,
1008
977
  ReactNodeViewRenderer,
1009
978
  ReactRenderer,