Socket
Socket
Sign inDemoInstall

@tiptap/react

Package Overview
Dependencies
Maintainers
5
Versions
231
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tiptap/react - npm Package Compare versions

Comparing version 2.5.7 to 2.5.8

158

dist/index.js

@@ -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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc