mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-02-24 04:00:59 +01:00
editor: only update node views if attributes change
This commit is contained in:
committed by
Abdullah Atta
parent
43034cf3a3
commit
dc62291fba
@@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<EmbedOptions>({
|
||||
},
|
||||
|
||||
addNodeView() {
|
||||
return createSelectionBasedNodeView(EmbedComponent);
|
||||
return createSelectionBasedNodeView(EmbedComponent, {
|
||||
shouldUpdate: (prev, next) => !hasSameAttributes(prev.attrs, next.attrs)
|
||||
});
|
||||
},
|
||||
|
||||
addCommands() {
|
||||
|
||||
@@ -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<ImageOptions>({
|
||||
},
|
||||
|
||||
addNodeView() {
|
||||
return createSelectionBasedNodeView(ImageComponent);
|
||||
return createSelectionBasedNodeView(ImageComponent, {
|
||||
shouldUpdate: (prev, next) => !hasSameAttributes(prev.attrs, next.attrs)
|
||||
});
|
||||
},
|
||||
|
||||
addCommands() {
|
||||
|
||||
@@ -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) {
|
||||
<>
|
||||
<TableRowToolbar
|
||||
editor={editor}
|
||||
table={tableRef.current}
|
||||
table={tableRef}
|
||||
textDirection={textDirection}
|
||||
/>
|
||||
<TableColumnToolbar
|
||||
editor={editor}
|
||||
table={tableRef.current}
|
||||
table={tableRef}
|
||||
textDirection={textDirection}
|
||||
/>
|
||||
</>
|
||||
@@ -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<HTMLTableElement | undefined>;
|
||||
textDirection: TextDirections;
|
||||
};
|
||||
|
||||
@@ -127,12 +133,11 @@ function TableRowToolbar(props: TableToolbarProps) {
|
||||
const { editor, textDirection } = props;
|
||||
const rowToolsRef = useRef<HTMLDivElement>(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 (
|
||||
<Flex
|
||||
@@ -192,9 +200,10 @@ function TableRowToolbar(props: TableToolbarProps) {
|
||||
function TableColumnToolbar(props: TableToolbarProps) {
|
||||
const { editor, table } = props;
|
||||
const columnToolsRef = useRef<HTMLDivElement>(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 (
|
||||
<Flex
|
||||
|
||||
@@ -24,7 +24,7 @@ import { TaskListComponent } from "./component";
|
||||
import { Plugin, PluginKey, NodeSelection } from "prosemirror-state";
|
||||
import TaskItem from "@tiptap/extension-task-item";
|
||||
import { dropPoint } from "prosemirror-transform";
|
||||
import { findChildrenByType } from "../../utils/prosemirror";
|
||||
import { findChildrenByType, hasSameAttributes } from "../../utils/prosemirror";
|
||||
|
||||
export type TaskListAttributes = {
|
||||
title: string;
|
||||
@@ -106,6 +106,12 @@ export const TaskListNode = TaskList.extend({
|
||||
content.classList.add(`${this.name.toLowerCase()}-content-wrapper`);
|
||||
content.style.whiteSpace = "inherit";
|
||||
return { dom: content };
|
||||
},
|
||||
shouldUpdate: (prev, next) => {
|
||||
return (
|
||||
!hasSameAttributes(prev.attrs, next.attrs) ||
|
||||
prev.childCount !== next.childCount
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<WebClipOptions>({
|
||||
},
|
||||
|
||||
addNodeView() {
|
||||
return createSelectionBasedNodeView(WebClipComponent);
|
||||
return createSelectionBasedNodeView(WebClipComponent, {
|
||||
shouldUpdate: (prev, next) => !hasSameAttributes(prev.attrs, next.attrs)
|
||||
});
|
||||
},
|
||||
|
||||
addCommands() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user