diff --git a/packages/editor/src/extensions/embed/embed.ts b/packages/editor/src/extensions/embed/embed.ts index ee061e965..4490ec51c 100644 --- a/packages/editor/src/extensions/embed/embed.ts +++ b/packages/editor/src/extensions/embed/embed.ts @@ -18,6 +18,7 @@ along with this program. If not, see . */ import { Node, mergeAttributes } from "@tiptap/core"; +import { hasSameAttributes } from "../../utils/prosemirror"; import { createSelectionBasedNodeView } from "../react"; import { TextDirections } from "../text-direction"; import { EmbedComponent } from "./component"; @@ -100,7 +101,9 @@ export const EmbedNode = Node.create({ }, addNodeView() { - return createSelectionBasedNodeView(EmbedComponent); + return createSelectionBasedNodeView(EmbedComponent, { + shouldUpdate: (prev, next) => !hasSameAttributes(prev.attrs, next.attrs) + }); }, addCommands() { diff --git a/packages/editor/src/extensions/image/image.ts b/packages/editor/src/extensions/image/image.ts index ca5373224..4981d151c 100644 --- a/packages/editor/src/extensions/image/image.ts +++ b/packages/editor/src/extensions/image/image.ts @@ -23,6 +23,7 @@ import { mergeAttributes, findChildren } from "@tiptap/core"; +import { hasSameAttributes } from "../../utils/prosemirror"; import { Attachment, getDataAttribute } from "../attachment"; import { createSelectionBasedNodeView } from "../react"; import { TextDirections } from "../text-direction"; @@ -133,7 +134,9 @@ export const ImageNode = Node.create({ }, addNodeView() { - return createSelectionBasedNodeView(ImageComponent); + return createSelectionBasedNodeView(ImageComponent, { + shouldUpdate: (prev, next) => !hasSameAttributes(prev.attrs, next.attrs) + }); }, addCommands() { diff --git a/packages/editor/src/extensions/table/component.tsx b/packages/editor/src/extensions/table/component.tsx index 5e8cce151..e87b850ae 100644 --- a/packages/editor/src/extensions/table/component.tsx +++ b/packages/editor/src/extensions/table/component.tsx @@ -35,7 +35,10 @@ import { } from "../../toolbar/tools/table"; import { getToolDefinition } from "../../toolbar/tool-definitions"; import { getPosition } from "../../utils/position"; -import { findSelectedDOMNode } from "../../utils/prosemirror"; +import { + findSelectedDOMNode, + hasSameAttributes +} from "../../utils/prosemirror"; import { DesktopOnly } from "../../components/responsive"; import { TextDirections } from "../text-direction"; @@ -59,12 +62,12 @@ export function TableComponent(props: SelectionBasedReactNodeViewProps) { <> @@ -98,7 +101,10 @@ export function TableNodeView(editor: Editor) { { component: TableComponent, shouldUpdate: (prev, next) => { - return prev.type === next.type; + return ( + !hasSameAttributes(prev.attrs, next.attrs) || + prev.childCount !== next.childCount + ); }, contentDOMFactory: () => { const dom = document.createElement("tbody"); @@ -119,7 +125,7 @@ export function TableNodeView(editor: Editor) { type TableToolbarProps = { editor: Editor; - table?: HTMLTableElement; + table?: React.MutableRefObject; textDirection: TextDirections; }; @@ -127,12 +133,11 @@ function TableRowToolbar(props: TableToolbarProps) { const { editor, textDirection } = props; const rowToolsRef = useRef(null); - useEffect( - () => { + useEffect(() => { + function onSelectionUpdate() { if (!rowToolsRef.current) { return; } - const currentRow = findSelectedDOMNode(editor, ["tableRow"]); if (!currentRow) return; @@ -151,10 +156,13 @@ function TableRowToolbar(props: TableToolbarProps) { rowToolsRef.current.style.left = `${pos.left}px`; rowToolsRef.current.style.right = `unset`; } - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [editor.state.selection, textDirection] - ); + } + + editor.current?.on("selectionUpdate", onSelectionUpdate); + return () => { + editor.current?.off("selectionUpdate", onSelectionUpdate); + }; + }, [textDirection]); return ( (null); - useEffect( - () => { - if (!columnToolsRef.current || !table) { + + useEffect(() => { + function onSelectionUpdate() { + if (!columnToolsRef.current || !table?.current) { return; } @@ -209,16 +218,19 @@ function TableColumnToolbar(props: TableToolbarProps) { location: "top", align: "center", target: currentCell as HTMLElement, - yAnchor: table, + yAnchor: table.current, yOffset: 2 }); columnToolsRef.current.style.left = `${pos.left}px`; columnToolsRef.current.style.top = `${pos.top}px`; - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [editor.state.selection, table] - ); + } + + editor.current?.on("selectionUpdate", onSelectionUpdate); + return () => { + editor.current?.off("selectionUpdate", onSelectionUpdate); + }; + }, []); return ( { + return ( + !hasSameAttributes(prev.attrs, next.attrs) || + prev.childCount !== next.childCount + ); } }); }, diff --git a/packages/editor/src/extensions/web-clip/web-clip.ts b/packages/editor/src/extensions/web-clip/web-clip.ts index a003ff64f..203051306 100644 --- a/packages/editor/src/extensions/web-clip/web-clip.ts +++ b/packages/editor/src/extensions/web-clip/web-clip.ts @@ -18,6 +18,7 @@ along with this program. If not, see . */ import { Node, mergeAttributes, findChildren } from "@tiptap/core"; +import { hasSameAttributes } from "../../utils/prosemirror"; import { getDataAttribute } from "../attachment"; import { createSelectionBasedNodeView } from "../react"; import { WebClipComponent } from "./component"; @@ -108,7 +109,9 @@ export const WebClipNode = Node.create({ }, addNodeView() { - return createSelectionBasedNodeView(WebClipComponent); + return createSelectionBasedNodeView(WebClipComponent, { + shouldUpdate: (prev, next) => !hasSameAttributes(prev.attrs, next.attrs) + }); }, addCommands() { diff --git a/packages/editor/src/utils/prosemirror.ts b/packages/editor/src/utils/prosemirror.ts index c6f3d04ea..fbd7b743d 100644 --- a/packages/editor/src/utils/prosemirror.ts +++ b/packages/editor/src/utils/prosemirror.ts @@ -28,10 +28,20 @@ import { Node as ProsemirrorNode, Mark, NodeType, - ResolvedPos + ResolvedPos, + Attrs } from "prosemirror-model"; import { EditorState, Selection } from "prosemirror-state"; +export function hasSameAttributes(prev: Attrs, next: Attrs) { + for (const key in prev) { + const prevValue = prev[key]; + const nextValue = next[key]; + if (prevValue !== nextValue) return false; + } + return true; +} + export type NodeWithOffset = { node?: ProsemirrorNode; from: number;