fix: empty snapLines arrays would cause re-render (#7454)
Co-authored-by: Lynda Lin <lynda.lin@optoma.com> Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
parent
7bd6496854
commit
2a0fe2584e
@ -268,6 +268,7 @@ import {
|
|||||||
muteFSAbortError,
|
muteFSAbortError,
|
||||||
isTestEnv,
|
isTestEnv,
|
||||||
easeOut,
|
easeOut,
|
||||||
|
updateStable,
|
||||||
} from "../utils";
|
} from "../utils";
|
||||||
import {
|
import {
|
||||||
createSrcDoc,
|
createSrcDoc,
|
||||||
@ -4736,13 +4737,31 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
event,
|
event,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.setState({
|
this.setState((prevState) => {
|
||||||
snapLines,
|
const nextSnapLines = updateStable(prevState.snapLines, snapLines);
|
||||||
originSnapOffset: originOffset,
|
const nextOriginOffset = prevState.originSnapOffset
|
||||||
|
? updateStable(prevState.originSnapOffset, originOffset)
|
||||||
|
: originOffset;
|
||||||
|
|
||||||
|
if (
|
||||||
|
prevState.snapLines === nextSnapLines &&
|
||||||
|
prevState.originSnapOffset === nextOriginOffset
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
snapLines: nextSnapLines,
|
||||||
|
originSnapOffset: nextOriginOffset,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
} else if (!this.state.draggingElement) {
|
} else if (!this.state.draggingElement) {
|
||||||
this.setState({
|
this.setState((prevState) => {
|
||||||
snapLines: [],
|
if (prevState.snapLines.length) {
|
||||||
|
return {
|
||||||
|
snapLines: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7227,7 +7246,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
isRotating,
|
isRotating,
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
this.setState({
|
this.setState((prevState) => ({
|
||||||
isResizing: false,
|
isResizing: false,
|
||||||
isRotating: false,
|
isRotating: false,
|
||||||
resizingElement: null,
|
resizingElement: null,
|
||||||
@ -7241,10 +7260,10 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
multiElement || isTextElement(this.state.editingElement)
|
multiElement || isTextElement(this.state.editingElement)
|
||||||
? this.state.editingElement
|
? this.state.editingElement
|
||||||
: null,
|
: null,
|
||||||
snapLines: [],
|
snapLines: updateStable(prevState.snapLines, []),
|
||||||
|
|
||||||
originSnapOffset: null,
|
originSnapOffset: null,
|
||||||
});
|
}));
|
||||||
|
|
||||||
SnapCache.setReferenceSnapPoints(null);
|
SnapCache.setReferenceSnapPoints(null);
|
||||||
SnapCache.setVisibleGaps(null);
|
SnapCache.setVisibleGaps(null);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`duplicate element on move when ALT is clicked > rectangle 1`] = `
|
exports[`duplicate element on move when ALT is clicked > rectangle 5`] = `
|
||||||
{
|
{
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
@ -32,7 +32,7 @@ exports[`duplicate element on move when ALT is clicked > rectangle 1`] = `
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`duplicate element on move when ALT is clicked > rectangle 2`] = `
|
exports[`duplicate element on move when ALT is clicked > rectangle 6`] = `
|
||||||
{
|
{
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
@ -64,7 +64,7 @@ exports[`duplicate element on move when ALT is clicked > rectangle 2`] = `
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`move element > rectangle 1`] = `
|
exports[`move element > rectangle 5`] = `
|
||||||
{
|
{
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
@ -96,7 +96,7 @@ exports[`move element > rectangle 1`] = `
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`move element > rectangles with binding arrow 1`] = `
|
exports[`move element > rectangles with binding arrow 5`] = `
|
||||||
{
|
{
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
@ -133,7 +133,7 @@ exports[`move element > rectangles with binding arrow 1`] = `
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`move element > rectangles with binding arrow 2`] = `
|
exports[`move element > rectangles with binding arrow 6`] = `
|
||||||
{
|
{
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
@ -170,7 +170,7 @@ exports[`move element > rectangles with binding arrow 2`] = `
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`move element > rectangles with binding arrow 3`] = `
|
exports[`move element > rectangles with binding arrow 7`] = `
|
||||||
{
|
{
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`multi point mode in linear elements > arrow 1`] = `
|
exports[`multi point mode in linear elements > arrow 3`] = `
|
||||||
{
|
{
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
@ -54,7 +54,7 @@ exports[`multi point mode in linear elements > arrow 1`] = `
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`multi point mode in linear elements > line 1`] = `
|
exports[`multi point mode in linear elements > line 3`] = `
|
||||||
{
|
{
|
||||||
"angle": 0,
|
"angle": 0,
|
||||||
"backgroundColor": "transparent",
|
"backgroundColor": "transparent",
|
||||||
|
@ -173,14 +173,14 @@ describe("Test Linear Elements", () => {
|
|||||||
createTwoPointerLinearElement("line");
|
createTwoPointerLinearElement("line");
|
||||||
const line = h.elements[0] as ExcalidrawLinearElement;
|
const line = h.elements[0] as ExcalidrawLinearElement;
|
||||||
|
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(5);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`5`);
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(5);
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`5`);
|
||||||
expect((h.elements[0] as ExcalidrawLinearElement).points.length).toEqual(2);
|
expect((h.elements[0] as ExcalidrawLinearElement).points.length).toEqual(2);
|
||||||
|
|
||||||
// drag line from midpoint
|
// drag line from midpoint
|
||||||
drag(midpoint, [midpoint[0] + delta, midpoint[1] + delta]);
|
drag(midpoint, [midpoint[0] + delta, midpoint[1] + delta]);
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(9);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`9`);
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(7);
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
|
||||||
expect(line.points.length).toEqual(3);
|
expect(line.points.length).toEqual(3);
|
||||||
expect(line.points).toMatchInlineSnapshot(`
|
expect(line.points).toMatchInlineSnapshot(`
|
||||||
[
|
[
|
||||||
@ -273,8 +273,10 @@ describe("Test Linear Elements", () => {
|
|||||||
|
|
||||||
// drag line from midpoint
|
// drag line from midpoint
|
||||||
drag(midpoint, [midpoint[0] + delta, midpoint[1] + delta]);
|
drag(midpoint, [midpoint[0] + delta, midpoint[1] + delta]);
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(14);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(6);
|
`12`,
|
||||||
|
);
|
||||||
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`);
|
||||||
|
|
||||||
expect(line.points.length).toEqual(3);
|
expect(line.points.length).toEqual(3);
|
||||||
expect(line.points).toMatchInlineSnapshot(`
|
expect(line.points).toMatchInlineSnapshot(`
|
||||||
@ -311,8 +313,10 @@ describe("Test Linear Elements", () => {
|
|||||||
// update roundness
|
// update roundness
|
||||||
fireEvent.click(screen.getByTitle("Round"));
|
fireEvent.click(screen.getByTitle("Round"));
|
||||||
|
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(10);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(8);
|
`10`,
|
||||||
|
);
|
||||||
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`8`);
|
||||||
|
|
||||||
const midPointsWithRoundEdge = LinearElementEditor.getEditorMidPoints(
|
const midPointsWithRoundEdge = LinearElementEditor.getEditorMidPoints(
|
||||||
h.elements[0] as ExcalidrawLinearElement,
|
h.elements[0] as ExcalidrawLinearElement,
|
||||||
@ -357,8 +361,10 @@ describe("Test Linear Elements", () => {
|
|||||||
// Move the element
|
// Move the element
|
||||||
drag(startPoint, endPoint);
|
drag(startPoint, endPoint);
|
||||||
|
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(14);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(9);
|
`13`,
|
||||||
|
);
|
||||||
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`9`);
|
||||||
|
|
||||||
expect([line.x, line.y]).toEqual([
|
expect([line.x, line.y]).toEqual([
|
||||||
points[0][0] + deltaX,
|
points[0][0] + deltaX,
|
||||||
@ -416,8 +422,10 @@ describe("Test Linear Elements", () => {
|
|||||||
lastSegmentMidpoint[1] + delta,
|
lastSegmentMidpoint[1] + delta,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(21);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(9);
|
`17`,
|
||||||
|
);
|
||||||
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`9`);
|
||||||
|
|
||||||
expect(line.points.length).toEqual(5);
|
expect(line.points.length).toEqual(5);
|
||||||
|
|
||||||
@ -457,8 +465,10 @@ describe("Test Linear Elements", () => {
|
|||||||
// Drag from first point
|
// Drag from first point
|
||||||
drag(hitCoords, [hitCoords[0] - delta, hitCoords[1] - delta]);
|
drag(hitCoords, [hitCoords[0] - delta, hitCoords[1] - delta]);
|
||||||
|
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(14);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(8);
|
`13`,
|
||||||
|
);
|
||||||
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`8`);
|
||||||
|
|
||||||
const newPoints = LinearElementEditor.getPointsGlobalCoordinates(line);
|
const newPoints = LinearElementEditor.getPointsGlobalCoordinates(line);
|
||||||
expect([newPoints[0][0], newPoints[0][1]]).toEqual([
|
expect([newPoints[0][0], newPoints[0][1]]).toEqual([
|
||||||
@ -484,8 +494,10 @@ describe("Test Linear Elements", () => {
|
|||||||
// Drag from first point
|
// Drag from first point
|
||||||
drag(hitCoords, [hitCoords[0] + delta, hitCoords[1] + delta]);
|
drag(hitCoords, [hitCoords[0] + delta, hitCoords[1] + delta]);
|
||||||
|
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(14);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(8);
|
`13`,
|
||||||
|
);
|
||||||
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`8`);
|
||||||
|
|
||||||
const newPoints = LinearElementEditor.getPointsGlobalCoordinates(line);
|
const newPoints = LinearElementEditor.getPointsGlobalCoordinates(line);
|
||||||
expect([newPoints[0][0], newPoints[0][1]]).toEqual([
|
expect([newPoints[0][0], newPoints[0][1]]).toEqual([
|
||||||
@ -519,8 +531,10 @@ describe("Test Linear Elements", () => {
|
|||||||
// delete 3rd point
|
// delete 3rd point
|
||||||
deletePoint(points[2]);
|
deletePoint(points[2]);
|
||||||
expect(line.points.length).toEqual(3);
|
expect(line.points.length).toEqual(3);
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(21);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(9);
|
`19`,
|
||||||
|
);
|
||||||
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`9`);
|
||||||
|
|
||||||
const newMidPoints = LinearElementEditor.getEditorMidPoints(
|
const newMidPoints = LinearElementEditor.getEditorMidPoints(
|
||||||
line,
|
line,
|
||||||
@ -566,8 +580,10 @@ describe("Test Linear Elements", () => {
|
|||||||
lastSegmentMidpoint[0] + delta,
|
lastSegmentMidpoint[0] + delta,
|
||||||
lastSegmentMidpoint[1] + delta,
|
lastSegmentMidpoint[1] + delta,
|
||||||
]);
|
]);
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(21);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(9);
|
`17`,
|
||||||
|
);
|
||||||
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`9`);
|
||||||
expect(line.points.length).toEqual(5);
|
expect(line.points.length).toEqual(5);
|
||||||
|
|
||||||
expect((h.elements[0] as ExcalidrawLinearElement).points)
|
expect((h.elements[0] as ExcalidrawLinearElement).points)
|
||||||
@ -642,8 +658,10 @@ describe("Test Linear Elements", () => {
|
|||||||
// Drag from first point
|
// Drag from first point
|
||||||
drag(hitCoords, [hitCoords[0] + delta, hitCoords[1] + delta]);
|
drag(hitCoords, [hitCoords[0] + delta, hitCoords[1] + delta]);
|
||||||
|
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(14);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(8);
|
`13`,
|
||||||
|
);
|
||||||
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`8`);
|
||||||
|
|
||||||
const newPoints = LinearElementEditor.getPointsGlobalCoordinates(line);
|
const newPoints = LinearElementEditor.getPointsGlobalCoordinates(line);
|
||||||
expect([newPoints[0][0], newPoints[0][1]]).toEqual([
|
expect([newPoints[0][0], newPoints[0][1]]).toEqual([
|
||||||
|
@ -42,8 +42,10 @@ describe("move element", () => {
|
|||||||
fireEvent.pointerMove(canvas, { clientX: 60, clientY: 70 });
|
fireEvent.pointerMove(canvas, { clientX: 60, clientY: 70 });
|
||||||
fireEvent.pointerUp(canvas);
|
fireEvent.pointerUp(canvas);
|
||||||
|
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(6);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(6);
|
`6`,
|
||||||
|
);
|
||||||
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`);
|
||||||
expect(h.state.selectionElement).toBeNull();
|
expect(h.state.selectionElement).toBeNull();
|
||||||
expect(h.elements.length).toEqual(1);
|
expect(h.elements.length).toEqual(1);
|
||||||
expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
|
expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
|
||||||
@ -57,8 +59,8 @@ describe("move element", () => {
|
|||||||
fireEvent.pointerMove(canvas, { clientX: 20, clientY: 40 });
|
fireEvent.pointerMove(canvas, { clientX: 20, clientY: 40 });
|
||||||
fireEvent.pointerUp(canvas);
|
fireEvent.pointerUp(canvas);
|
||||||
|
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(3);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`3`);
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(2);
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`2`);
|
||||||
expect(h.state.selectionElement).toBeNull();
|
expect(h.state.selectionElement).toBeNull();
|
||||||
expect(h.elements.length).toEqual(1);
|
expect(h.elements.length).toEqual(1);
|
||||||
expect([h.elements[0].x, h.elements[0].y]).toEqual([0, 40]);
|
expect([h.elements[0].x, h.elements[0].y]).toEqual([0, 40]);
|
||||||
@ -84,8 +86,10 @@ describe("move element", () => {
|
|||||||
// select the second rectangles
|
// select the second rectangles
|
||||||
new Pointer("mouse").clickOn(rectB);
|
new Pointer("mouse").clickOn(rectB);
|
||||||
|
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(24);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(19);
|
`21`,
|
||||||
|
);
|
||||||
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`19`);
|
||||||
expect(h.state.selectionElement).toBeNull();
|
expect(h.state.selectionElement).toBeNull();
|
||||||
expect(h.elements.length).toEqual(3);
|
expect(h.elements.length).toEqual(3);
|
||||||
expect(h.state.selectedElementIds[rectB.id]).toBeTruthy();
|
expect(h.state.selectedElementIds[rectB.id]).toBeTruthy();
|
||||||
@ -103,8 +107,8 @@ describe("move element", () => {
|
|||||||
Keyboard.keyDown(KEYS.ARROW_DOWN);
|
Keyboard.keyDown(KEYS.ARROW_DOWN);
|
||||||
|
|
||||||
// Check that the arrow size has been changed according to moving the rectangle
|
// Check that the arrow size has been changed according to moving the rectangle
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(3);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`3`);
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(3);
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`3`);
|
||||||
expect(h.state.selectionElement).toBeNull();
|
expect(h.state.selectionElement).toBeNull();
|
||||||
expect(h.elements.length).toEqual(3);
|
expect(h.elements.length).toEqual(3);
|
||||||
expect(h.state.selectedElementIds[rectB.id]).toBeTruthy();
|
expect(h.state.selectedElementIds[rectB.id]).toBeTruthy();
|
||||||
@ -130,8 +134,10 @@ describe("duplicate element on move when ALT is clicked", () => {
|
|||||||
fireEvent.pointerMove(canvas, { clientX: 60, clientY: 70 });
|
fireEvent.pointerMove(canvas, { clientX: 60, clientY: 70 });
|
||||||
fireEvent.pointerUp(canvas);
|
fireEvent.pointerUp(canvas);
|
||||||
|
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(6);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(6);
|
`6`,
|
||||||
|
);
|
||||||
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`);
|
||||||
expect(h.state.selectionElement).toBeNull();
|
expect(h.state.selectionElement).toBeNull();
|
||||||
expect(h.elements.length).toEqual(1);
|
expect(h.elements.length).toEqual(1);
|
||||||
expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
|
expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
|
||||||
@ -152,8 +158,8 @@ describe("duplicate element on move when ALT is clicked", () => {
|
|||||||
|
|
||||||
// TODO: This used to be 4, but binding made it go up to 5. Do we need
|
// TODO: This used to be 4, but binding made it go up to 5. Do we need
|
||||||
// that additional render?
|
// that additional render?
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(5);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`4`);
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(3);
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`3`);
|
||||||
expect(h.state.selectionElement).toBeNull();
|
expect(h.state.selectionElement).toBeNull();
|
||||||
expect(h.elements.length).toEqual(2);
|
expect(h.elements.length).toEqual(2);
|
||||||
|
|
||||||
|
@ -47,8 +47,8 @@ describe("remove shape in non linear elements", () => {
|
|||||||
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
|
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
fireEvent.pointerUp(canvas, { clientX: 30, clientY: 30 });
|
fireEvent.pointerUp(canvas, { clientX: 30, clientY: 30 });
|
||||||
|
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(5);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`5`);
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(5);
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`5`);
|
||||||
expect(h.elements.length).toEqual(0);
|
expect(h.elements.length).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -62,8 +62,8 @@ describe("remove shape in non linear elements", () => {
|
|||||||
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
|
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
fireEvent.pointerUp(canvas, { clientX: 30, clientY: 30 });
|
fireEvent.pointerUp(canvas, { clientX: 30, clientY: 30 });
|
||||||
|
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(5);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`5`);
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(5);
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`5`);
|
||||||
expect(h.elements.length).toEqual(0);
|
expect(h.elements.length).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -77,8 +77,8 @@ describe("remove shape in non linear elements", () => {
|
|||||||
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
|
fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 });
|
||||||
fireEvent.pointerUp(canvas, { clientX: 30, clientY: 30 });
|
fireEvent.pointerUp(canvas, { clientX: 30, clientY: 30 });
|
||||||
|
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(5);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`5`);
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(5);
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`5`);
|
||||||
expect(h.elements.length).toEqual(0);
|
expect(h.elements.length).toEqual(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -110,8 +110,8 @@ describe("multi point mode in linear elements", () => {
|
|||||||
key: KEYS.ENTER,
|
key: KEYS.ENTER,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(11);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`9`);
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(9);
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`9`);
|
||||||
expect(h.elements.length).toEqual(1);
|
expect(h.elements.length).toEqual(1);
|
||||||
|
|
||||||
const element = h.elements[0] as ExcalidrawLinearElement;
|
const element = h.elements[0] as ExcalidrawLinearElement;
|
||||||
@ -153,8 +153,8 @@ describe("multi point mode in linear elements", () => {
|
|||||||
fireEvent.keyDown(document, {
|
fireEvent.keyDown(document, {
|
||||||
key: KEYS.ENTER,
|
key: KEYS.ENTER,
|
||||||
});
|
});
|
||||||
expect(renderInteractiveScene).toHaveBeenCalledTimes(11);
|
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`9`);
|
||||||
expect(renderStaticScene).toHaveBeenCalledTimes(9);
|
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`9`);
|
||||||
expect(h.elements.length).toEqual(1);
|
expect(h.elements.length).toEqual(1);
|
||||||
|
|
||||||
const element = h.elements[0] as ExcalidrawLinearElement;
|
const element = h.elements[0] as ExcalidrawLinearElement;
|
||||||
|
@ -769,6 +769,24 @@ export const queryFocusableElements = (container: HTMLElement | null) => {
|
|||||||
: [];
|
: [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** use as a fallback after identity check (for perf reasons) */
|
||||||
|
const _defaultIsShallowComparatorFallback = (a: any, b: any): boolean => {
|
||||||
|
// consider two empty arrays equal
|
||||||
|
if (
|
||||||
|
Array.isArray(a) &&
|
||||||
|
Array.isArray(b) &&
|
||||||
|
a.length === 0 &&
|
||||||
|
b.length === 0
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return a === b;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether object/array is shallow equal.
|
||||||
|
* Considers empty object/arrays as equal (whether top-level or second-level).
|
||||||
|
*/
|
||||||
export const isShallowEqual = <
|
export const isShallowEqual = <
|
||||||
T extends Record<string, any>,
|
T extends Record<string, any>,
|
||||||
K extends readonly unknown[],
|
K extends readonly unknown[],
|
||||||
@ -796,10 +814,12 @@ export const isShallowEqual = <
|
|||||||
|
|
||||||
if (comparators && Array.isArray(comparators)) {
|
if (comparators && Array.isArray(comparators)) {
|
||||||
for (const key of comparators) {
|
for (const key of comparators) {
|
||||||
const ret = objA[key] === objB[key];
|
const ret =
|
||||||
|
objA[key] === objB[key] ||
|
||||||
|
_defaultIsShallowComparatorFallback(objA[key], objB[key]);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
if (debug) {
|
if (debug) {
|
||||||
console.info(
|
console.warn(
|
||||||
`%cisShallowEqual: ${key} not equal ->`,
|
`%cisShallowEqual: ${key} not equal ->`,
|
||||||
"color: #8B4000",
|
"color: #8B4000",
|
||||||
objA[key],
|
objA[key],
|
||||||
@ -818,9 +838,11 @@ export const isShallowEqual = <
|
|||||||
)?.[key as keyof T];
|
)?.[key as keyof T];
|
||||||
const ret = comparator
|
const ret = comparator
|
||||||
? comparator(objA[key], objB[key])
|
? comparator(objA[key], objB[key])
|
||||||
: objA[key] === objB[key];
|
: objA[key] === objB[key] ||
|
||||||
|
_defaultIsShallowComparatorFallback(objA[key], objB[key]);
|
||||||
|
|
||||||
if (!ret && debug) {
|
if (!ret && debug) {
|
||||||
console.info(
|
console.warn(
|
||||||
`%cisShallowEqual: ${key} not equal ->`,
|
`%cisShallowEqual: ${key} not equal ->`,
|
||||||
"color: #8B4000",
|
"color: #8B4000",
|
||||||
objA[key],
|
objA[key],
|
||||||
@ -960,3 +982,13 @@ export const cloneJSON = <T>(obj: T): T => JSON.parse(JSON.stringify(obj));
|
|||||||
export const isFiniteNumber = (value: any): value is number => {
|
export const isFiniteNumber = (value: any): value is number => {
|
||||||
return typeof value === "number" && Number.isFinite(value);
|
return typeof value === "number" && Number.isFinite(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const updateStable = <T extends any[] | Record<string, any>>(
|
||||||
|
prevValue: T,
|
||||||
|
nextValue: T,
|
||||||
|
) => {
|
||||||
|
if (isShallowEqual(prevValue, nextValue)) {
|
||||||
|
return prevValue;
|
||||||
|
}
|
||||||
|
return nextValue;
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user