@tiptap/react 2.5.9 → 3.0.0-next.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.umd.js CHANGED
@@ -125,6 +125,17 @@
125
125
  });
126
126
  const EditorContent = React.memo(EditorContentWithKey);
127
127
 
128
+ class Editor extends core.Editor {
129
+ constructor() {
130
+ super(...arguments);
131
+ this.contentComponent = null;
132
+ }
133
+ }
134
+
135
+ var withSelector = {exports: {}};
136
+
137
+ var withSelector_production_min = {};
138
+
128
139
  var shim = {exports: {}};
129
140
 
130
141
  var useSyncExternalStoreShim_production_min = {};
@@ -395,25 +406,20 @@
395
406
  return useSyncExternalStoreShim_development;
396
407
  }
397
408
 
398
- if (process.env.NODE_ENV === 'production') {
399
- shim.exports = requireUseSyncExternalStoreShim_production_min();
400
- } else {
401
- shim.exports = requireUseSyncExternalStoreShim_development();
402
- }
409
+ var hasRequiredShim;
403
410
 
404
- var shimExports = shim.exports;
411
+ function requireShim () {
412
+ if (hasRequiredShim) return shim.exports;
413
+ hasRequiredShim = 1;
405
414
 
406
- class Editor extends core.Editor {
407
- constructor() {
408
- super(...arguments);
409
- this.contentComponent = null;
410
- }
415
+ if (process.env.NODE_ENV === 'production') {
416
+ shim.exports = requireUseSyncExternalStoreShim_production_min();
417
+ } else {
418
+ shim.exports = requireUseSyncExternalStoreShim_development();
419
+ }
420
+ return shim.exports;
411
421
  }
412
422
 
413
- var withSelector = {exports: {}};
414
-
415
- var withSelector_production_min = {};
416
-
417
423
  /**
418
424
  * @license React
419
425
  * use-sync-external-store-shim/with-selector.production.min.js
@@ -429,7 +435,7 @@
429
435
  function requireWithSelector_production_min () {
430
436
  if (hasRequiredWithSelector_production_min) return withSelector_production_min;
431
437
  hasRequiredWithSelector_production_min = 1;
432
- var h=React,n=shimExports;function p(a,b){return a===b&&(0!==a||1/a===1/b)||a!==a&&b!==b}var q="function"===typeof Object.is?Object.is:p,r=n.useSyncExternalStore,t=h.useRef,u=h.useEffect,v=h.useMemo,w=h.useDebugValue;
438
+ var h=React,n=requireShim();function p(a,b){return a===b&&(0!==a||1/a===1/b)||a!==a&&b!==b}var q="function"===typeof Object.is?Object.is:p,r=n.useSyncExternalStore,t=h.useRef,u=h.useEffect,v=h.useMemo,w=h.useDebugValue;
433
439
  withSelector_production_min.useSyncExternalStoreWithSelector=function(a,b,e,l,g){var c=t(null);if(null===c.current){var f={hasValue:!1,value:null};c.current=f;}else f=c.current;c=v(function(){function a(a){if(!c){c=!0;d=a;a=l(a);if(void 0!==g&&f.hasValue){var b=f.value;if(g(b,a))return k=b}return k=a}b=k;if(q(d,a))return b;var e=l(a);if(void 0!==g&&g(b,e))return b;d=a;return k=e}var c=!1,d,k,m=void 0===e?null:e;return [function(){return a(b())},null===m?void 0:function(){return a(m())}]},[b,e,l,g]);var d=r(a,c[0],c[1]);
434
440
  u(function(){f.hasValue=!0;f.value=d;},[d]);w(d);return d};
435
441
  return withSelector_production_min;
@@ -465,7 +471,7 @@
465
471
  __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error());
466
472
  }
467
473
  var React$1 = React;
468
- var shim = shimExports;
474
+ var shim = requireShim();
469
475
 
470
476
  /**
471
477
  * inlined Object.is polyfill to avoid requiring consumers ship their own
@@ -619,75 +625,71 @@
619
625
  * To synchronize the editor instance with the component state,
620
626
  * we need to create a separate instance that is not affected by the component re-renders.
621
627
  */
622
- class EditorStateManager {
623
- constructor(initialEditor) {
624
- this.transactionNumber = 0;
625
- this.lastTransactionNumber = 0;
626
- this.subscribers = new Set();
627
- this.editor = initialEditor;
628
- this.lastSnapshot = { editor: initialEditor, transactionNumber: 0 };
629
- this.getSnapshot = this.getSnapshot.bind(this);
630
- this.getServerSnapshot = this.getServerSnapshot.bind(this);
631
- this.watch = this.watch.bind(this);
632
- this.subscribe = this.subscribe.bind(this);
633
- }
634
- /**
635
- * Get the current editor instance.
636
- */
637
- getSnapshot() {
638
- if (this.transactionNumber === this.lastTransactionNumber) {
639
- return this.lastSnapshot;
640
- }
641
- this.lastTransactionNumber = this.transactionNumber;
642
- this.lastSnapshot = { editor: this.editor, transactionNumber: this.transactionNumber };
643
- return this.lastSnapshot;
644
- }
645
- /**
646
- * Always disable the editor on the server-side.
647
- */
648
- getServerSnapshot() {
649
- return { editor: null, transactionNumber: 0 };
650
- }
651
- /**
652
- * Subscribe to the editor instance's changes.
653
- */
654
- subscribe(callback) {
655
- this.subscribers.add(callback);
656
- return () => {
657
- this.subscribers.delete(callback);
658
- };
659
- }
660
- /**
661
- * Watch the editor instance for changes.
662
- */
663
- watch(nextEditor) {
664
- this.editor = nextEditor;
665
- if (this.editor) {
666
- /**
667
- * This will force a re-render when the editor state changes.
668
- * This is to support things like `editor.can().toggleBold()` in components that `useEditor`.
669
- * This could be more efficient, but it's a good trade-off for now.
670
- */
671
- const fn = () => {
672
- this.transactionNumber += 1;
673
- this.subscribers.forEach(callback => callback());
674
- };
675
- const currentEditor = this.editor;
676
- currentEditor.on('transaction', fn);
628
+ function makeEditorStateInstance(initialEditor) {
629
+ let transactionNumber = 0;
630
+ let lastTransactionNumber = 0;
631
+ let lastSnapshot = { editor: initialEditor, transactionNumber: 0 };
632
+ let editor = initialEditor;
633
+ const subscribers = new Set();
634
+ const editorInstance = {
635
+ /**
636
+ * Get the current editor instance.
637
+ */
638
+ getSnapshot() {
639
+ if (transactionNumber === lastTransactionNumber) {
640
+ return lastSnapshot;
641
+ }
642
+ lastTransactionNumber = transactionNumber;
643
+ lastSnapshot = { editor, transactionNumber };
644
+ return lastSnapshot;
645
+ },
646
+ /**
647
+ * Always disable the editor on the server-side.
648
+ */
649
+ getServerSnapshot() {
650
+ return { editor: null, transactionNumber: 0 };
651
+ },
652
+ /**
653
+ * Subscribe to the editor instance's changes.
654
+ */
655
+ subscribe(callback) {
656
+ subscribers.add(callback);
677
657
  return () => {
678
- currentEditor.off('transaction', fn);
658
+ subscribers.delete(callback);
679
659
  };
680
- }
681
- return undefined;
682
- }
660
+ },
661
+ /**
662
+ * Watch the editor instance for changes.
663
+ */
664
+ watch(nextEditor) {
665
+ editor = nextEditor;
666
+ if (editor) {
667
+ /**
668
+ * This will force a re-render when the editor state changes.
669
+ * This is to support things like `editor.can().toggleBold()` in components that `useEditor`.
670
+ * This could be more efficient, but it's a good trade-off for now.
671
+ */
672
+ const fn = () => {
673
+ transactionNumber += 1;
674
+ subscribers.forEach(callback => callback());
675
+ };
676
+ const currentEditor = editor;
677
+ currentEditor.on('transaction', fn);
678
+ return () => {
679
+ currentEditor.off('transaction', fn);
680
+ };
681
+ }
682
+ },
683
+ };
684
+ return editorInstance;
683
685
  }
684
686
  function useEditorState(options) {
685
- const [editorInstance] = React.useState(() => new EditorStateManager(options.editor));
687
+ const [editorInstance] = React.useState(() => makeEditorStateInstance(options.editor));
686
688
  // Using the `useSyncExternalStore` hook to sync the editor instance with the component state
687
689
  const selectedState = withSelectorExports.useSyncExternalStoreWithSelector(editorInstance.subscribe, editorInstance.getSnapshot, editorInstance.getServerSnapshot, options.selector, options.equalityFn);
688
690
  React.useEffect(() => {
689
691
  return editorInstance.watch(options.editor);
690
- }, [options.editor, editorInstance]);
692
+ }, [options.editor]);
691
693
  React.useDebugValue(selectedState);
692
694
  return selectedState;
693
695
  }
