Sign In

@tiptap/react

Package Overview
Dependencies
Maintainers
6
Versions
409
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
3.23.4
to
3.23.5
+61
-37
dist/index.cjs

@@ -336,8 +336,15 @@ "use strict";

getInitialEditor() {
var _a;
let immediatelyRender = (_a = this.options.current.immediatelyRender) != null ? _a : true;
if (immediatelyRender && (isSSR || isNext)) {
const explicit = this.options.current.immediatelyRender;
let immediatelyRender = explicit != null ? explicit : true;
if (isSSR) {
if (immediatelyRender && isDev) {
console.warn("SSR detected. `immediatelyRender` has been set to false to avoid hydration mismatches");
}
immediatelyRender = false;
} else if (isNext && explicit === void 0) {
immediatelyRender = false;
if (isDev) {
console.warn("SSR detected. `immediatelyRender` has been set to false to avoid hydration mismatches");
console.warn(
"Next.js detected. `immediatelyRender` defaults to false to avoid hydration mismatches. Pass `immediatelyRender: true` explicitly if you are rendering the editor only on the client."
);
}

@@ -748,2 +755,4 @@ }

* Re-renders the React component with new props.
* Skips the render if none of the supplied props actually changed,
* to avoid unnecessary portal re-creation.
*/

@@ -754,2 +763,14 @@ updateProps(props = {}) {

}
let changed = false;
const keys = Object.keys(props);
for (let i = 0; i < keys.length; i += 1) {
const key = keys[i];
if (props[key] !== this.props[key]) {
changed = true;
break;
}
}
if (!changed) {
return;
}
this.props = {

@@ -851,6 +872,16 @@ ...this.props,

/**
* Callback registered with the per-editor position-update registry.
* Stored so it can be unregistered in destroy().
* Fires on editor updates when trackNodeViewPosition is enabled.
* Detects position shifts where update() is NOT called (e.g. typing above).
*/
this.positionCheckCallback = null;
this.handlePositionUpdate = () => {
const newPos = this.getPos();
if (typeof newPos !== "number" || newPos === this.currentPos) {
return;
}
this.currentPos = newPos;
this.renderer.updateProps({ getPos: () => this.getPos() });
if (typeof this.options.attrs === "function") {
this.updateElementAttributes();
}
};
this.cachedExtensionWithSyncedStorage = null;

@@ -872,2 +903,5 @@ if (!this.node.isLeaf) {

}
if (this.options.trackNodeViewPosition) {
this.editor.on("update", this.handlePositionUpdate);
}
}

@@ -914,2 +948,3 @@ /**

};
const mountProps = props;
if (!this.component.displayName) {

@@ -944,3 +979,3 @@ const capitalizeFirstChar = (string) => {

editor: this.editor,
props,
props: mountProps,
as,

@@ -952,14 +987,2 @@ className: `node-${this.node.type.name} ${className}`.trim()

this.currentPos = this.getPos();
this.positionCheckCallback = () => {
const newPos = this.getPos();
if (typeof newPos !== "number" || newPos === this.currentPos) {
return;
}
this.currentPos = newPos;
this.renderer.updateProps({ getPos: () => this.getPos() });
if (typeof this.options.attrs === "function") {
this.updateElementAttributes();
}
};
(0, import_core3.schedulePositionCheck)(this.editor, this.positionCheckCallback);
}

@@ -1053,17 +1076,10 @@ /**

}
const newPos = this.getPos();
if (node === this.node && this.decorations === decorations && this.innerDecorations === innerDecorations) {
if (newPos === this.currentPos) {
return true;
}
this.currentPos = newPos;
rerenderComponent({
node,
decorations,
innerDecorations,
extension: this.extensionWithSyncedStorage,
getPos: () => this.getPos()
});
const nodeChanged = node !== this.node;
if (!nodeChanged) {
this.node = node;
this.decorations = decorations;
this.innerDecorations = innerDecorations;
return true;
}
const newPos = this.getPos();
this.node = node;

@@ -1073,3 +1089,12 @@ this.decorations = decorations;

this.currentPos = newPos;
rerenderComponent({ node, decorations, innerDecorations, extension: this.extensionWithSyncedStorage });
const extraProps = {
node,
decorations,
innerDecorations,
extension: this.extensionWithSyncedStorage
};
if (this.options.trackNodeViewPosition) {
extraProps.getPos = () => this.getPos();
}
rerenderComponent(extraProps);
return true;

@@ -1103,5 +1128,4 @@ }

this.editor.off("selectionUpdate", this.handleSelectionUpdate);
if (this.positionCheckCallback) {
(0, import_core3.cancelPositionCheck)(this.editor, this.positionCheckCallback);
this.positionCheckCallback = null;
if (this.options.trackNodeViewPosition) {
this.editor.off("update", this.handlePositionUpdate);
}

@@ -1108,0 +1132,0 @@ this.contentDOMElement = null;

@@ -168,2 +168,4 @@ import * as react_jsx_runtime from 'react/jsx-runtime';

* Re-renders the React component with new props.
* Skips the render if none of the supplied props actually changed,
* to avoid unnecessary portal re-creation.
*/

@@ -263,6 +265,6 @@ updateProps(props?: Record<string, any>): void;

/**
* Callback registered with the per-editor position-update registry.
* Stored so it can be unregistered in destroy().
* Fires on editor updates when trackNodeViewPosition is enabled.
* Detects position shifts where update() is NOT called (e.g. typing above).
*/
private positionCheckCallback;
private handlePositionUpdate;
constructor(component: Component, props: NodeViewRendererProps, options?: Partial<Options>);

@@ -269,0 +271,0 @@ private cachedExtensionWithSyncedStorage;

@@ -168,2 +168,4 @@ import * as react_jsx_runtime from 'react/jsx-runtime';

* Re-renders the React component with new props.
* Skips the render if none of the supplied props actually changed,
* to avoid unnecessary portal re-creation.
*/

@@ -263,6 +265,6 @@ updateProps(props?: Record<string, any>): void;

/**
* Callback registered with the per-editor position-update registry.
* Stored so it can be unregistered in destroy().
* Fires on editor updates when trackNodeViewPosition is enabled.
* Detects position shifts where update() is NOT called (e.g. typing above).
*/
private positionCheckCallback;
private handlePositionUpdate;
constructor(component: Component, props: NodeViewRendererProps, options?: Partial<Options>);

@@ -269,0 +271,0 @@ private cachedExtensionWithSyncedStorage;

@@ -274,8 +274,15 @@ // src/Context.tsx

getInitialEditor() {
var _a;
let immediatelyRender = (_a = this.options.current.immediatelyRender) != null ? _a : true;
if (immediatelyRender && (isSSR || isNext)) {
const explicit = this.options.current.immediatelyRender;
let immediatelyRender = explicit != null ? explicit : true;
if (isSSR) {
if (immediatelyRender && isDev) {
console.warn("SSR detected. `immediatelyRender` has been set to false to avoid hydration mismatches");
}
immediatelyRender = false;
} else if (isNext && explicit === void 0) {
immediatelyRender = false;
if (isDev) {
console.warn("SSR detected. `immediatelyRender` has been set to false to avoid hydration mismatches");
console.warn(
"Next.js detected. `immediatelyRender` defaults to false to avoid hydration mismatches. Pass `immediatelyRender: true` explicitly if you are rendering the editor only on the client."
);
}

@@ -686,2 +693,4 @@ }

* Re-renders the React component with new props.
* Skips the render if none of the supplied props actually changed,
* to avoid unnecessary portal re-creation.
*/

@@ -692,2 +701,14 @@ updateProps(props = {}) {

}
let changed = false;
const keys = Object.keys(props);
for (let i = 0; i < keys.length; i += 1) {
const key = keys[i];
if (props[key] !== this.props[key]) {
changed = true;
break;
}
}
if (!changed) {
return;
}
this.props = {

@@ -778,9 +799,3 @@ ...this.props,

// src/ReactNodeViewRenderer.tsx
import {
cancelPositionCheck,
getRenderedAttributes,
isNodeViewSelected,
NodeView,
schedulePositionCheck
} from "@tiptap/core";
import { getRenderedAttributes, isNodeViewSelected, NodeView } from "@tiptap/core";
import { createElement as createElement2, createRef, memo } from "react";

@@ -796,6 +811,16 @@ import { jsx as jsx7 } from "react/jsx-runtime";

/**
* Callback registered with the per-editor position-update registry.
* Stored so it can be unregistered in destroy().
* Fires on editor updates when trackNodeViewPosition is enabled.
* Detects position shifts where update() is NOT called (e.g. typing above).
*/
this.positionCheckCallback = null;
this.handlePositionUpdate = () => {
const newPos = this.getPos();
if (typeof newPos !== "number" || newPos === this.currentPos) {
return;
}
this.currentPos = newPos;
this.renderer.updateProps({ getPos: () => this.getPos() });
if (typeof this.options.attrs === "function") {
this.updateElementAttributes();
}
};
this.cachedExtensionWithSyncedStorage = null;

@@ -817,2 +842,5 @@ if (!this.node.isLeaf) {

}
if (this.options.trackNodeViewPosition) {
this.editor.on("update", this.handlePositionUpdate);
}
}

@@ -859,2 +887,3 @@ /**

};
const mountProps = props;
if (!this.component.displayName) {

@@ -889,3 +918,3 @@ const capitalizeFirstChar = (string) => {

editor: this.editor,
props,
props: mountProps,
as,

@@ -897,14 +926,2 @@ className: `node-${this.node.type.name} ${className}`.trim()

this.currentPos = this.getPos();
this.positionCheckCallback = () => {
const newPos = this.getPos();
if (typeof newPos !== "number" || newPos === this.currentPos) {
return;
}
this.currentPos = newPos;
this.renderer.updateProps({ getPos: () => this.getPos() });
if (typeof this.options.attrs === "function") {
this.updateElementAttributes();
}
};
schedulePositionCheck(this.editor, this.positionCheckCallback);
}

@@ -998,17 +1015,10 @@ /**

}
const newPos = this.getPos();
if (node === this.node && this.decorations === decorations && this.innerDecorations === innerDecorations) {
if (newPos === this.currentPos) {
return true;
}
this.currentPos = newPos;
rerenderComponent({
node,
decorations,
innerDecorations,
extension: this.extensionWithSyncedStorage,
getPos: () => this.getPos()
});
const nodeChanged = node !== this.node;
if (!nodeChanged) {
this.node = node;
this.decorations = decorations;
this.innerDecorations = innerDecorations;
return true;
}
const newPos = this.getPos();
this.node = node;

@@ -1018,3 +1028,12 @@ this.decorations = decorations;

this.currentPos = newPos;
rerenderComponent({ node, decorations, innerDecorations, extension: this.extensionWithSyncedStorage });
const extraProps = {
node,
decorations,
innerDecorations,
extension: this.extensionWithSyncedStorage
};
if (this.options.trackNodeViewPosition) {
extraProps.getPos = () => this.getPos();
}
rerenderComponent(extraProps);
return true;

@@ -1048,5 +1067,4 @@ }

this.editor.off("selectionUpdate", this.handleSelectionUpdate);
if (this.positionCheckCallback) {
cancelPositionCheck(this.editor, this.positionCheckCallback);
this.positionCheckCallback = null;
if (this.options.trackNodeViewPosition) {
this.editor.off("update", this.handlePositionUpdate);
}

@@ -1053,0 +1071,0 @@ this.contentDOMElement = null;

{
"name": "@tiptap/react",
"description": "React components for tiptap",
"version": "3.23.4",
"version": "3.23.5",
"homepage": "https://tiptap.dev",

@@ -51,8 +51,8 @@ "keywords": [

"react-dom": "^19.0.0",
"@tiptap/core": "^3.23.4",
"@tiptap/pm": "^3.23.4"
"@tiptap/core": "^3.23.5",
"@tiptap/pm": "^3.23.5"
},
"optionalDependencies": {
"@tiptap/extension-bubble-menu": "^3.23.4",
"@tiptap/extension-floating-menu": "^3.23.4"
"@tiptap/extension-bubble-menu": "^3.23.5",
"@tiptap/extension-floating-menu": "^3.23.5"
},

@@ -64,4 +64,4 @@ "peerDependencies": {

"@types/react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0",
"@tiptap/core": "3.23.4",
"@tiptap/pm": "3.23.4"
"@tiptap/core": "3.23.5",
"@tiptap/pm": "3.23.5"
},

@@ -68,0 +68,0 @@ "repository": {

@@ -8,9 +8,3 @@ import type {

} from '@tiptap/core'
import {
cancelPositionCheck,
getRenderedAttributes,
isNodeViewSelected,
NodeView,
schedulePositionCheck,
} from '@tiptap/core'
import { getRenderedAttributes, isNodeViewSelected, NodeView } from '@tiptap/core'
import type { Node, Node as ProseMirrorNode } from '@tiptap/pm/model'

@@ -89,7 +83,18 @@ import type { Decoration, DecorationSource, NodeView as ProseMirrorNodeView } from '@tiptap/pm/view'

/**
* Callback registered with the per-editor position-update registry.
* Stored so it can be unregistered in destroy().
* Fires on editor updates when trackNodeViewPosition is enabled.
* Detects position shifts where update() is NOT called (e.g. typing above).
*/
private positionCheckCallback: (() => void) | null = null
private handlePositionUpdate = () => {
const newPos = this.getPos()
if (typeof newPos !== 'number' || newPos === this.currentPos) {
return
}
this.currentPos = newPos
this.renderer.updateProps({ getPos: () => this.getPos() })
if (typeof this.options.attrs === 'function') {
this.updateElementAttributes()
}
}
constructor(component: Component, props: NodeViewRendererProps, options?: Partial<Options>) {

@@ -121,2 +126,6 @@ super(component, props, options)

}
if (this.options.trackNodeViewPosition) {
this.editor.on('update', this.handlePositionUpdate)
}
}

@@ -154,3 +163,3 @@

mount() {
const props = {
const props: Record<string, any> = {
editor: this.editor,

@@ -168,4 +177,6 @@ node: this.node,

ref: createRef<T>(),
} satisfies ReactNodeViewProps<T>
}
const mountProps = props as ReactNodeViewProps<T>
if (!(this.component as any).displayName) {

@@ -215,3 +226,3 @@ const capitalizeFirstChar = (string: string): string => {

editor: this.editor,
props,
props: mountProps,
as,

@@ -224,21 +235,2 @@ className: `node-${this.node.type.name} ${className}`.trim(),

this.currentPos = this.getPos()
this.positionCheckCallback = () => {
const newPos = this.getPos()
if (typeof newPos !== 'number' || newPos === this.currentPos) {
return
}
this.currentPos = newPos
// Pass a fresh getPos reference so React's memo detects a prop change.
this.renderer.updateProps({ getPos: () => this.getPos() })
if (typeof this.options.attrs === 'function') {
this.updateElementAttributes()
}
}
schedulePositionCheck(this.editor, this.positionCheckCallback)
}

@@ -352,23 +344,20 @@

const newPos = this.getPos()
const nodeChanged = node !== this.node
if (node === this.node && this.decorations === decorations && this.innerDecorations === innerDecorations) {
if (newPos === this.currentPos) {
return true
}
// Position changed without a content/decoration change — trigger re-render
// so the component receives an up-to-date value from getPos().
// Pass a fresh getPos reference so React's memo detects a prop change.
this.currentPos = newPos
rerenderComponent({
node,
decorations,
innerDecorations,
extension: this.extensionWithSyncedStorage,
getPos: () => this.getPos(),
})
// Node reference unchanged — only decorations may have changed.
// ProseMirror renders decorations independently on the contentDOM,
// and the getPos closure (bound in mount()) calls through to
// ProseMirror's position function at call time, so it is always
// current. Update internal refs and skip the React re-render.
// Keep currentPos unchanged here so the editor update listener can
// still detect and publish a position shift for tracked node views.
if (!nodeChanged) {
this.node = node
this.decorations = decorations
this.innerDecorations = innerDecorations
return true
}
const newPos = this.getPos()
this.node = node

@@ -379,4 +368,14 @@ this.decorations = decorations

rerenderComponent({ node, decorations, innerDecorations, extension: this.extensionWithSyncedStorage })
const extraProps: Record<string, any> = {
node,
decorations,
innerDecorations,
extension: this.extensionWithSyncedStorage,
}
if (this.options.trackNodeViewPosition) {
extraProps.getPos = () => this.getPos()
}
rerenderComponent(extraProps)
return true

@@ -414,5 +413,4 @@ }

if (this.positionCheckCallback) {
cancelPositionCheck(this.editor, this.positionCheckCallback)
this.positionCheckCallback = null
if (this.options.trackNodeViewPosition) {
this.editor.off('update', this.handlePositionUpdate)
}

@@ -419,0 +417,0 @@

@@ -239,2 +239,4 @@ import type { Editor } from '@tiptap/core'

* Re-renders the React component with new props.
* Skips the render if none of the supplied props actually changed,
* to avoid unnecessary portal re-creation.
*/

@@ -246,2 +248,18 @@ updateProps(props: Record<string, any> = {}): void {

// Shallow comparison — skip if every supplied key already holds the same value.
let changed = false
const keys = Object.keys(props)
for (let i = 0; i < keys.length; i += 1) {
const key = keys[i]
if (props[key] !== this.props[key]) {
changed = true
break
}
}
if (!changed) {
return
}
this.props = {

@@ -248,0 +266,0 @@ ...this.props,

@@ -96,8 +96,16 @@ import { type EditorOptions, Editor } from '@tiptap/core'

private getInitialEditor() {
let immediatelyRender = this.options.current.immediatelyRender ?? true
const explicit = this.options.current.immediatelyRender
let immediatelyRender = explicit ?? true
if (immediatelyRender && (isSSR || isNext)) {
if (isSSR) {
if (immediatelyRender && isDev) {
console.warn('SSR detected. `immediatelyRender` has been set to false to avoid hydration mismatches')
}
immediatelyRender = false
} else if (isNext && explicit === undefined) {
immediatelyRender = false
if (isDev) {
console.warn('SSR detected. `immediatelyRender` has been set to false to avoid hydration mismatches')
console.warn(
'Next.js detected. `immediatelyRender` defaults to false to avoid hydration mismatches. Pass `immediatelyRender: true` explicitly if you are rendering the editor only on the client.',
)
}

@@ -104,0 +112,0 @@ }

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display