@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.cjs +171 -273
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +172 -274
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +171 -273
- package/dist/index.umd.js.map +1 -1
- package/dist/packages/core/src/helpers/isNodeEmpty.d.ts +4 -10
- package/dist/packages/core/src/style.d.ts +1 -1
- package/dist/packages/extension-bubble-menu/src/bubble-menu-plugin.d.ts +35 -12
- package/dist/packages/extension-floating-menu/src/floating-menu-plugin.d.ts +29 -14
- package/dist/packages/react/src/BubbleMenu.d.ts +2 -0
- package/dist/packages/react/src/FloatingMenu.d.ts +1 -0
- package/package.json +7 -7
- package/src/BubbleMenu.tsx +29 -12
- package/src/FloatingMenu.tsx +25 -12
- package/src/useEditor.ts +87 -241
- package/src/useEditorState.ts +60 -75
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
|
-
|
|
399
|
-
shim.exports = requireUseSyncExternalStoreShim_production_min();
|
|
400
|
-
} else {
|
|
401
|
-
shim.exports = requireUseSyncExternalStoreShim_development();
|
|
402
|
-
}
|
|
409
|
+
var hasRequiredShim;
|
|
403
410
|
|
|
404
|
-
|
|
411
|
+
function requireShim () {
|
|
412
|
+
if (hasRequiredShim) return shim.exports;
|
|
413
|
+
hasRequiredShim = 1;
|
|
405
414
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
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=
|
|
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 =
|
|
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
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
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
|
-
|
|
658
|
+
subscribers.delete(callback);
|
|
679
659
|
};
|
|
680
|
-
}
|
|
681
|
-
|
|
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(() =>
|
|
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
|
|
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
|
-
*
|
|
701
|
+
* Create a new editor instance. And attach event listeners.
|
|
700
702
|
*/
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
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
|
|
733
|
+
return createEditor(mostRecentOptions);
|
|
757
734
|
}
|
|
758
|
-
if (
|
|
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 (
|
|
763
|
-
return
|
|
739
|
+
if (options.immediatelyRender) {
|
|
740
|
+
return createEditor(mostRecentOptions);
|
|
764
741
|
}
|
|
765
742
|
return null;
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
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
|
-
|
|
838
|
-
|
|
839
|
-
|
|
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 (
|
|
855
|
-
//
|
|
856
|
-
|
|
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
|
-
|
|
859
|
-
//
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
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
|
|
827
|
+
const menuEl = React.useRef(document.createElement('div'));
|
|
944
828
|
const { editor: currentEditor } = useCurrentEditor();
|
|
945
829
|
React.useEffect(() => {
|
|
946
830
|
var _a;
|
|
947
|
-
|
|
948
|
-
|
|
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,
|
|
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
|
-
|
|
849
|
+
options: props.options,
|
|
966
850
|
});
|
|
967
851
|
menuEditor.registerPlugin(plugin);
|
|
968
|
-
return () =>
|
|
969
|
-
|
|
970
|
-
|
|
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
|
|
866
|
+
const menuEl = React.useRef(document.createElement('div'));
|
|
975
867
|
const { editor: currentEditor } = useCurrentEditor();
|
|
976
868
|
React.useEffect(() => {
|
|
977
869
|
var _a;
|
|
978
|
-
|
|
979
|
-
|
|
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,
|
|
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
|
-
|
|
884
|
+
element: menuEl.current,
|
|
885
|
+
options,
|
|
995
886
|
shouldShow,
|
|
996
887
|
});
|
|
997
888
|
menuEditor.registerPlugin(plugin);
|
|
998
|
-
return () =>
|
|
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
|
-
|
|
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({
|