@@ -696,50 +698,25 @@
696
698
  const isSSR = typeof window === 'undefined';
697
699
  const isNext = isSSR || Boolean(typeof window !== 'undefined' && window.next);
698
700
  /**
699
- * This class handles the creation, destruction, and re-creation of the editor instance.
701
+ * Create a new editor instance. And attach event listeners.
700
702
  */
701
- class EditorInstanceManager {
702
- constructor(options) {
703
- /**
704
- * The current editor instance.
705
- */
706
- this.editor = null;
707
- /**
708
- * The subscriptions to notify when the editor instance
709
- * has been created or destroyed.
710
- */
711
- this.subscriptions = new Set();
712
- /**
713
- * Whether the editor has been mounted.
714
- */
715
- this.isComponentMounted = false;
716
- /**
717
- * The most recent dependencies array.
718
- */
719
- this.previousDeps = null;
720
- /**
721
- * The unique instance ID. This is used to identify the editor instance. And will be re-generated for each new instance.
722
- */
723
- this.instanceId = '';
724
- this.options = options;
725
- this.subscriptions = new Set();
726
- this.setEditor(this.getInitialEditor());
727
- this.getEditor = this.getEditor.bind(this);
728
- this.getServerSnapshot = this.getServerSnapshot.bind(this);
729
- this.subscribe = this.subscribe.bind(this);
730
- this.refreshEditorInstance = this.refreshEditorInstance.bind(this);
731
- this.scheduleDestroy = this.scheduleDestroy.bind(this);
732
- this.onRender = this.onRender.bind(this);
733
- this.createEditor = this.createEditor.bind(this);
734
- }
735
- setEditor(editor) {
736
- this.editor = editor;
737
- this.instanceId = Math.random().toString(36).slice(2, 9);
738
- // Notify all subscribers that the editor instance has been created
739
- this.subscriptions.forEach(cb => cb());
740
- }
741
- getInitialEditor() {
742
- if (this.options.current.immediatelyRender === undefined) {
703
+ function createEditor(options) {
704
+ const editor = new Editor(options.current);
705
+ editor.on('beforeCreate', (...args) => { var _a, _b; return (_b = (_a = options.current).onBeforeCreate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
706
+ editor.on('blur', (...args) => { var _a, _b; return (_b = (_a = options.current).onBlur) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
707
+ editor.on('create', (...args) => { var _a, _b; return (_b = (_a = options.current).onCreate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
708
+ editor.on('destroy', (...args) => { var _a, _b; return (_b = (_a = options.current).onDestroy) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
709
+ editor.on('focus', (...args) => { var _a, _b; return (_b = (_a = options.current).onFocus) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
710
+ editor.on('selectionUpdate', (...args) => { var _a, _b; return (_b = (_a = options.current).onSelectionUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
711
+ editor.on('transaction', (...args) => { var _a, _b; return (_b = (_a = options.current).onTransaction) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
712
+ editor.on('update', (...args) => { var _a, _b; return (_b = (_a = options.current).onUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
713
+ editor.on('contentError', (...args) => { var _a, _b; return (_b = (_a = options.current).onContentError) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
714
+ return editor;
715
+ }
716
+ function useEditor(options = {}, deps = []) {
717
+ const mostRecentOptions = React.useRef(options);
718
+ const [editor, setEditor] = React.useState(() => {
719
+ if (options.immediatelyRender === undefined) {
743
720
  if (isSSR || isNext) {
744
721
  // TODO in the next major release, we should throw an error here
745
722
  if (isDev) {
@@ -753,148 +730,55 @@
753
730
  return null;
754
731
  }
755
732
  // Default to immediately rendering when client-side rendering
756
- return this.createEditor();
733
+ return createEditor(mostRecentOptions);
757
734
  }
758
- if (this.options.current.immediatelyRender && isSSR && isDev) {
735
+ if (options.immediatelyRender && isSSR && isDev) {
759
736
  // Warn in development, to make sure the developer is aware that tiptap cannot be SSR'd, set `immediatelyRender` to `false` to avoid hydration mismatches.
760
737
  throw new Error('Tiptap Error: SSR has been detected, and `immediatelyRender` has been set to `true` this is an unsupported configuration that may result in errors, explicitly set `immediatelyRender` to `false` to avoid hydration mismatches.');
761
738
  }
762
- if (this.options.current.immediatelyRender) {
763
- return this.createEditor();
739
+ if (options.immediatelyRender) {
740
+ return createEditor(mostRecentOptions);
764
741
  }
765
742
  return null;
766
- }
767
- /**
768
- * Create a new editor instance. And attach event listeners.
769
- */
770
- createEditor() {
771
- const editor = new Editor(this.options.current);
772
- // Always call the most recent version of the callback function by default
773
- editor.on('beforeCreate', (...args) => { var _a, _b; return (_b = (_a = this.options.current).onBeforeCreate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
774
- editor.on('blur', (...args) => { var _a, _b; return (_b = (_a = this.options.current).onBlur) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
775
- editor.on('create', (...args) => { var _a, _b; return (_b = (_a = this.options.current).onCreate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
776
- editor.on('destroy', (...args) => { var _a, _b; return (_b = (_a = this.options.current).onDestroy) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
777
- editor.on('focus', (...args) => { var _a, _b; return (_b = (_a = this.options.current).onFocus) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
778
- editor.on('selectionUpdate', (...args) => { var _a, _b; return (_b = (_a = this.options.current).onSelectionUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
779
- editor.on('transaction', (...args) => { var _a, _b; return (_b = (_a = this.options.current).onTransaction) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
780
- editor.on('update', (...args) => { var _a, _b; return (_b = (_a = this.options.current).onUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
781
- editor.on('contentError', (...args) => { var _a, _b; return (_b = (_a = this.options.current).onContentError) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); });
782
- // no need to keep track of the event listeners, they will be removed when the editor is destroyed
783
- return editor;
784
- }
785
- /**
786
- * Get the current editor instance.
787
- */
788
- getEditor() {
789
- return this.editor;
790
- }
791
- /**
792
- * Always disable the editor on the server-side.
793
- */
794
- getServerSnapshot() {
795
- return null;
796
- }
797
- /**
798
- * Subscribe to the editor instance's changes.
799
- */
800
- subscribe(onStoreChange) {
801
- this.subscriptions.add(onStoreChange);
802
- return () => {
803
- this.subscriptions.delete(onStoreChange);
804
- };
805
- }
806
- /**
807
- * On each render, we will create, update, or destroy the editor instance.
808
- * @param deps The dependencies to watch for changes
809
- * @returns A cleanup function
810
- */
811
- onRender(deps) {
812
- // The returned callback will run on each render
813
- return () => {
814
- this.isComponentMounted = true;
815
- // Cleanup any scheduled destructions, since we are currently rendering
816
- clearTimeout(this.scheduledDestructionTimeout);
817
- if (this.editor && !this.editor.isDestroyed && deps.length === 0) {
818
- // if the editor does exist & deps are empty, we don't need to re-initialize the editor
819
- // we can fast-path to update the editor options on the existing instance
820
- this.editor.setOptions(this.options.current);
821
- }
822
- else {
823
- // When the editor:
824
- // - does not yet exist
825
- // - is destroyed
826
- // - the deps array changes
827
- // We need to destroy the editor instance and re-initialize it
828
- this.refreshEditorInstance(deps);
743
+ });
744
+ const mostRecentEditor = React.useRef(editor);
745
+ mostRecentEditor.current = editor;
746
+ React.useDebugValue(editor);
747
+ // This effect will handle creating/updating the editor instance
748
+ React.useEffect(() => {
749
+ const destroyUnusedEditor = (editorInstance) => {
750
+ if (editorInstance) {
751
+ // We need to destroy the editor asynchronously to avoid memory leaks
752
+ // because the editor instance is still being used in the component.
753
+ setTimeout(() => {
754
+ // re-use the editor instance if it hasn't been replaced yet
755
+ // otherwise, asynchronously destroy the old editor instance
756
+ if (editorInstance !== mostRecentEditor.current && !editorInstance.isDestroyed) {
757
+ editorInstance.destroy();
758
+ }
759
+ });
829
760
  }
830
- return () => {
831
- this.isComponentMounted = false;
832
- this.scheduleDestroy();
833
- };
834
761
  };
835
- }
836
- /**
837
- * Recreate the editor instance if the dependencies have changed.
838
- */
839
- refreshEditorInstance(deps) {
840
- if (this.editor && !this.editor.isDestroyed) {
841
- // Editor instance already exists
842
- if (this.previousDeps === null) {
843
- // If lastDeps has not yet been initialized, reuse the current editor instance
844
- this.previousDeps = deps;
845
- return;
846
- }
847
- const depsAreEqual = this.previousDeps.length === deps.length
848
- && this.previousDeps.every((dep, index) => dep === deps[index]);
849
- if (depsAreEqual) {
850
- // deps exist and are equal, no need to recreate
851
- return;
852
- }
762
+ let editorInstance = mostRecentEditor.current;
763
+ if (!editorInstance) {
764
+ editorInstance = createEditor(mostRecentOptions);
765
+ setEditor(editorInstance);
766
+ return () => destroyUnusedEditor(editorInstance);
853
767
  }
854
- if (this.editor && !this.editor.isDestroyed) {
855
- // Destroy the editor instance if it exists
856
- this.editor.destroy();
768
+ if (!Array.isArray(deps) || deps.length === 0) {
769
+ // if the editor does exist & deps are empty, we don't need to re-initialize the editor
770
+ // we can fast-path to update the editor options on the existing instance
771
+ editorInstance.setOptions(options);
772
+ return () => destroyUnusedEditor(editorInstance);
857
773
  }
858
- this.setEditor(this.createEditor());
859
- // Update the lastDeps to the current deps
860
- this.previousDeps = deps;
861
- }
862
- /**
863
- * Schedule the destruction of the editor instance.
864
- * This will only destroy the editor if it was not mounted on the next tick.
865
- * This is to avoid destroying the editor instance when it's actually still mounted.
866
- */
867
- scheduleDestroy() {
868
- const currentInstanceId = this.instanceId;
869
- const currentEditor = this.editor;
870
- // Wait a tick to see if the component is still mounted
871
- this.scheduledDestructionTimeout = setTimeout(() => {
872
- if (this.isComponentMounted && this.instanceId === currentInstanceId) {
873
- // If still mounted on the next tick, with the same instanceId, do not destroy the editor
874
- if (currentEditor) {
875
- // just re-apply options as they might have changed
876
- currentEditor.setOptions(this.options.current);
877
- }
878
- return;
879
- }
880
- if (currentEditor && !currentEditor.isDestroyed) {
881
- currentEditor.destroy();
882
- if (this.instanceId === currentInstanceId) {
883
- this.setEditor(null);
884
- }
885
- }
886
- }, 0);
887
- }
888
- }
889
- function useEditor(options = {}, deps = []) {
890
- const mostRecentOptions = React.useRef(options);
891
- mostRecentOptions.current = options;
892
- const [instanceManager] = React.useState(() => new EditorInstanceManager(mostRecentOptions));
893
- const editor = shimExports.useSyncExternalStore(instanceManager.subscribe, instanceManager.getEditor, instanceManager.getServerSnapshot);
894
- React.useDebugValue(editor);
895
- // This effect will handle creating/updating the editor instance
896
- // eslint-disable-next-line react-hooks/exhaustive-deps
897
- React.useEffect(instanceManager.onRender(deps));
774
+ // We need to destroy the editor instance and re-initialize it
775
+ // when the deps array changes
776
+ editorInstance.destroy();
777
+ // the deps array is used to re-initialize the editor instance
778
+ editorInstance = createEditor(mostRecentOptions);
779
+ setEditor(editorInstance);
780
+ return () => destroyUnusedEditor(editorInstance);
781
+ }, deps);
898
782
  // The default behavior is to re-render on each transaction
899
783
  // This is legacy behavior that will be removed in future versions
900
784
  useEditorState({
@@ -940,17 +824,16 @@
940
824
  }
941
825
 
942
826
  const BubbleMenu = (props) => {
943
- const [element, setElement] = React.useState(null);
827
+ const menuEl = React.useRef(document.createElement('div'));
944
828
  const { editor: currentEditor } = useCurrentEditor();
945
829
  React.useEffect(() => {
946
830
  var _a;
947
- if (!element) {
948
- return;
949
- }
831
+ menuEl.current.style.visibility = 'hidden';
832
+ menuEl.current.style.position = 'absolute';
950
833
  if (((_a = props.editor) === null || _a === void 0 ? void 0 : _a.isDestroyed) || (currentEditor === null || currentEditor === void 0 ? void 0 : currentEditor.isDestroyed)) {
951
834
  return;
952
835
  }
953
- const { pluginKey = 'bubbleMenu', editor, tippyOptions = {}, updateDelay, shouldShow = null, } = props;
836
+ const { pluginKey = 'bubbleMenu', editor, updateDelay, resizeDelay, shouldShow = null, } = props;
954
837
  const menuEditor = editor || currentEditor;
955
838
  if (!menuEditor) {
956
839
  console.warn('BubbleMenu component is not rendered inside of an editor component or does not have editor prop.');
@@ -958,30 +841,38 @@
958
841
  }
959
842
  const plugin = extensionBubbleMenu.BubbleMenuPlugin({
960
843
  updateDelay,
844
+ resizeDelay,
961
845
  editor: menuEditor,
962
- element,
846
+ element: menuEl.current,
963
847
  pluginKey,
964
848
  shouldShow,
965
- tippyOptions,
849
+ options: props.options,
966
850
  });
967
851
  menuEditor.registerPlugin(plugin);
968
- return () => menuEditor.unregisterPlugin(pluginKey);
969
- }, [props.editor, currentEditor, element]);
970
- return (React.createElement("div", { ref: setElement, className: props.className, style: { visibility: 'hidden' } }, props.children));
852
+ return () => {
853
+ menuEditor.unregisterPlugin(pluginKey);
854
+ window.requestAnimationFrame(() => {
855
+ if (menuEl.current.parentNode) {
856
+ menuEl.current.parentNode.removeChild(menuEl.current);
857
+ }
858
+ });
859
+ };
860
+ }, [props.editor, currentEditor]);
861
+ const portal = ReactDOM.createPortal((React.createElement("div", { className: props.className }, props.children)), menuEl.current);
862
+ return (React.createElement(React.Fragment, null, portal));
971
863
  };
972
864
 
973
865
  const FloatingMenu = (props) => {
974
- const [element, setElement] = React.useState(null);
866
+ const menuEl = React.useRef(document.createElement('div'));
975
867
  const { editor: currentEditor } = useCurrentEditor();
976
868
  React.useEffect(() => {
977
869
  var _a;
978
- if (!element) {
979
- return;
980
- }
870
+ menuEl.current.style.visibility = 'hidden';
871
+ menuEl.current.style.position = 'absolute';
981
872
  if (((_a = props.editor) === null || _a === void 0 ? void 0 : _a.isDestroyed) || (currentEditor === null || currentEditor === void 0 ? void 0 : currentEditor.isDestroyed)) {
982
873
  return;
983
874
  }
984
- const { pluginKey = 'floatingMenu', editor, tippyOptions = {}, shouldShow = null, } = props;
875
+ const { pluginKey = 'floatingMenu', editor, options, shouldShow = null, } = props;
985
876
  const menuEditor = editor || currentEditor;
986
877
  if (!menuEditor) {
987
878
  console.warn('FloatingMenu component is not rendered inside of an editor component or does not have editor prop.');
@@ -990,18 +881,25 @@
990
881
  const plugin = extensionFloatingMenu.FloatingMenuPlugin({
991
882
  pluginKey,
992
883
  editor: menuEditor,
993
- element,
994
- tippyOptions,
884
+ element: menuEl.current,
885
+ options,
995
886
  shouldShow,
996
887
  });
997
888
  menuEditor.registerPlugin(plugin);
998
- return () => menuEditor.unregisterPlugin(pluginKey);
889
+ return () => {
890
+ menuEditor.unregisterPlugin(pluginKey);
891
+ window.requestAnimationFrame(() => {
892
+ if (menuEl.current.parentNode) {
893
+ menuEl.current.parentNode.removeChild(menuEl.current);
894
+ }
895
+ });
896
+ };
999
897
  }, [
1000
898
  props.editor,
1001
899
  currentEditor,
1002
- element,
1003
900
  ]);
1004
- return (React.createElement("div", { ref: setElement, className: props.className, style: { visibility: 'hidden' } }, props.children));
901
+ const portal = ReactDOM.createPortal((React.createElement("div", { className: props.className }, props.children)), menuEl.current);
902
+ return (React.createElement(React.Fragment, null, portal));
1005
903
  };
1006
904
 
1007
905
  const ReactNodeViewContext = React.createContext({