@tiptap/react
Advanced tools
Comparing version 2.5.7 to 2.5.8
@@ -701,4 +701,20 @@ import { BubbleMenuPlugin } from '@tiptap/extension-bubble-menu'; | ||
const isNext = isSSR || Boolean(typeof window !== 'undefined' && window.next); | ||
/** | ||
* Create a new editor instance. And attach event listeners. | ||
*/ | ||
function createEditor(options) { | ||
const editor = new Editor(options.current); | ||
editor.on('beforeCreate', (...args) => { var _a, _b; return (_b = (_a = options.current).onBeforeCreate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); }); | ||
editor.on('blur', (...args) => { var _a, _b; return (_b = (_a = options.current).onBlur) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); }); | ||
editor.on('create', (...args) => { var _a, _b; return (_b = (_a = options.current).onCreate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); }); | ||
editor.on('destroy', (...args) => { var _a, _b; return (_b = (_a = options.current).onDestroy) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); }); | ||
editor.on('focus', (...args) => { var _a, _b; return (_b = (_a = options.current).onFocus) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); }); | ||
editor.on('selectionUpdate', (...args) => { var _a, _b; return (_b = (_a = options.current).onSelectionUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); }); | ||
editor.on('transaction', (...args) => { var _a, _b; return (_b = (_a = options.current).onTransaction) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); }); | ||
editor.on('update', (...args) => { var _a, _b; return (_b = (_a = options.current).onUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); }); | ||
editor.on('contentError', (...args) => { var _a, _b; return (_b = (_a = options.current).onContentError) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); }); | ||
return editor; | ||
} | ||
function useEditor(options = {}, deps = []) { | ||
const isMounted = useRef(false); | ||
const mostRecentOptions = useRef(options); | ||
const [editor, setEditor] = useState(() => { | ||
@@ -719,3 +735,3 @@ if (options.immediatelyRender === undefined) { | ||
// Default to immediately rendering when client-side rendering | ||
return new Editor(options); | ||
return createEditor(mostRecentOptions); | ||
} | ||
@@ -727,126 +743,44 @@ if (options.immediatelyRender && isSSR && isDev) { | ||
if (options.immediatelyRender) { | ||
return new Editor(options); | ||
return createEditor(mostRecentOptions); | ||
} | ||
return null; | ||
}); | ||
const mostRecentEditor = useRef(editor); | ||
mostRecentEditor.current = editor; | ||
useDebugValue(editor); | ||
// This effect will handle creating/updating the editor instance | ||
useEffect(() => { | ||
let editorInstance = editor; | ||
const destroyUnusedEditor = (editorInstance) => { | ||
if (editorInstance) { | ||
// We need to destroy the editor asynchronously to avoid memory leaks | ||
// because the editor instance is still being used in the component. | ||
setTimeout(() => { | ||
// re-use the editor instance if it hasn't been replaced yet | ||
// otherwise, asynchronously destroy the old editor instance | ||
if (editorInstance !== mostRecentEditor.current && !editorInstance.isDestroyed) { | ||
editorInstance.destroy(); | ||
} | ||
}); | ||
} | ||
}; | ||
let editorInstance = mostRecentEditor.current; | ||
if (!editorInstance) { | ||
editorInstance = new Editor(options); | ||
// instantiate the editor if it doesn't exist | ||
// for ssr, this is the first time the editor is created | ||
editorInstance = createEditor(mostRecentOptions); | ||
setEditor(editorInstance); | ||
return () => destroyUnusedEditor(editorInstance); | ||
} | ||
else if (Array.isArray(deps) && deps.length) { | ||
// We need to destroy the editor instance and re-initialize it | ||
// when the deps array changes | ||
editorInstance.destroy(); | ||
// the deps array is used to re-initialize the editor instance | ||
editorInstance = new Editor(options); | ||
setEditor(editorInstance); | ||
} | ||
else { | ||
if (!Array.isArray(deps) || deps.length === 0) { | ||
// if the editor does exist & deps are empty, we don't need to re-initialize the editor | ||
// we can fast-path to update the editor options on the existing instance | ||
editorInstance.setOptions(options); | ||
return () => destroyUnusedEditor(editorInstance); | ||
} | ||
// We need to destroy the editor instance and re-initialize it | ||
// when the deps array changes | ||
editorInstance.destroy(); | ||
// the deps array is used to re-initialize the editor instance | ||
editorInstance = createEditor(mostRecentOptions); | ||
setEditor(editorInstance); | ||
return () => destroyUnusedEditor(editorInstance); | ||
}, deps); | ||
const { onBeforeCreate, onBlur, onCreate, onDestroy, onFocus, onSelectionUpdate, onTransaction, onUpdate, onContentError, } = options; | ||
const onBeforeCreateRef = useRef(onBeforeCreate); | ||
const onBlurRef = useRef(onBlur); | ||
const onCreateRef = useRef(onCreate); | ||
const onDestroyRef = useRef(onDestroy); | ||
const onFocusRef = useRef(onFocus); | ||
const onSelectionUpdateRef = useRef(onSelectionUpdate); | ||
const onTransactionRef = useRef(onTransaction); | ||
const onUpdateRef = useRef(onUpdate); | ||
const onContentErrorRef = useRef(onContentError); | ||
// This effect will handle updating the editor instance | ||
// when the event handlers change. | ||
useEffect(() => { | ||
if (!editor) { | ||
return; | ||
} | ||
if (onBeforeCreate) { | ||
editor.off('beforeCreate', onBeforeCreateRef.current); | ||
editor.on('beforeCreate', onBeforeCreate); | ||
onBeforeCreateRef.current = onBeforeCreate; | ||
} | ||
if (onBlur) { | ||
editor.off('blur', onBlurRef.current); | ||
editor.on('blur', onBlur); | ||
onBlurRef.current = onBlur; | ||
} | ||
if (onCreate) { | ||
editor.off('create', onCreateRef.current); | ||
editor.on('create', onCreate); | ||
onCreateRef.current = onCreate; | ||
} | ||
if (onDestroy) { | ||
editor.off('destroy', onDestroyRef.current); | ||
editor.on('destroy', onDestroy); | ||
onDestroyRef.current = onDestroy; | ||
} | ||
if (onFocus) { | ||
editor.off('focus', onFocusRef.current); | ||
editor.on('focus', onFocus); | ||
onFocusRef.current = onFocus; | ||
} | ||
if (onSelectionUpdate) { | ||
editor.off('selectionUpdate', onSelectionUpdateRef.current); | ||
editor.on('selectionUpdate', onSelectionUpdate); | ||
onSelectionUpdateRef.current = onSelectionUpdate; | ||
} | ||
if (onTransaction) { | ||
editor.off('transaction', onTransactionRef.current); | ||
editor.on('transaction', onTransaction); | ||
onTransactionRef.current = onTransaction; | ||
} | ||
if (onUpdate) { | ||
editor.off('update', onUpdateRef.current); | ||
editor.on('update', onUpdate); | ||
onUpdateRef.current = onUpdate; | ||
} | ||
if (onContentError) { | ||
editor.off('contentError', onContentErrorRef.current); | ||
editor.on('contentError', onContentError); | ||
onContentErrorRef.current = onContentError; | ||
} | ||
}, [ | ||
onBeforeCreate, | ||
onBlur, | ||
onCreate, | ||
onDestroy, | ||
onFocus, | ||
onSelectionUpdate, | ||
onTransaction, | ||
onUpdate, | ||
onContentError, | ||
editor, | ||
]); | ||
/** | ||
* Destroy the editor instance when the component completely unmounts | ||
* As opposed to the cleanup function in the effect above, this will | ||
* only be called when the component is removed from the DOM, since it has no deps. | ||
* */ | ||
useEffect(() => { | ||
isMounted.current = true; | ||
return () => { | ||
isMounted.current = false; | ||
if (editor) { | ||
// We need to destroy the editor asynchronously to avoid memory leaks | ||
// because the editor instance is still being used in the component. | ||
setTimeout(() => { | ||
// re-use the editor instance if it hasn't been destroyed yet | ||
// and the component is still mounted | ||
// otherwise, asynchronously destroy the editor instance | ||
if (!isMounted.current && !editor.isDestroyed) { | ||
editor.destroy(); | ||
} | ||
}); | ||
} | ||
}; | ||
}, []); | ||
// The default behavior is to re-render on each transaction | ||
@@ -853,0 +787,0 @@ // This is legacy behavior that will be removed in future versions |
@@ -700,4 +700,20 @@ (function (global, factory) { | ||
const isNext = isSSR || Boolean(typeof window !== 'undefined' && window.next); | ||
/** | ||
* Create a new editor instance. And attach event listeners. | ||
*/ | ||
function createEditor(options) { | ||
const editor = new Editor(options.current); | ||
editor.on('beforeCreate', (...args) => { var _a, _b; return (_b = (_a = options.current).onBeforeCreate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); }); | ||
editor.on('blur', (...args) => { var _a, _b; return (_b = (_a = options.current).onBlur) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); }); | ||
editor.on('create', (...args) => { var _a, _b; return (_b = (_a = options.current).onCreate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); }); | ||
editor.on('destroy', (...args) => { var _a, _b; return (_b = (_a = options.current).onDestroy) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); }); | ||
editor.on('focus', (...args) => { var _a, _b; return (_b = (_a = options.current).onFocus) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); }); | ||
editor.on('selectionUpdate', (...args) => { var _a, _b; return (_b = (_a = options.current).onSelectionUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); }); | ||
editor.on('transaction', (...args) => { var _a, _b; return (_b = (_a = options.current).onTransaction) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); }); | ||
editor.on('update', (...args) => { var _a, _b; return (_b = (_a = options.current).onUpdate) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); }); | ||
editor.on('contentError', (...args) => { var _a, _b; return (_b = (_a = options.current).onContentError) === null || _b === void 0 ? void 0 : _b.call(_a, ...args); }); | ||
return editor; | ||
} | ||
function useEditor(options = {}, deps = []) { | ||
const isMounted = React.useRef(false); | ||
const mostRecentOptions = React.useRef(options); | ||
const [editor, setEditor] = React.useState(() => { | ||
@@ -718,3 +734,3 @@ if (options.immediatelyRender === undefined) { | ||
// Default to immediately rendering when client-side rendering | ||
return new Editor(options); | ||
return createEditor(mostRecentOptions); | ||
} | ||
@@ -726,126 +742,44 @@ if (options.immediatelyRender && isSSR && isDev) { | ||
if (options.immediatelyRender) { | ||
return new Editor(options); | ||
return createEditor(mostRecentOptions); | ||
} | ||
return null; | ||
}); | ||
const mostRecentEditor = React.useRef(editor); | ||
mostRecentEditor.current = editor; | ||
React.useDebugValue(editor); | ||
// This effect will handle creating/updating the editor instance | ||
React.useEffect(() => { | ||
let editorInstance = editor; | ||
const destroyUnusedEditor = (editorInstance) => { | ||
if (editorInstance) { | ||
// We need to destroy the editor asynchronously to avoid memory leaks | ||
// because the editor instance is still being used in the component. | ||
setTimeout(() => { | ||
// re-use the editor instance if it hasn't been replaced yet | ||
// otherwise, asynchronously destroy the old editor instance | ||
if (editorInstance !== mostRecentEditor.current && !editorInstance.isDestroyed) { | ||
editorInstance.destroy(); | ||
} | ||
}); | ||
} | ||
}; | ||
let editorInstance = mostRecentEditor.current; | ||
if (!editorInstance) { | ||
editorInstance = new Editor(options); | ||
// instantiate the editor if it doesn't exist | ||
// for ssr, this is the first time the editor is created | ||
editorInstance = createEditor(mostRecentOptions); | ||
setEditor(editorInstance); | ||
return () => destroyUnusedEditor(editorInstance); | ||
} | ||
else if (Array.isArray(deps) && deps.length) { | ||
// We need to destroy the editor instance and re-initialize it | ||
// when the deps array changes | ||
editorInstance.destroy(); | ||
// the deps array is used to re-initialize the editor instance | ||
editorInstance = new Editor(options); | ||
setEditor(editorInstance); | ||
} | ||
else { | ||
if (!Array.isArray(deps) || deps.length === 0) { | ||
// if the editor does exist & deps are empty, we don't need to re-initialize the editor | ||
// we can fast-path to update the editor options on the existing instance | ||
editorInstance.setOptions(options); | ||
return () => destroyUnusedEditor(editorInstance); | ||
} | ||
// We need to destroy the editor instance and re-initialize it | ||
// when the deps array changes | ||
editorInstance.destroy(); | ||
// the deps array is used to re-initialize the editor instance | ||
editorInstance = createEditor(mostRecentOptions); | ||
setEditor(editorInstance); | ||
return () => destroyUnusedEditor(editorInstance); | ||
}, deps); | ||
const { onBeforeCreate, onBlur, onCreate, onDestroy, onFocus, onSelectionUpdate, onTransaction, onUpdate, onContentError, } = options; | ||
const onBeforeCreateRef = React.useRef(onBeforeCreate); | ||
const onBlurRef = React.useRef(onBlur); | ||
const onCreateRef = React.useRef(onCreate); | ||
const onDestroyRef = React.useRef(onDestroy); | ||
const onFocusRef = React.useRef(onFocus); | ||
const onSelectionUpdateRef = React.useRef(onSelectionUpdate); | ||
const onTransactionRef = React.useRef(onTransaction); | ||
const onUpdateRef = React.useRef(onUpdate); | ||
const onContentErrorRef = React.useRef(onContentError); | ||
// This effect will handle updating the editor instance | ||
// when the event handlers change. | ||
React.useEffect(() => { | ||
if (!editor) { | ||
return; | ||
} | ||
if (onBeforeCreate) { | ||
editor.off('beforeCreate', onBeforeCreateRef.current); | ||
editor.on('beforeCreate', onBeforeCreate); | ||
onBeforeCreateRef.current = onBeforeCreate; | ||
} | ||
if (onBlur) { | ||
editor.off('blur', onBlurRef.current); | ||
editor.on('blur', onBlur); | ||
onBlurRef.current = onBlur; | ||
} | ||
if (onCreate) { | ||
editor.off('create', onCreateRef.current); | ||
editor.on('create', onCreate); | ||
onCreateRef.current = onCreate; | ||
} | ||
if (onDestroy) { | ||
editor.off('destroy', onDestroyRef.current); | ||
editor.on('destroy', onDestroy); | ||
onDestroyRef.current = onDestroy; | ||
} | ||
if (onFocus) { | ||
editor.off('focus', onFocusRef.current); | ||
editor.on('focus', onFocus); | ||
onFocusRef.current = onFocus; | ||
} | ||
if (onSelectionUpdate) { | ||
editor.off('selectionUpdate', onSelectionUpdateRef.current); | ||
editor.on('selectionUpdate', onSelectionUpdate); | ||
onSelectionUpdateRef.current = onSelectionUpdate; | ||
} | ||
if (onTransaction) { | ||
editor.off('transaction', onTransactionRef.current); | ||
editor.on('transaction', onTransaction); | ||
onTransactionRef.current = onTransaction; | ||
} | ||
if (onUpdate) { | ||
editor.off('update', onUpdateRef.current); | ||
editor.on('update', onUpdate); | ||
onUpdateRef.current = onUpdate; | ||
} | ||
if (onContentError) { | ||
editor.off('contentError', onContentErrorRef.current); | ||
editor.on('contentError', onContentError); | ||
onContentErrorRef.current = onContentError; | ||
} | ||
}, [ | ||
onBeforeCreate, | ||
onBlur, | ||
onCreate, | ||
onDestroy, | ||
onFocus, | ||
onSelectionUpdate, | ||
onTransaction, | ||
onUpdate, | ||
onContentError, | ||
editor, | ||
]); | ||
/** | ||
* Destroy the editor instance when the component completely unmounts | ||
* As opposed to the cleanup function in the effect above, this will | ||
* only be called when the component is removed from the DOM, since it has no deps. | ||
* */ | ||
React.useEffect(() => { | ||
isMounted.current = true; | ||
return () => { | ||
isMounted.current = false; | ||
if (editor) { | ||
// We need to destroy the editor asynchronously to avoid memory leaks | ||
// because the editor instance is still being used in the component. | ||
setTimeout(() => { | ||
// re-use the editor instance if it hasn't been destroyed yet | ||
// and the component is still mounted | ||
// otherwise, asynchronously destroy the editor instance | ||
if (!isMounted.current && !editor.isDestroyed) { | ||
editor.destroy(); | ||
} | ||
}); | ||
} | ||
}; | ||
}, []); | ||
// The default behavior is to re-render on each transaction | ||
@@ -852,0 +786,0 @@ // This is legacy behavior that will be removed in future versions |
{ | ||
"name": "@tiptap/react", | ||
"description": "React components for tiptap", | ||
"version": "2.5.7", | ||
"version": "2.5.8", | ||
"homepage": "https://tiptap.dev", | ||
@@ -32,4 +32,4 @@ "keywords": [ | ||
"dependencies": { | ||
"@tiptap/extension-bubble-menu": "^2.5.7", | ||
"@tiptap/extension-floating-menu": "^2.5.7", | ||
"@tiptap/extension-bubble-menu": "^2.5.8", | ||
"@tiptap/extension-floating-menu": "^2.5.8", | ||
"@types/use-sync-external-store": "^0.0.6", | ||
@@ -39,4 +39,4 @@ "use-sync-external-store": "^1.2.2" | ||
"devDependencies": { | ||
"@tiptap/core": "^2.5.7", | ||
"@tiptap/pm": "^2.5.7", | ||
"@tiptap/core": "^2.5.8", | ||
"@tiptap/pm": "^2.5.8", | ||
"@types/react": "^18.2.14", | ||
@@ -48,4 +48,4 @@ "@types/react-dom": "^18.2.6", | ||
"peerDependencies": { | ||
"@tiptap/core": "^2.5.7", | ||
"@tiptap/pm": "^2.5.7", | ||
"@tiptap/core": "^2.5.8", | ||
"@tiptap/pm": "^2.5.8", | ||
"react": "^17.0.0 || ^18.0.0", | ||
@@ -52,0 +52,0 @@ "react-dom": "^17.0.0 || ^18.0.0" |
import { EditorOptions } from '@tiptap/core' | ||
import { | ||
DependencyList, useDebugValue, useEffect, useRef, useState, | ||
DependencyList, MutableRefObject, | ||
useDebugValue, useEffect, useRef, useState, | ||
} from 'react' | ||
@@ -33,2 +34,21 @@ | ||
/** | ||
* Create a new editor instance. And attach event listeners. | ||
*/ | ||
function createEditor(options: MutableRefObject<UseEditorOptions>): Editor { | ||
const editor = new Editor(options.current) | ||
editor.on('beforeCreate', (...args) => options.current.onBeforeCreate?.(...args)) | ||
editor.on('blur', (...args) => options.current.onBlur?.(...args)) | ||
editor.on('create', (...args) => options.current.onCreate?.(...args)) | ||
editor.on('destroy', (...args) => options.current.onDestroy?.(...args)) | ||
editor.on('focus', (...args) => options.current.onFocus?.(...args)) | ||
editor.on('selectionUpdate', (...args) => options.current.onSelectionUpdate?.(...args)) | ||
editor.on('transaction', (...args) => options.current.onTransaction?.(...args)) | ||
editor.on('update', (...args) => options.current.onUpdate?.(...args)) | ||
editor.on('contentError', (...args) => options.current.onContentError?.(...args)) | ||
return editor | ||
} | ||
/** | ||
* This hook allows you to create an editor instance. | ||
@@ -61,3 +81,3 @@ * @param options The editor options | ||
): Editor | null { | ||
const isMounted = useRef(false) | ||
const mostRecentOptions = useRef(options) | ||
const [editor, setEditor] = useState(() => { | ||
@@ -82,3 +102,3 @@ if (options.immediatelyRender === undefined) { | ||
// Default to immediately rendering when client-side rendering | ||
return new Editor(options) | ||
return createEditor(mostRecentOptions) | ||
} | ||
@@ -94,3 +114,3 @@ | ||
if (options.immediatelyRender) { | ||
return new Editor(options) | ||
return createEditor(mostRecentOptions) | ||
} | ||
@@ -100,3 +120,6 @@ | ||
}) | ||
const mostRecentEditor = useRef<Editor | null>(editor) | ||
mostRecentEditor.current = editor | ||
useDebugValue(editor) | ||
@@ -106,154 +129,43 @@ | ||
useEffect(() => { | ||
let editorInstance: Editor | null = editor | ||
const destroyUnusedEditor = (editorInstance: Editor | null) => { | ||
if (editorInstance) { | ||
// We need to destroy the editor asynchronously to avoid memory leaks | ||
// because the editor instance is still being used in the component. | ||
setTimeout(() => { | ||
// re-use the editor instance if it hasn't been replaced yet | ||
// otherwise, asynchronously destroy the old editor instance | ||
if (editorInstance !== mostRecentEditor.current && !editorInstance.isDestroyed) { | ||
editorInstance.destroy() | ||
} | ||
}) | ||
} | ||
} | ||
let editorInstance = mostRecentEditor.current | ||
if (!editorInstance) { | ||
editorInstance = new Editor(options) | ||
// instantiate the editor if it doesn't exist | ||
// for ssr, this is the first time the editor is created | ||
editorInstance = createEditor(mostRecentOptions) | ||
setEditor(editorInstance) | ||
} else if (Array.isArray(deps) && deps.length) { | ||
// We need to destroy the editor instance and re-initialize it | ||
// when the deps array changes | ||
editorInstance.destroy() | ||
return () => destroyUnusedEditor(editorInstance) | ||
} | ||
// the deps array is used to re-initialize the editor instance | ||
editorInstance = new Editor(options) | ||
setEditor(editorInstance) | ||
} else { | ||
if (!Array.isArray(deps) || deps.length === 0) { | ||
// if the editor does exist & deps are empty, we don't need to re-initialize the editor | ||
// we can fast-path to update the editor options on the existing instance | ||
editorInstance.setOptions(options) | ||
} | ||
}, deps) | ||
const { | ||
onBeforeCreate, | ||
onBlur, | ||
onCreate, | ||
onDestroy, | ||
onFocus, | ||
onSelectionUpdate, | ||
onTransaction, | ||
onUpdate, | ||
onContentError, | ||
} = options | ||
const onBeforeCreateRef = useRef(onBeforeCreate) | ||
const onBlurRef = useRef(onBlur) | ||
const onCreateRef = useRef(onCreate) | ||
const onDestroyRef = useRef(onDestroy) | ||
const onFocusRef = useRef(onFocus) | ||
const onSelectionUpdateRef = useRef(onSelectionUpdate) | ||
const onTransactionRef = useRef(onTransaction) | ||
const onUpdateRef = useRef(onUpdate) | ||
const onContentErrorRef = useRef(onContentError) | ||
// This effect will handle updating the editor instance | ||
// when the event handlers change. | ||
useEffect(() => { | ||
if (!editor) { | ||
return | ||
return () => destroyUnusedEditor(editorInstance) | ||
} | ||
if (onBeforeCreate) { | ||
editor.off('beforeCreate', onBeforeCreateRef.current) | ||
editor.on('beforeCreate', onBeforeCreate) | ||
// We need to destroy the editor instance and re-initialize it | ||
// when the deps array changes | ||
editorInstance.destroy() | ||
onBeforeCreateRef.current = onBeforeCreate | ||
} | ||
// the deps array is used to re-initialize the editor instance | ||
editorInstance = createEditor(mostRecentOptions) | ||
setEditor(editorInstance) | ||
return () => destroyUnusedEditor(editorInstance) | ||
}, deps) | ||
if (onBlur) { | ||
editor.off('blur', onBlurRef.current) | ||
editor.on('blur', onBlur) | ||
onBlurRef.current = onBlur | ||
} | ||
if (onCreate) { | ||
editor.off('create', onCreateRef.current) | ||
editor.on('create', onCreate) | ||
onCreateRef.current = onCreate | ||
} | ||
if (onDestroy) { | ||
editor.off('destroy', onDestroyRef.current) | ||
editor.on('destroy', onDestroy) | ||
onDestroyRef.current = onDestroy | ||
} | ||
if (onFocus) { | ||
editor.off('focus', onFocusRef.current) | ||
editor.on('focus', onFocus) | ||
onFocusRef.current = onFocus | ||
} | ||
if (onSelectionUpdate) { | ||
editor.off('selectionUpdate', onSelectionUpdateRef.current) | ||
editor.on('selectionUpdate', onSelectionUpdate) | ||
onSelectionUpdateRef.current = onSelectionUpdate | ||
} | ||
if (onTransaction) { | ||
editor.off('transaction', onTransactionRef.current) | ||
editor.on('transaction', onTransaction) | ||
onTransactionRef.current = onTransaction | ||
} | ||
if (onUpdate) { | ||
editor.off('update', onUpdateRef.current) | ||
editor.on('update', onUpdate) | ||
onUpdateRef.current = onUpdate | ||
} | ||
if (onContentError) { | ||
editor.off('contentError', onContentErrorRef.current) | ||
editor.on('contentError', onContentError) | ||
onContentErrorRef.current = onContentError | ||
} | ||
}, [ | ||
onBeforeCreate, | ||
onBlur, | ||
onCreate, | ||
onDestroy, | ||
onFocus, | ||
onSelectionUpdate, | ||
onTransaction, | ||
onUpdate, | ||
onContentError, | ||
editor, | ||
]) | ||
/** | ||
* Destroy the editor instance when the component completely unmounts | ||
* As opposed to the cleanup function in the effect above, this will | ||
* only be called when the component is removed from the DOM, since it has no deps. | ||
* */ | ||
useEffect(() => { | ||
isMounted.current = true | ||
return () => { | ||
isMounted.current = false | ||
if (editor) { | ||
// We need to destroy the editor asynchronously to avoid memory leaks | ||
// because the editor instance is still being used in the component. | ||
setTimeout(() => { | ||
// re-use the editor instance if it hasn't been destroyed yet | ||
// and the component is still mounted | ||
// otherwise, asynchronously destroy the editor instance | ||
if (!isMounted.current && !editor.isDestroyed) { | ||
editor.destroy() | ||
} | ||
}) | ||
} | ||
} | ||
}, []) | ||
// The default behavior is to re-render on each transaction | ||
@@ -260,0 +172,0 @@ // This is legacy behavior that will be removed in future versions |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
575969
8279