From 4ef7cb7365820f38f66e76af8d502b643b0c965b Mon Sep 17 00:00:00 2001 From: David Luzar Date: Sun, 25 Apr 2021 14:09:38 +0200 Subject: [PATCH] feat: bump element version on z-index change (#3483) * feat: bump element version on z-index change * update snaps * update changelog --- src/element/mutateElement.ts | 11 ++++++ src/packages/excalidraw/CHANGELOG.md | 2 +- .../__snapshots__/contextmenu.test.tsx.snap | 32 ++++++++-------- src/zindex.ts | 38 ++++++++++++++----- 4 files changed, 57 insertions(+), 26 deletions(-) diff --git a/src/element/mutateElement.ts b/src/element/mutateElement.ts index 32795c33..172f1295 100644 --- a/src/element/mutateElement.ts +++ b/src/element/mutateElement.ts @@ -114,3 +114,14 @@ export const newElementWith = ( versionNonce: randomInteger(), }; }; + +/** + * Mutates element and updates `version` & `versionNonce`. + * + * NOTE: does not trigger re-render. + */ +export const bumpVersion = (element: Mutable) => { + element.version = element.version + 1; + element.versionNonce = randomInteger(); + return element; +}; diff --git a/src/packages/excalidraw/CHANGELOG.md b/src/packages/excalidraw/CHANGELOG.md index d3bce033..ceace674 100644 --- a/src/packages/excalidraw/CHANGELOG.md +++ b/src/packages/excalidraw/CHANGELOG.md @@ -44,9 +44,9 @@ Please add the latest change on the top under the correct section. ### Fixes +- Changing z-index of elements (sorting them below/above other elements) now updates their `version` and `versionNonce` (only applies to the selected elements). This fix will allow you account for z-index changes if you're syncing just the elements that changed (and not the whole scene) [#3483](https://github.com/excalidraw/excalidraw/pull/3483). - Only handle cut/paste events inside excalidraw [#3484](https://github.com/excalidraw/excalidraw/pull/3484). - Make history local to a given Excalidraw instance. This fixes a case where history was getting shared when you have multiple Excalidraw components on the same page [#3481](https://github.com/excalidraw/excalidraw/pull/3481). - - Use active Excalidraw component when editing text. This fixes a case where text editing was not working when you have multiple Excalidraw components on the same page [#3478](https://github.com/excalidraw/excalidraw/pull/3478). - When switching theme, apply it only to the active Excalidraw component. This fixes a case where the theme was getting applied to the first Excalidraw component if you had multiple Excalidraw components on the same page [#3446](https://github.com/excalidraw/excalidraw/pull/3446) diff --git a/src/tests/__snapshots__/contextmenu.test.tsx.snap b/src/tests/__snapshots__/contextmenu.test.tsx.snap index e2d3f3b6..421c8561 100644 --- a/src/tests/__snapshots__/contextmenu.test.tsx.snap +++ b/src/tests/__snapshots__/contextmenu.test.tsx.snap @@ -287,8 +287,8 @@ Object { "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", - "version": 2, - "versionNonce": 449462985, + "version": 3, + "versionNonce": 2019559783, "width": 20, "x": -10, "y": 0, @@ -456,8 +456,8 @@ Object { "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", - "version": 2, - "versionNonce": 449462985, + "version": 3, + "versionNonce": 2019559783, "width": 20, "x": -10, "y": 0, @@ -595,8 +595,8 @@ Object { "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", - "version": 2, - "versionNonce": 449462985, + "version": 3, + "versionNonce": 2019559783, "width": 20, "x": -10, "y": 0, @@ -764,8 +764,8 @@ Object { "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", - "version": 2, - "versionNonce": 449462985, + "version": 3, + "versionNonce": 2019559783, "width": 20, "x": -10, "y": 0, @@ -2531,8 +2531,8 @@ Object { "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", - "version": 2, - "versionNonce": 401146281, + "version": 3, + "versionNonce": 2019559783, "width": 20, "x": 20, "y": 30, @@ -2703,8 +2703,8 @@ Object { "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", - "version": 2, - "versionNonce": 401146281, + "version": 3, + "versionNonce": 2019559783, "width": 20, "x": 20, "y": 30, @@ -2839,8 +2839,8 @@ Object { "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", - "version": 2, - "versionNonce": 401146281, + "version": 3, + "versionNonce": 2019559783, "width": 20, "x": 20, "y": 30, @@ -3011,8 +3011,8 @@ Object { "strokeStyle": "solid", "strokeWidth": 1, "type": "rectangle", - "version": 2, - "versionNonce": 401146281, + "version": 3, + "versionNonce": 2019559783, "width": 20, "x": 20, "y": 30, diff --git a/src/zindex.ts b/src/zindex.ts index 05571410..ac9cf7d0 100644 --- a/src/zindex.ts +++ b/src/zindex.ts @@ -1,3 +1,4 @@ +import { bumpVersion } from "./element/mutateElement"; import { ExcalidrawElement } from "./element/types"; import { getElementsInGroup } from "./groups"; import { AppState } from "./types"; @@ -51,7 +52,7 @@ const toContiguousGroups = (array: number[]) => { */ const getTargetIndex = ( appState: AppState, - elements: ExcalidrawElement[], + elements: readonly ExcalidrawElement[], boundaryIndex: number, direction: "left" | "right", ) => { @@ -117,12 +118,24 @@ const getTargetIndex = ( return candidateIndex; }; +const getTargetElementsMap = ( + elements: readonly ExcalidrawElement[], + indices: number[], +) => { + return indices.reduce((acc, index) => { + const element = elements[index]; + acc[element.id] = element; + return acc; + }, {} as Record); +}; + const shiftElements = ( appState: AppState, - elements: ExcalidrawElement[], + elements: readonly ExcalidrawElement[], direction: "left" | "right", ) => { const indicesToMove = getIndicesToMove(elements, appState); + const targetElementsMap = getTargetElementsMap(elements, indicesToMove); let groupedIndices = toContiguousGroups(indicesToMove); if (direction === "right") { @@ -175,7 +188,12 @@ const shiftElements = ( ]; }); - return elements; + return elements.map((element) => { + if (targetElementsMap[element.id]) { + return bumpVersion(element); + } + return element; + }); }; const shiftElementsToEnd = ( @@ -184,7 +202,7 @@ const shiftElementsToEnd = ( direction: "left" | "right", ) => { const indicesToMove = getIndicesToMove(elements, appState); - const targetElements: ExcalidrawElement[] = []; + const targetElementsMap = getTargetElementsMap(elements, indicesToMove); const displacedElements: ExcalidrawElement[] = []; let leadingIndex: number; @@ -222,13 +240,15 @@ const shiftElementsToEnd = ( } for (let index = leadingIndex; index < trailingIndex + 1; index++) { - if (indicesToMove.includes(index)) { - targetElements.push(elements[index]); - } else { + if (!indicesToMove.includes(index)) { displacedElements.push(elements[index]); } } + const targetElements = Object.values(targetElementsMap).map((element) => { + return bumpVersion(element); + }); + const leadingElements = elements.slice(0, leadingIndex); const trailingElements = elements.slice(trailingIndex + 1); @@ -254,14 +274,14 @@ export const moveOneLeft = ( elements: readonly ExcalidrawElement[], appState: AppState, ) => { - return shiftElements(appState, elements.slice(), "left"); + return shiftElements(appState, elements, "left"); }; export const moveOneRight = ( elements: readonly ExcalidrawElement[], appState: AppState, ) => { - return shiftElements(appState, elements.slice(), "right"); + return shiftElements(appState, elements, "right"); }; export const moveAllLeft = (