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