From 0d7c8d832aa4be98e71d71934cb431637dee844b Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Mon, 29 Jul 2024 18:11:34 +0800 Subject: [PATCH 01/16] PoC for a new element canvas --- .../excalidraw/actions/actionFinalize.tsx | 2 + packages/excalidraw/components/App.tsx | 44 +++++++++++-- .../components/canvases/NewElementCanvas.tsx | 58 ++++++++++++++++ packages/excalidraw/locales/en.json | 1 + .../renderer/renderNewElementScene.ts | 66 +++++++++++++++++++ packages/excalidraw/scene/types.ts | 12 ++++ packages/excalidraw/types.ts | 1 + 7 files changed, 180 insertions(+), 4 deletions(-) create mode 100644 packages/excalidraw/components/canvases/NewElementCanvas.tsx create mode 100644 packages/excalidraw/renderer/renderNewElementScene.ts diff --git a/packages/excalidraw/actions/actionFinalize.tsx b/packages/excalidraw/actions/actionFinalize.tsx index 15956b3a39ed7..ca91931a3cb70 100644 --- a/packages/excalidraw/actions/actionFinalize.tsx +++ b/packages/excalidraw/actions/actionFinalize.tsx @@ -74,6 +74,8 @@ export const actionFinalize = register({ ? appState.multiElement : appState.editingElement?.type === "freedraw" ? appState.editingElement + : appState.draggingElement?.type === "freedraw" + ? appState.draggingElement : null; if (multiPointElement) { diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 6f1ac7ffd386c..ba0d11572b52d 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -427,6 +427,7 @@ import { getShortcutFromShortcutName } from "../actions/shortcuts"; import { actionTextAutoResize } from "../actions/actionTextAutoResize"; import { getVisibleSceneBounds } from "../element/bounds"; import { isMaybeMermaidDefinition } from "../mermaid"; +import NewElementCanvas from "./canvases/NewElementCanvas"; const AppContext = React.createContext(null!); const AppPropsContext = React.createContext(null!); @@ -523,6 +524,7 @@ const gesture: Gesture = { class App extends React.Component { canvas: AppClassProperties["canvas"]; interactiveCanvas: AppClassProperties["interactiveCanvas"] = null; + newElementCanvas: AppClassProperties["newElementCanvas"] = null; rc: RoughCanvas; unmounted: boolean = false; actionManager: ActionManager; @@ -1684,6 +1686,25 @@ class App extends React.Component { elementsPendingErasure: this.elementsPendingErasure, }} /> + { pointerDownState.origin, this.scene.getNonDeletedElementsMap(), ); - this.scene.insertElement(element); + // this.scene.insertElement(element); this.setState({ draggingElement: element, - editingElement: element, + // editingElement: element, startBoundElement: boundElement, suggestedBindings: [], }); @@ -7141,7 +7162,7 @@ class App extends React.Component { draggingElement: element, }); } else { - this.scene.insertElement(element); + // this.scene.insertElement(element); this.setState({ multiElement: null, draggingElement: element, @@ -7644,10 +7665,15 @@ class App extends React.Component { ? draggingElement.pressures : [...draggingElement.pressures, event.pressure]; - mutateElement(draggingElement, { + const _draggingElement = newElementWith(draggingElement, { points: [...points, [dx, dy]], pressures, }); + + // ANCHOR + this.setState({ + draggingElement: _draggingElement, + }); } } else if (isLinearElement(draggingElement)) { pointerDownState.drag.hasOccurred = true; @@ -7957,6 +7983,10 @@ class App extends React.Component { childEvent, ); + if (draggingElement && draggingElement.type !== "selection") { + this.scene.insertElement(draggingElement); + } + if (draggingElement?.type === "freedraw") { const pointerCoords = viewportCoordsToSceneCoords( childEvent, @@ -9199,6 +9229,12 @@ class App extends React.Component { } }; + private handleNewElementCanvasRef = (canvas: HTMLCanvasElement | null) => { + if (canvas !== null) { + this.newElementCanvas = canvas; + } + }; + private handleAppOnDrop = async (event: React.DragEvent) => { // must be retrieved first, in the same frame const { file, fileHandle } = await getFileFromEvent(event); diff --git a/packages/excalidraw/components/canvases/NewElementCanvas.tsx b/packages/excalidraw/components/canvases/NewElementCanvas.tsx new file mode 100644 index 0000000000000..a463a201d49c9 --- /dev/null +++ b/packages/excalidraw/components/canvases/NewElementCanvas.tsx @@ -0,0 +1,58 @@ +import { useEffect } from "react"; +import type { + ExcalidrawElement, + NonDeletedSceneElementsMap, +} from "../../element/types"; +import { t } from "../../i18n"; +import type { AppState } from "../../types"; +import type { + RenderableElementsMap, + StaticCanvasRenderConfig, +} from "../../scene/types"; +import type { RoughCanvas } from "roughjs/bin/canvas"; +import { renderNewElementScene } from "../../renderer/renderNewElementScene"; + +interface NewElementCanvasProps { + newElement: ExcalidrawElement | null; + canvas: HTMLCanvasElement | null; + appState: AppState; + elementsMap: RenderableElementsMap; + allElementsMap: NonDeletedSceneElementsMap; + scale: number; + rc: RoughCanvas; + renderConfig: StaticCanvasRenderConfig; + handleCanvasRef: (canvas: HTMLCanvasElement | null) => void; +} + +const NewElementCanvas = (props: NewElementCanvasProps) => { + // handle collab + + useEffect(() => { + renderNewElementScene({ + canvas: props.canvas, + scale: props.scale, + newElement: props.newElement, + elementsMap: props.elementsMap, + allElementsMap: props.allElementsMap, + rc: props.rc, + renderConfig: props.renderConfig, + appState: props.appState, + }); + }); + + return ( + + {t("labels.newElementCanvas")} + + ); +}; + +export default NewElementCanvas; diff --git a/packages/excalidraw/locales/en.json b/packages/excalidraw/locales/en.json index 2fe4418105a4c..f71be46f67eea 100644 --- a/packages/excalidraw/locales/en.json +++ b/packages/excalidraw/locales/en.json @@ -74,6 +74,7 @@ "canvasColors": "Used on canvas", "canvasBackground": "Canvas background", "drawingCanvas": "Drawing canvas", + "newElementCanvas": "New element canvas", "clearCanvas": "Clear canvas", "layers": "Layers", "actions": "Actions", diff --git a/packages/excalidraw/renderer/renderNewElementScene.ts b/packages/excalidraw/renderer/renderNewElementScene.ts new file mode 100644 index 0000000000000..caa7f581c7d21 --- /dev/null +++ b/packages/excalidraw/renderer/renderNewElementScene.ts @@ -0,0 +1,66 @@ +import type { NewElementSceneRenderConfig } from "../scene/types"; +import { throttleRAF } from "../utils"; +import { bootstrapCanvas, getNormalizedCanvasDimensions } from "./helpers"; +import { renderElement } from "./renderElement"; + +const _renderNewElementScene = ({ + canvas, + rc, + newElement, + elementsMap, + allElementsMap, + scale, + appState, + renderConfig, +}: NewElementSceneRenderConfig) => { + if (canvas) { + const [normalizedWidth, normalizedHeight] = getNormalizedCanvasDimensions( + canvas, + scale, + ); + + const context = bootstrapCanvas({ + canvas, + scale, + normalizedWidth, + normalizedHeight, + }); + + // Apply zoom + context.save(); + context.scale(appState.zoom.value, appState.zoom.value); + + if (newElement && newElement.type !== "selection") { + renderElement( + newElement, + elementsMap, + allElementsMap, + rc, + context, + renderConfig, + appState, + ); + } else { + context.clearRect(0, 0, normalizedWidth, normalizedHeight); + } + } +}; + +export const renderNewElementSceneThrottled = throttleRAF( + (config: NewElementSceneRenderConfig) => { + _renderNewElementScene(config); + }, + { trailing: true }, +); + +export const renderNewElementScene = ( + renderConfig: NewElementSceneRenderConfig, + throttle?: boolean, +) => { + if (throttle) { + renderNewElementSceneThrottled(renderConfig); + return; + } + + _renderNewElementScene(renderConfig); +}; diff --git a/packages/excalidraw/scene/types.ts b/packages/excalidraw/scene/types.ts index 6f478b3106aa0..85c253149bb2a 100644 --- a/packages/excalidraw/scene/types.ts +++ b/packages/excalidraw/scene/types.ts @@ -90,6 +90,18 @@ export type InteractiveSceneRenderConfig = { callback: (data: RenderInteractiveSceneCallback) => void; }; +export type NewElementSceneRenderConfig = { + canvas: HTMLCanvasElement | null; + rc: RoughCanvas; + newElement: ExcalidrawElement | null; + elementsMap: RenderableElementsMap; + allElementsMap: NonDeletedSceneElementsMap; + scale: number; + // TODO: narrow down so that unrelated state is not taken into consideration + appState: AppState; + renderConfig: StaticCanvasRenderConfig; +}; + export type SceneScroll = { scrollX: number; scrollY: number; diff --git a/packages/excalidraw/types.ts b/packages/excalidraw/types.ts index e45d5a69257a6..ded7dbea6db19 100644 --- a/packages/excalidraw/types.ts +++ b/packages/excalidraw/types.ts @@ -593,6 +593,7 @@ export type AppProps = Merge< export type AppClassProperties = { props: AppProps; interactiveCanvas: HTMLCanvasElement | null; + newElementCanvas: HTMLCanvasElement | null; /** static canvas */ canvas: HTMLCanvasElement; focusContainer(): void; From cbde10655a212fd15eebfc87e09982da05866e94 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Wed, 7 Aug 2024 16:31:16 +0800 Subject: [PATCH 02/16] add optional triggerUpdate flag --- packages/excalidraw/scene/Scene.ts | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/packages/excalidraw/scene/Scene.ts b/packages/excalidraw/scene/Scene.ts index 813b3cbf53f30..83375e34f82c5 100644 --- a/packages/excalidraw/scene/Scene.ts +++ b/packages/excalidraw/scene/Scene.ts @@ -285,7 +285,7 @@ class Scene { return didChange; } - replaceAllElements(nextElements: ElementsMapOrArray) { + replaceAllElements(nextElements: ElementsMapOrArray, triggerUpdate = true) { const _nextElements = // ts doesn't like `Array.isArray` of `instanceof Map` nextElements instanceof Array @@ -311,7 +311,9 @@ class Scene { this.frames = nextFrameLikes; this.nonDeletedFramesLikes = getNonDeletedElements(this.frames).elements; - this.triggerUpdate(); + if (triggerUpdate) { + this.triggerUpdate(); + } } triggerUpdate() { @@ -358,7 +360,11 @@ class Scene { this.callbacks.clear(); } - insertElementAtIndex(element: ExcalidrawElement, index: number) { + insertElementAtIndex( + element: ExcalidrawElement, + index: number, + triggerUpdate = true, + ) { if (!Number.isFinite(index) || index < 0) { throw new Error( "insertElementAtIndex can only be called with index >= 0", @@ -373,10 +379,14 @@ class Scene { syncMovedIndices(nextElements, arrayToMap([element])); - this.replaceAllElements(nextElements); + this.replaceAllElements(nextElements, triggerUpdate); } - insertElementsAtIndex(elements: ExcalidrawElement[], index: number) { + insertElementsAtIndex( + elements: ExcalidrawElement[], + index: number, + triggerUpdate = true, + ) { if (!Number.isFinite(index) || index < 0) { throw new Error( "insertElementAtIndex can only be called with index >= 0", @@ -391,23 +401,23 @@ class Scene { syncMovedIndices(nextElements, arrayToMap(elements)); - this.replaceAllElements(nextElements); + this.replaceAllElements(nextElements, triggerUpdate); } - insertElement = (element: ExcalidrawElement) => { + insertElement = (element: ExcalidrawElement, triggerUpdate = true) => { const index = element.frameId ? this.getElementIndex(element.frameId) : this.elements.length; - this.insertElementAtIndex(element, index); + this.insertElementAtIndex(element, index, triggerUpdate); }; - insertElements = (elements: ExcalidrawElement[]) => { + insertElements = (elements: ExcalidrawElement[], triggerUpdate = true) => { const index = elements[0].frameId ? this.getElementIndex(elements[0].frameId) : this.elements.length; - this.insertElementsAtIndex(elements, index); + this.insertElementsAtIndex(elements, index, triggerUpdate); }; getElementIndex(elementId: string) { From aa9c82239a97de4354e7d3469d3fb67ed8ff461e Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Wed, 7 Aug 2024 17:53:18 +0800 Subject: [PATCH 03/16] do insert element to scene on creation --- packages/excalidraw/components/App.tsx | 226 +++++++++++++------- packages/excalidraw/element/dragElements.ts | 66 ++++-- 2 files changed, 196 insertions(+), 96 deletions(-) diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 1047830f9ea6f..fd6d1b88382d0 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -5361,8 +5361,16 @@ class App extends React.Component { lastPoint[1], ) >= LINE_CONFIRM_THRESHOLD ) { - mutateElement(multiElement, { - points: [...points, [scenePointerX - rx, scenePointerY - ry]], + mutateElement( + multiElement, + { + points: [...points, [scenePointerX - rx, scenePointerY - ry]], + }, + false, + ); + this.setState({ + multiElement, + newElement: multiElement, }); } else { setCursor(this.interactiveCanvas, CURSOR_TYPE.POINTER); @@ -5380,8 +5388,16 @@ class App extends React.Component { ) < LINE_CONFIRM_THRESHOLD ) { setCursor(this.interactiveCanvas, CURSOR_TYPE.POINTER); - mutateElement(multiElement, { - points: points.slice(0, -1), + mutateElement( + multiElement, + { + points: points.slice(0, -1), + }, + false, + ); + this.setState({ + multiElement, + newElement: multiElement, }); } else { const [gridX, gridY] = getGridPoint( @@ -5432,14 +5448,22 @@ class App extends React.Component { ); } else { // update last uncommitted point - mutateElement(multiElement, { - points: [ - ...points.slice(0, -1), - [ - lastCommittedX + dxFromLastCommitted, - lastCommittedY + dyFromLastCommitted, + mutateElement( + multiElement, + { + points: [ + ...points.slice(0, -1), + [ + lastCommittedX + dxFromLastCommitted, + lastCommittedY + dyFromLastCommitted, + ], ], - ], + }, + false, + ); + this.setState({ + multiElement, + newElement: multiElement, }); } } @@ -6027,7 +6051,6 @@ class App extends React.Component { this.setState({ newElement: pendingImageElement as ExcalidrawNonSelectionElement, - editingElement: pendingImageElement, pendingImageElementId: null, multiElement: null, }); @@ -6862,17 +6885,21 @@ class App extends React.Component { ? element.pressures : [...element.pressures, event.pressure]; - mutateElement(element, { - points: [[0, 0]], - pressures, - }); + mutateElement( + element, + { + points: [[0, 0]], + pressures, + }, + false, + ); const boundElement = getHoveredElementForBinding( pointerDownState.origin, this.scene.getNonDeletedElements(), this.scene.getNonDeletedElementsMap(), ); - // this.scene.insertElement(element); + this.scene.insertElement(element, false); this.setState({ newElement: element, startBoundElement: boundElement, @@ -7031,10 +7058,14 @@ class App extends React.Component { multiElement.type === "line" && isPathALoop(multiElement.points, this.state.zoom.value) ) { - mutateElement(multiElement, { - lastCommittedPoint: - multiElement.points[multiElement.points.length - 1], - }); + mutateElement( + multiElement, + { + lastCommittedPoint: + multiElement.points[multiElement.points.length - 1], + }, + false, + ); this.actionManager.executeAction(actionFinalize); return; } @@ -7063,7 +7094,7 @@ class App extends React.Component { lastCommittedPoint[1], ) < LINE_CONFIRM_THRESHOLD ) { - this.actionManager.executeAction(actionFinalize); + // this.actionManager.executeAction(actionFinalize); return; } @@ -7078,9 +7109,14 @@ class App extends React.Component { })); // clicking outside commit zone → update reference for last committed // point - mutateElement(multiElement, { - lastCommittedPoint: multiElement.points[multiElement.points.length - 1], - }); + mutateElement( + multiElement, + { + lastCommittedPoint: + multiElement.points[multiElement.points.length - 1], + }, + false, + ); setCursor(this.interactiveCanvas, CURSOR_TYPE.POINTER); } else { const [gridX, gridY] = getGridPoint( @@ -7161,9 +7197,13 @@ class App extends React.Component { ), }; }); - mutateElement(element, { - points: [...element.points, [0, 0]], - }); + mutateElement( + element, + { + points: [...element.points, [0, 0]], + }, + false, + ); const boundElement = getHoveredElementForBinding( pointerDownState.origin, this.scene.getNonDeletedElements(), @@ -7171,10 +7211,9 @@ class App extends React.Component { isElbowArrow(element), ); - this.scene.insertElement(element); + this.scene.insertElement(element, false); this.setState({ newElement: element, - editingElement: element, startBoundElement: boundElement, suggestedBindings: [], }); @@ -7249,7 +7288,7 @@ class App extends React.Component { selectionElement: element, }); } else { - // this.scene.insertElement(element); + this.scene.insertElement(element, false); this.setState({ multiElement: null, newElement: element, @@ -7765,9 +7804,17 @@ class App extends React.Component { ? newElement.pressures : [...newElement.pressures, event.pressure]; - mutateElement(newElement, { - points: [...points, [dx, dy]], - pressures, + mutateElement( + newElement, + { + points: [...points, [dx, dy]], + pressures, + }, + false, + ); + + this.setState({ + newElement, }); } } else if (isLinearElement(newElement)) { @@ -7786,8 +7833,15 @@ class App extends React.Component { } if (points.length === 1) { - mutateElement(newElement, { - points: [...points, [dx, dy]], + mutateElement( + newElement, + { + points: [...points, [dx, dy]], + }, + false, + ); + this.setState({ + newElement, }); } else if (points.length > 1 && isElbowArrow(newElement)) { mutateElbowArrow( @@ -7801,8 +7855,16 @@ class App extends React.Component { }, ); } else if (points.length === 2) { - mutateElement(newElement, { - points: [...points.slice(0, -1), [dx, dy]], + mutateElement( + newElement, + { + points: [...points.slice(0, -1), [dx, dy]], + }, + false, + ); + + this.setState({ + newElement, }); } @@ -7817,7 +7879,7 @@ class App extends React.Component { } else { pointerDownState.lastCoords.x = pointerCoords.x; pointerDownState.lastCoords.y = pointerCoords.y; - this.maybeDragNewGenericElement(pointerDownState, event); + this.maybeDragNewGenericElement(pointerDownState, event, false); } } @@ -8157,15 +8219,22 @@ class App extends React.Component { ); if (!pointerDownState.drag.hasOccurred && newElement && !multiElement) { - mutateElement(newElement, { - points: [ - ...newElement.points, - [pointerCoords.x - newElement.x, pointerCoords.y - newElement.y], - ], - }); + mutateElement( + newElement, + { + points: [ + ...newElement.points, + [ + pointerCoords.x - newElement.x, + pointerCoords.y - newElement.y, + ], + ], + }, + false, + ); this.setState({ multiElement: newElement, - editingElement: this.state.newElement, + newElement, }); } else if (pointerDownState.drag.hasOccurred && !multiElement) { if ( @@ -8202,6 +8271,8 @@ class App extends React.Component { newElement: null, })); } + // so that the scene gets rendered again to display the newly drawn linear as well + this.scene.triggerUpdate(); } return; } @@ -8266,6 +8337,8 @@ class App extends React.Component { if (newElement) { mutateElement(newElement, getNormalizedDimensions(newElement)); + // the above does not guarantee the scene to be rendered again, hence the trigger below + this.scene.triggerUpdate(); } if (pointerDownState.drag.hasOccurred) { @@ -9576,23 +9649,25 @@ class App extends React.Component { private maybeDragNewGenericElement = ( pointerDownState: PointerDownState, event: MouseEvent | KeyboardEvent, + informMutation = true, ): void => { const selectionElement = this.state.selectionElement; const pointerCoords = pointerDownState.lastCoords; if (selectionElement && this.state.activeTool.type !== "eraser") { - dragNewElement( - selectionElement, - this.state.activeTool.type, - pointerDownState.origin.x, - pointerDownState.origin.y, - pointerCoords.x, - pointerCoords.y, - distance(pointerDownState.origin.x, pointerCoords.x), - distance(pointerDownState.origin.y, pointerCoords.y), - shouldMaintainAspectRatio(event), - shouldResizeFromCenter(event), - this.state.zoom.value, - ); + dragNewElement({ + newElement: selectionElement, + elementType: this.state.activeTool.type, + originX: pointerDownState.origin.x, + originY: pointerDownState.origin.y, + x: pointerCoords.x, + y: pointerCoords.y, + width: distance(pointerDownState.origin.x, pointerCoords.x), + height: distance(pointerDownState.origin.y, pointerCoords.y), + shouldMaintainAspectRatio: shouldMaintainAspectRatio(event), + shouldResizeFromCenter: shouldResizeFromCenter(event), + zoom: this.state.zoom.value, + informMutation, + }); return; } @@ -9641,23 +9716,28 @@ class App extends React.Component { snapLines, }); - dragNewElement( + dragNewElement({ newElement, - this.state.activeTool.type, - pointerDownState.originInGrid.x, - pointerDownState.originInGrid.y, - gridX, - gridY, - distance(pointerDownState.originInGrid.x, gridX), - distance(pointerDownState.originInGrid.y, gridY), - isImageElement(newElement) + elementType: this.state.activeTool.type, + originX: pointerDownState.originInGrid.x, + originY: pointerDownState.originInGrid.y, + x: gridX, + y: gridY, + width: distance(pointerDownState.originInGrid.x, gridX), + height: distance(pointerDownState.originInGrid.y, gridY), + shouldMaintainAspectRatio: isImageElement(newElement) ? !shouldMaintainAspectRatio(event) : shouldMaintainAspectRatio(event), - shouldResizeFromCenter(event), - this.state.zoom.value, - aspectRatio, - this.state.originSnapOffset, - ); + shouldResizeFromCenter: shouldResizeFromCenter(event), + zoom: this.state.zoom.value, + widthAspectRatio: aspectRatio, + originOffset: this.state.originSnapOffset, + informMutation, + }); + + this.setState({ + newElement, + }); // highlight elements that are to be added to frames on frames creation if ( diff --git a/packages/excalidraw/element/dragElements.ts b/packages/excalidraw/element/dragElements.ts index e0b5365a9d4c9..cf93dba7ae410 100644 --- a/packages/excalidraw/element/dragElements.ts +++ b/packages/excalidraw/element/dragElements.ts @@ -159,26 +159,42 @@ export const getDragOffsetXY = ( return [x - x1, y - y1]; }; -export const dragNewElement = ( - newElement: NonDeletedExcalidrawElement, - elementType: AppState["activeTool"]["type"], - originX: number, - originY: number, - x: number, - y: number, - width: number, - height: number, - shouldMaintainAspectRatio: boolean, - shouldResizeFromCenter: boolean, - zoom: NormalizedZoomValue, +export const dragNewElement = ({ + newElement, + elementType, + originX, + originY, + x, + y, + width, + height, + shouldMaintainAspectRatio, + shouldResizeFromCenter, + zoom, + widthAspectRatio = null, + originOffset = null, + informMutation = true, +}: { + newElement: NonDeletedExcalidrawElement; + elementType: AppState["activeTool"]["type"]; + originX: number; + originY: number; + x: number; + y: number; + width: number; + height: number; + shouldMaintainAspectRatio: boolean; + shouldResizeFromCenter: boolean; + zoom: NormalizedZoomValue; /** whether to keep given aspect ratio when `isResizeWithSidesSameLength` is true */ - widthAspectRatio?: number | null, - originOffset: { + widthAspectRatio?: number | null; + originOffset?: { x: number; y: number; - } | null = null, -) => { + } | null; + informMutation?: boolean; +}) => { if (shouldMaintainAspectRatio && newElement.type !== "selection") { if (widthAspectRatio) { height = width / widthAspectRatio; @@ -242,12 +258,16 @@ export const dragNewElement = ( } if (width !== 0 && height !== 0) { - mutateElement(newElement, { - x: newX + (originOffset?.x ?? 0), - y: newY + (originOffset?.y ?? 0), - width, - height, - ...textAutoResize, - }); + mutateElement( + newElement, + { + x: newX + (originOffset?.x ?? 0), + y: newY + (originOffset?.y ?? 0), + width, + height, + ...textAutoResize, + }, + informMutation, + ); } }; From a0a04a63c4188d21f5433b6cfba95839a27d7ddd Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Thu, 8 Aug 2024 15:03:34 +0800 Subject: [PATCH 04/16] extend to elbow arrow as well --- packages/excalidraw/components/App.tsx | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index fd6d1b88382d0..ba98fac74f370 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -5444,6 +5444,7 @@ class App extends React.Component { undefined, { isDragging: true, + informMutation: false, }, ); } else { @@ -5461,11 +5462,11 @@ class App extends React.Component { }, false, ); - this.setState({ - multiElement, - newElement: multiElement, - }); } + this.setState({ + multiElement, + newElement: multiElement, + }); } return; @@ -7094,7 +7095,7 @@ class App extends React.Component { lastCommittedPoint[1], ) < LINE_CONFIRM_THRESHOLD ) { - // this.actionManager.executeAction(actionFinalize); + this.actionManager.executeAction(actionFinalize); return; } @@ -7840,9 +7841,6 @@ class App extends React.Component { }, false, ); - this.setState({ - newElement, - }); } else if (points.length > 1 && isElbowArrow(newElement)) { mutateElbowArrow( newElement, @@ -7852,6 +7850,7 @@ class App extends React.Component { undefined, { isDragging: true, + informMutation: false, }, ); } else if (points.length === 2) { @@ -7862,12 +7861,12 @@ class App extends React.Component { }, false, ); - - this.setState({ - newElement, - }); } + this.setState({ + newElement, + }); + if (isBindingElement(newElement, false)) { // When creating a linear element by dragging this.maybeSuggestBindingsForLinearElementAtCoords( From 8671c55dbee32e1f30bd9a2025b55bcd2450b1b5 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Thu, 8 Aug 2024 15:32:56 +0800 Subject: [PATCH 05/16] opt new el canvas render --- packages/excalidraw/components/App.tsx | 41 ++++++++++--------- .../components/canvases/NewElementCanvas.tsx | 10 +---- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index ba98fac74f370..de1b8b5a661e8 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -1679,25 +1679,28 @@ class App extends React.Component { elementsPendingErasure: this.elementsPendingErasure, }} /> - + {this.state.newElement && ( + + )} { - // handle collab - useEffect(() => { renderNewElementScene({ canvas: props.canvas, scale: props.scale, - newElement: props.newElement, + newElement: props.appState.newElement, elementsMap: props.elementsMap, allElementsMap: props.allElementsMap, rc: props.rc, From 0f5f76cfa4ef122d2ffbe6275b1772ead5c01867 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Thu, 8 Aug 2024 15:47:07 +0800 Subject: [PATCH 06/16] update tests & snapshots --- .../__snapshots__/contextmenu.test.tsx.snap | 96 ++++++++--------- .../__snapshots__/dragCreate.test.tsx.snap | 10 +- .../tests/__snapshots__/history.test.tsx.snap | 60 +++++------ .../tests/__snapshots__/move.test.tsx.snap | 18 ++-- .../multiPointCreate.test.tsx.snap | 4 +- .../regressionTests.test.tsx.snap | 100 +++++++++--------- .../__snapshots__/selection.test.tsx.snap | 10 +- packages/excalidraw/tests/dragCreate.test.tsx | 30 +++--- packages/excalidraw/tests/move.test.tsx | 12 +-- .../tests/multiPointCreate.test.tsx | 14 +-- packages/excalidraw/tests/selection.test.tsx | 20 ++-- 11 files changed, 187 insertions(+), 187 deletions(-) diff --git a/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap index 4bad1516e1be3..c216027e3a49a 100644 --- a/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap @@ -1123,7 +1123,7 @@ exports[`contextMenu element > selecting 'Add to library' in context menu adds e "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 1150084233, + "versionNonce": 2019559783, "width": 20, "x": -10, "y": 0, @@ -1197,7 +1197,7 @@ History { exports[`contextMenu element > selecting 'Add to library' in context menu adds element to library > [end of test] number of elements 1`] = `1`; -exports[`contextMenu element > selecting 'Add to library' in context menu adds element to library > [end of test] number of renders 1`] = `6`; +exports[`contextMenu element > selecting 'Add to library' in context menu adds element to library > [end of test] number of renders 1`] = `4`; exports[`contextMenu element > selecting 'Bring forward' in context menu brings element forward > [end of test] appState 1`] = ` { @@ -1327,14 +1327,14 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings "roundness": { "type": 3, }, - "seed": 1014066025, + "seed": 1116226695, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 1604849351, + "versionNonce": 238820263, "width": 20, "x": 20, "y": 30, @@ -1368,7 +1368,7 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 23633383, + "versionNonce": 1604849351, "width": 20, "x": -10, "y": 0, @@ -1525,7 +1525,7 @@ History { exports[`contextMenu element > selecting 'Bring forward' in context menu brings element forward > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > selecting 'Bring forward' in context menu brings element forward > [end of test] number of renders 1`] = `12`; +exports[`contextMenu element > selecting 'Bring forward' in context menu brings element forward > [end of test] number of renders 1`] = `8`; exports[`contextMenu element > selecting 'Bring to front' in context menu brings element to front > [end of test] appState 1`] = ` { @@ -1655,14 +1655,14 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings "roundness": { "type": 3, }, - "seed": 1014066025, + "seed": 1116226695, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 1604849351, + "versionNonce": 238820263, "width": 20, "x": 20, "y": 30, @@ -1696,7 +1696,7 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 23633383, + "versionNonce": 1604849351, "width": 20, "x": -10, "y": 0, @@ -1853,7 +1853,7 @@ History { exports[`contextMenu element > selecting 'Bring to front' in context menu brings element to front > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > selecting 'Bring to front' in context menu brings element to front > [end of test] number of renders 1`] = `12`; +exports[`contextMenu element > selecting 'Bring to front' in context menu brings element to front > [end of test] number of renders 1`] = `8`; exports[`contextMenu element > selecting 'Copy styles' in context menu copies styles > [end of test] appState 1`] = ` { @@ -1992,7 +1992,7 @@ exports[`contextMenu element > selecting 'Copy styles' in context menu copies st "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 1150084233, + "versionNonce": 2019559783, "width": 20, "x": -10, "y": 0, @@ -2066,7 +2066,7 @@ History { exports[`contextMenu element > selecting 'Copy styles' in context menu copies styles > [end of test] number of elements 1`] = `1`; -exports[`contextMenu element > selecting 'Copy styles' in context menu copies styles > [end of test] number of renders 1`] = `6`; +exports[`contextMenu element > selecting 'Copy styles' in context menu copies styles > [end of test] number of renders 1`] = `4`; exports[`contextMenu element > selecting 'Delete' in context menu deletes element > [end of test] appState 1`] = ` { @@ -2201,7 +2201,7 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 1014066025, + "versionNonce": 1116226695, "width": 20, "x": -10, "y": 0, @@ -2303,7 +2303,7 @@ History { exports[`contextMenu element > selecting 'Delete' in context menu deletes element > [end of test] number of elements 1`] = `1`; -exports[`contextMenu element > selecting 'Delete' in context menu deletes element > [end of test] number of renders 1`] = `7`; +exports[`contextMenu element > selecting 'Delete' in context menu deletes element > [end of test] number of renders 1`] = `5`; exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates element > [end of test] appState 1`] = ` { @@ -2440,7 +2440,7 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 1150084233, + "versionNonce": 2019559783, "width": 20, "x": -10, "y": 0, @@ -2467,14 +2467,14 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates "roundness": { "type": 3, }, - "seed": 1014066025, + "seed": 1116226695, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 238820263, + "versionNonce": 1014066025, "width": 20, "x": 0, "y": 10, @@ -2601,7 +2601,7 @@ History { exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates element > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates element > [end of test] number of renders 1`] = `7`; +exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates element > [end of test] number of renders 1`] = `5`; exports[`contextMenu element > selecting 'Group selection' in context menu groups selected elements > [end of test] appState 1`] = ` { @@ -2745,7 +2745,7 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 493213705, + "versionNonce": 1505387817, "width": 20, "x": -10, "y": 0, @@ -2774,14 +2774,14 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group "roundness": { "type": 3, }, - "seed": 1014066025, + "seed": 1116226695, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 915032327, + "versionNonce": 23633383, "width": 20, "x": 20, "y": 30, @@ -2967,7 +2967,7 @@ History { exports[`contextMenu element > selecting 'Group selection' in context menu groups selected elements > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > selecting 'Group selection' in context menu groups selected elements > [end of test] number of renders 1`] = `12`; +exports[`contextMenu element > selecting 'Group selection' in context menu groups selected elements > [end of test] number of renders 1`] = `8`; exports[`contextMenu element > selecting 'Paste styles' in context menu pastes styles > [end of test] appState 1`] = ` { @@ -3106,7 +3106,7 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 941653321, + "versionNonce": 640725609, "width": 20, "x": -10, "y": 0, @@ -3133,14 +3133,14 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "roundness": { "type": 3, }, - "seed": 289600103, + "seed": 760410951, "strokeColor": "#e03131", "strokeStyle": "dotted", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 9, - "versionNonce": 640725609, + "versionNonce": 1315507081, "width": 20, "x": 20, "y": 30, @@ -3439,7 +3439,7 @@ History { exports[`contextMenu element > selecting 'Paste styles' in context menu pastes styles > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > selecting 'Paste styles' in context menu pastes styles > [end of test] number of renders 1`] = `18`; +exports[`contextMenu element > selecting 'Paste styles' in context menu pastes styles > [end of test] number of renders 1`] = `14`; exports[`contextMenu element > selecting 'Send backward' in context menu sends element backward > [end of test] appState 1`] = ` { @@ -3569,14 +3569,14 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e "roundness": { "type": 3, }, - "seed": 1014066025, + "seed": 1116226695, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 23633383, + "versionNonce": 1604849351, "width": 20, "x": 20, "y": 30, @@ -3610,7 +3610,7 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 1150084233, + "versionNonce": 2019559783, "width": 20, "x": -10, "y": 0, @@ -3759,7 +3759,7 @@ History { exports[`contextMenu element > selecting 'Send backward' in context menu sends element backward > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > selecting 'Send backward' in context menu sends element backward > [end of test] number of renders 1`] = `11`; +exports[`contextMenu element > selecting 'Send backward' in context menu sends element backward > [end of test] number of renders 1`] = `7`; exports[`contextMenu element > selecting 'Send to back' in context menu sends element to back > [end of test] appState 1`] = ` { @@ -3889,14 +3889,14 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el "roundness": { "type": 3, }, - "seed": 1014066025, + "seed": 1116226695, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 23633383, + "versionNonce": 1604849351, "width": 20, "x": 20, "y": 30, @@ -3930,7 +3930,7 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 1150084233, + "versionNonce": 2019559783, "width": 20, "x": -10, "y": 0, @@ -4079,7 +4079,7 @@ History { exports[`contextMenu element > selecting 'Send to back' in context menu sends element to back > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > selecting 'Send to back' in context menu sends element to back > [end of test] number of renders 1`] = `11`; +exports[`contextMenu element > selecting 'Send to back' in context menu sends element to back > [end of test] number of renders 1`] = `7`; exports[`contextMenu element > selecting 'Ungroup selection' in context menu ungroups selected group > [end of test] appState 1`] = ` { @@ -4219,7 +4219,7 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung "type": "rectangle", "updated": 1, "version": 5, - "versionNonce": 1723083209, + "versionNonce": 81784553, "width": 20, "x": -10, "y": 0, @@ -4246,14 +4246,14 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung "roundness": { "type": 3, }, - "seed": 238820263, + "seed": 1014066025, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 5, - "versionNonce": 760410951, + "versionNonce": 747212839, "width": 20, "x": 20, "y": 30, @@ -4479,7 +4479,7 @@ History { exports[`contextMenu element > selecting 'Ungroup selection' in context menu ungroups selected group > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > selecting 'Ungroup selection' in context menu ungroups selected group > [end of test] number of renders 1`] = `13`; +exports[`contextMenu element > selecting 'Ungroup selection' in context menu ungroups selected group > [end of test] number of renders 1`] = `9`; exports[`contextMenu element > shows 'Group selection' in context menu for multiple selected elements > [end of test] appState 1`] = ` { @@ -5402,7 +5402,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 1014066025, + "versionNonce": 1116226695, "width": 10, "x": -10, "y": 0, @@ -5429,14 +5429,14 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi "roundness": { "type": 3, }, - "seed": 400692809, + "seed": 238820263, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 23633383, + "versionNonce": 1604849351, "width": 10, "x": 12, "y": 0, @@ -5603,7 +5603,7 @@ History { exports[`contextMenu element > shows 'Group selection' in context menu for multiple selected elements > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > shows 'Group selection' in context menu for multiple selected elements > [end of test] number of renders 1`] = `12`; +exports[`contextMenu element > shows 'Group selection' in context menu for multiple selected elements > [end of test] number of renders 1`] = `8`; exports[`contextMenu element > shows 'Ungroup selection' in context menu for group inside selected elements > [end of test] appState 1`] = ` { @@ -6530,7 +6530,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 81784553, + "versionNonce": 493213705, "width": 10, "x": -10, "y": 0, @@ -6559,14 +6559,14 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro "roundness": { "type": 3, }, - "seed": 238820263, + "seed": 1014066025, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 747212839, + "versionNonce": 915032327, "width": 10, "x": 12, "y": 0, @@ -6773,7 +6773,7 @@ History { exports[`contextMenu element > shows 'Ungroup selection' in context menu for group inside selected elements > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > shows 'Ungroup selection' in context menu for group inside selected elements > [end of test] number of renders 1`] = `13`; +exports[`contextMenu element > shows 'Ungroup selection' in context menu for group inside selected elements > [end of test] number of renders 1`] = `9`; exports[`contextMenu element > shows context menu for canvas > [end of test] appState 1`] = ` { @@ -9258,7 +9258,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] el "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 1150084233, + "versionNonce": 2019559783, "width": 20, "x": -10, "y": 0, @@ -9415,6 +9415,6 @@ exports[`contextMenu element > shows context menu for element > [end of test] nu exports[`contextMenu element > shows context menu for element > [end of test] number of elements 2`] = `2`; -exports[`contextMenu element > shows context menu for element > [end of test] number of renders 1`] = `6`; +exports[`contextMenu element > shows context menu for element > [end of test] number of renders 1`] = `4`; exports[`contextMenu element > shows context menu for element > [end of test] number of renders 2`] = `6`; diff --git a/packages/excalidraw/tests/__snapshots__/dragCreate.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/dragCreate.test.tsx.snap index 74330e6e5fc27..244e1f81b0fec 100644 --- a/packages/excalidraw/tests/__snapshots__/dragCreate.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/dragCreate.test.tsx.snap @@ -45,7 +45,7 @@ exports[`Test dragCreate > add element to the scene when pointer dragging long e "type": "arrow", "updated": 1, "version": 4, - "versionNonce": 2019559783, + "versionNonce": 401146281, "width": 30, "x": 30, "y": 20, @@ -81,7 +81,7 @@ exports[`Test dragCreate > add element to the scene when pointer dragging long e "type": "diamond", "updated": 1, "version": 3, - "versionNonce": 401146281, + "versionNonce": 453191, "width": 30, "x": 30, "y": 20, @@ -117,7 +117,7 @@ exports[`Test dragCreate > add element to the scene when pointer dragging long e "type": "ellipse", "updated": 1, "version": 3, - "versionNonce": 401146281, + "versionNonce": 453191, "width": 30, "x": 30, "y": 20, @@ -166,7 +166,7 @@ exports[`Test dragCreate > add element to the scene when pointer dragging long e "type": "line", "updated": 1, "version": 4, - "versionNonce": 2019559783, + "versionNonce": 401146281, "width": 30, "x": 30, "y": 20, @@ -202,7 +202,7 @@ exports[`Test dragCreate > add element to the scene when pointer dragging long e "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 401146281, + "versionNonce": 453191, "width": 30, "x": 30, "y": 20, diff --git a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap index 55348b8d83429..4dce7d1981449 100644 --- a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap @@ -597,7 +597,7 @@ History { exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and the arrow got bound to a different element in the meantime > [end of test] number of elements 1`] = `4`; -exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and the arrow got bound to a different element in the meantime > [end of test] number of renders 1`] = `22`; +exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and the arrow got bound to a different element in the meantime > [end of test] number of renders 1`] = `20`; exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] appState 1`] = ` { @@ -1100,7 +1100,7 @@ History { exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] number of elements 1`] = `3`; -exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] number of renders 1`] = `24`; +exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] number of renders 1`] = `22`; exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind remotely added arrow when it's bindable elements are added through the history > [end of test] appState 1`] = ` { @@ -2532,7 +2532,7 @@ History { exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should update bound element points when rectangle was remotely moved and arrow is added back through the history > [end of test] number of elements 1`] = `3`; -exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should update bound element points when rectangle was remotely moved and arrow is added back through the history > [end of test] number of renders 1`] = `10`; +exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should update bound element points when rectangle was remotely moved and arrow is added back through the history > [end of test] number of renders 1`] = `8`; exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should preserve latest remotely added binding and unbind previous one when the container is added through the history > [end of test] appState 1`] = ` { @@ -6355,7 +6355,7 @@ History { exports[`history > multiplayer undo/redo > should iterate through the history when element changes relate only to remotely deleted elements > [end of test] number of elements 1`] = `3`; -exports[`history > multiplayer undo/redo > should iterate through the history when element changes relate only to remotely deleted elements > [end of test] number of renders 1`] = `20`; +exports[`history > multiplayer undo/redo > should iterate through the history when element changes relate only to remotely deleted elements > [end of test] number of renders 1`] = `14`; exports[`history > multiplayer undo/redo > should iterate through the history when selected elements relate only to remotely deleted elements > [end of test] appState 1`] = ` { @@ -7341,7 +7341,7 @@ History { exports[`history > multiplayer undo/redo > should iterate through the history when selected or editing linear element was remotely deleted > [end of test] number of elements 1`] = `1`; -exports[`history > multiplayer undo/redo > should iterate through the history when selected or editing linear element was remotely deleted > [end of test] number of renders 1`] = `11`; +exports[`history > multiplayer undo/redo > should iterate through the history when selected or editing linear element was remotely deleted > [end of test] number of renders 1`] = `8`; exports[`history > multiplayer undo/redo > should iterate through the history when when element change relates to remotely deleted element > [end of test] appState 1`] = ` { @@ -7567,7 +7567,7 @@ History { exports[`history > multiplayer undo/redo > should iterate through the history when when element change relates to remotely deleted element > [end of test] number of elements 1`] = `1`; -exports[`history > multiplayer undo/redo > should iterate through the history when when element change relates to remotely deleted element > [end of test] number of renders 1`] = `10`; +exports[`history > multiplayer undo/redo > should iterate through the history when when element change relates to remotely deleted element > [end of test] number of renders 1`] = `8`; exports[`history > multiplayer undo/redo > should iterate through the history when z-index changes do not produce visible change and we synced all indices > [end of test] appState 1`] = ` { @@ -8672,7 +8672,7 @@ History { exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress dragging > [end of test] number of elements 1`] = `3`; -exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress dragging > [end of test] number of renders 1`] = `27`; +exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress dragging > [end of test] number of renders 1`] = `23`; exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress freedraw > [end of test] appState 1`] = ` { @@ -8956,7 +8956,7 @@ History { exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress freedraw > [end of test] number of elements 1`] = `2`; -exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress freedraw > [end of test] number of renders 1`] = `10`; +exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress freedraw > [end of test] number of renders 1`] = `7`; exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress resizing > [end of test] appState 1`] = ` { @@ -9218,7 +9218,7 @@ History { exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress resizing > [end of test] number of elements 1`] = `2`; -exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress resizing > [end of test] number of renders 1`] = `14`; +exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress resizing > [end of test] number of renders 1`] = `12`; exports[`history > multiplayer undo/redo > should not override remote changes on different elements > [end of test] appState 1`] = ` { @@ -9479,7 +9479,7 @@ History { exports[`history > multiplayer undo/redo > should not override remote changes on different elements > [end of test] number of elements 1`] = `2`; -exports[`history > multiplayer undo/redo > should not override remote changes on different elements > [end of test] number of renders 1`] = `11`; +exports[`history > multiplayer undo/redo > should not override remote changes on different elements > [end of test] number of renders 1`] = `9`; exports[`history > multiplayer undo/redo > should not override remote changes on different properties > [end of test] appState 1`] = ` { @@ -9707,7 +9707,7 @@ History { exports[`history > multiplayer undo/redo > should not override remote changes on different properties > [end of test] number of elements 1`] = `1`; -exports[`history > multiplayer undo/redo > should not override remote changes on different properties > [end of test] number of renders 1`] = `10`; +exports[`history > multiplayer undo/redo > should not override remote changes on different properties > [end of test] number of renders 1`] = `8`; exports[`history > multiplayer undo/redo > should override remotely added groups on undo, but restore them on redo > [end of test] appState 1`] = ` { @@ -10342,7 +10342,7 @@ History { exports[`history > multiplayer undo/redo > should override remotely added points on undo, but restore them on redo > [end of test] number of elements 1`] = `1`; -exports[`history > multiplayer undo/redo > should override remotely added points on undo, but restore them on redo > [end of test] number of renders 1`] = `17`; +exports[`history > multiplayer undo/redo > should override remotely added points on undo, but restore them on redo > [end of test] number of renders 1`] = `13`; exports[`history > multiplayer undo/redo > should redistribute deltas when element gets removed locally but is restored remotely > [end of test] appState 1`] = ` { @@ -10574,7 +10574,7 @@ History { exports[`history > multiplayer undo/redo > should redistribute deltas when element gets removed locally but is restored remotely > [end of test] number of elements 1`] = `1`; -exports[`history > multiplayer undo/redo > should redistribute deltas when element gets removed locally but is restored remotely > [end of test] number of renders 1`] = `12`; +exports[`history > multiplayer undo/redo > should redistribute deltas when element gets removed locally but is restored remotely > [end of test] number of renders 1`] = `10`; exports[`history > multiplayer undo/redo > should redraw arrows on undo > [end of test] appState 1`] = ` { @@ -11275,7 +11275,7 @@ History { exports[`history > multiplayer undo/redo > should update history entries after remote changes on the same properties > [end of test] number of elements 1`] = `1`; -exports[`history > multiplayer undo/redo > should update history entries after remote changes on the same properties > [end of test] number of renders 1`] = `16`; +exports[`history > multiplayer undo/redo > should update history entries after remote changes on the same properties > [end of test] number of renders 1`] = `14`; exports[`history > singleplayer undo/redo > remounting undo/redo buttons should initialize undo/redo state correctly > [end of test] appState 1`] = ` { @@ -11511,7 +11511,7 @@ History { exports[`history > singleplayer undo/redo > remounting undo/redo buttons should initialize undo/redo state correctly > [end of test] number of elements 1`] = `2`; -exports[`history > singleplayer undo/redo > remounting undo/redo buttons should initialize undo/redo state correctly > [end of test] number of renders 1`] = `12`; +exports[`history > singleplayer undo/redo > remounting undo/redo buttons should initialize undo/redo state correctly > [end of test] number of renders 1`] = `10`; exports[`history > singleplayer undo/redo > should clear the redo stack on elements change > [end of test] appState 1`] = ` { @@ -11749,7 +11749,7 @@ History { exports[`history > singleplayer undo/redo > should clear the redo stack on elements change > [end of test] number of elements 1`] = `2`; -exports[`history > singleplayer undo/redo > should clear the redo stack on elements change > [end of test] number of renders 1`] = `10`; +exports[`history > singleplayer undo/redo > should clear the redo stack on elements change > [end of test] number of renders 1`] = `6`; exports[`history > singleplayer undo/redo > should create entry when selecting freedraw > [end of test] appState 1`] = ` { @@ -12147,7 +12147,7 @@ History { exports[`history > singleplayer undo/redo > should create entry when selecting freedraw > [end of test] number of elements 1`] = `3`; -exports[`history > singleplayer undo/redo > should create entry when selecting freedraw > [end of test] number of renders 1`] = `15`; +exports[`history > singleplayer undo/redo > should create entry when selecting freedraw > [end of test] number of renders 1`] = `9`; exports[`history > singleplayer undo/redo > should create new history entry on scene import via drag&drop > [end of test] appState 1`] = ` { @@ -12629,7 +12629,7 @@ History { exports[`history > singleplayer undo/redo > should disable undo/redo buttons when stacks empty > [end of test] number of elements 1`] = `2`; -exports[`history > singleplayer undo/redo > should disable undo/redo buttons when stacks empty > [end of test] number of renders 1`] = `8`; +exports[`history > singleplayer undo/redo > should disable undo/redo buttons when stacks empty > [end of test] number of renders 1`] = `6`; exports[`history > singleplayer undo/redo > should end up with no history entry after initializing scene > [end of test] appState 1`] = ` { @@ -12867,7 +12867,7 @@ History { exports[`history > singleplayer undo/redo > should end up with no history entry after initializing scene > [end of test] number of elements 1`] = `2`; -exports[`history > singleplayer undo/redo > should end up with no history entry after initializing scene > [end of test] number of renders 1`] = `8`; +exports[`history > singleplayer undo/redo > should end up with no history entry after initializing scene > [end of test] number of renders 1`] = `6`; exports[`history > singleplayer undo/redo > should iterate through the history when selection changes do not produce visible change > [end of test] appState 1`] = ` { @@ -13111,7 +13111,7 @@ History { exports[`history > singleplayer undo/redo > should iterate through the history when selection changes do not produce visible change > [end of test] number of elements 1`] = `1`; -exports[`history > singleplayer undo/redo > should iterate through the history when selection changes do not produce visible change > [end of test] number of renders 1`] = `14`; +exports[`history > singleplayer undo/redo > should iterate through the history when selection changes do not produce visible change > [end of test] number of renders 1`] = `12`; exports[`history > singleplayer undo/redo > should not clear the redo stack on standalone appstate change > [end of test] appState 1`] = ` { @@ -13440,7 +13440,7 @@ History { exports[`history > singleplayer undo/redo > should not clear the redo stack on standalone appstate change > [end of test] number of elements 1`] = `2`; -exports[`history > singleplayer undo/redo > should not clear the redo stack on standalone appstate change > [end of test] number of renders 1`] = `14`; +exports[`history > singleplayer undo/redo > should not clear the redo stack on standalone appstate change > [end of test] number of renders 1`] = `10`; exports[`history > singleplayer undo/redo > should not collapse when applying corrupted history entry > [end of test] appState 1`] = ` { @@ -14430,7 +14430,7 @@ History { exports[`history > singleplayer undo/redo > should not override appstate changes when redo stack is not cleared > [end of test] number of elements 1`] = `1`; -exports[`history > singleplayer undo/redo > should not override appstate changes when redo stack is not cleared > [end of test] number of renders 1`] = `16`; +exports[`history > singleplayer undo/redo > should not override appstate changes when redo stack is not cleared > [end of test] number of renders 1`] = `14`; exports[`history > singleplayer undo/redo > should support appstate name or viewBackgroundColor change > [end of test] appState 1`] = ` { @@ -15281,7 +15281,7 @@ History { exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on deletion and rebind on undo > [end of test] number of elements 1`] = `4`; -exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on deletion and rebind on undo > [end of test] number of renders 1`] = `13`; +exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on deletion and rebind on undo > [end of test] number of renders 1`] = `11`; exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on undo and rebind on redo > [end of test] appState 1`] = ` { @@ -15898,7 +15898,7 @@ History { exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on undo and rebind on redo > [end of test] number of elements 1`] = `4`; -exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on undo and rebind on redo > [end of test] number of renders 1`] = `13`; +exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on undo and rebind on redo > [end of test] number of renders 1`] = `11`; exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind everything from non deleted elements when iterating through the whole undo stack and vice versa rebind everything on redo > [end of test] appState 1`] = ` { @@ -16515,7 +16515,7 @@ History { exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind everything from non deleted elements when iterating through the whole undo stack and vice versa rebind everything on redo > [end of test] number of elements 1`] = `4`; -exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind everything from non deleted elements when iterating through the whole undo stack and vice versa rebind everything on redo > [end of test] number of renders 1`] = `21`; +exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind everything from non deleted elements when iterating through the whole undo stack and vice versa rebind everything on redo > [end of test] number of renders 1`] = `19`; exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangle from arrow on deletion and rebind on undo > [end of test] appState 1`] = ` { @@ -17224,7 +17224,7 @@ History { exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangle from arrow on deletion and rebind on undo > [end of test] number of elements 1`] = `4`; -exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangle from arrow on deletion and rebind on undo > [end of test] number of renders 1`] = `15`; +exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangle from arrow on deletion and rebind on undo > [end of test] number of renders 1`] = `13`; exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangles from arrow on deletion and rebind on undo > [end of test] appState 1`] = ` { @@ -17971,7 +17971,7 @@ History { exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangles from arrow on deletion and rebind on undo > [end of test] number of elements 1`] = `4`; -exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangles from arrow on deletion and rebind on undo > [end of test] number of renders 1`] = `16`; +exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangles from arrow on deletion and rebind on undo > [end of test] number of renders 1`] = `14`; exports[`history > singleplayer undo/redo > should support changes in elements' order > [end of test] appState 1`] = ` { @@ -18442,7 +18442,7 @@ History { exports[`history > singleplayer undo/redo > should support changes in elements' order > [end of test] number of elements 1`] = `3`; -exports[`history > singleplayer undo/redo > should support changes in elements' order > [end of test] number of renders 1`] = `23`; +exports[`history > singleplayer undo/redo > should support changes in elements' order > [end of test] number of renders 1`] = `17`; exports[`history > singleplayer undo/redo > should support duplication of groups, appstate group selection and editing group > [end of test] appState 1`] = ` { @@ -19414,7 +19414,7 @@ History { exports[`history > singleplayer undo/redo > should support element creation, deletion and appstate element selection change > [end of test] number of elements 1`] = `3`; -exports[`history > singleplayer undo/redo > should support element creation, deletion and appstate element selection change > [end of test] number of renders 1`] = `30`; +exports[`history > singleplayer undo/redo > should support element creation, deletion and appstate element selection change > [end of test] number of renders 1`] = `24`; exports[`history > singleplayer undo/redo > should support linear element creation and points manipulation through the editor > [end of test] appState 1`] = ` { @@ -19821,4 +19821,4 @@ History { exports[`history > singleplayer undo/redo > should support linear element creation and points manipulation through the editor > [end of test] number of elements 1`] = `1`; -exports[`history > singleplayer undo/redo > should support linear element creation and points manipulation through the editor > [end of test] number of renders 1`] = `23`; +exports[`history > singleplayer undo/redo > should support linear element creation and points manipulation through the editor > [end of test] number of renders 1`] = `19`; diff --git a/packages/excalidraw/tests/__snapshots__/move.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/move.test.tsx.snap index c6ea4b647342e..1eba8956760a4 100644 --- a/packages/excalidraw/tests/__snapshots__/move.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/move.test.tsx.snap @@ -20,14 +20,14 @@ exports[`duplicate element on move when ALT is clicked > rectangle 5`] = ` "roundness": { "type": 3, }, - "seed": 238820263, + "seed": 1014066025, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 5, - "versionNonce": 400692809, + "versionNonce": 238820263, "width": 30, "x": 30, "y": 20, @@ -61,7 +61,7 @@ exports[`duplicate element on move when ALT is clicked > rectangle 6`] = ` "type": "rectangle", "updated": 1, "version": 6, - "versionNonce": 23633383, + "versionNonce": 1505387817, "width": 30, "x": -10, "y": 60, @@ -95,7 +95,7 @@ exports[`move element > rectangle 5`] = ` "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 1116226695, + "versionNonce": 1150084233, "width": 30, "x": 0, "y": 40, @@ -134,7 +134,7 @@ exports[`move element > rectangles with binding arrow 5`] = ` "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 760410951, + "versionNonce": 915032327, "width": 100, "x": 0, "y": 0, @@ -166,14 +166,14 @@ exports[`move element > rectangles with binding arrow 6`] = ` "roundness": { "type": 3, }, - "seed": 1150084233, + "seed": 2019559783, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, "type": "rectangle", "updated": 1, "version": 7, - "versionNonce": 745419401, + "versionNonce": 927333447, "width": 300, "x": 201, "y": 2, @@ -219,7 +219,7 @@ exports[`move element > rectangles with binding arrow 7`] = ` "roundness": { "type": 2, }, - "seed": 1604849351, + "seed": 238820263, "startArrowhead": null, "startBinding": { "elementId": "id0", @@ -233,7 +233,7 @@ exports[`move element > rectangles with binding arrow 7`] = ` "type": "arrow", "updated": 1, "version": 11, - "versionNonce": 1996028265, + "versionNonce": 1508694887, "width": 81, "x": 110, "y": 50, diff --git a/packages/excalidraw/tests/__snapshots__/multiPointCreate.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/multiPointCreate.test.tsx.snap index 05d6b9cddc11d..490bc91d223f4 100644 --- a/packages/excalidraw/tests/__snapshots__/multiPointCreate.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/multiPointCreate.test.tsx.snap @@ -50,7 +50,7 @@ exports[`multi point mode in linear elements > arrow 3`] = ` "type": "arrow", "updated": 1, "version": 8, - "versionNonce": 23633383, + "versionNonce": 1014066025, "width": 70, "x": 30, "y": 30, @@ -106,7 +106,7 @@ exports[`multi point mode in linear elements > line 3`] = ` "type": "line", "updated": 1, "version": 8, - "versionNonce": 23633383, + "versionNonce": 1014066025, "width": 70, "x": 30, "y": 30, diff --git a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap index 2c8e4dde7eed5..93d87aaebea78 100644 --- a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap @@ -407,7 +407,7 @@ History { exports[`given element A and group of elements B and given both are selected when user clicks on B, on pointer up only elements from B should be selected > [end of test] number of elements 1`] = `0`; -exports[`given element A and group of elements B and given both are selected when user clicks on B, on pointer up only elements from B should be selected > [end of test] number of renders 1`] = `21`; +exports[`given element A and group of elements B and given both are selected when user clicks on B, on pointer up only elements from B should be selected > [end of test] number of renders 1`] = `15`; exports[`given element A and group of elements B and given both are selected when user shift-clicks on B, on pointer up only element A should be selected > [end of test] appState 1`] = ` { @@ -807,7 +807,7 @@ History { exports[`given element A and group of elements B and given both are selected when user shift-clicks on B, on pointer up only element A should be selected > [end of test] number of elements 1`] = `0`; -exports[`given element A and group of elements B and given both are selected when user shift-clicks on B, on pointer up only element A should be selected > [end of test] number of renders 1`] = `19`; +exports[`given element A and group of elements B and given both are selected when user shift-clicks on B, on pointer up only element A should be selected > [end of test] number of renders 1`] = `13`; exports[`regression tests > Cmd/Ctrl-click exclusively select element under pointer > [end of test] appState 1`] = ` { @@ -1346,7 +1346,7 @@ History { exports[`regression tests > Cmd/Ctrl-click exclusively select element under pointer > [end of test] number of elements 1`] = `0`; -exports[`regression tests > Cmd/Ctrl-click exclusively select element under pointer > [end of test] number of renders 1`] = `29`; +exports[`regression tests > Cmd/Ctrl-click exclusively select element under pointer > [end of test] number of renders 1`] = `23`; exports[`regression tests > Drags selected element when hitting only bounding box and keeps element selected > [end of test] appState 1`] = ` { @@ -1544,7 +1544,7 @@ History { exports[`regression tests > Drags selected element when hitting only bounding box and keeps element selected > [end of test] number of elements 1`] = `0`; -exports[`regression tests > Drags selected element when hitting only bounding box and keeps element selected > [end of test] number of renders 1`] = `11`; +exports[`regression tests > Drags selected element when hitting only bounding box and keeps element selected > [end of test] number of renders 1`] = `9`; exports[`regression tests > adjusts z order when grouping > [end of test] appState 1`] = ` { @@ -1913,7 +1913,7 @@ History { exports[`regression tests > adjusts z order when grouping > [end of test] number of elements 1`] = `0`; -exports[`regression tests > adjusts z order when grouping > [end of test] number of renders 1`] = `18`; +exports[`regression tests > adjusts z order when grouping > [end of test] number of renders 1`] = `12`; exports[`regression tests > alt-drag duplicates an element > [end of test] appState 1`] = ` { @@ -2147,7 +2147,7 @@ History { exports[`regression tests > alt-drag duplicates an element > [end of test] number of elements 1`] = `0`; -exports[`regression tests > alt-drag duplicates an element > [end of test] number of renders 1`] = `9`; +exports[`regression tests > alt-drag duplicates an element > [end of test] number of renders 1`] = `7`; exports[`regression tests > arrow keys > [end of test] appState 1`] = ` { @@ -2321,7 +2321,7 @@ History { exports[`regression tests > arrow keys > [end of test] number of elements 1`] = `0`; -exports[`regression tests > arrow keys > [end of test] number of renders 1`] = `13`; +exports[`regression tests > arrow keys > [end of test] number of renders 1`] = `11`; exports[`regression tests > can drag element that covers another element, while another elem is selected > [end of test] appState 1`] = ` { @@ -2635,7 +2635,7 @@ History { exports[`regression tests > can drag element that covers another element, while another elem is selected > [end of test] number of elements 1`] = `0`; -exports[`regression tests > can drag element that covers another element, while another elem is selected > [end of test] number of renders 1`] = `18`; +exports[`regression tests > can drag element that covers another element, while another elem is selected > [end of test] number of renders 1`] = `12`; exports[`regression tests > change the properties of a shape > [end of test] appState 1`] = ` { @@ -2875,7 +2875,7 @@ History { exports[`regression tests > change the properties of a shape > [end of test] number of elements 1`] = `0`; -exports[`regression tests > change the properties of a shape > [end of test] number of renders 1`] = `10`; +exports[`regression tests > change the properties of a shape > [end of test] number of renders 1`] = `8`; exports[`regression tests > click on an element and drag it > [dragged] appState 1`] = ` { @@ -3014,7 +3014,7 @@ exports[`regression tests > click on an element and drag it > [dragged] element "type": "rectangle", "updated": 1, "version": 4, - "versionNonce": 1116226695, + "versionNonce": 1150084233, "width": 10, "x": 20, "y": 20, @@ -3112,7 +3112,7 @@ History { exports[`regression tests > click on an element and drag it > [dragged] number of elements 1`] = `1`; -exports[`regression tests > click on an element and drag it > [dragged] number of renders 1`] = `9`; +exports[`regression tests > click on an element and drag it > [dragged] number of renders 1`] = `7`; exports[`regression tests > click on an element and drag it > [end of test] appState 1`] = ` { @@ -3336,7 +3336,7 @@ History { exports[`regression tests > click on an element and drag it > [end of test] number of elements 1`] = `0`; -exports[`regression tests > click on an element and drag it > [end of test] number of renders 1`] = `11`; +exports[`regression tests > click on an element and drag it > [end of test] number of renders 1`] = `9`; exports[`regression tests > click to select a shape > [end of test] appState 1`] = ` { @@ -3586,7 +3586,7 @@ History { exports[`regression tests > click to select a shape > [end of test] number of elements 1`] = `0`; -exports[`regression tests > click to select a shape > [end of test] number of renders 1`] = `12`; +exports[`regression tests > click to select a shape > [end of test] number of renders 1`] = `8`; exports[`regression tests > click-drag to select a group > [end of test] appState 1`] = ` { @@ -3891,7 +3891,7 @@ History { exports[`regression tests > click-drag to select a group > [end of test] number of elements 1`] = `0`; -exports[`regression tests > click-drag to select a group > [end of test] number of renders 1`] = `17`; +exports[`regression tests > click-drag to select a group > [end of test] number of renders 1`] = `11`; exports[`regression tests > deleting last but one element in editing group should unselect the group > [end of test] appState 1`] = ` { @@ -4299,7 +4299,7 @@ History { exports[`regression tests > deleting last but one element in editing group should unselect the group > [end of test] number of elements 1`] = `0`; -exports[`regression tests > deleting last but one element in editing group should unselect the group > [end of test] number of renders 1`] = `19`; +exports[`regression tests > deleting last but one element in editing group should unselect the group > [end of test] number of renders 1`] = `15`; exports[`regression tests > deselects group of selected elements on pointer down when pointer doesn't hit any element > [end of test] appState 1`] = ` { @@ -4405,7 +4405,7 @@ exports[`regression tests > deselects group of selected elements on pointer down "roundness": { "type": 2, }, - "seed": 1505387817, + "seed": 400692809, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -4576,7 +4576,7 @@ History { exports[`regression tests > deselects group of selected elements on pointer down when pointer doesn't hit any element > [end of test] number of elements 1`] = `0`; -exports[`regression tests > deselects group of selected elements on pointer down when pointer doesn't hit any element > [end of test] number of renders 1`] = `13`; +exports[`regression tests > deselects group of selected elements on pointer down when pointer doesn't hit any element > [end of test] number of renders 1`] = `9`; exports[`regression tests > deselects group of selected elements on pointer up when pointer hits common bounding box without hitting any element > [end of test] appState 1`] = ` { @@ -4823,7 +4823,7 @@ History { exports[`regression tests > deselects group of selected elements on pointer up when pointer hits common bounding box without hitting any element > [end of test] number of elements 1`] = `0`; -exports[`regression tests > deselects group of selected elements on pointer up when pointer hits common bounding box without hitting any element > [end of test] number of renders 1`] = `13`; +exports[`regression tests > deselects group of selected elements on pointer up when pointer hits common bounding box without hitting any element > [end of test] number of renders 1`] = `9`; exports[`regression tests > deselects selected element on pointer down when pointer doesn't hit any element > [end of test] appState 1`] = ` { @@ -4928,7 +4928,7 @@ exports[`regression tests > deselects selected element on pointer down when poin "roundness": { "type": 2, }, - "seed": 1150084233, + "seed": 2019559783, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -5027,7 +5027,7 @@ History { exports[`regression tests > deselects selected element on pointer down when pointer doesn't hit any element > [end of test] number of elements 1`] = `0`; -exports[`regression tests > deselects selected element on pointer down when pointer doesn't hit any element > [end of test] number of renders 1`] = `8`; +exports[`regression tests > deselects selected element on pointer down when pointer doesn't hit any element > [end of test] number of renders 1`] = `6`; exports[`regression tests > deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element > [end of test] appState 1`] = ` { @@ -5220,7 +5220,7 @@ History { exports[`regression tests > deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element > [end of test] number of elements 1`] = `0`; -exports[`regression tests > deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element > [end of test] number of renders 1`] = `8`; +exports[`regression tests > deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element > [end of test] number of renders 1`] = `6`; exports[`regression tests > double click to edit a group > [end of test] appState 1`] = ` { @@ -5596,7 +5596,7 @@ History { exports[`regression tests > double click to edit a group > [end of test] number of elements 1`] = `0`; -exports[`regression tests > double click to edit a group > [end of test] number of renders 1`] = `18`; +exports[`regression tests > double click to edit a group > [end of test] number of renders 1`] = `12`; exports[`regression tests > drags selected elements from point inside common bounding box that doesn't hit any element and keeps elements selected after dragging > [end of test] appState 1`] = ` { @@ -5880,7 +5880,7 @@ History { exports[`regression tests > drags selected elements from point inside common bounding box that doesn't hit any element and keeps elements selected after dragging > [end of test] number of elements 1`] = `0`; -exports[`regression tests > drags selected elements from point inside common bounding box that doesn't hit any element and keeps elements selected after dragging > [end of test] number of renders 1`] = `14`; +exports[`regression tests > drags selected elements from point inside common bounding box that doesn't hit any element and keeps elements selected after dragging > [end of test] number of renders 1`] = `10`; exports[`regression tests > draw every type of shape > [end of test] appState 1`] = ` { @@ -6682,7 +6682,7 @@ History { exports[`regression tests > draw every type of shape > [end of test] number of elements 1`] = `0`; -exports[`regression tests > draw every type of shape > [end of test] number of renders 1`] = `43`; +exports[`regression tests > draw every type of shape > [end of test] number of renders 1`] = `23`; exports[`regression tests > given a group of selected elements with an element that is not selected inside the group common bounding box when element that is not selected is clicked should switch selection to not selected element on pointer up > [end of test] appState 1`] = ` { @@ -7006,7 +7006,7 @@ History { exports[`regression tests > given a group of selected elements with an element that is not selected inside the group common bounding box when element that is not selected is clicked should switch selection to not selected element on pointer up > [end of test] number of elements 1`] = `0`; -exports[`regression tests > given a group of selected elements with an element that is not selected inside the group common bounding box when element that is not selected is clicked should switch selection to not selected element on pointer up > [end of test] number of renders 1`] = `17`; +exports[`regression tests > given a group of selected elements with an element that is not selected inside the group common bounding box when element that is not selected is clicked should switch selection to not selected element on pointer up > [end of test] number of renders 1`] = `11`; exports[`regression tests > given a selected element A and a not selected element B with higher z-index than A and given B partially overlaps A when there's a shift-click on the overlapped section B is added to the selection > [end of test] appState 1`] = ` { @@ -7276,7 +7276,7 @@ History { exports[`regression tests > given a selected element A and a not selected element B with higher z-index than A and given B partially overlaps A when there's a shift-click on the overlapped section B is added to the selection > [end of test] number of elements 1`] = `0`; -exports[`regression tests > given a selected element A and a not selected element B with higher z-index than A and given B partially overlaps A when there's a shift-click on the overlapped section B is added to the selection > [end of test] number of renders 1`] = `14`; +exports[`regression tests > given a selected element A and a not selected element B with higher z-index than A and given B partially overlaps A when there's a shift-click on the overlapped section B is added to the selection > [end of test] number of renders 1`] = `10`; exports[`regression tests > given selected element A with lower z-index than unselected element B and given B is partially over A when clicking intersection between A and B B should be selected on pointer up > [end of test] appState 1`] = ` { @@ -7909,7 +7909,7 @@ History { exports[`regression tests > key 2 selects rectangle tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key 2 selects rectangle tool > [end of test] number of renders 1`] = `7`; +exports[`regression tests > key 2 selects rectangle tool > [end of test] number of renders 1`] = `5`; exports[`regression tests > key 3 selects diamond tool > [end of test] appState 1`] = ` { @@ -8083,7 +8083,7 @@ History { exports[`regression tests > key 3 selects diamond tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key 3 selects diamond tool > [end of test] number of renders 1`] = `7`; +exports[`regression tests > key 3 selects diamond tool > [end of test] number of renders 1`] = `5`; exports[`regression tests > key 4 selects ellipse tool > [end of test] appState 1`] = ` { @@ -8257,7 +8257,7 @@ History { exports[`regression tests > key 4 selects ellipse tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key 4 selects ellipse tool > [end of test] number of renders 1`] = `7`; +exports[`regression tests > key 4 selects ellipse tool > [end of test] number of renders 1`] = `5`; exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`] = ` { @@ -8473,7 +8473,7 @@ History { exports[`regression tests > key 5 selects arrow tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key 5 selects arrow tool > [end of test] number of renders 1`] = `7`; +exports[`regression tests > key 5 selects arrow tool > [end of test] number of renders 1`] = `5`; exports[`regression tests > key 6 selects line tool > [end of test] appState 1`] = ` { @@ -8688,7 +8688,7 @@ History { exports[`regression tests > key 6 selects line tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key 6 selects line tool > [end of test] number of renders 1`] = `7`; +exports[`regression tests > key 6 selects line tool > [end of test] number of renders 1`] = `5`; exports[`regression tests > key 7 selects freedraw tool > [end of test] appState 1`] = ` { @@ -8876,7 +8876,7 @@ History { exports[`regression tests > key 7 selects freedraw tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key 7 selects freedraw tool > [end of test] number of renders 1`] = `7`; +exports[`regression tests > key 7 selects freedraw tool > [end of test] number of renders 1`] = `5`; exports[`regression tests > key a selects arrow tool > [end of test] appState 1`] = ` { @@ -9092,7 +9092,7 @@ History { exports[`regression tests > key a selects arrow tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key a selects arrow tool > [end of test] number of renders 1`] = `7`; +exports[`regression tests > key a selects arrow tool > [end of test] number of renders 1`] = `5`; exports[`regression tests > key d selects diamond tool > [end of test] appState 1`] = ` { @@ -9266,7 +9266,7 @@ History { exports[`regression tests > key d selects diamond tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key d selects diamond tool > [end of test] number of renders 1`] = `7`; +exports[`regression tests > key d selects diamond tool > [end of test] number of renders 1`] = `5`; exports[`regression tests > key l selects line tool > [end of test] appState 1`] = ` { @@ -9481,7 +9481,7 @@ History { exports[`regression tests > key l selects line tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key l selects line tool > [end of test] number of renders 1`] = `7`; +exports[`regression tests > key l selects line tool > [end of test] number of renders 1`] = `5`; exports[`regression tests > key o selects ellipse tool > [end of test] appState 1`] = ` { @@ -9655,7 +9655,7 @@ History { exports[`regression tests > key o selects ellipse tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key o selects ellipse tool > [end of test] number of renders 1`] = `7`; +exports[`regression tests > key o selects ellipse tool > [end of test] number of renders 1`] = `5`; exports[`regression tests > key p selects freedraw tool > [end of test] appState 1`] = ` { @@ -9843,7 +9843,7 @@ History { exports[`regression tests > key p selects freedraw tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key p selects freedraw tool > [end of test] number of renders 1`] = `7`; +exports[`regression tests > key p selects freedraw tool > [end of test] number of renders 1`] = `5`; exports[`regression tests > key r selects rectangle tool > [end of test] appState 1`] = ` { @@ -10017,7 +10017,7 @@ History { exports[`regression tests > key r selects rectangle tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key r selects rectangle tool > [end of test] number of renders 1`] = `7`; +exports[`regression tests > key r selects rectangle tool > [end of test] number of renders 1`] = `5`; exports[`regression tests > make a group and duplicate it > [end of test] appState 1`] = ` { @@ -10525,7 +10525,7 @@ History { exports[`regression tests > make a group and duplicate it > [end of test] number of elements 1`] = `0`; -exports[`regression tests > make a group and duplicate it > [end of test] number of renders 1`] = `20`; +exports[`regression tests > make a group and duplicate it > [end of test] number of renders 1`] = `14`; exports[`regression tests > noop interaction after undo shouldn't create history entry > [end of test] appState 1`] = ` { @@ -10796,7 +10796,7 @@ History { exports[`regression tests > noop interaction after undo shouldn't create history entry > [end of test] number of elements 1`] = `0`; -exports[`regression tests > noop interaction after undo shouldn't create history entry > [end of test] number of renders 1`] = `16`; +exports[`regression tests > noop interaction after undo shouldn't create history entry > [end of test] number of renders 1`] = `12`; exports[`regression tests > pinch-to-zoom works > [end of test] appState 1`] = ` { @@ -11109,7 +11109,7 @@ History { exports[`regression tests > shift click on selected element should deselect it on pointer up > [end of test] number of elements 1`] = `0`; -exports[`regression tests > shift click on selected element should deselect it on pointer up > [end of test] number of renders 1`] = `8`; +exports[`regression tests > shift click on selected element should deselect it on pointer up > [end of test] number of renders 1`] = `6`; exports[`regression tests > shift-click to multiselect, then drag > [end of test] appState 1`] = ` { @@ -11414,7 +11414,7 @@ History { exports[`regression tests > shift-click to multiselect, then drag > [end of test] number of elements 1`] = `0`; -exports[`regression tests > shift-click to multiselect, then drag > [end of test] number of renders 1`] = `15`; +exports[`regression tests > shift-click to multiselect, then drag > [end of test] number of renders 1`] = `11`; exports[`regression tests > should group elements and ungroup them > [end of test] appState 1`] = ` { @@ -11820,7 +11820,7 @@ History { exports[`regression tests > should group elements and ungroup them > [end of test] number of elements 1`] = `0`; -exports[`regression tests > should group elements and ungroup them > [end of test] number of renders 1`] = `21`; +exports[`regression tests > should group elements and ungroup them > [end of test] number of renders 1`] = `15`; exports[`regression tests > single-clicking on a subgroup of a selected group should not alter selection > [end of test] appState 1`] = ` { @@ -12427,7 +12427,7 @@ History { exports[`regression tests > single-clicking on a subgroup of a selected group should not alter selection > [end of test] number of elements 1`] = `0`; -exports[`regression tests > single-clicking on a subgroup of a selected group should not alter selection > [end of test] number of renders 1`] = `29`; +exports[`regression tests > single-clicking on a subgroup of a selected group should not alter selection > [end of test] number of renders 1`] = `21`; exports[`regression tests > spacebar + drag scrolls the canvas > [end of test] appState 1`] = ` { @@ -13128,7 +13128,7 @@ History { exports[`regression tests > supports nested groups > [end of test] number of elements 1`] = `0`; -exports[`regression tests > supports nested groups > [end of test] number of renders 1`] = `26`; +exports[`regression tests > supports nested groups > [end of test] number of renders 1`] = `20`; exports[`regression tests > switches from group of selected elements to another element on pointer down > [end of test] appState 1`] = ` { @@ -13236,7 +13236,7 @@ exports[`regression tests > switches from group of selected elements to another "roundness": { "type": 2, }, - "seed": 1723083209, + "seed": 915032327, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -13460,7 +13460,7 @@ History { exports[`regression tests > switches from group of selected elements to another element on pointer down > [end of test] number of elements 1`] = `0`; -exports[`regression tests > switches from group of selected elements to another element on pointer down > [end of test] number of renders 1`] = `17`; +exports[`regression tests > switches from group of selected elements to another element on pointer down > [end of test] number of renders 1`] = `11`; exports[`regression tests > switches selected element on pointer down > [end of test] appState 1`] = ` { @@ -13567,7 +13567,7 @@ exports[`regression tests > switches selected element on pointer down > [end of "roundness": { "type": 2, }, - "seed": 1604849351, + "seed": 238820263, "strokeColor": "#1e1e1e", "strokeStyle": "solid", "strokeWidth": 2, @@ -13719,7 +13719,7 @@ History { exports[`regression tests > switches selected element on pointer down > [end of test] number of elements 1`] = `0`; -exports[`regression tests > switches selected element on pointer down > [end of test] number of renders 1`] = `12`; +exports[`regression tests > switches selected element on pointer down > [end of test] number of renders 1`] = `8`; exports[`regression tests > two-finger scroll works > [end of test] appState 1`] = ` { @@ -14212,7 +14212,7 @@ History { exports[`regression tests > undo/redo drawing an element > [end of test] number of elements 1`] = `0`; -exports[`regression tests > undo/redo drawing an element > [end of test] number of renders 1`] = `24`; +exports[`regression tests > undo/redo drawing an element > [end of test] number of renders 1`] = `16`; exports[`regression tests > updates fontSize & fontFamily appState > [end of test] appState 1`] = ` { diff --git a/packages/excalidraw/tests/__snapshots__/selection.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/selection.test.tsx.snap index 2eea908425aeb..56375aa50822e 100644 --- a/packages/excalidraw/tests/__snapshots__/selection.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/selection.test.tsx.snap @@ -43,7 +43,7 @@ exports[`select single element on the scene > arrow 1`] = ` "type": "arrow", "updated": 1, "version": 4, - "versionNonce": 2019559783, + "versionNonce": 401146281, "width": 30, "x": 10, "y": 10, @@ -92,7 +92,7 @@ exports[`select single element on the scene > arrow escape 1`] = ` "type": "line", "updated": 1, "version": 4, - "versionNonce": 2019559783, + "versionNonce": 401146281, "width": 30, "x": 10, "y": 10, @@ -126,7 +126,7 @@ exports[`select single element on the scene > diamond 1`] = ` "type": "diamond", "updated": 1, "version": 3, - "versionNonce": 401146281, + "versionNonce": 453191, "width": 30, "x": 10, "y": 10, @@ -160,7 +160,7 @@ exports[`select single element on the scene > ellipse 1`] = ` "type": "ellipse", "updated": 1, "version": 3, - "versionNonce": 401146281, + "versionNonce": 453191, "width": 30, "x": 10, "y": 10, @@ -194,7 +194,7 @@ exports[`select single element on the scene > rectangle 1`] = ` "type": "rectangle", "updated": 1, "version": 3, - "versionNonce": 401146281, + "versionNonce": 453191, "width": 30, "x": 10, "y": 10, diff --git a/packages/excalidraw/tests/dragCreate.test.tsx b/packages/excalidraw/tests/dragCreate.test.tsx index 7d0bcb27757d9..8a1a18173829d 100644 --- a/packages/excalidraw/tests/dragCreate.test.tsx +++ b/packages/excalidraw/tests/dragCreate.test.tsx @@ -51,8 +51,8 @@ describe("Test dragCreate", () => { // finish (position does not matter) fireEvent.pointerUp(canvas); - expect(renderInteractiveScene).toHaveBeenCalledTimes(6); - expect(renderStaticScene).toHaveBeenCalledTimes(6); + expect(renderInteractiveScene).toHaveBeenCalledTimes(5); + expect(renderStaticScene).toHaveBeenCalledTimes(4); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); @@ -83,8 +83,8 @@ describe("Test dragCreate", () => { // finish (position does not matter) fireEvent.pointerUp(canvas); - expect(renderInteractiveScene).toHaveBeenCalledTimes(6); - expect(renderStaticScene).toHaveBeenCalledTimes(6); + expect(renderInteractiveScene).toHaveBeenCalledTimes(5); + expect(renderStaticScene).toHaveBeenCalledTimes(4); expect(h.state.selectionElement).toBeNull(); @@ -116,8 +116,8 @@ describe("Test dragCreate", () => { // finish (position does not matter) fireEvent.pointerUp(canvas); - expect(renderInteractiveScene).toHaveBeenCalledTimes(6); - expect(renderStaticScene).toHaveBeenCalledTimes(6); + expect(renderInteractiveScene).toHaveBeenCalledTimes(5); + expect(renderStaticScene).toHaveBeenCalledTimes(4); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); @@ -148,8 +148,8 @@ describe("Test dragCreate", () => { // finish (position does not matter) fireEvent.pointerUp(canvas); - expect(renderInteractiveScene).toHaveBeenCalledTimes(6); - expect(renderStaticScene).toHaveBeenCalledTimes(6); + expect(renderInteractiveScene).toHaveBeenCalledTimes(5); + expect(renderStaticScene).toHaveBeenCalledTimes(4); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); @@ -184,8 +184,8 @@ describe("Test dragCreate", () => { // finish (position does not matter) fireEvent.pointerUp(canvas); - expect(renderInteractiveScene).toHaveBeenCalledTimes(6); - expect(renderStaticScene).toHaveBeenCalledTimes(6); + expect(renderInteractiveScene).toHaveBeenCalledTimes(5); + expect(renderStaticScene).toHaveBeenCalledTimes(4); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); @@ -226,7 +226,7 @@ describe("Test dragCreate", () => { fireEvent.pointerUp(canvas); expect(renderInteractiveScene).toHaveBeenCalledTimes(5); - expect(renderStaticScene).toHaveBeenCalledTimes(5); + expect(renderStaticScene).toHaveBeenCalledTimes(4); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(0); }); @@ -246,7 +246,7 @@ describe("Test dragCreate", () => { fireEvent.pointerUp(canvas); expect(renderInteractiveScene).toHaveBeenCalledTimes(5); - expect(renderStaticScene).toHaveBeenCalledTimes(5); + expect(renderStaticScene).toHaveBeenCalledTimes(4); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(0); }); @@ -266,7 +266,7 @@ describe("Test dragCreate", () => { fireEvent.pointerUp(canvas); expect(renderInteractiveScene).toHaveBeenCalledTimes(5); - expect(renderStaticScene).toHaveBeenCalledTimes(5); + expect(renderStaticScene).toHaveBeenCalledTimes(4); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(0); }); @@ -293,7 +293,7 @@ describe("Test dragCreate", () => { }); expect(renderInteractiveScene).toHaveBeenCalledTimes(6); - expect(renderStaticScene).toHaveBeenCalledTimes(6); + expect(renderStaticScene).toHaveBeenCalledTimes(4); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(0); }); @@ -320,7 +320,7 @@ describe("Test dragCreate", () => { }); expect(renderInteractiveScene).toHaveBeenCalledTimes(6); - expect(renderStaticScene).toHaveBeenCalledTimes(6); + expect(renderStaticScene).toHaveBeenCalledTimes(4); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(0); }); diff --git a/packages/excalidraw/tests/move.test.tsx b/packages/excalidraw/tests/move.test.tsx index c693c57b37447..692f8cf1efdf4 100644 --- a/packages/excalidraw/tests/move.test.tsx +++ b/packages/excalidraw/tests/move.test.tsx @@ -48,9 +48,9 @@ describe("move element", () => { fireEvent.pointerUp(canvas); expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot( - `6`, + `5`, ); - expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`); + expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`4`); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); @@ -96,9 +96,9 @@ describe("move element", () => { new Pointer("mouse").clickOn(rectB); expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot( - `19`, + `17`, ); - expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`16`); + expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`10`); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(3); expect(h.state.selectedElementIds[rectB.id]).toBeTruthy(); @@ -146,9 +146,9 @@ describe("duplicate element on move when ALT is clicked", () => { fireEvent.pointerUp(canvas); expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot( - `6`, + `5`, ); - expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`); + expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`4`); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); diff --git a/packages/excalidraw/tests/multiPointCreate.test.tsx b/packages/excalidraw/tests/multiPointCreate.test.tsx index ecbc8344d2453..ccca6a22e048e 100644 --- a/packages/excalidraw/tests/multiPointCreate.test.tsx +++ b/packages/excalidraw/tests/multiPointCreate.test.tsx @@ -53,7 +53,7 @@ describe("remove shape in non linear elements", () => { fireEvent.pointerUp(canvas, { clientX: 30, clientY: 30 }); expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`5`); - expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`5`); + expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`4`); expect(h.elements.length).toEqual(0); }); @@ -68,7 +68,7 @@ describe("remove shape in non linear elements", () => { fireEvent.pointerUp(canvas, { clientX: 30, clientY: 30 }); expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`5`); - expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`5`); + expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`4`); expect(h.elements.length).toEqual(0); }); @@ -83,7 +83,7 @@ describe("remove shape in non linear elements", () => { fireEvent.pointerUp(canvas, { clientX: 30, clientY: 30 }); expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`5`); - expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`5`); + expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`4`); expect(h.elements.length).toEqual(0); }); }); @@ -115,8 +115,8 @@ describe("multi point mode in linear elements", () => { key: KEYS.ENTER, }); - expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`9`); - expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`9`); + expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`7`); + expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`5`); expect(h.elements.length).toEqual(1); const element = h.elements[0] as ExcalidrawLinearElement; @@ -158,8 +158,8 @@ describe("multi point mode in linear elements", () => { fireEvent.keyDown(document, { key: KEYS.ENTER, }); - expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`9`); - expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`9`); + expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`7`); + expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`5`); expect(h.elements.length).toEqual(1); const element = h.elements[0] as ExcalidrawLinearElement; diff --git a/packages/excalidraw/tests/selection.test.tsx b/packages/excalidraw/tests/selection.test.tsx index d47f3037f7391..1ef7955c228e8 100644 --- a/packages/excalidraw/tests/selection.test.tsx +++ b/packages/excalidraw/tests/selection.test.tsx @@ -314,8 +314,8 @@ describe("select single element on the scene", () => { fireEvent.pointerDown(canvas, { clientX: 45, clientY: 20 }); fireEvent.pointerUp(canvas); - expect(renderInteractiveScene).toHaveBeenCalledTimes(9); - expect(renderStaticScene).toHaveBeenCalledTimes(7); + expect(renderInteractiveScene).toHaveBeenCalledTimes(8); + expect(renderStaticScene).toHaveBeenCalledTimes(5); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); @@ -346,8 +346,8 @@ describe("select single element on the scene", () => { fireEvent.pointerDown(canvas, { clientX: 45, clientY: 20 }); fireEvent.pointerUp(canvas); - expect(renderInteractiveScene).toHaveBeenCalledTimes(9); - expect(renderStaticScene).toHaveBeenCalledTimes(7); + expect(renderInteractiveScene).toHaveBeenCalledTimes(8); + expect(renderStaticScene).toHaveBeenCalledTimes(5); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); @@ -378,8 +378,8 @@ describe("select single element on the scene", () => { fireEvent.pointerDown(canvas, { clientX: 45, clientY: 20 }); fireEvent.pointerUp(canvas); - expect(renderInteractiveScene).toHaveBeenCalledTimes(9); - expect(renderStaticScene).toHaveBeenCalledTimes(7); + expect(renderInteractiveScene).toHaveBeenCalledTimes(8); + expect(renderStaticScene).toHaveBeenCalledTimes(5); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); @@ -423,8 +423,8 @@ describe("select single element on the scene", () => { fireEvent.pointerDown(canvas, { clientX: 40, clientY: 40 }); fireEvent.pointerUp(canvas); - expect(renderInteractiveScene).toHaveBeenCalledTimes(9); - expect(renderStaticScene).toHaveBeenCalledTimes(7); + expect(renderInteractiveScene).toHaveBeenCalledTimes(8); + expect(renderStaticScene).toHaveBeenCalledTimes(5); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); @@ -467,8 +467,8 @@ describe("select single element on the scene", () => { fireEvent.pointerDown(canvas, { clientX: 40, clientY: 40 }); fireEvent.pointerUp(canvas); - expect(renderInteractiveScene).toHaveBeenCalledTimes(9); - expect(renderStaticScene).toHaveBeenCalledTimes(7); + expect(renderInteractiveScene).toHaveBeenCalledTimes(8); + expect(renderStaticScene).toHaveBeenCalledTimes(5); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); From a8e978731e73d71869105e12f23dda4d6b28902a Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Thu, 8 Aug 2024 19:09:43 +0800 Subject: [PATCH 07/16] fix linear el state --- packages/excalidraw/actions/actionFinalize.tsx | 1 - .../tests/__snapshots__/history.test.tsx.snap | 16 +++++++--------- packages/excalidraw/tests/history.test.tsx | 10 +++++----- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/packages/excalidraw/actions/actionFinalize.tsx b/packages/excalidraw/actions/actionFinalize.tsx index 0197fb7db0a64..908e83b41f5f0 100644 --- a/packages/excalidraw/actions/actionFinalize.tsx +++ b/packages/excalidraw/actions/actionFinalize.tsx @@ -50,7 +50,6 @@ export const actionFinalize = register({ ...appState, cursorButton: "up", editingLinearElement: null, - selectedLinearElement: null, }, storeAction: StoreAction.CAPTURE, }; diff --git a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap index 4dce7d1981449..92df0bf28a332 100644 --- a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap @@ -7124,7 +7124,9 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "resizingElement": null, "scrollX": 0, "scrollY": 0, - "selectedElementIds": {}, + "selectedElementIds": { + "id113": true, + }, "selectedElementsAreBeingDragged": false, "selectedGroupIds": {}, "selectionElement": null, @@ -7195,7 +7197,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "strokeWidth": 2, "type": "arrow", "updated": 1, - "version": 8, + "version": 7, "width": 10, "x": -10, "y": -10, @@ -7227,8 +7229,7 @@ History { }, "elementsChange": ElementsChange { "added": Map {}, - "removed": Map {}, - "updated": Map { + "removed": Map { "id113" => Delta { "deleted": { "angle": 0, @@ -7243,7 +7244,7 @@ History { "groupIds": [], "height": 10, "index": "a0", - "isDeleted": true, + "isDeleted": false, "lastCommittedPoint": [ 10, 10, @@ -7280,6 +7281,7 @@ History { }, }, }, + "updated": Map {}, }, }, HistoryEntry { @@ -7321,11 +7323,9 @@ History { "delta": Delta { "deleted": { "editingLinearElementId": null, - "selectedLinearElementId": null, }, "inserted": { "editingLinearElementId": "id113", - "selectedLinearElementId": "id113", }, }, }, @@ -19801,11 +19801,9 @@ History { "delta": Delta { "deleted": { "editingLinearElementId": null, - "selectedLinearElementId": null, }, "inserted": { "editingLinearElementId": "id27", - "selectedLinearElementId": "id27", }, }, }, diff --git a/packages/excalidraw/tests/history.test.tsx b/packages/excalidraw/tests/history.test.tsx index dcbfb34fdf816..16968e8bc5d72 100644 --- a/packages/excalidraw/tests/history.test.tsx +++ b/packages/excalidraw/tests/history.test.tsx @@ -756,7 +756,7 @@ describe("history", () => { expect(API.getRedoStack().length).toBe(0); expect(assertSelectedElements(h.elements[0])); expect(h.state.editingLinearElement).toBeNull(); - expect(h.state.selectedLinearElement).toBeNull(); + expect(h.state.selectedLinearElement).not.toBeNull(); expect(h.elements).toEqual([ expect.objectContaining({ isDeleted: false, @@ -964,7 +964,7 @@ describe("history", () => { expect(API.getRedoStack().length).toBe(0); expect(assertSelectedElements(h.elements[0])); expect(h.state.editingLinearElement).toBeNull(); - expect(h.state.selectedLinearElement).toBeNull(); + expect(h.state.selectedLinearElement).not.toBeNull(); expect(h.elements).toEqual([ expect.objectContaining({ isDeleted: false, @@ -2730,7 +2730,7 @@ describe("history", () => { expect(API.getUndoStack().length).toBe(4); expect(API.getRedoStack().length).toBe(0); expect(h.state.editingLinearElement).toBeNull(); - expect(h.state.selectedLinearElement).toBeNull(); + expect(h.state.selectedLinearElement).not.toBeNull(); // Simulate remote update API.updateScene({ @@ -2743,8 +2743,8 @@ describe("history", () => { }); Keyboard.undo(); - expect(API.getUndoStack().length).toBe(0); - expect(API.getRedoStack().length).toBe(4); + expect(API.getUndoStack().length).toBe(1); + expect(API.getRedoStack().length).toBe(3); expect(h.state.editingLinearElement).toBeNull(); expect(h.state.selectedLinearElement).toBeNull(); From 4bd657898894a83e588a7109de24c8c49497a7d6 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Fri, 9 Aug 2024 21:09:24 +0800 Subject: [PATCH 08/16] make editingElement editingTextElement --- .../excalidraw/actions/actionFinalize.tsx | 2 +- packages/excalidraw/actions/actionHistory.tsx | 3 +- .../excalidraw/actions/actionProperties.tsx | 23 ++-- packages/excalidraw/appState.ts | 4 +- packages/excalidraw/components/Actions.tsx | 4 +- packages/excalidraw/components/App.tsx | 76 +++++------- packages/excalidraw/components/HintViewer.tsx | 4 +- .../components/canvases/InteractiveCanvas.tsx | 2 +- packages/excalidraw/data/reconcile.ts | 2 +- .../element/showSelectedShapeActions.ts | 2 +- .../excalidraw/element/textWysiwyg.test.tsx | 18 +-- .../excalidraw/renderer/interactiveScene.ts | 9 +- packages/excalidraw/scene/Renderer.ts | 16 +-- packages/excalidraw/scene/selection.ts | 6 +- .../__snapshots__/contextmenu.test.tsx.snap | 34 ++--- .../tests/__snapshots__/history.test.tsx.snap | 116 +++++++++--------- .../regressionTests.test.tsx.snap | 104 ++++++++-------- .../excalidraw/tests/elementLocking.test.tsx | 20 +-- .../scene/__snapshots__/export.test.ts.snap | 20 +-- packages/excalidraw/types.ts | 10 +- .../utils/__snapshots__/export.test.ts.snap | 2 +- 21 files changed, 234 insertions(+), 243 deletions(-) diff --git a/packages/excalidraw/actions/actionFinalize.tsx b/packages/excalidraw/actions/actionFinalize.tsx index 908e83b41f5f0..95cc19c96fa77 100644 --- a/packages/excalidraw/actions/actionFinalize.tsx +++ b/packages/excalidraw/actions/actionFinalize.tsx @@ -178,7 +178,7 @@ export const actionFinalize = register({ newElement: null, selectionElement: null, multiElement: null, - editingElement: null, + editingTextElement: null, startBoundElement: null, suggestedBindings: [], selectedElementIds: diff --git a/packages/excalidraw/actions/actionHistory.tsx b/packages/excalidraw/actions/actionHistory.tsx index 26a4a60618e7c..5ed14ac8072f8 100644 --- a/packages/excalidraw/actions/actionHistory.tsx +++ b/packages/excalidraw/actions/actionHistory.tsx @@ -20,7 +20,8 @@ const writeData = ( if ( !appState.multiElement && !appState.resizingElement && - !appState.editingElement && + // MARK: do check this again + !appState.editingTextElement && !appState.newElement && !appState.selectedElementsAreBeingDragged && !appState.selectionElement diff --git a/packages/excalidraw/actions/actionProperties.tsx b/packages/excalidraw/actions/actionProperties.tsx index add2e34e3bd9b..64709ee4c7e93 100644 --- a/packages/excalidraw/actions/actionProperties.tsx +++ b/packages/excalidraw/actions/actionProperties.tsx @@ -133,7 +133,7 @@ export const changeProperty = ( return elements.map((element) => { if ( selectedElementIds.get(element.id) || - element.id === appState.editingElement?.id + element.id === appState.editingTextElement?.id ) { return callback(element); } @@ -148,13 +148,13 @@ export const getFormValue = function ( isRelevantElement: true | ((element: ExcalidrawElement) => boolean), defaultValue: T | ((isSomeElementSelected: boolean) => T), ): T { - const editingElement = appState.editingElement; + const editingTextElement = appState.editingTextElement; const nonDeletedElements = getNonDeletedElements(elements); let ret: T | null = null; - if (editingElement) { - ret = getAttribute(editingElement); + if (editingTextElement) { + ret = getAttribute(editingTextElement); } if (!ret) { @@ -1076,19 +1076,20 @@ export const actionChangeFontFamily = register({ // open, populate the cache from scratch cachedElementsRef.current.clear(); - const { editingElement } = appState; + const { editingTextElement } = appState; - if (editingElement?.type === "text") { - // retrieve the latest version from the scene, as `editingElement` isn't mutated - const latestEditingElement = app.scene.getElement( - editingElement.id, + // still check type to be safe + if (editingTextElement?.type === "text") { + // retrieve the latest version from the scene, as `editingTextElement` isn't mutated + const latesteditingTextElement = app.scene.getElement( + editingTextElement.id, ); // inside the wysiwyg editor cachedElementsRef.current.set( - editingElement.id, + editingTextElement.id, newElementWith( - latestEditingElement || editingElement, + latesteditingTextElement || editingTextElement, {}, true, ), diff --git a/packages/excalidraw/appState.ts b/packages/excalidraw/appState.ts index 12a0f43dd5858..fb85bf10eddf6 100644 --- a/packages/excalidraw/appState.ts +++ b/packages/excalidraw/appState.ts @@ -42,7 +42,7 @@ export const getDefaultAppState = (): Omit< cursorButton: "up", activeEmbeddable: null, newElement: null, - editingElement: null, + editingTextElement: null, editingGroupId: null, editingLinearElement: null, activeTool: { @@ -161,7 +161,7 @@ const APP_STATE_STORAGE_CONF = (< cursorButton: { browser: true, export: false, server: false }, activeEmbeddable: { browser: false, export: false, server: false }, newElement: { browser: false, export: false, server: false }, - editingElement: { browser: false, export: false, server: false }, + editingTextElement: { browser: false, export: false, server: false }, editingGroupId: { browser: true, export: false, server: false }, editingLinearElement: { browser: false, export: false, server: false }, activeTool: { browser: true, export: false, server: false }, diff --git a/packages/excalidraw/components/Actions.tsx b/packages/excalidraw/components/Actions.tsx index 91102aef2cef4..2f24d291865e4 100644 --- a/packages/excalidraw/components/Actions.tsx +++ b/packages/excalidraw/components/Actions.tsx @@ -104,7 +104,7 @@ export const SelectedShapeActions = ({ ) { isSingleElementBoundContainer = true; } - const isEditing = Boolean(appState.editingElement); + const isEditingText = Boolean(appState.editingTextElement); const device = useDevice(); const isRTL = document.documentElement.getAttribute("dir") === "rtl"; @@ -234,7 +234,7 @@ export const SelectedShapeActions = ({ )} - {!isEditing && targetElements.length > 0 && ( + {!isEditingText && targetElements.length > 0 && (
{t("labels.actions")}
diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index de1b8b5a661e8..480e0c27a5358 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -1452,25 +1452,20 @@ class App extends React.Component { scrollY: this.state.scrollY, height: this.state.height, width: this.state.width, - editingElement: this.state.editingElement, + editingTextElement: this.state.editingTextElement, pendingImageElementId: this.state.pendingImageElementId, }); const allElementsMap = this.scene.getNonDeletedElementsMap(); const shouldBlockPointerEvents = - !( - this.state.editingElement && isLinearElement(this.state.editingElement) - ) && - (this.state.selectionElement || - this.state.newElement || - this.state.selectedElementsAreBeingDragged || - this.state.resizingElement || - (this.state.activeTool.type === "laser" && - // technically we can just test on this once we make it more safe - this.state.cursorButton === "down") || - (this.state.editingElement && - !isTextElement(this.state.editingElement))); + this.state.selectionElement || + this.state.newElement || + this.state.selectedElementsAreBeingDragged || + this.state.resizingElement || + (this.state.activeTool.type === "laser" && + // technically we can just test on this once we make it more safe + this.state.cursorButton === "down"); const firstSelectedElement = selectedElements[0]; @@ -2163,7 +2158,7 @@ class App extends React.Component { let didUpdate = false; - let editingElement: AppState["editingElement"] | null = null; + let editingTextElement: AppState["editingTextElement"] | null = null; if (actionResult.elements) { this.scene.replaceAllElements(actionResult.elements); didUpdate = true; @@ -2176,7 +2171,7 @@ class App extends React.Component { this.addNewImagesToImageCache(); } - if (actionResult.appState || editingElement || this.state.contextMenu) { + if (actionResult.appState || editingTextElement || this.state.contextMenu) { let viewModeEnabled = actionResult?.appState?.viewModeEnabled || false; let zenModeEnabled = actionResult?.appState?.zenModeEnabled || false; let gridSize = actionResult?.appState?.gridSize || null; @@ -2197,23 +2192,24 @@ class App extends React.Component { gridSize = this.props.gridModeEnabled ? GRID_SIZE : null; } - editingElement = actionResult.appState?.editingElement || null; + editingTextElement = actionResult.appState?.editingTextElement || null; - // make sure editingElement points to latest element reference - if (actionResult.elements && editingElement) { + // make sure editingTextElement points to latest element reference + if (actionResult.elements && editingTextElement) { actionResult.elements.forEach((element) => { if ( - editingElement?.id === element.id && - editingElement !== element && - isNonDeletedElement(element) + editingTextElement?.id === element.id && + editingTextElement !== element && + isNonDeletedElement(element) && + isTextElement(element) ) { - editingElement = element; + editingTextElement = element; } }); } - if (editingElement?.isDeleted) { - editingElement = null; + if (editingTextElement?.isDeleted) { + editingTextElement = null; } this.setState((state) => { @@ -2225,7 +2221,7 @@ class App extends React.Component { // or programmatically from the host, so it will need to be // rewritten later contextMenu: null, - editingElement, + editingTextElement, viewModeEnabled, zenModeEnabled, gridSize, @@ -2811,9 +2807,9 @@ class App extends React.Component { } // failsafe in case the state is being updated in incorrect order resulting - // in the editingElement being now a deleted element - if (this.state.editingElement?.isDeleted) { - this.setState({ editingElement: null }); + // in the editingTextElement being now a deleted element + if (this.state.editingTextElement?.isDeleted) { + this.setState({ editingTextElement: null }); } if ( @@ -2869,7 +2865,7 @@ class App extends React.Component { } const scrolledOutside = // hide when editing text - isTextElement(this.state.editingElement) + isTextElement(this.state.editingTextElement) ? false : !atLeastOneVisibleElement && elementsMap.size > 0; if (this.state.scrolledOutside !== scrolledOutside) { @@ -4533,7 +4529,7 @@ class App extends React.Component { this.setState({ newElement: null, - editingElement: null, + editingTextElement: null, }); if (this.state.activeTool.locked) { setCursorForShape(this.interactiveCanvas, this.state); @@ -4907,7 +4903,7 @@ class App extends React.Component { }), }); } - this.setState({ editingElement: element }); + this.setState({ editingTextElement: element }); if (!existingTextElement) { if (container && shouldBindToContainer) { @@ -5872,7 +5868,7 @@ class App extends React.Component { : {}), appState: { newElement: null, - editingElement: null, + editingTextElement: null, startBoundElement: null, suggestedBindings: [], selectedElementIds: makeNextSelectedElementIds( @@ -6260,7 +6256,7 @@ class App extends React.Component { isHandToolActive(this.state) || this.state.viewModeEnabled) ) || - isTextElement(this.state.editingElement) + this.state.editingTextElement ) { return false; } @@ -6804,7 +6800,7 @@ class App extends React.Component { // if we're currently still editing text, clicking outside // should only finalize it, not create another (irrespective // of state.activeTool.locked) - if (isTextElement(this.state.editingElement)) { + if (this.state.editingTextElement) { return; } let sceneX = pointerDownState.origin.x; @@ -7609,11 +7605,11 @@ class App extends React.Component { // prevent dragging even if we're no longer holding cmd/ctrl otherwise // it would have weird results (stuff jumping all over the screen) - // Checking for editingElement to avoid jump while editing on mobile #6503 + // Checking for editingTextElement to avoid jump while editing on mobile #6503 if ( selectedElements.length > 0 && !pointerDownState.withCmdOrCtrl && - !this.state.editingElement && + !this.state.editingTextElement && this.state.activeEmbeddable?.state !== "active" ) { const dragOffset = { @@ -8039,12 +8035,6 @@ class App extends React.Component { frameToHighlight: null, elementsToHighlight: null, cursorButton: "up", - // text elements are reset on finalize, and resetting on pointerup - // may cause issues with double taps - editingElement: - multiElement || isTextElement(this.state.editingElement) - ? this.state.editingElement - : null, snapLines: updateStable(prevState.snapLines, []), originSnapOffset: null, })); @@ -9149,7 +9139,7 @@ class App extends React.Component { this.setState( { pendingImageElementId: null, - editingElement: null, + newElement: null, activeTool: updateActiveTool(this.state, { type: "selection" }), }, () => { diff --git a/packages/excalidraw/components/HintViewer.tsx b/packages/excalidraw/components/HintViewer.tsx index 8bc43dd898056..2a085d5519b53 100644 --- a/packages/excalidraw/components/HintViewer.tsx +++ b/packages/excalidraw/components/HintViewer.tsx @@ -79,7 +79,7 @@ const getHints = ({ appState, isMobile, device, app }: HintViewerProps) => { return t("hints.text_selected"); } - if (appState.editingElement && isTextElement(appState.editingElement)) { + if (appState.editingTextElement) { return t("hints.text_editing"); } @@ -87,7 +87,7 @@ const getHints = ({ appState, isMobile, device, app }: HintViewerProps) => { if ( appState.selectionElement && !selectedElements.length && - !appState.editingElement && + !appState.editingTextElement && !appState.editingLinearElement ) { return t("hints.deepBoxSelect"); diff --git a/packages/excalidraw/components/canvases/InteractiveCanvas.tsx b/packages/excalidraw/components/canvases/InteractiveCanvas.tsx index 2c14a6ab3a751..d546bc9d55c89 100644 --- a/packages/excalidraw/components/canvases/InteractiveCanvas.tsx +++ b/packages/excalidraw/components/canvases/InteractiveCanvas.tsx @@ -202,7 +202,7 @@ const getRelevantAppStateProps = ( activeEmbeddable: appState.activeEmbeddable, snapLines: appState.snapLines, zenModeEnabled: appState.zenModeEnabled, - editingElement: appState.editingElement, + editingTextElement: appState.editingTextElement, }); const areEqual = ( diff --git a/packages/excalidraw/data/reconcile.ts b/packages/excalidraw/data/reconcile.ts index 80b0470bb5885..fa4cff8d11b66 100644 --- a/packages/excalidraw/data/reconcile.ts +++ b/packages/excalidraw/data/reconcile.ts @@ -24,7 +24,7 @@ const shouldDiscardRemoteElement = ( if ( local && // local element is being edited - (local.id === localAppState.editingElement?.id || + (local.id === localAppState.editingTextElement?.id || local.id === localAppState.resizingElement?.id || local.id === localAppState.newElement?.id || // TODO: Is this still valid? As newElement is selection element, which is never part of the elements array // local element is newer diff --git a/packages/excalidraw/element/showSelectedShapeActions.ts b/packages/excalidraw/element/showSelectedShapeActions.ts index c464e69cf3256..eea9336749246 100644 --- a/packages/excalidraw/element/showSelectedShapeActions.ts +++ b/packages/excalidraw/element/showSelectedShapeActions.ts @@ -9,7 +9,7 @@ export const showSelectedShapeActions = ( Boolean( !appState.viewModeEnabled && ((appState.activeTool.type !== "custom" && - (appState.editingElement || + (appState.editingTextElement || (appState.activeTool.type !== "selection" && appState.activeTool.type !== "eraser" && appState.activeTool.type !== "hand" && diff --git a/packages/excalidraw/element/textWysiwyg.test.tsx b/packages/excalidraw/element/textWysiwyg.test.tsx index 7b78f56677cd4..7c80e5b54af74 100644 --- a/packages/excalidraw/element/textWysiwyg.test.tsx +++ b/packages/excalidraw/element/textWysiwyg.test.tsx @@ -61,9 +61,9 @@ describe("textWysiwyg", () => { Keyboard.keyPress(KEYS.ENTER); - expect(h.state.editingElement?.id).toBe(text.id); + expect(h.state.editingTextElement?.id).toBe(text.id); expect( - (h.state.editingElement as ExcalidrawTextElement).containerId, + (h.state.editingTextElement as ExcalidrawTextElement).containerId, ).toBe(null); }); @@ -105,7 +105,7 @@ describe("textWysiwyg", () => { Keyboard.keyPress(KEYS.ENTER); - expect(h.state.editingElement?.id).toBe(boundText2.id); + expect(h.state.editingTextElement?.id).toBe(boundText2.id); }); it("should not create bound text on ENTER if text exists at container center", () => { @@ -133,7 +133,7 @@ describe("textWysiwyg", () => { Keyboard.keyPress(KEYS.ENTER); - expect(h.state.editingElement?.id).toBe(text.id); + expect(h.state.editingTextElement?.id).toBe(text.id); }); it("should edit existing bound text on ENTER even if higher z-index unbound text exists at container center", () => { @@ -174,7 +174,7 @@ describe("textWysiwyg", () => { Keyboard.keyPress(KEYS.ENTER); - expect(h.state.editingElement?.id).toBe(boundText.id); + expect(h.state.editingTextElement?.id).toBe(boundText.id); }); it("should edit text under cursor when clicked with text tool", async () => { @@ -195,7 +195,7 @@ describe("textWysiwyg", () => { const editor = await getTextEditor(textEditorSelector, false); expect(editor).not.toBe(null); - expect(h.state.editingElement?.id).toBe(text.id); + expect(h.state.editingTextElement?.id).toBe(text.id); expect(h.elements.length).toBe(1); }); @@ -217,7 +217,7 @@ describe("textWysiwyg", () => { const editor = await getTextEditor(textEditorSelector, false); expect(editor).not.toBe(null); - expect(h.state.editingElement?.id).toBe(text.id); + expect(h.state.editingTextElement?.id).toBe(text.id); expect(h.elements.length).toBe(1); }); @@ -286,7 +286,7 @@ describe("textWysiwyg", () => { mouse.doubleClickAt(text.x + text.width / 2, text.y + text.height / 2); const editor = await getTextEditor(textEditorSelector); expect(editor).not.toBe(null); - expect(h.state.editingElement?.id).toBe(text.id); + expect(h.state.editingTextElement?.id).toBe(text.id); expect(h.elements.length).toBe(1); const nextText = `${wrappedText} is great!`; @@ -881,7 +881,7 @@ describe("textWysiwyg", () => { expect(await getTextEditor(textEditorSelector, false)).toBe(null); - expect(h.state.editingElement).toBe(null); + expect(h.state.editingTextElement).toBe(null); expect(text.fontFamily).toEqual(FONT_FAMILY.Excalifont); diff --git a/packages/excalidraw/renderer/interactiveScene.ts b/packages/excalidraw/renderer/interactiveScene.ts index ab37a14256f51..597ab06961c8a 100644 --- a/packages/excalidraw/renderer/interactiveScene.ts +++ b/packages/excalidraw/renderer/interactiveScene.ts @@ -680,8 +680,11 @@ const _renderInteractiveScene = ({ } } - if (appState.editingElement && isTextElement(appState.editingElement)) { - const textElement = allElementsMap.get(appState.editingElement.id) as + if ( + appState.editingTextElement && + isTextElement(appState.editingTextElement) + ) { + const textElement = allElementsMap.get(appState.editingTextElement.id) as | ExcalidrawTextElement | undefined; if (textElement && !textElement.autoResize) { @@ -894,7 +897,7 @@ const _renderInteractiveScene = ({ !appState.viewModeEnabled && showBoundingBox && // do not show transform handles when text is being edited - !isTextElement(appState.editingElement) + !isTextElement(appState.editingTextElement) ) { renderTransformHandles( context, diff --git a/packages/excalidraw/scene/Renderer.ts b/packages/excalidraw/scene/Renderer.ts index 63b7e7da7d980..9bedb1e75eff8 100644 --- a/packages/excalidraw/scene/Renderer.ts +++ b/packages/excalidraw/scene/Renderer.ts @@ -64,11 +64,11 @@ export class Renderer { const getRenderableElements = ({ elements, - editingElement, + editingTextElement, pendingImageElementId, }: { elements: readonly NonDeletedExcalidrawElement[]; - editingElement: AppState["editingElement"]; + editingTextElement: AppState["editingTextElement"]; pendingImageElementId: AppState["pendingImageElementId"]; }) => { const elementsMap = toBrandedType(new Map()); @@ -86,9 +86,9 @@ export class Renderer { // we don't want to render text element that's being currently edited // (it's rendered on remote only) if ( - !editingElement || - editingElement.type !== "text" || - element.id !== editingElement.id + !editingTextElement || + editingTextElement.type !== "text" || + element.id !== editingTextElement.id ) { elementsMap.set(element.id, element); } @@ -105,7 +105,7 @@ export class Renderer { scrollY, height, width, - editingElement, + editingTextElement, pendingImageElementId, // cache-invalidation nonce sceneNonce: _sceneNonce, @@ -117,7 +117,7 @@ export class Renderer { scrollY: AppState["scrollY"]; height: AppState["height"]; width: AppState["width"]; - editingElement: AppState["editingElement"]; + editingTextElement: AppState["editingTextElement"]; pendingImageElementId: AppState["pendingImageElementId"]; sceneNonce: ReturnType["getSceneNonce"]>; }) => { @@ -125,7 +125,7 @@ export class Renderer { const elementsMap = getRenderableElements({ elements, - editingElement, + editingTextElement, pendingImageElementId, }); diff --git a/packages/excalidraw/scene/selection.ts b/packages/excalidraw/scene/selection.ts index 547416c72dfb5..7593cd5d98f25 100644 --- a/packages/excalidraw/scene/selection.ts +++ b/packages/excalidraw/scene/selection.ts @@ -218,10 +218,10 @@ export const getSelectedElements = ( export const getTargetElements = ( elements: ElementsMapOrArray, - appState: Pick, + appState: Pick, ) => - appState.editingElement - ? [appState.editingElement] + appState.editingTextElement + ? [appState.editingTextElement] : getSelectedElements(elements, appState, { includeBoundTextElement: true, }); diff --git a/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap index c216027e3a49a..e04a8b945d1b2 100644 --- a/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap @@ -812,10 +812,10 @@ exports[`contextMenu element > right-clicking on a group should select whole gro "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -1015,10 +1015,10 @@ exports[`contextMenu element > selecting 'Add to library' in context menu adds e "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -1228,10 +1228,10 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -1556,10 +1556,10 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -1884,10 +1884,10 @@ exports[`contextMenu element > selecting 'Copy styles' in context menu copies st "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -2097,10 +2097,10 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -2334,10 +2334,10 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -2632,10 +2632,10 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -2998,10 +2998,10 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -3470,10 +3470,10 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -3790,10 +3790,10 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -4110,10 +4110,10 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -5293,10 +5293,10 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -6417,10 +6417,10 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -7349,10 +7349,10 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -8258,10 +8258,10 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -9149,10 +9149,10 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, diff --git a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap index 92df0bf28a332..4b9910f0e9971 100644 --- a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap @@ -29,10 +29,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -628,10 +628,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -1131,10 +1131,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -1496,10 +1496,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -1862,10 +1862,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -2126,10 +2126,10 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -2563,10 +2563,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -2859,10 +2859,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -3140,10 +3140,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -3431,10 +3431,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -3714,10 +3714,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -3946,10 +3946,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -4202,10 +4202,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -4472,10 +4472,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -4700,10 +4700,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -4928,10 +4928,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -5154,10 +5154,10 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -5380,10 +5380,10 @@ exports[`history > multiplayer undo/redo > conflicts in frames and their childre "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -5636,10 +5636,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -5964,10 +5964,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -6386,10 +6386,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -6761,10 +6761,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -7077,10 +7077,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -7372,10 +7372,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -7598,10 +7598,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -7950,10 +7950,10 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -8302,10 +8302,10 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -8703,10 +8703,10 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -8987,10 +8987,10 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -9249,10 +9249,10 @@ exports[`history > multiplayer undo/redo > should not override remote changes on "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -9510,10 +9510,10 @@ exports[`history > multiplayer undo/redo > should not override remote changes on "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -9738,10 +9738,10 @@ exports[`history > multiplayer undo/redo > should override remotely added groups "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -10036,10 +10036,10 @@ exports[`history > multiplayer undo/redo > should override remotely added points "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -10373,10 +10373,10 @@ exports[`history > multiplayer undo/redo > should redistribute deltas when eleme "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -10605,10 +10605,10 @@ exports[`history > multiplayer undo/redo > should redraw arrows on undo > [end o "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -11055,10 +11055,10 @@ exports[`history > multiplayer undo/redo > should update history entries after r "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -11306,10 +11306,10 @@ exports[`history > singleplayer undo/redo > remounting undo/redo buttons should "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -11542,10 +11542,10 @@ exports[`history > singleplayer undo/redo > should clear the redo stack on eleme "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -11780,10 +11780,10 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -12178,10 +12178,10 @@ exports[`history > singleplayer undo/redo > should create new history entry on s "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -12422,10 +12422,10 @@ exports[`history > singleplayer undo/redo > should disable undo/redo buttons whe "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -12660,10 +12660,10 @@ exports[`history > singleplayer undo/redo > should end up with no history entry "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -12898,10 +12898,10 @@ exports[`history > singleplayer undo/redo > should iterate through the history w "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -13142,10 +13142,10 @@ exports[`history > singleplayer undo/redo > should not clear the redo stack on s "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -13471,10 +13471,10 @@ exports[`history > singleplayer undo/redo > should not collapse when applying co "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -13640,10 +13640,10 @@ exports[`history > singleplayer undo/redo > should not end up with history entry "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -13925,10 +13925,10 @@ exports[`history > singleplayer undo/redo > should not end up with history entry "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -14189,10 +14189,10 @@ exports[`history > singleplayer undo/redo > should not override appstate changes "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -14461,10 +14461,10 @@ exports[`history > singleplayer undo/redo > should support appstate name or view "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -14619,10 +14619,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -15312,10 +15312,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -15929,10 +15929,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -16546,10 +16546,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -17255,10 +17255,10 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -18002,10 +18002,10 @@ exports[`history > singleplayer undo/redo > should support changes in elements' "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -18473,10 +18473,10 @@ exports[`history > singleplayer undo/redo > should support duplication of groups "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -18992,10 +18992,10 @@ exports[`history > singleplayer undo/redo > should support element creation, del "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -19445,10 +19445,10 @@ exports[`history > singleplayer undo/redo > should support linear element creati "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, diff --git a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap index 93d87aaebea78..52a347ffe851a 100644 --- a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap @@ -29,10 +29,10 @@ exports[`given element A and group of elements B and given both are selected whe "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -438,10 +438,10 @@ exports[`given element A and group of elements B and given both are selected whe "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -838,10 +838,10 @@ exports[`regression tests > Cmd/Ctrl-click exclusively select element under poin "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": "id10", "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -1377,10 +1377,10 @@ exports[`regression tests > Drags selected element when hitting only bounding bo "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -1575,10 +1575,10 @@ exports[`regression tests > adjusts z order when grouping > [end of test] appSta "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -1944,10 +1944,10 @@ exports[`regression tests > alt-drag duplicates an element > [end of test] appSt "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -2178,10 +2178,10 @@ exports[`regression tests > arrow keys > [end of test] appState 1`] = ` "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -2352,10 +2352,10 @@ exports[`regression tests > can drag element that covers another element, while "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -2666,10 +2666,10 @@ exports[`regression tests > change the properties of a shape > [end of test] app "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -2906,10 +2906,10 @@ exports[`regression tests > click on an element and drag it > [dragged] appState "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -3143,10 +3143,10 @@ exports[`regression tests > click on an element and drag it > [end of test] appS "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -3367,10 +3367,10 @@ exports[`regression tests > click to select a shape > [end of test] appState 1`] "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -3617,10 +3617,10 @@ exports[`regression tests > click-drag to select a group > [end of test] appStat "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -3922,10 +3922,10 @@ exports[`regression tests > deleting last but one element in editing group shoul "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -4330,10 +4330,10 @@ exports[`regression tests > deselects group of selected elements on pointer down "currentItemTextAlign": "left", "cursorButton": "down", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -4607,10 +4607,10 @@ exports[`regression tests > deselects group of selected elements on pointer up w "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -4854,10 +4854,10 @@ exports[`regression tests > deselects selected element on pointer down when poin "currentItemTextAlign": "left", "cursorButton": "down", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -5058,10 +5058,10 @@ exports[`regression tests > deselects selected element, on pointer up, when clic "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -5251,10 +5251,10 @@ exports[`regression tests > double click to edit a group > [end of test] appStat "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": "id3", "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -5627,10 +5627,10 @@ exports[`regression tests > drags selected elements from point inside common bou "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -5911,10 +5911,10 @@ exports[`regression tests > draw every type of shape > [end of test] appState 1` "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -6713,10 +6713,10 @@ exports[`regression tests > given a group of selected elements with an element t "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -7037,10 +7037,10 @@ exports[`regression tests > given a selected element A and a not selected elemen "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -7307,10 +7307,10 @@ exports[`regression tests > given selected element A with lower z-index than uns "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -7535,10 +7535,10 @@ exports[`regression tests > given selected element A with lower z-index than uns "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -7766,10 +7766,10 @@ exports[`regression tests > key 2 selects rectangle tool > [end of test] appStat "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -7940,10 +7940,10 @@ exports[`regression tests > key 3 selects diamond tool > [end of test] appState "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -8114,10 +8114,10 @@ exports[`regression tests > key 4 selects ellipse tool > [end of test] appState "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -8288,10 +8288,10 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1` "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -8504,10 +8504,10 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`] "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -8719,10 +8719,10 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] appState "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -8907,10 +8907,10 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1` "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -9123,10 +9123,10 @@ exports[`regression tests > key d selects diamond tool > [end of test] appState "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -9297,10 +9297,10 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`] "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -9512,10 +9512,10 @@ exports[`regression tests > key o selects ellipse tool > [end of test] appState "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -9686,10 +9686,10 @@ exports[`regression tests > key p selects freedraw tool > [end of test] appState "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -9874,10 +9874,10 @@ exports[`regression tests > key r selects rectangle tool > [end of test] appStat "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -10048,10 +10048,10 @@ exports[`regression tests > make a group and duplicate it > [end of test] appSta "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -10556,10 +10556,10 @@ exports[`regression tests > noop interaction after undo shouldn't create history "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -10827,10 +10827,10 @@ exports[`regression tests > pinch-to-zoom works > [end of test] appState 1`] = ` "currentItemTextAlign": "left", "cursorButton": "down", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -10947,10 +10947,10 @@ exports[`regression tests > shift click on selected element should deselect it o "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -11140,10 +11140,10 @@ exports[`regression tests > shift-click to multiselect, then drag > [end of test "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -11445,10 +11445,10 @@ exports[`regression tests > should group elements and ungroup them > [end of tes "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -11851,10 +11851,10 @@ exports[`regression tests > single-clicking on a subgroup of a selected group sh "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -12458,10 +12458,10 @@ exports[`regression tests > spacebar + drag scrolls the canvas > [end of test] a "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -12581,10 +12581,10 @@ exports[`regression tests > supports nested groups > [end of test] appState 1`] "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": "id3", "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -13159,10 +13159,10 @@ exports[`regression tests > switches from group of selected elements to another "currentItemTextAlign": "left", "cursorButton": "down", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -13491,10 +13491,10 @@ exports[`regression tests > switches selected element on pointer down > [end of "currentItemTextAlign": "left", "cursorButton": "down", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -13750,10 +13750,10 @@ exports[`regression tests > two-finger scroll works > [end of test] appState 1`] "currentItemTextAlign": "left", "cursorButton": "down", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -13870,10 +13870,10 @@ exports[`regression tests > undo/redo drawing an element > [end of test] appStat "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -14243,10 +14243,10 @@ exports[`regression tests > updates fontSize & fontFamily appState > [end of tes "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, @@ -14363,10 +14363,10 @@ exports[`regression tests > zoom hotkeys > [end of test] appState 1`] = ` "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, diff --git a/packages/excalidraw/tests/elementLocking.test.tsx b/packages/excalidraw/tests/elementLocking.test.tsx index ab096e53e8263..e469ca542c979 100644 --- a/packages/excalidraw/tests/elementLocking.test.tsx +++ b/packages/excalidraw/tests/elementLocking.test.tsx @@ -232,8 +232,8 @@ describe("element locking", () => { API.setElements([container, text]); API.setSelectedElements([container]); Keyboard.keyPress(KEYS.ENTER); - expect(h.state.editingElement?.id).not.toBe(text.id); - expect(h.state.editingElement?.id).toBe(h.elements[1].id); + expect(h.state.editingTextElement?.id).not.toBe(text.id); + expect(h.state.editingTextElement?.id).toBe(h.elements[1].id); }); it("should ignore locked text under cursor when clicked with text tool", () => { @@ -253,9 +253,9 @@ describe("element locking", () => { ".excalidraw-textEditorContainer > textarea", ) as HTMLTextAreaElement; expect(editor).not.toBe(null); - expect(h.state.editingElement?.id).not.toBe(text.id); + expect(h.state.editingTextElement?.id).not.toBe(text.id); expect(h.elements.length).toBe(2); - expect(h.state.editingElement?.id).toBe(h.elements[1].id); + expect(h.state.editingTextElement?.id).toBe(h.elements[1].id); }); it("should ignore text under cursor when double-clicked with selection tool", () => { @@ -275,9 +275,9 @@ describe("element locking", () => { ".excalidraw-textEditorContainer > textarea", ) as HTMLTextAreaElement; expect(editor).not.toBe(null); - expect(h.state.editingElement?.id).not.toBe(text.id); + expect(h.state.editingTextElement?.id).not.toBe(text.id); expect(h.elements.length).toBe(2); - expect(h.state.editingElement?.id).toBe(h.elements[1].id); + expect(h.state.editingTextElement?.id).toBe(h.elements[1].id); }); it("locking should include bound text", () => { @@ -348,9 +348,9 @@ describe("element locking", () => { ".excalidraw-textEditorContainer > textarea", ) as HTMLTextAreaElement; expect(editor).not.toBe(null); - expect(h.state.editingElement?.id).not.toBe(text.id); + expect(h.state.editingTextElement?.id).not.toBe(text.id); expect(h.elements.length).toBe(3); - expect(h.state.editingElement?.id).toBe(h.elements[2].id); + expect(h.state.editingTextElement?.id).toBe(h.elements[2].id); }); it("bound text shouldn't be editable via text tool", () => { @@ -382,8 +382,8 @@ describe("element locking", () => { ".excalidraw-textEditorContainer > textarea", ) as HTMLTextAreaElement; expect(editor).not.toBe(null); - expect(h.state.editingElement?.id).not.toBe(text.id); + expect(h.state.editingTextElement?.id).not.toBe(text.id); expect(h.elements.length).toBe(3); - expect(h.state.editingElement?.id).toBe(h.elements[2].id); + expect(h.state.editingTextElement?.id).toBe(h.elements[2].id); }); }); diff --git a/packages/excalidraw/tests/scene/__snapshots__/export.test.ts.snap b/packages/excalidraw/tests/scene/__snapshots__/export.test.ts.snap index a75a36d0b4c6f..a3cf8d69e62f0 100644 --- a/packages/excalidraw/tests/scene/__snapshots__/export.test.ts.snap +++ b/packages/excalidraw/tests/scene/__snapshots__/export.test.ts.snap @@ -27,23 +27,23 @@ exports[`exportToSvg > with default arguments 1`] = ` } @font-face { font-family: Nunito; - src: url(data:font/woff2;base64,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); + src: url(https://fonts.gstatic.com/s/nunito/v26/XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTk3j6zbXWjgevT5.woff2); } @font-face { font-family: Nunito; - src: url(data:font/woff2;base64,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); + src: url(https://fonts.gstatic.com/s/nunito/v26/XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTA3j6zbXWjgevT5.woff2); } @font-face { font-family: Nunito; - src: url(data:font/woff2;base64,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); + src: url(https://fonts.gstatic.com/s/nunito/v26/XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTs3j6zbXWjgevT5.woff2); } @font-face { font-family: Nunito; - src: url(data:font/woff2;base64,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); + src: url(https://fonts.gstatic.com/s/nunito/v26/XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTo3j6zbXWjgevT5.woff2); } @font-face { font-family: Nunito; - src: url(data:font/woff2;base64,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); + src: url(https://fonts.gstatic.com/s/nunito/v26/XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTQ3j6zbXWjgeg.woff2); } @@ -153,23 +153,23 @@ exports[`exportToSvg > with exportEmbedScene 1`] = ` } @font-face { font-family: Nunito; - src: url(data:font/woff2;base64,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); + src: url(https://fonts.gstatic.com/s/nunito/v26/XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTk3j6zbXWjgevT5.woff2); } @font-face { font-family: Nunito; - src: url(data:font/woff2;base64,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); + src: url(https://fonts.gstatic.com/s/nunito/v26/XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTA3j6zbXWjgevT5.woff2); } @font-face { font-family: Nunito; - src: url(data:font/woff2;base64,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); + src: url(https://fonts.gstatic.com/s/nunito/v26/XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTs3j6zbXWjgevT5.woff2); } @font-face { font-family: Nunito; - src: url(data:font/woff2;base64,d09GMgABAAAAADx0AA8AAAAAoXwAADwRAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoM+G7JeHIUOBmA/U1RBVEQAiHoRCAqBwQiBnV4LhlAAATYCJAONHAQgBYUgB6AYG3uLN8Tdd4kC3QEk3dNOBBSwYy+4HYBUpe0SRf2inNpn////WQtqyNAH5w5Ioka17TrhRUYZVKkIaL3G1ttOUyszSlVlQgnR0ZHhMqfptnTMmbZXlU5Tl0u4LMDfnc3ez/r5Hdq+2vP1bhEmbVj8iYtlc0LXz3zQjT4iXHDBBRccdMSCiNO+qrYwg/TeTzfNEOR+TNUgQwiF/sIM5VeRaSgh0FdMOxQ4ucJ/U7WrLmVHsSBX0P0+1Jx8rrZjasXp3y6wkiM09kkufE/7/c7c3e+I+JNMp3kjFCohkfGSvSazEv/8PD+3P+e+t7fHoCVSxzAQqTKD+Mr3E0aPKmHaG2P4mYIftDHAH4k22HwdJkZTZdRowREbDDI42Hb3caAxRhxTllmgo/h+vyd7zvuLwqwFDpJemzgA1HFRhI4so0XhImO3fNCl6g7Pz+n/KVUI5GruvSEQBwIxEqyE6I0QJEKEBPNgHqgYUFlXsZXayjbaaUfr88rUa+v7XSdO+1cqtvL/9Be7+5clYAxDqGkK3lmasxHk0o4oQ0ZtXij1FO33bOeeYEm2arUEEUP7gqGX238389RkumUUHysqgR/EUvxxQ2sTKltbJ1dKF/EXAyZnmPjLSl7boE6VWpaaT7IcZ+MC8HEPDAmXBnQ86eO88gvUcsIjYNCGsd7TpAiCi+BmgniEhEcnMGzIqIoUrW1MpCAvSc1JuDNF01ZHAQBuG+bP8Gsb+UcGAWTCsBW6vrJQ2Wn8ApPNpSnJgjRelYK0BW2NNhv1iG5gybxwcD6b+rUzWo0j6Uv/WSH2Z2wlfQAsqv+vw/HMrkar3bFWaFgrdoDkgL8cB/3+eVZxbiXbAZR9wOT4E0KZ+rgiKq+76ory6pahPJ6P9r/lt4fvoP9mKMGsjIm7CUzQDKHaDSkK/9/v92r/zgqr3AC5yEgan4lSMfLlvtD9JwCgXl4QS6hRVrgIXcLxlairXKeqwvkao8rD/19N3512wWUV+yfgaAXMi9aHRRIF1hmwNLKB/769zib/ZaiqFRUVY/c65EiUTIO+tKIQpimOL23ociUeoQxGA1Fj2u8dQkpnkDgGDS3t4Xn39s1zb2aqeydNxSchL1dEREIagp1Frdvy5f1+6/+o3HpV7rYBAjooKWPd+HxRiyJEsNk9hp75ge3/1QwgmNapDfSgxqhSheO0y1gG7bEu47bZ0ygIE0dMh1iIhwfp0YMMjYLMWELWbCA7jpATN8iTN+RrGjTDDGiWWdAcc6B5gqHFFkMhlkErxELxUqE0OyCJLOhn+dB+h6AjjkMnFUG/+gP6SzF0xhnonHPQRZehq65C112HbiqDbnkIPfIYeuoVVKUWqtcMtWqF3nkPffQZ+qob+uYb1EcNjcQCxkN9wAzRDGYRHyZIAnNKBfMqA+aXBjYtA2w2c9h89rDbgRQOfrElpOcSJVGQujFAl6tw1NlncCiY3p+kJTL6CRQlXw4agLV5C5/3+CctGQTvHZPB9kkzSTXNwpCjGso1AfngARIaPAyjQUL0K3hqiwdq518FWucQpHvVHZ836LVuA6N16UsYabraqjv5SNiCzv/Lkf7nKtnFbLMQ/LZsoXk9ovGDw7Ngmde0vT78IPvR8d4vsGe+qKjLXbrC2RbouaDGaZZbQs2lzRznmR2HkZ6bRlMB6cMyCqAPxYw44Dfbmz7Z6vPrrfS5FW6FSLxjmfAuAu3rFgXmUtSCOpHu065tVL9OzTT12UFgnxmyFlRuFns3tLZEZEy3+Uv/FvVubsmMMSiitwfAzHVpVe8l1xAcyjIkxdGIEBIR6auim1FKPpjN1CIw6jVPL/wDFNygDasXnPCNBONPEnZ4X2WRICEc2FPVlhB9eNbteQU+nNiJN2m0wEJgpypFBB/ugdx6Cm3MAYfhgGzwhhiA7mtnv7Co11AYEoqumT+0moCXNCxsrRuYj3tP+7/VvpvbbLkIiujtn2DKhVJLY7xBoYxy19p3oF1hqRbft76VMixYj1lYGwKjjNUsn2sioQl1r/DJ0wcPIHebiXIsVxTxRlbQ5G/8/WzdL682YPl5ZX2aj27P+zZOGkpfG8DZfhbpyVA1PWPoYoul3pbUc7LUj1CgMSZjfC60OC6c3eTN5jlToD8SZCRi5HkEZHu1uV2buXkt8FWhwH6rWcYcZTmTiXmzXY98Z0WBJhNSnyeAjM+4WgDtSE55p2Kcx4Axn3hn8Il3fS6c42IN559xBGvHkxyRPJIvuWdMd1+gNTOsOU0KtCRChIsQnoyzZCJTZtJTpUuXnnM4N703sweZRWaOR4WHyTqTNbLOSfxd4trwLmT/zKGCjkdKpMz5awUdiSiDiIiILLs0X7zPM2Wt4FNvhO/H2cCxEksHj6FRzNibwIkHT168n6f70QwLhFklWqItdpDKIveLPPkOOeyIAr/7U7FzSpS64rpydzxWpU4rpR6DQ1OBMufPmw92gMvl/aOdgLMbgr0FfgM6F8E9ivURlwFDJv96UwSLHFwaD9k7Kxq0P7tXNpa5Gc7a7vW8cq0Cd+l5w63ppTsH3FbDwVWuJ96MuDUeDvNv4cD9VIYMUvseTLSJw+aw9pLW5jNY+7bewPCxM+62X7ZXCa0XFWDC42PWeVbzKoz7/DHUAJypwqr0+aC3VDSsDQ4qok3jeoL2hvfb5oXMBnljbitxNfA1X6LWJQ0Z69S4IAfebIhuW0ilqZfCtthblqB4u66oDR52qKrDTa/SJdeQT6SBiwKgBM4B9ulq5wYyR3+Vmt1OkyEbrI0qyZ4kIZ0aBbpUaH/qS2nubIpS2+wUawtvWbCrlEqqTehKm7a97Fe9uqh0erXLqoP0dGj0sEfOKlZZWskNMMKPysjgVZU3778lvVWS/tKoD+lmcAxs/8fE6tPcxEq1h4HaNlipWn28yXTv2r3tv2n0qvDQ88Af9MXN7NKb/nok9qBVdft6FlQ+LTt4ita7DFMamO42ffcD4xvqS3K/Zsut9fV13UH09Y4zXm9wT8R3Kd0NFUP3YFbfZ7g+mu3X9INP3o02tFjXHbl7qWeaufUatxsXuWrPdDd978ZN7W6idzZ8yxoYvCq2O7hBVNbnOChcPDQ9+tiDhGz8EQJzJ+Cx25GfGZwPD3jLJwngKwimHZ8hRJiZIpT5LFR42U6riSVZ2yIQb8922mk5WnZern75kjIH3PJYgade+0ulWmfUa3XxkMA1bvC/7pdpPOAF9TTzUV3TGVTHg6IiZszmHQxSJhB+nYEDR5zIBY6b0Wc2iUosEVZXMztyiSQTEI4Y1TEoCIRRIjNBiDgiBAIFmeLZKUZ6hQEsRuhiLJMIZ+K80WrYMWFfxbfwzLBvILTo5B1T7xEdPoXw+WpMD6HFhD5xKpprfjsPBj3T72QOt5hOcTpFGTIPLtyWXEbL1O+37easIRswgANiBgWFpcaEeXM6XwDDXYihqNMhLP0oDLUXoUAz6jC62Ms8yaZDft1tZbd8Ot3GGj1sYGEgsohoyHfNdbQbzsFNRyszgwPvFKMCI6MwgyHksX4HQ8suUmdM2VCgTQdjnbtpXboZD0RsMog1xG6amgY7FggEE/QnRyVnhC3w4H3eAApGA1Z3sdsPp5q+f92ftWB+Htnw52e3lCu2ULWn9B3g10T2PCxwxFEFjjnuhJMKFanXoFGTZq3eU+rOoawWlp0mbbr0GTIyoZkzSICfiGtZxrbwaIFsGlo6egZGJnSYX0jWB0vn8VSiSrUateo1aNSkWYtW7330yVdKbdp16NSle5mbgF0iYgkSJYXkDRbcFNgAAAAAAABwV1xVVVVVVW2lP0mSJEmSJEmSWtm2bdu2bdu27dYAAAAAAAAAAKAFSZIkSZIkSZJstneky4MViekyhFQmmazhfr4OOOjQHRMvhq6/rp+EVCaZrOGRda6jChxz3AknFSpaJvQ5skL2PAK6Foj/wQruee6nTeH1r2A+vKOisDgtFP7QRd2b7n8npYL1uvIECxMPeU64Ss9PGGxruLlTknozgfFnsggDtK0yu6H5ohdtJo2T+AcPP1ERxl5pllnAmQmKKQNsxyPtMR5pl92RckwdLSuwnR27CT1M2Zd3j6Zps4vS79YZHIgWpZeJdNPTUcA2qNVowNSt05Ud+bHPeMyWTmVrEU+LuhZGXJkpRugXNQZ0lmYE9c0CEDQ0/GMQXEDYl5krxtY7HYrwULCv9vckmCLMRDx//IOHHsZYMtY58cUVP/P/BhKT3RwhzCVYK8t22kAS6Sb5iIpsILedPBPpPtS3Rbahx7eZ2BzipQkGHF2su7JNaH7qDpx8aev/T57vAgqzj4xTN7cd5CuTHQZ8MwCdm/KAFRTcazPAxJrZOPXUN1aEAPj7gVmMzZiikzZI9qDV+EXtHuyrL3a0TaR45+hd9L/mlhSDMVt57qkrstQK62y0xYQpx3yu0mdtusZmeCMZ+aRN1ngnMCWz5cyiaIqMDuXwV9KHfuQgN/kpSkkqUpXG3rLmzkWjJcrElusf1x8AKyipauoYmvzxjxYEVbnb1f+82rVuXfLxvhbdUNvAE3lSdTopiv06CnrTl+zkIh9FKEEFqlCnsLSyLby8eOl7/JX9QI0rGtr6xiWJC08fBdMA9F9Z/o653jziCCP84TM/xv55n27V5PF+FhU++G3Nv+H79a9m8HXB5zng85vPK59/2Suf14Gavbwoy9rfBT0kpEVboKetDPRMoN9UeJ62p5nHkf+KnnqtVr1GzVq988EnfYcQmlgPfxInddQA4pJJ13l3+qpZOJrRjlH/s9hWjPIXHacZushEqVEuM3KJuassXDPWPXZuEbhjgodGu83Zc06ecvWSixe81PBQaYZW0zTzU2+6FlPM8t4cn3w231cLtVlAaZF2wbr9qM9P+i2l8t0yGuubCyuMWNtsiA+CxBAJwdIibSnO5jhEsUkTy0hEklBe6XJK9XMpfinN7hT2pnaghY6kddSvWfu93H7L1poiQJ7ciYyZsVFmnkCdQoQbQvvba5M881FkC4DnDD3nRBUFHP/g+o+9cg7u8tdgqiYraeHdHEgKlRIuO5k9KW0tXmYJGP8aY1UATouB1c2Cwmhd+lQLZ6yEpeus3TTeA+Pcx6fg5hVvtTxVmaxRgA5Buiz2TagBYQZFUIuOATFFg7D5sKF5kBwmNZZtcW2PJz3KpmLtiE9Wkqwk8suQm8qhNPaX5WDZCtL5I3vHMziW3slMFWVWxM+nUikPL6cK5YoFlIVwaXsC1D8BpBsC/sH0GwDzvwMMPRe0HwmAQNY8FsuTQiOfTjwJtoBcVwwhEZMZ4mJxWdhipVZarLeyGtriSlEwupE1Im6rJP3bhLjM1CQhR2i0QLFaKG/Rwh7W5nS426WEja5nKy3KlUZWiRKQSDhWT1CwQHESypSiKEmK/ZqU2MZXvRKbLCtLyfxKZVijdqrd8ayrIMGAyacLu0Ja9CtLTZMzbA9ScXkOYdiJWQxhLBrDAfoKGAADGLw+a9kX1aIWwZGN++L1qN3vSEHeHoLmKYuYHt5Li3ZhFoIapJQzE5amAAwAYfEzxgzQX64GrDyYwe8CcDF0vSqC0WCe/TJWIwfGoMWyFHLIgxgDerzM5WUY4WPEaJ4jnXEvZ7IPk4N8VjjyI5eCEl6F8AWPyyMXJXWmbU52yaVob6g7foU/UatJ1GYEqwR6/dbEJGXAQTINM4e+SILsGw0wwYs5dsnBOHo+CyBBrS/W+7JiNsmNbxO/4b8UlUBoEFgQvwOdy1e5BoicphuGUgXlUPjc4I3z4hpK5VX4ZPQyV6sNraYNm6uebPFuOS88VnmWK6FSdW6e6sBCZhp5KuuWrsuV8JoU0SsnvWZaubrWSUoBdut+lQI7ogq5wdXpHZxD7VMuAmc5fxNV/YD9gClLFYCHmE5IW79hiHgRAu5YAJvOkYdyWOv0IhWq30V2ISx1ua2OqJJFOh4pR6obVs5KUkg8RHoDUbG8dtVxTE+EYJtUJkxXHF9GbKHg7XAkP7Z2oiMPLdfV9eGFalAF+8iV88gYfM7BF3XJ2uEzVvY8BglnkR23pZiNNdkdDJ9B5wI2rFzBURPwVcZxQyeqMnoBqUvqHBcvcTmP/MBhH26IgYvuEbVoetkZeritFPMXh4ULNuBpc3FRLK48Uj7H9SOvApKEH67oZAtBrUQfKQX9PMNV66I8UJQ9wpQAUKe8AgJYoXKYzRUgNWCpWE7NxnnwHW90PUCFWu9ajNbhUy9kDiEJO5M5TCntj+O3TaFMsEuJycHF0xgiuiWPxG3RcGYMJVzyMTwSHavTy+O0NTRrtdmXYdAOIGUKnEHud9N0fDPyg8glIMDXCQN6rngeOpyYJ/IyxgGaL10uw4fuut1F5JbxAn3pSdgAbYA35pXrvXPGVNFmzlcbTwQLYsBKsLACsCbUc449uqMtHK/hVRXQAWowRHLq81CRR2zDJAfGRfQhmGQ4dmyTgAHbRXV7rHGaWTgHaN/vLIglpgHTVd2m9mW4wHcdxMr+S5WymAreEMI7Ehklm1Zq5nEBLMq+sxrqGlsNpIscRGfYOMjhaSds1EPqQOvKas+wU5YScQTa6IkQM9KjLPBOACS1N8oBEg714hVgFC6Hs8DPuNlQPbwB0RFFSEhG3xpJP+vr+itPmO7WRXdCVcseZAIdmWk3nV9pveKw6TngUKSGUdk1VWQFJAlR9mS5DDQlmxOhOD33akelOH1L2gydyHDiA6gYgepBqiZQOyOQthhtKv0s0r4XODWp36XtBy8trc6ERj0RzMUm/06X3Rua9E6eAbpUlws1QdHf6pQVPAKLxvUyEU4h7JH29h5ZDyzggO5iqOGk+n5U8IkjHBxbznAyMTPIarFRGiZhEgXa9GA8miNmW0B7x6MC8qjciJtyfauu0mgbSqNwSelEqQp9j3gCC0+gNoTIeS8vSnF/pkjA8IIBS/bw3CHPL5VxHAXKVJ9poFOqsddvIOmCcnVbKeY4UMu4P+qCN8dk59xkjRCmc2FurW51agrJyL22bbWST6FmyYIKYFlZgmfdHBIdNoi3a6fwu4X8zJcFRDCiOy7FmxHeoBe2l0IoIYtlTkXQEzjWimn1Oe2Fiz7InFn9YGVO4i4tXk15v8Jh2RsNZXAZLLBZ9PwPQNtC1GgoKM98BuYt17tUgFk5ts/nWoSIFn7OOTeiW3NY01qUhcJmHHmQ8DuSrAIVwmYYsqq6ki7ZpJCLEY0Wj05M7WBCt3nMJJ0UCyeoYRa9KYe6hpY2DuM2hhxnLWyAzLzd16+ww/LIkESd2CLIG7ynTCfd9G+jk94REYS7ttU3/WfGtUOHGK/NtqGui3+F/VawPr8EMMc3t6lyHdpN2GS8ciPOeiRsh2kE1EAZBox1iytjOelkjPJu2GFe4akOrDbdAZwY2DmDjA0TogPj67s0cUJ5uh6e44Gk4dDktss5waawNpO6vCqXPa9CrJPeKZcwLpNHNxlfNv2m6d2pjpR26rlw4LmtJm+UFOvUpZDxG1Bls1+Up0ASqbGw8DL6/l7CK/H60+1vXeTxYMFu1TAW1sVbMc8pRu/KyAgNqV7GC8Hc4qOBj45sQfWH97fymYgwQsXFvbJyVBq+VeTRwm44cJfjyYa8Bme0bI1WfPGKjgdtxsVTmAZzKw4TTBbtWEoMmzGqhO1q59XHBmS6qKVpEpNXiTF5Z24Y/FTBbtpS2NGxIWMCvCMLJB7scqEdHxvSHE2YdBbaKIAYet/IfA1p1RZrpQJVLC5fzCzPUItUBp7O6axdQlXPU7TdRkE4mZbgDMTxHC/KrklYo6DKd/LsFm18KpiwxbaI4GpjuGTtQB7H8ESsdYHah7prtaAWYc+3Qncfuuvl4GDcUbcjV2Z/AsdLqfVFdx0uYv3jDGMGNUUeA07uch2qOVBkSa9+P2nOsCBfe1I3qFTOo2sRhx2AJm79IfLwcXW/GyKaVNqOb89s5JGBGNLExplgVUGtJ5rhu8YjWNnKNl1phjuxgSwhFly9H94SHboO29uqmFkfWHWNnCFSugwAhZABMZHwTh1zem3gEiEyDZDKWDJqSAFUkXpipO2Ttj/xbqXK3uIIR8LeczD5JhX0l5i/wRxsecSUwH27RGIWGr3axsoOqaYY6a2cPLwKBpauKrwr2EJQohZEhgcoEM5jmIblzlkjNwE8h26y3p82dcAkm/4kcEDhBO9dmxfXbYxE7aGG1b+5TNc2CT1Zj1ewfsSKRzzb+2ZmNUtFIHYcmLUphUBnvgasIuWExitlr94XmSNVV6IXy7EgATd0MVHVUhQb1r2rYMGX9zA1eJK4snZ8/2VJZDhGwHDt3KPHG60frUe+ULyOu10RUJxNu8ZIEymO+G/LxucpzaJc8k9C2oezVLQus0g9ISkl0TBiMDbgCs9Y585CY3Tj/yjpKz9dMUsq8QF8vtTB7QTriSpZZZNSnRafrF5WFV6UTNm2rVj1FYH0UFQVPXmcIZn0mq4Quq2K9TuxR3W0f1N/hUqGyEAgg7pyuuDmkSMI8sy2+AR1yfQo3rfKNnnw5YO2yVEPVLm7q6+lfk8XeFahnpTzI4/FN+zLq4qgb44q6EJu70rH+5NP8XAOg70gouen++Ytx375Gveym//mf9/MyFm6tHvJYvgjnEYxM77PoeXdDeJpKKbG7QGDRJuC0xhG4zJxr+hA1Ji9+fCGyp6yix2j1vnOLhBpOU7l8TJV6VhkdxQzhrEiiuWp8ldn5jVKM4o0psKAkQnlLfCV5lUO13d9af/AWaA1GApynB/knyws1Go0hdrCkyCHbd4ecD/T6ZWP+CsXq1zaDsHS+7tD/Kn7KR5K6WgxZg6XBDMXtxgdSh9bc3+CGxq6uLJLCOSW41SF//k+88rrx17yK1eVBUcUge3OTZY6AW0WNFrXjq0e2wTvbSr8ZUiDYTucmyEfjMY2i010YRrJYfY/0rD7HJY2Y8fufy9jQM56F6V5q5NHPVgEkuAEo6vSljYanbkNpowlZaXaRT1Gn6469q27W8Ai+YWI5cL81l3F/olur2zEV9mvAsfY7j3F7okun3wkWLlU5db38mdONQVmrbzwZJCd4Wo3Zi4uWbv8yWXKILJR9f9rUDOCmNDDqBmbBZ/4dlMvC8gYIkx2UoMEOUgxdjKoQZIYpDrJMEGGSdZOFhkCOxgyTP6x258oQtRoYVRj9azGS8cvHS5F40oUIyo0+NlfPJXQOPS+xJPjy8ZF53eSIfCkQuVnC74lLcaookHg97eVZsdxGFRkULnSVt6ba+B7axBlzoGvzc5Jv0wOEsQgeTlH4nEpjknzdJGPCklG5Mh+eAJiibWf5mUwg+b/YAsLaZ/OS48QkiEwYr6WaKTalmx6lhnDLSwgZfAAPshqxFHHcsZtHuP2ch2KF7MG8VwWKxfnENdPL46GmPLWf89YxuG5YBmDN7F6yQCKcA4dVLH5RCOLVUz0s3IRuPDQARUpYAXA5f9BUKT4v9NzqxZmzD9hu+6WxXHj9tWU+8EKtn5z0P1Mh1c+4qsMqwoSf8A1cS9GfVWDqvwie4Mpc0lwdGBzh73RmLG4ZGRwa2//UmwmVxPTPcMttcas0mZlwV5CcrC17PmN8WoM71re+l7JsDL8iAwRfYfdLtpkcpnch8FUVhlgOuJ/+fAF+6zei/+r5+iCHkO6dMoW08yqwMrLHMqEQmtWZbxG3yaYOhXOhVb8schLqdPyeWsSFb2mmBBeh1cX5ynEeeb0mjhQwqaVUMTJAdtV78mbRkRsttI5OQV6ZzXiRTEV7DDmG3K0bp2jqjpY9jQZJokwOeEzdy/PLitsl+V4NUZzxduQOE8hKUwzpAdqFcCNIcNk3mXMh2FeDMPNGGbBL+eRIdDO2lrEuXZxm30ZNUCQA9Ti1ppQVVVNqHVxCoiX87Iq44qlJpDD4L39F9vHOjlYUf2HDvFnBX1eFDM3fJTP/9hR58HJqoHLHfW9OKu3/6ySOJfaVwekDBGmzLo7gb1MLwYtefUzDvkZZ385gtIx79wJ6Myq2qFDFA24D2fMrf/t/ZgkJn7TflPDEzrZUUvf75p3Yy55S/qJQEerwUqTjjUbp3ZmC1axBhBnvSLuZacrt7C8T5+PBd6zaneSzJySWbEstk2pkTuCMWpeUk1q4jZucm/OTLbAinh+9Z2dN/nt8WI00eSVJPvoBWToLE/mRvYdN8aBv0fLouKNGWarK+pydSeLa4X//F1pIudyf6jIf1d+E5W25blbX4OSzfQkyc0pme3L2O3ybCGDqSTb+aaUNi0rS3jjqz+y7dv92ffZaxpzvkx18NvjggtnM+WoPVv5d1q8bVImNyULnVnzS90VRfEW+Kffl/+X/tQFIkil+PsKiHxWjLXODXJZusJ051CQbCJYg+S/3kC5T/QNhvx8et6ZSOk11bOMWxVGk6lam97ldGT0VGn9uVJjssiVE3SU0TKjRLh/OZYDDpvfqs/ucWr4ZTpjULBQ5GAtOOizTtd80O2iEla3YUap31WdR+lXfOCZTm84cKeABQhrrNZm9Dic6V3VWpOpwniLISAbCWKA7CEHgVxa2cRvlSZprsyYLOwKSKEIOBOzWThhPofxF+ah/YgKhlTIe9ZytJ9F9KPl1moUgWAEzXls0UQQTWTp5l8rTFLVC6rxQ2zCW1zuE3+DITOnOV9FplxTzSj0qCezri6trstRqO1uMVhVTv6SuOBCmI8Wawwx6Vz7pCzVLBO5M+aV+suK+DT0szXw46AUQNZavTCtrQBKpbxyXXq8/bhCYUoRuLLml/jL3X/7hWfudU9n7viAfMmlOLu1uk5noaY7ZAAOZZn15JoPRqxXLQdOuRBxrs1ua4s8X20y0jXajDZ7Fje4wSVUm6pM518JkgMEa4Dc1d3TPQjLjRJhYbrLUWqe8kQFGU5nmaDKOmLcZbv+oDX68NTUa9d3VjHhmBiY2dwbSzBGIn+rMJhMtZrMJlrN9e5181WmxbRfGXZC6MuA2I0o4gJqJtDXBwaLSjBri7U6RWZMFNqUdoePlpkSRFaV3e0D/QxrkOwhB1jEABkfY6/M1uUUpCT4TfNshLOXMsvEyTIWOs1/K5kGe+yPCGCBuNDgxem/FnCv4TCGQMKEvS/ytaZZQ+RGKkx+mNpINoPl43VxYcUco783uigP+eDAxl/ZGye2vBmztqa39m8q9k9O/Mex1KdA9/8bZX3p06dpNPMz3XV8Xy9xupLmHMVoXHGXDt8P4jDvy7qIc29PL8MwdfyVLz6SX7t0JYZG8I03vnkY8TrRd1JJU8eF4pdCNoEf2QJH0Hf77vqvpz8jifyyev9eFjZHuBwGW0Q8aqxG0j+R6MvJ0RdoPmES5QZ9li1F5KPnkYMsYpCMML6Rnk07rX+ajJ1W05k75TlkXJB8GPQVTrs1S9uXPv2lT7kws6QHCs6bm66XON0SYMHam3XZ3Q4Nv1xnKhZmnsEuR0W3GSNqVdMPpKlY3Jsz+KR09pKeceESMMiQcH5zOKIeBHT07BupsyMyTbBpni3X8CfZBG4o5KX40IER8f/RJxrsiDhrUBDnbCpHr+iNafJUOiDKljmJ2yfqLVc87587zc1sFsbOyipHjTEmbbqlxQlQNseZnOjS3DaiahhRocZ2coAgGsn2IUyFwGpsaDrrfAa2I2r5Zxhz7NzRAXC7WZP6LEW7jvP0sZnafBf9z+lX006ljGgiA6ezg1qm7+BvZL3nbMYdvjAZcyF6raNlPXvigORbz7Xi3w/+83clScuObrCcwd47B77LsCP929bXllWhiKF+9TLqiRU11QjaZVq7gry1rquEUURWVVu6/hyGnevbsFrBw9N3FFy7ARtlnebxxDdPVufU4Ihh1Z6VcU+v7K3CEEHOsge2bc73+zHJO8w7E986Bbrcrt7ftyOGrzoGkyRnUfSbmLk/RnFXxH5/Y6QSBA3jG5pfxtvIuYgQRgSICnE0BF+iutioWAQLEfChTFNLBs6PZl73fnizEFO4HDazrtCY54ZO23df/JPgojQqTvLA8uLmF768NqQzV8rUnhzzwqqWNDBmLGcWmwNsbG5w2P8PdssQHwRbYEymO1lxKrIZ8UKQF+lTMK1IUVVJEQmLYZjFxJQFp2JM/2ut+adsKKXqrUlVYWFSBvjzMCyEiz0iHqSAPSUiEYwgJR4RlwkjnmIRmM3mmCyGdW+3r039e846Z2BuCtc0kqgc0yYSBWnFpyYOJr4fB73GvDTybcrHo5PW9daWdJGoOCU7gdrBA6u2QX6kjvbNGQ6adre4EpbbyurVN+k6xA8hVqQ2YsrEvLFzTdYos/qjT2yE1FxqUAwV+xXDpUaz1ELEnXIzR+wvDD5uQ1MRtYgVtG2D79CZ77tapaOBkG5HT6BgPszrT37AQDJpdlnV/o+zfxcuTWZEoYm0aMXRE5uu7MxqYHo+umwjpHSZQS72psrN1Ienuh+OZr0w3STRxhQtL+d2Jj9gvPHi59R3jKyHv5ftl8oAzepL9cpuR6Gyq1Sn1/q0sTGvDkI0EzJB611e/CCGr8a9kB5WQUw1LJ+Nj2H4GB54ie3TfT8KeZiQB+qEaYhJw29/Jnme59QGbeXa5PtddGlLrKVgL4PvwoeSzVAak6mGTNFXED/SifhgW6f5McGQ9NYmLDkOqZnMNOgj7WJ8F1i6DfYjLXleM+a3mHYPB7xziArnBqjDqht4Y+P2Bu5O/6uvQHmTAsrhMiMtKIQEnX+2olYIMqNbex+uuVGbt6b6Wec+bkGsgMcaS4VKWsHbdUWphtVMiMba48c6Cy7DsB5dOMF1cfZhlmhbVoqdsF/o+c/fcPJ6B18XqLQYxf/zpi6EaSbTDA+9vrJD93N6N6SK37/lJtApBnkRVXah+r+Ghqf6bHw/Co4Pd7KYUwTR94KGijhifBzH1+JURKTiCTYDqi74/AYe/WPNjb/KuI5+VeCGGI7d82URFL4OLDFqhJEGeFn/PvipDqA8L+jX9zMVfLCY/vkWU2pZjSovtTou58NwI+iuO29hSYyPG6ZNe6BaJrMO2lK85V4JMWvv9SQPaUDgRgQ81y87HvNNUr7k7uoT6xbUZP65OClPsmDN8cZ8hb+AM3OOxawfy4986viiBc+VBq3KbnoKI58t/bZDo8jgYmMYNsYSlFT66kAtwwpTE0XkmoxGv+74zQbUgiAWtOHme2G69EZyTdEEFWIR1Q41sauyc2/9Mu+2zvLLL0k9Z1VN5VaAHQweYF3WeVABBAtQj7bnHeRfxXdUGEcm+n6GOFGsJqwld1HrRVI3ivVeXY84VY/ieSpIIJtHfmZyIlkBsIshQ9RmA8KHYT5i2E4OEkP2emVW5axc2lJwbyyWCGtWdYPKVvAZFSIcbpEqTZKUzjP9o3RzAgsBgqkJiHDYl/N2GAjrUj96+/2Nmj7Kyy55w4QKYEiA+pwE3Um7ZZ07EaZCUHytr+c3qzLKjLqsYEOqdUtgo5hHdWOICrH6VuU79SbaYSxYBWoZyP5FcOV79xR7uB2YBUHN2AtejynC/G6tvhat/bnflWE/2lT/93qvL814DuXzg7fCT/KyKlpUhZGY5Nynnc8fUngft6Xe+LIf+sNvi3z5BhXCR+j1hyIoy90mT3ieyLvTvGPtr0vNlQ0Zd0Krw78tpT/7CrdgmBn/D39k1oR/+XSpXO8a+vXS3ibD4DjDTY2/lCtypj6qOM3FN4riz4jFCKLC6Nz4arfiUXTMI2404s1dHdUwyhLxZyina5uVjOKcyQXBt8wcfymVG++qLeTVFbpAcAU1TlE7PzWv/Zh6IWjPH+/sOLArWKO+72nRh5aEGq4SL7/7HfUcC3+OorbhrG3jYKRtA46ALXdgHpPJhW8gLM6EkC9GqUkqsL1i+7dxFKyweoNin2LHPs9mv8gRNPCgA4Fz3VNPZsH94WXufeV1Gi8QOQ+bNb3lRfs6w6OwZDFgBnj3LV3TDyetb3hq2JttIA6zW9mOTd601a5588T7pCkTBj1bM9rx/tPZBH7oEbiepZy+SkBooj5lbBKJkH9hdGMi+HlRW12yuaV4XfG6FnNyXZtr6+ZXEeSdFcDaeGKza0trvYSuaKYl9a3pla44DPjGb0wVDQRVf2Lh2s7rnDXYJVWQt9n/CfR5D15645zvJtmref9OxTziNmYmJdmKuTHRp6/x3El2owQI7Dtv8QUzHQJh5YyAf6uKywtxuU087iCXGwY8e+dPfP5PDgEWeSGXfrH2+pydhcb7x1nOaF4TzYtyEOwNiP5ckXnnkJqiih/ewoirBdTF6KnPFY5nDvEpf/QtlLhewL4I5A77v9CN3BLGjQdxpMKtubR/6h3dyFxB3AtBDGk3pvwp3kBN4vgkRW0P220f91Ps0S42+3aO94dV9zyt+qYlof4b816y6aY8LuK9ErA1mc9l/gff5MczIcg4ZkGeA0p80QYKHKjYAXbAMdwUPPnbuq3SXfcScb0/tMQQKqMjVXX7Ka0cUkXSZYZnM9R/nXgJ2Bs8YLAVjSIms4KM9D7z7ZzknOpfbjewlLSQ3f5eCYvxJxjvSj9d2a9hOw0pE9JDOLE68nyY3iCdB6SCqX8tachkPiKJjzjv2unoGG6xLSkps5H7CIDWV7jYMPX2OvOfovWHtkBKzkU2+RFwu/gfwXtycBu1dr01ljw3OGf1OsV+jR37Apt6ERipWV1bma7LJH72S+YHHjY8HxAFVn/76CoPdezoNpjzIxodjy+4urKbYVZzIhmOrOiCp470RiXcFCT8A0wU6km5JN127tvb5/kvjd8JUDPdbXxd+fXU8qO72HXZSZLkOn3U4dNnla/TB4QL3TDACs75nse7sd8vLY3XDFnGfgOcgzxqnCLHKWqcRAo8Sy9g2uOb3iFVFB0Cb3/u7vfPBxPN3u8o4GbtxQrvAdyF7/DuwHeDjwG+1Yvghbc/zqZ2NQkaeNgAEUY09O+ed7VpdL1/aYs5rghEpEesrYkztxQvXd8/eHXebkDeHGRD8LDJq8ieHKph+J4oXrZvddM1qvIS9ooYEt0pyqNHKkL104nr5YvC6F1VvnVVe5NvmtgDbGpippkvY2kYKsKhFxmA82bWrhoOvcjXt/8tBHlrytu3iGbU7KroADOat1719Q+bpZ5d5Z0Vnbs8HT/D3v5XPwPfNS9NFQ2EVJewNbWddZ1h7JIq5EaMOz9QK7cybYabjE3vDxNbjckJife2EsPfL2fcNDBt5VZwy3lnBCS3SKRb3mvOA7xQMz33hQLjvSIGzU1jHIycui5/7r487tabo3gsL0/6x6boxfjLirh5F0u5BOTD+6dkUbvZ2o2IMR/f94ZNiPApafiRtefW92KsHbtJj4uYt8ZmyfnxzMcwwueadx1wszioQYGZ7rrdOIHPH7PVc19d63/1toCbhV8kSiqXQNITghv+3UD11wFOdisZjDJyAb3lJ1yT3P3tL6MshSqOCJ71YQvugfCK8A6tT5yuD1XQI3lFd0Rr5gcXrSemfYElllX5pt9RsE+1/6aemVtu0WorLDG5+pv7I78bJrbeS0y49ywx/B5wy30s+Tu5EK3CcCem4NO/gqLZqBBBBKgOSUURNQL20udX/mcb+01/8vyq/2zbL4BL1oty/Y+Di5Nte3j/WFLsrbkNjwNLkm0v8/62AEIv6pPo5SIRHMFHlke+AdLrIFYb+5UA/c7nMh/DwD737nIPmvy9jIfSOGZBpUKzMVEGShcN0/ew9a9uYSo5f5LUx7Gxn/Gw4TugOb5AQECrHJ0FX8r9zGch5SxigR3MurX0WzYgHUnzfytaZmU85lHJa7luelE4NT+UGL3BW6Ys1ud/7XoU2+syVgstZJm/JhLOZdmW+1lhfpqh4p5kFkY5LGIBT/D4hNR1TfT7rWM+87zE5ii3cwFy95mW+jxLNsTUcuWzYGbz5FPuLwsW8mfKWcQCO6SZE3k9zLM3s2lsozF3dAo1Vzkr4n8h9BLprUBDjS/F0sv5tzM2ynKav3UBZT/oUF6i+qWx5LteZT4llFfiVeVbk2l5ud8KWMhs7vZ/+TDutWMRLOAJHp+ReuO86Jmb9K14PCI8bEcV53MUM99LBGKhTTGLTKaNZQ4tzGU+9/kM+pgHJZSn4s2CW3GJy1+lwnxmUEKxybTL79fBQn9qzHGvxiJYwGNe6mA8QDyEHdE+nzMS5nGX7dFhn0fGXZR7MXncQzwJC+yQTvkc6cynfEIsQ3/6JAgTuI1CbqfIUnR2Itp+u5CSacJY0bJ74jEeE+qKjxuFF0uqZMq9j59WoBz9XyZhkyT0GnmLHY/bhEJup4hbuHlMqulsLwaE+sleG6O15yf1XyYrExjPHRSaSG98Jh7zmWfiet1aU15cPt2Wrk+3pyKl6t1I/D9+qNzXCUkjm19SDnIu7TER10v78vKm+kCzN8S25aXe5hJlOc2spEube7apqdy7C//KA/lUBzYDxF7o1SphNaCEwkqs3Ps4qWnWK56GyyQU3MYNjPQ7OWOsxu1QxC3c3NbKe1RkF25pTFNubKSPxvTR1acJP5pJfia3pWJulywTZTUkIsYIE5joM+qJ8TYlFKbizYJbcQmu/+xfxpR/pNUyowYoae1q37oRxWQZSm4liYVM4DbGcjtF3MRkplqaMlvRDgSM5zqLUo6PN5tCL7YuRhG3QpGlyuKj62YChZX4P9n5uP+qmdWh8/+Dj/be7v3u/EcpTvj4PUxGrdc97L3Z1LVFh/nmS7llqbPi10osy7Z/G7GzZxpqzzM91znCNqmXRIUMlWmdHX8eXAgupjxTGZSTBk7vIXcQ9Xh4FpMcg/BSzixeCspG/zpjtz8jqqYz5a1kcyyWgBLX0jwOeTb7j82NFv9QAUpbqEGMDot7NZPdLN7di+QCVboBqgxooyzJnqSyY/X/rkGqnI3dVRXhqfVGV5caP9YmnMNeQqylSSoUA+5748OwoTZqfPsMAmnpUryx5eh+qKO1MMyC2ZzQHI+hGbJ1raJHxKHSULWlAmLoX2fs2mcEEO2t9qeKmrG1JG2Jb2wVbSzfSLllJ4T/SlZTRZ1Xkx1SO0vcZwm0Fo+ttReCbB8cdNjwygbKxW2JLqrfoeIbDh8sbiHXYqm0TEv1hIL+RbGwCShNBbwV56nLOKOM03O21KGSmMwCsIsgBSSD2YA0FaBSfgEUe/BTSQ6gLUUlINuFy6A86dIXtDukRlqkQEpnsceZu9FXArLte9uN2q6Qa3EoxpBOxTAgyDvkuEQ9vp20UwLFtSAFUjqLj64vUF67w3g896/3ydBS/g0OhYVIi3qRYtni5Fn9TgWgR7ckijXA6qg7iva9ZDf5kmi17TOLlC/1yjVRZUTxbl+SKy17YHa5RFvC0WwMWnpe6mQpOKUWctJWC0f807eTRdyw9JSp7QugabtbayDaDk2h0QTqUhhfuzUFMlVDN3ckk9FkadLukDZ4pD8dkhhDSr2Yo1O+QLQk+NZHEYkxkJbUeCFut3GoY9z0fkt6uKMWHFC35y0o12xDe7n0igTn3LVRA+Rttwvt0QcUPjiIT5PLJiETWKFLqt9h6naak9FzN7mTm22nQ52aYxF8tPHTcBpuAGrt6BcH1VGCD23sFlWUvV0yUAFItRMWQwO8WFq3RBH0TWR8qIHChSe2n7/hLYvy0z1OyANOg/ExwMKI8c7sA2CTv+nnIe9An2QRmHVWMLI7w/xsLgSkdx5Xfd6EmAy1/7EU9SWAl0PPVQDwftmzj5bb/zSO3lGAJgIAgX/6aTQurLhM+kLyNaIPzeQ5V+IvcMyO/O1C1IWfCOLdpk7+q7A9cs/8lViVG7u1B8buLU7EyX+FbrNh6lxUH9YbhLgSlnjzcBTFtTXAu2AgDUtCtWGGgtyFq2B7ZdzZXhgQJ7cdToRaFay89fleUQTG/IJ7l9rNL9Ru30Pbf73J+Z+Jws6cltzVT3njqnaYM62hkHPduRt33lOSUanGsP+iJnKGWLy9W+UrOQUF9FXOOM+ALkyNXTwn1hB7JDk2k+75n8U5V2oFJFaHE/DocK86+JK3e9DkZrbgdj3rAee8NAWEkut+ksN1EQfylvJeXZCyeoXqr73Jw7doKmc9e+0FDGUWb3Ni+tFs8/U+l7UbV3PQ42Phxq0wh80zFyx/ZCz429e5ch57oxnrw1kWv7z04zVJOlNNY8fDFDyOPPmu4jGgg57ygDeJzidI1ebX+HsAmY4UQrvlCijXiSmj/Z4r0uPRE2p45E/SFObUxbXSeSq+0905I6GTUIZy/l6/1C3DH2ZlaAnT+CU3lMj5vkvfrsCSINCHrUZJwoFmLdEw5NwpvtOZRzzk3hm5x9+ZMMhkZ8o8z+10fGcOa6U7M1xl72zAV8jORgRcdzKmRxBHAJlDRDw7h5tijwc4liLJeskCiOL+E8URihBVHyN2rf6gaqRbdpMki22SjCp6Y/98820lkhYLTiQLtrtPlW4Kt7nphNIqaqqtT+eq3404iVylSBPDzRILBJcsfFns0oAaPmtpRb7ZFMn4vLjy5c7ztN+pFltisfmrsjBcqsagJtZ7m7bZYn5m/lwpUm17wmJb8+TOgze+0BWMsiiohnS2TREvinAyZ9vURS1lg/3zOXbUjBEXzd9kA1fC8VEDK0zB0hAlOtMs1NzlbpI7apqI/FSyDdn68CdGHwZseBRBCmnkIINcZFEH9hWFujDeMC0OoD4awIQgNAoJDQuPxTEiMip2sXGKKz5uvPgJOBlIkChxCSWaVFKSkkvhnDRZ8hSGcis1VWoupXEtnVsZZf5skkiO+xzecU/H42eU3EMWVrY8y2WXJ1+BQg5OLm5F35N5Rx9/Pv8XElSiVJnyfKtQ2YfWpm6dGrXq1GvIr0ZNQpq1aM2/Nu06dOrSrUevPv0GmtKgsCHDTWtRP+UmKxs7BycXdzpZ/crLl4VfQFBIWERUrP3iEtkaoZOUki5Xhl5PoTHY7Dg8gUiSlZP36cu3H6D8BkEIRhRwKFbgtLKKqlrnXdDQ1NLW0c3hqn5O1w2NcikzMTUzV+5O7wtxtx/dc98DD1V45LEnnrbUM8+98NIrr71RqUq1mn7zq069hsI0atKsRau33hXuvQ999DGNTz774itlEdq069CpS7eeor7p1ec7lX4DBg1R0xguboQWcCn3oDTdMC07FbL5DXZcLwciA/k0tAmMnoGRiZmFlY2dA3FycfPw8vELCAoJi4iKiUtISknLyMrJKygqKauoqqlraGqpqWtoamnr6OrpGxgaGZuYmplbWFpZ29ja2Ts4Ojm7uEISmUAUiFKhJnkUUSp09FdsPR9OMXpJscuGmv0fuMVE+bccaDCztV8wAC8rw4D0VkKbewp+zLcRy7HxZ/OF/z1Rc7INwYElvx2B0skUgeb/HUp1RmzSGDTgTQAyPhjNBC2ISWhlimJ6eQ2RKlguh1Yb9DKroQVapuOaRyQn90JpzZzQkbpWrgNYLn4rokNHIuXE+/mbroTeSbkdu+zydTtZ9frQMyoFoajpo5G10AOl99LPF3qBbgnK9VtPs2qgIcNQyxhpqNTM981QMChGx8u5YkKfUKPBuHngOC2JgUselsD9/GOVdctRYdIXvWVesqU5bicae07BYr2Yil5oWxia/xQjTNKJMj22seKw3MS30NeUUtrjLeOji8YGc9CBc558M41RGrdzROUDFu/TKnm5Hhcalul5KecxQ6SUffY6NksJPVi27VPixsZbVj5gZabpKNuVWQ5jdQ7UsDKypbIv4H4yupKw8gilwiyw6ctauQ30981shE5/OjqW0aqHUcBOfpcqI58+P2FXLUNPOxfxb/dxOjd/Yd/G+rL7kH+bSoATBRoIUR7BAREG4NGQRlDik9ejPEROg9A2ZeCdA2U+QZgKlK0NxIjw7cZ0IEw4ZQ6E8slToEZKNec1dmaMCSpGhFZPlQ8qR46ytNGwgrvT+59HDTP6JNDvUUVzhAcd6ZKuuK7ffDQUSo2a43zyZP7mE8r/dbdRBmskBVpvxW1joQjKqCJvZHD8D4/kN6jAb77PTSNwkAQpSiij5q9rCmLUkQ/DLR8Wn3IGRozw1D3HqKM5vIMX5KGMEDniU0zwUTr1fPRRRYi4oW4CBAkKEDvdVzPvyckmhFnsQmumbWiewwhJIAuJK7uCKFIYFA6vEAfGQ2JnHDpB8xRfkCBBP4iH/8F/yH+59zNk4Of3+ODyv2+K/OivhkZtmVa+I5L8baKn838nUrXPkcDUJU/iztViTrlT2lt/snQP3yJDbXGFG/kU3CHkPUXVWXw2aNn8V47lmFR7Ox651KEMc1L2xhH/1xBaRgNkr2QQeWZHPr99f/+Cax+FcHlnVq4JMmgJ3FtWkA65tjxLSl46t7PCSKDYyzEwdsSzxmyixINRuPSZ+xARtfhJcPALmHSiTJMmKKPiHD7GdD5plfyvJuxlY1teSMLzb4WaITlWdIB8yrQg0FJXCIKCnDpFqJEI5UU6SyFFmgQZNAljRRsJdZClUuLFhoWZRD0ECXWo5UXIKGFx1cKCOGnyvK2Fk0A/BqegLJWigjET//sz0iD9fwmZ5PfnlYwhCW8AAAA=); + src: url(https://fonts.gstatic.com/s/nunito/v26/XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTo3j6zbXWjgevT5.woff2); } @font-face { font-family: Nunito; - src: url(data:font/woff2;base64,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); + src: url(https://fonts.gstatic.com/s/nunito/v26/XRXI3I6Li01BKofiOc5wtlZ2di8HDIkhdTQ3j6zbXWjgeg.woff2); } diff --git a/packages/excalidraw/types.ts b/packages/excalidraw/types.ts index d566dd0192c3a..79f9e311ad5cc 100644 --- a/packages/excalidraw/types.ts +++ b/packages/excalidraw/types.ts @@ -199,7 +199,7 @@ export type InteractiveCanvasAppState = Readonly< // SnapLines snapLines: AppState["snapLines"]; zenModeEnabled: AppState["zenModeEnabled"]; - editingElement: AppState["editingElement"]; + editingTextElement: AppState["editingTextElement"]; } >; @@ -267,13 +267,9 @@ export interface AppState { editingFrame: string | null; elementsToHighlight: NonDeleted[] | null; /** - * currently set for: - * - text elements while in wysiwyg - * - newly created linear elements while in line editor (not set for existing - * elements in line editor) - * - and new images while being placed on canvas + * set when a new text is created or when an existing text is being edited */ - editingElement: NonDeletedExcalidrawElement | null; + editingTextElement: NonDeletedExcalidrawElement | null; editingLinearElement: LinearElementEditor | null; activeTool: { /** diff --git a/packages/utils/__snapshots__/export.test.ts.snap b/packages/utils/__snapshots__/export.test.ts.snap index 7521e9cd12adc..dd0168f8a3516 100644 --- a/packages/utils/__snapshots__/export.test.ts.snap +++ b/packages/utils/__snapshots__/export.test.ts.snap @@ -29,10 +29,10 @@ exports[`exportToSvg > with default arguments 1`] = ` "currentItemTextAlign": "left", "cursorButton": "up", "defaultSidebarDockedPreference": false, - "editingElement": null, "editingFrame": null, "editingGroupId": null, "editingLinearElement": null, + "editingTextElement": null, "elementsToHighlight": null, "errorMessage": null, "exportBackground": true, From 48e4978d9186f3ac5235215cb5ecf16b9bc7ca5e Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Mon, 12 Aug 2024 10:16:40 +1000 Subject: [PATCH 09/16] clean up --- packages/excalidraw/components/App.tsx | 2 +- packages/excalidraw/scene/types.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 480e0c27a5358..9313193041e9f 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -2865,7 +2865,7 @@ class App extends React.Component { } const scrolledOutside = // hide when editing text - isTextElement(this.state.editingTextElement) + this.state.editingTextElement ? false : !atLeastOneVisibleElement && elementsMap.size > 0; if (this.state.scrolledOutside !== scrolledOutside) { diff --git a/packages/excalidraw/scene/types.ts b/packages/excalidraw/scene/types.ts index 85c253149bb2a..3a3a51d17d713 100644 --- a/packages/excalidraw/scene/types.ts +++ b/packages/excalidraw/scene/types.ts @@ -97,7 +97,6 @@ export type NewElementSceneRenderConfig = { elementsMap: RenderableElementsMap; allElementsMap: NonDeletedSceneElementsMap; scale: number; - // TODO: narrow down so that unrelated state is not taken into consideration appState: AppState; renderConfig: StaticCanvasRenderConfig; }; From 4d28dfb88a8a3576e75a4480632b2f1e9958d353 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Thu, 15 Aug 2024 15:28:18 +1000 Subject: [PATCH 10/16] improve collab experience --- excalidraw-app/collab/Portal.tsx | 1 + packages/excalidraw/components/App.tsx | 4 +- packages/excalidraw/scene/Renderer.ts | 10 +++ .../__snapshots__/contextmenu.test.tsx.snap | 28 +++--- .../tests/__snapshots__/history.test.tsx.snap | 60 ++++++------- .../regressionTests.test.tsx.snap | 90 +++++++++---------- packages/excalidraw/tests/dragCreate.test.tsx | 20 ++--- packages/excalidraw/tests/move.test.tsx | 6 +- .../tests/multiPointCreate.test.tsx | 10 +-- packages/excalidraw/tests/selection.test.tsx | 10 +-- 10 files changed, 126 insertions(+), 113 deletions(-) diff --git a/excalidraw-app/collab/Portal.tsx b/excalidraw-app/collab/Portal.tsx index e9a4b5bf00fcb..79410cb08e1c4 100644 --- a/excalidraw-app/collab/Portal.tsx +++ b/excalidraw-app/collab/Portal.tsx @@ -129,6 +129,7 @@ class Portal { return element; }), storeAction: StoreAction.UPDATE, + triggerUpdate: false, }); }, FILE_UPLOAD_TIMEOUT); diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index baa9264d9b9b7..0ca668cfa39c9 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -1467,6 +1467,7 @@ class App extends React.Component { height: this.state.height, width: this.state.width, editingTextElement: this.state.editingTextElement, + newElementId: this.state.newElement?.id, pendingImageElementId: this.state.pendingImageElementId, }); @@ -3781,6 +3782,7 @@ class App extends React.Component { collaborators?: SceneData["collaborators"]; /** @default StoreAction.NONE */ storeAction?: SceneData["storeAction"]; + triggerUpdate?: boolean; }) => { const nextElements = syncInvalidIndices(sceneData.elements ?? []); @@ -3819,7 +3821,7 @@ class App extends React.Component { } if (sceneData.elements) { - this.scene.replaceAllElements(nextElements); + this.scene.replaceAllElements(nextElements, sceneData.triggerUpdate); } if (sceneData.collaborators) { diff --git a/packages/excalidraw/scene/Renderer.ts b/packages/excalidraw/scene/Renderer.ts index 9bedb1e75eff8..19240b9d16c8d 100644 --- a/packages/excalidraw/scene/Renderer.ts +++ b/packages/excalidraw/scene/Renderer.ts @@ -1,6 +1,7 @@ import { isElementInViewport } from "../element/sizeHelpers"; import { isImageElement } from "../element/typeChecks"; import type { + ExcalidrawElement, NonDeletedElementsMap, NonDeletedExcalidrawElement, } from "../element/types"; @@ -65,10 +66,12 @@ export class Renderer { const getRenderableElements = ({ elements, editingTextElement, + newElementId, pendingImageElementId, }: { elements: readonly NonDeletedExcalidrawElement[]; editingTextElement: AppState["editingTextElement"]; + newElementId: ExcalidrawElement["id"] | undefined; pendingImageElementId: AppState["pendingImageElementId"]; }) => { const elementsMap = toBrandedType(new Map()); @@ -83,6 +86,10 @@ export class Renderer { } } + if (newElementId === element.id) { + continue; + } + // we don't want to render text element that's being currently edited // (it's rendered on remote only) if ( @@ -106,6 +113,7 @@ export class Renderer { height, width, editingTextElement, + newElementId, pendingImageElementId, // cache-invalidation nonce sceneNonce: _sceneNonce, @@ -118,6 +126,7 @@ export class Renderer { height: AppState["height"]; width: AppState["width"]; editingTextElement: AppState["editingTextElement"]; + newElementId: ExcalidrawElement["id"] | undefined; pendingImageElementId: AppState["pendingImageElementId"]; sceneNonce: ReturnType["getSceneNonce"]>; }) => { @@ -126,6 +135,7 @@ export class Renderer { const elementsMap = getRenderableElements({ elements, editingTextElement, + newElementId, pendingImageElementId, }); diff --git a/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap index e04a8b945d1b2..da49a95ed04fa 100644 --- a/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap @@ -1197,7 +1197,7 @@ History { exports[`contextMenu element > selecting 'Add to library' in context menu adds element to library > [end of test] number of elements 1`] = `1`; -exports[`contextMenu element > selecting 'Add to library' in context menu adds element to library > [end of test] number of renders 1`] = `4`; +exports[`contextMenu element > selecting 'Add to library' in context menu adds element to library > [end of test] number of renders 1`] = `5`; exports[`contextMenu element > selecting 'Bring forward' in context menu brings element forward > [end of test] appState 1`] = ` { @@ -1525,7 +1525,7 @@ History { exports[`contextMenu element > selecting 'Bring forward' in context menu brings element forward > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > selecting 'Bring forward' in context menu brings element forward > [end of test] number of renders 1`] = `8`; +exports[`contextMenu element > selecting 'Bring forward' in context menu brings element forward > [end of test] number of renders 1`] = `10`; exports[`contextMenu element > selecting 'Bring to front' in context menu brings element to front > [end of test] appState 1`] = ` { @@ -1853,7 +1853,7 @@ History { exports[`contextMenu element > selecting 'Bring to front' in context menu brings element to front > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > selecting 'Bring to front' in context menu brings element to front > [end of test] number of renders 1`] = `8`; +exports[`contextMenu element > selecting 'Bring to front' in context menu brings element to front > [end of test] number of renders 1`] = `10`; exports[`contextMenu element > selecting 'Copy styles' in context menu copies styles > [end of test] appState 1`] = ` { @@ -2066,7 +2066,7 @@ History { exports[`contextMenu element > selecting 'Copy styles' in context menu copies styles > [end of test] number of elements 1`] = `1`; -exports[`contextMenu element > selecting 'Copy styles' in context menu copies styles > [end of test] number of renders 1`] = `4`; +exports[`contextMenu element > selecting 'Copy styles' in context menu copies styles > [end of test] number of renders 1`] = `5`; exports[`contextMenu element > selecting 'Delete' in context menu deletes element > [end of test] appState 1`] = ` { @@ -2303,7 +2303,7 @@ History { exports[`contextMenu element > selecting 'Delete' in context menu deletes element > [end of test] number of elements 1`] = `1`; -exports[`contextMenu element > selecting 'Delete' in context menu deletes element > [end of test] number of renders 1`] = `5`; +exports[`contextMenu element > selecting 'Delete' in context menu deletes element > [end of test] number of renders 1`] = `6`; exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates element > [end of test] appState 1`] = ` { @@ -2601,7 +2601,7 @@ History { exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates element > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates element > [end of test] number of renders 1`] = `5`; +exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates element > [end of test] number of renders 1`] = `6`; exports[`contextMenu element > selecting 'Group selection' in context menu groups selected elements > [end of test] appState 1`] = ` { @@ -2967,7 +2967,7 @@ History { exports[`contextMenu element > selecting 'Group selection' in context menu groups selected elements > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > selecting 'Group selection' in context menu groups selected elements > [end of test] number of renders 1`] = `8`; +exports[`contextMenu element > selecting 'Group selection' in context menu groups selected elements > [end of test] number of renders 1`] = `10`; exports[`contextMenu element > selecting 'Paste styles' in context menu pastes styles > [end of test] appState 1`] = ` { @@ -3439,7 +3439,7 @@ History { exports[`contextMenu element > selecting 'Paste styles' in context menu pastes styles > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > selecting 'Paste styles' in context menu pastes styles > [end of test] number of renders 1`] = `14`; +exports[`contextMenu element > selecting 'Paste styles' in context menu pastes styles > [end of test] number of renders 1`] = `16`; exports[`contextMenu element > selecting 'Send backward' in context menu sends element backward > [end of test] appState 1`] = ` { @@ -3759,7 +3759,7 @@ History { exports[`contextMenu element > selecting 'Send backward' in context menu sends element backward > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > selecting 'Send backward' in context menu sends element backward > [end of test] number of renders 1`] = `7`; +exports[`contextMenu element > selecting 'Send backward' in context menu sends element backward > [end of test] number of renders 1`] = `9`; exports[`contextMenu element > selecting 'Send to back' in context menu sends element to back > [end of test] appState 1`] = ` { @@ -4079,7 +4079,7 @@ History { exports[`contextMenu element > selecting 'Send to back' in context menu sends element to back > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > selecting 'Send to back' in context menu sends element to back > [end of test] number of renders 1`] = `7`; +exports[`contextMenu element > selecting 'Send to back' in context menu sends element to back > [end of test] number of renders 1`] = `9`; exports[`contextMenu element > selecting 'Ungroup selection' in context menu ungroups selected group > [end of test] appState 1`] = ` { @@ -4479,7 +4479,7 @@ History { exports[`contextMenu element > selecting 'Ungroup selection' in context menu ungroups selected group > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > selecting 'Ungroup selection' in context menu ungroups selected group > [end of test] number of renders 1`] = `9`; +exports[`contextMenu element > selecting 'Ungroup selection' in context menu ungroups selected group > [end of test] number of renders 1`] = `11`; exports[`contextMenu element > shows 'Group selection' in context menu for multiple selected elements > [end of test] appState 1`] = ` { @@ -5603,7 +5603,7 @@ History { exports[`contextMenu element > shows 'Group selection' in context menu for multiple selected elements > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > shows 'Group selection' in context menu for multiple selected elements > [end of test] number of renders 1`] = `8`; +exports[`contextMenu element > shows 'Group selection' in context menu for multiple selected elements > [end of test] number of renders 1`] = `10`; exports[`contextMenu element > shows 'Ungroup selection' in context menu for group inside selected elements > [end of test] appState 1`] = ` { @@ -6773,7 +6773,7 @@ History { exports[`contextMenu element > shows 'Ungroup selection' in context menu for group inside selected elements > [end of test] number of elements 1`] = `2`; -exports[`contextMenu element > shows 'Ungroup selection' in context menu for group inside selected elements > [end of test] number of renders 1`] = `9`; +exports[`contextMenu element > shows 'Ungroup selection' in context menu for group inside selected elements > [end of test] number of renders 1`] = `11`; exports[`contextMenu element > shows context menu for canvas > [end of test] appState 1`] = ` { @@ -9415,6 +9415,6 @@ exports[`contextMenu element > shows context menu for element > [end of test] nu exports[`contextMenu element > shows context menu for element > [end of test] number of elements 2`] = `2`; -exports[`contextMenu element > shows context menu for element > [end of test] number of renders 1`] = `4`; +exports[`contextMenu element > shows context menu for element > [end of test] number of renders 1`] = `5`; exports[`contextMenu element > shows context menu for element > [end of test] number of renders 2`] = `6`; diff --git a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap index 4b9910f0e9971..a6b6303671907 100644 --- a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap @@ -597,7 +597,7 @@ History { exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and the arrow got bound to a different element in the meantime > [end of test] number of elements 1`] = `4`; -exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and the arrow got bound to a different element in the meantime > [end of test] number of renders 1`] = `20`; +exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and the arrow got bound to a different element in the meantime > [end of test] number of renders 1`] = `21`; exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] appState 1`] = ` { @@ -1100,7 +1100,7 @@ History { exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] number of elements 1`] = `3`; -exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] number of renders 1`] = `22`; +exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] number of renders 1`] = `23`; exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind remotely added arrow when it's bindable elements are added through the history > [end of test] appState 1`] = ` { @@ -2532,7 +2532,7 @@ History { exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should update bound element points when rectangle was remotely moved and arrow is added back through the history > [end of test] number of elements 1`] = `3`; -exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should update bound element points when rectangle was remotely moved and arrow is added back through the history > [end of test] number of renders 1`] = `8`; +exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should update bound element points when rectangle was remotely moved and arrow is added back through the history > [end of test] number of renders 1`] = `9`; exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should preserve latest remotely added binding and unbind previous one when the container is added through the history > [end of test] appState 1`] = ` { @@ -6355,7 +6355,7 @@ History { exports[`history > multiplayer undo/redo > should iterate through the history when element changes relate only to remotely deleted elements > [end of test] number of elements 1`] = `3`; -exports[`history > multiplayer undo/redo > should iterate through the history when element changes relate only to remotely deleted elements > [end of test] number of renders 1`] = `14`; +exports[`history > multiplayer undo/redo > should iterate through the history when element changes relate only to remotely deleted elements > [end of test] number of renders 1`] = `17`; exports[`history > multiplayer undo/redo > should iterate through the history when selected elements relate only to remotely deleted elements > [end of test] appState 1`] = ` { @@ -7341,7 +7341,7 @@ History { exports[`history > multiplayer undo/redo > should iterate through the history when selected or editing linear element was remotely deleted > [end of test] number of elements 1`] = `1`; -exports[`history > multiplayer undo/redo > should iterate through the history when selected or editing linear element was remotely deleted > [end of test] number of renders 1`] = `8`; +exports[`history > multiplayer undo/redo > should iterate through the history when selected or editing linear element was remotely deleted > [end of test] number of renders 1`] = `9`; exports[`history > multiplayer undo/redo > should iterate through the history when when element change relates to remotely deleted element > [end of test] appState 1`] = ` { @@ -7567,7 +7567,7 @@ History { exports[`history > multiplayer undo/redo > should iterate through the history when when element change relates to remotely deleted element > [end of test] number of elements 1`] = `1`; -exports[`history > multiplayer undo/redo > should iterate through the history when when element change relates to remotely deleted element > [end of test] number of renders 1`] = `8`; +exports[`history > multiplayer undo/redo > should iterate through the history when when element change relates to remotely deleted element > [end of test] number of renders 1`] = `9`; exports[`history > multiplayer undo/redo > should iterate through the history when z-index changes do not produce visible change and we synced all indices > [end of test] appState 1`] = ` { @@ -8672,7 +8672,7 @@ History { exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress dragging > [end of test] number of elements 1`] = `3`; -exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress dragging > [end of test] number of renders 1`] = `23`; +exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress dragging > [end of test] number of renders 1`] = `25`; exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress freedraw > [end of test] appState 1`] = ` { @@ -8956,7 +8956,7 @@ History { exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress freedraw > [end of test] number of elements 1`] = `2`; -exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress freedraw > [end of test] number of renders 1`] = `7`; +exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress freedraw > [end of test] number of renders 1`] = `8`; exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress resizing > [end of test] appState 1`] = ` { @@ -9218,7 +9218,7 @@ History { exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress resizing > [end of test] number of elements 1`] = `2`; -exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress resizing > [end of test] number of renders 1`] = `12`; +exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress resizing > [end of test] number of renders 1`] = `13`; exports[`history > multiplayer undo/redo > should not override remote changes on different elements > [end of test] appState 1`] = ` { @@ -9479,7 +9479,7 @@ History { exports[`history > multiplayer undo/redo > should not override remote changes on different elements > [end of test] number of elements 1`] = `2`; -exports[`history > multiplayer undo/redo > should not override remote changes on different elements > [end of test] number of renders 1`] = `9`; +exports[`history > multiplayer undo/redo > should not override remote changes on different elements > [end of test] number of renders 1`] = `10`; exports[`history > multiplayer undo/redo > should not override remote changes on different properties > [end of test] appState 1`] = ` { @@ -9707,7 +9707,7 @@ History { exports[`history > multiplayer undo/redo > should not override remote changes on different properties > [end of test] number of elements 1`] = `1`; -exports[`history > multiplayer undo/redo > should not override remote changes on different properties > [end of test] number of renders 1`] = `8`; +exports[`history > multiplayer undo/redo > should not override remote changes on different properties > [end of test] number of renders 1`] = `9`; exports[`history > multiplayer undo/redo > should override remotely added groups on undo, but restore them on redo > [end of test] appState 1`] = ` { @@ -10342,7 +10342,7 @@ History { exports[`history > multiplayer undo/redo > should override remotely added points on undo, but restore them on redo > [end of test] number of elements 1`] = `1`; -exports[`history > multiplayer undo/redo > should override remotely added points on undo, but restore them on redo > [end of test] number of renders 1`] = `13`; +exports[`history > multiplayer undo/redo > should override remotely added points on undo, but restore them on redo > [end of test] number of renders 1`] = `14`; exports[`history > multiplayer undo/redo > should redistribute deltas when element gets removed locally but is restored remotely > [end of test] appState 1`] = ` { @@ -10574,7 +10574,7 @@ History { exports[`history > multiplayer undo/redo > should redistribute deltas when element gets removed locally but is restored remotely > [end of test] number of elements 1`] = `1`; -exports[`history > multiplayer undo/redo > should redistribute deltas when element gets removed locally but is restored remotely > [end of test] number of renders 1`] = `10`; +exports[`history > multiplayer undo/redo > should redistribute deltas when element gets removed locally but is restored remotely > [end of test] number of renders 1`] = `11`; exports[`history > multiplayer undo/redo > should redraw arrows on undo > [end of test] appState 1`] = ` { @@ -11275,7 +11275,7 @@ History { exports[`history > multiplayer undo/redo > should update history entries after remote changes on the same properties > [end of test] number of elements 1`] = `1`; -exports[`history > multiplayer undo/redo > should update history entries after remote changes on the same properties > [end of test] number of renders 1`] = `14`; +exports[`history > multiplayer undo/redo > should update history entries after remote changes on the same properties > [end of test] number of renders 1`] = `15`; exports[`history > singleplayer undo/redo > remounting undo/redo buttons should initialize undo/redo state correctly > [end of test] appState 1`] = ` { @@ -11511,7 +11511,7 @@ History { exports[`history > singleplayer undo/redo > remounting undo/redo buttons should initialize undo/redo state correctly > [end of test] number of elements 1`] = `2`; -exports[`history > singleplayer undo/redo > remounting undo/redo buttons should initialize undo/redo state correctly > [end of test] number of renders 1`] = `10`; +exports[`history > singleplayer undo/redo > remounting undo/redo buttons should initialize undo/redo state correctly > [end of test] number of renders 1`] = `11`; exports[`history > singleplayer undo/redo > should clear the redo stack on elements change > [end of test] appState 1`] = ` { @@ -11749,7 +11749,7 @@ History { exports[`history > singleplayer undo/redo > should clear the redo stack on elements change > [end of test] number of elements 1`] = `2`; -exports[`history > singleplayer undo/redo > should clear the redo stack on elements change > [end of test] number of renders 1`] = `6`; +exports[`history > singleplayer undo/redo > should clear the redo stack on elements change > [end of test] number of renders 1`] = `8`; exports[`history > singleplayer undo/redo > should create entry when selecting freedraw > [end of test] appState 1`] = ` { @@ -12147,7 +12147,7 @@ History { exports[`history > singleplayer undo/redo > should create entry when selecting freedraw > [end of test] number of elements 1`] = `3`; -exports[`history > singleplayer undo/redo > should create entry when selecting freedraw > [end of test] number of renders 1`] = `9`; +exports[`history > singleplayer undo/redo > should create entry when selecting freedraw > [end of test] number of renders 1`] = `12`; exports[`history > singleplayer undo/redo > should create new history entry on scene import via drag&drop > [end of test] appState 1`] = ` { @@ -12629,7 +12629,7 @@ History { exports[`history > singleplayer undo/redo > should disable undo/redo buttons when stacks empty > [end of test] number of elements 1`] = `2`; -exports[`history > singleplayer undo/redo > should disable undo/redo buttons when stacks empty > [end of test] number of renders 1`] = `6`; +exports[`history > singleplayer undo/redo > should disable undo/redo buttons when stacks empty > [end of test] number of renders 1`] = `7`; exports[`history > singleplayer undo/redo > should end up with no history entry after initializing scene > [end of test] appState 1`] = ` { @@ -12867,7 +12867,7 @@ History { exports[`history > singleplayer undo/redo > should end up with no history entry after initializing scene > [end of test] number of elements 1`] = `2`; -exports[`history > singleplayer undo/redo > should end up with no history entry after initializing scene > [end of test] number of renders 1`] = `6`; +exports[`history > singleplayer undo/redo > should end up with no history entry after initializing scene > [end of test] number of renders 1`] = `7`; exports[`history > singleplayer undo/redo > should iterate through the history when selection changes do not produce visible change > [end of test] appState 1`] = ` { @@ -13111,7 +13111,7 @@ History { exports[`history > singleplayer undo/redo > should iterate through the history when selection changes do not produce visible change > [end of test] number of elements 1`] = `1`; -exports[`history > singleplayer undo/redo > should iterate through the history when selection changes do not produce visible change > [end of test] number of renders 1`] = `12`; +exports[`history > singleplayer undo/redo > should iterate through the history when selection changes do not produce visible change > [end of test] number of renders 1`] = `13`; exports[`history > singleplayer undo/redo > should not clear the redo stack on standalone appstate change > [end of test] appState 1`] = ` { @@ -13440,7 +13440,7 @@ History { exports[`history > singleplayer undo/redo > should not clear the redo stack on standalone appstate change > [end of test] number of elements 1`] = `2`; -exports[`history > singleplayer undo/redo > should not clear the redo stack on standalone appstate change > [end of test] number of renders 1`] = `10`; +exports[`history > singleplayer undo/redo > should not clear the redo stack on standalone appstate change > [end of test] number of renders 1`] = `12`; exports[`history > singleplayer undo/redo > should not collapse when applying corrupted history entry > [end of test] appState 1`] = ` { @@ -14430,7 +14430,7 @@ History { exports[`history > singleplayer undo/redo > should not override appstate changes when redo stack is not cleared > [end of test] number of elements 1`] = `1`; -exports[`history > singleplayer undo/redo > should not override appstate changes when redo stack is not cleared > [end of test] number of renders 1`] = `14`; +exports[`history > singleplayer undo/redo > should not override appstate changes when redo stack is not cleared > [end of test] number of renders 1`] = `15`; exports[`history > singleplayer undo/redo > should support appstate name or viewBackgroundColor change > [end of test] appState 1`] = ` { @@ -15281,7 +15281,7 @@ History { exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on deletion and rebind on undo > [end of test] number of elements 1`] = `4`; -exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on deletion and rebind on undo > [end of test] number of renders 1`] = `11`; +exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on deletion and rebind on undo > [end of test] number of renders 1`] = `12`; exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on undo and rebind on redo > [end of test] appState 1`] = ` { @@ -15898,7 +15898,7 @@ History { exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on undo and rebind on redo > [end of test] number of elements 1`] = `4`; -exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on undo and rebind on redo > [end of test] number of renders 1`] = `11`; +exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on undo and rebind on redo > [end of test] number of renders 1`] = `12`; exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind everything from non deleted elements when iterating through the whole undo stack and vice versa rebind everything on redo > [end of test] appState 1`] = ` { @@ -16515,7 +16515,7 @@ History { exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind everything from non deleted elements when iterating through the whole undo stack and vice versa rebind everything on redo > [end of test] number of elements 1`] = `4`; -exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind everything from non deleted elements when iterating through the whole undo stack and vice versa rebind everything on redo > [end of test] number of renders 1`] = `19`; +exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind everything from non deleted elements when iterating through the whole undo stack and vice versa rebind everything on redo > [end of test] number of renders 1`] = `20`; exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangle from arrow on deletion and rebind on undo > [end of test] appState 1`] = ` { @@ -17224,7 +17224,7 @@ History { exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangle from arrow on deletion and rebind on undo > [end of test] number of elements 1`] = `4`; -exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangle from arrow on deletion and rebind on undo > [end of test] number of renders 1`] = `13`; +exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangle from arrow on deletion and rebind on undo > [end of test] number of renders 1`] = `14`; exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangles from arrow on deletion and rebind on undo > [end of test] appState 1`] = ` { @@ -17971,7 +17971,7 @@ History { exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangles from arrow on deletion and rebind on undo > [end of test] number of elements 1`] = `4`; -exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangles from arrow on deletion and rebind on undo > [end of test] number of renders 1`] = `14`; +exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangles from arrow on deletion and rebind on undo > [end of test] number of renders 1`] = `15`; exports[`history > singleplayer undo/redo > should support changes in elements' order > [end of test] appState 1`] = ` { @@ -18442,7 +18442,7 @@ History { exports[`history > singleplayer undo/redo > should support changes in elements' order > [end of test] number of elements 1`] = `3`; -exports[`history > singleplayer undo/redo > should support changes in elements' order > [end of test] number of renders 1`] = `17`; +exports[`history > singleplayer undo/redo > should support changes in elements' order > [end of test] number of renders 1`] = `20`; exports[`history > singleplayer undo/redo > should support duplication of groups, appstate group selection and editing group > [end of test] appState 1`] = ` { @@ -19414,7 +19414,7 @@ History { exports[`history > singleplayer undo/redo > should support element creation, deletion and appstate element selection change > [end of test] number of elements 1`] = `3`; -exports[`history > singleplayer undo/redo > should support element creation, deletion and appstate element selection change > [end of test] number of renders 1`] = `24`; +exports[`history > singleplayer undo/redo > should support element creation, deletion and appstate element selection change > [end of test] number of renders 1`] = `27`; exports[`history > singleplayer undo/redo > should support linear element creation and points manipulation through the editor > [end of test] appState 1`] = ` { @@ -19819,4 +19819,4 @@ History { exports[`history > singleplayer undo/redo > should support linear element creation and points manipulation through the editor > [end of test] number of elements 1`] = `1`; -exports[`history > singleplayer undo/redo > should support linear element creation and points manipulation through the editor > [end of test] number of renders 1`] = `19`; +exports[`history > singleplayer undo/redo > should support linear element creation and points manipulation through the editor > [end of test] number of renders 1`] = `20`; diff --git a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap index 52a347ffe851a..65d301ef5dc7d 100644 --- a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap @@ -407,7 +407,7 @@ History { exports[`given element A and group of elements B and given both are selected when user clicks on B, on pointer up only elements from B should be selected > [end of test] number of elements 1`] = `0`; -exports[`given element A and group of elements B and given both are selected when user clicks on B, on pointer up only elements from B should be selected > [end of test] number of renders 1`] = `15`; +exports[`given element A and group of elements B and given both are selected when user clicks on B, on pointer up only elements from B should be selected > [end of test] number of renders 1`] = `18`; exports[`given element A and group of elements B and given both are selected when user shift-clicks on B, on pointer up only element A should be selected > [end of test] appState 1`] = ` { @@ -807,7 +807,7 @@ History { exports[`given element A and group of elements B and given both are selected when user shift-clicks on B, on pointer up only element A should be selected > [end of test] number of elements 1`] = `0`; -exports[`given element A and group of elements B and given both are selected when user shift-clicks on B, on pointer up only element A should be selected > [end of test] number of renders 1`] = `13`; +exports[`given element A and group of elements B and given both are selected when user shift-clicks on B, on pointer up only element A should be selected > [end of test] number of renders 1`] = `16`; exports[`regression tests > Cmd/Ctrl-click exclusively select element under pointer > [end of test] appState 1`] = ` { @@ -1346,7 +1346,7 @@ History { exports[`regression tests > Cmd/Ctrl-click exclusively select element under pointer > [end of test] number of elements 1`] = `0`; -exports[`regression tests > Cmd/Ctrl-click exclusively select element under pointer > [end of test] number of renders 1`] = `23`; +exports[`regression tests > Cmd/Ctrl-click exclusively select element under pointer > [end of test] number of renders 1`] = `26`; exports[`regression tests > Drags selected element when hitting only bounding box and keeps element selected > [end of test] appState 1`] = ` { @@ -1544,7 +1544,7 @@ History { exports[`regression tests > Drags selected element when hitting only bounding box and keeps element selected > [end of test] number of elements 1`] = `0`; -exports[`regression tests > Drags selected element when hitting only bounding box and keeps element selected > [end of test] number of renders 1`] = `9`; +exports[`regression tests > Drags selected element when hitting only bounding box and keeps element selected > [end of test] number of renders 1`] = `10`; exports[`regression tests > adjusts z order when grouping > [end of test] appState 1`] = ` { @@ -1913,7 +1913,7 @@ History { exports[`regression tests > adjusts z order when grouping > [end of test] number of elements 1`] = `0`; -exports[`regression tests > adjusts z order when grouping > [end of test] number of renders 1`] = `12`; +exports[`regression tests > adjusts z order when grouping > [end of test] number of renders 1`] = `15`; exports[`regression tests > alt-drag duplicates an element > [end of test] appState 1`] = ` { @@ -2147,7 +2147,7 @@ History { exports[`regression tests > alt-drag duplicates an element > [end of test] number of elements 1`] = `0`; -exports[`regression tests > alt-drag duplicates an element > [end of test] number of renders 1`] = `7`; +exports[`regression tests > alt-drag duplicates an element > [end of test] number of renders 1`] = `8`; exports[`regression tests > arrow keys > [end of test] appState 1`] = ` { @@ -2321,7 +2321,7 @@ History { exports[`regression tests > arrow keys > [end of test] number of elements 1`] = `0`; -exports[`regression tests > arrow keys > [end of test] number of renders 1`] = `11`; +exports[`regression tests > arrow keys > [end of test] number of renders 1`] = `12`; exports[`regression tests > can drag element that covers another element, while another elem is selected > [end of test] appState 1`] = ` { @@ -2635,7 +2635,7 @@ History { exports[`regression tests > can drag element that covers another element, while another elem is selected > [end of test] number of elements 1`] = `0`; -exports[`regression tests > can drag element that covers another element, while another elem is selected > [end of test] number of renders 1`] = `12`; +exports[`regression tests > can drag element that covers another element, while another elem is selected > [end of test] number of renders 1`] = `15`; exports[`regression tests > change the properties of a shape > [end of test] appState 1`] = ` { @@ -2875,7 +2875,7 @@ History { exports[`regression tests > change the properties of a shape > [end of test] number of elements 1`] = `0`; -exports[`regression tests > change the properties of a shape > [end of test] number of renders 1`] = `8`; +exports[`regression tests > change the properties of a shape > [end of test] number of renders 1`] = `9`; exports[`regression tests > click on an element and drag it > [dragged] appState 1`] = ` { @@ -3112,7 +3112,7 @@ History { exports[`regression tests > click on an element and drag it > [dragged] number of elements 1`] = `1`; -exports[`regression tests > click on an element and drag it > [dragged] number of renders 1`] = `7`; +exports[`regression tests > click on an element and drag it > [dragged] number of renders 1`] = `8`; exports[`regression tests > click on an element and drag it > [end of test] appState 1`] = ` { @@ -3336,7 +3336,7 @@ History { exports[`regression tests > click on an element and drag it > [end of test] number of elements 1`] = `0`; -exports[`regression tests > click on an element and drag it > [end of test] number of renders 1`] = `9`; +exports[`regression tests > click on an element and drag it > [end of test] number of renders 1`] = `10`; exports[`regression tests > click to select a shape > [end of test] appState 1`] = ` { @@ -3586,7 +3586,7 @@ History { exports[`regression tests > click to select a shape > [end of test] number of elements 1`] = `0`; -exports[`regression tests > click to select a shape > [end of test] number of renders 1`] = `8`; +exports[`regression tests > click to select a shape > [end of test] number of renders 1`] = `10`; exports[`regression tests > click-drag to select a group > [end of test] appState 1`] = ` { @@ -3891,7 +3891,7 @@ History { exports[`regression tests > click-drag to select a group > [end of test] number of elements 1`] = `0`; -exports[`regression tests > click-drag to select a group > [end of test] number of renders 1`] = `11`; +exports[`regression tests > click-drag to select a group > [end of test] number of renders 1`] = `14`; exports[`regression tests > deleting last but one element in editing group should unselect the group > [end of test] appState 1`] = ` { @@ -4299,7 +4299,7 @@ History { exports[`regression tests > deleting last but one element in editing group should unselect the group > [end of test] number of elements 1`] = `0`; -exports[`regression tests > deleting last but one element in editing group should unselect the group > [end of test] number of renders 1`] = `15`; +exports[`regression tests > deleting last but one element in editing group should unselect the group > [end of test] number of renders 1`] = `17`; exports[`regression tests > deselects group of selected elements on pointer down when pointer doesn't hit any element > [end of test] appState 1`] = ` { @@ -4576,7 +4576,7 @@ History { exports[`regression tests > deselects group of selected elements on pointer down when pointer doesn't hit any element > [end of test] number of elements 1`] = `0`; -exports[`regression tests > deselects group of selected elements on pointer down when pointer doesn't hit any element > [end of test] number of renders 1`] = `9`; +exports[`regression tests > deselects group of selected elements on pointer down when pointer doesn't hit any element > [end of test] number of renders 1`] = `11`; exports[`regression tests > deselects group of selected elements on pointer up when pointer hits common bounding box without hitting any element > [end of test] appState 1`] = ` { @@ -4823,7 +4823,7 @@ History { exports[`regression tests > deselects group of selected elements on pointer up when pointer hits common bounding box without hitting any element > [end of test] number of elements 1`] = `0`; -exports[`regression tests > deselects group of selected elements on pointer up when pointer hits common bounding box without hitting any element > [end of test] number of renders 1`] = `9`; +exports[`regression tests > deselects group of selected elements on pointer up when pointer hits common bounding box without hitting any element > [end of test] number of renders 1`] = `11`; exports[`regression tests > deselects selected element on pointer down when pointer doesn't hit any element > [end of test] appState 1`] = ` { @@ -5027,7 +5027,7 @@ History { exports[`regression tests > deselects selected element on pointer down when pointer doesn't hit any element > [end of test] number of elements 1`] = `0`; -exports[`regression tests > deselects selected element on pointer down when pointer doesn't hit any element > [end of test] number of renders 1`] = `6`; +exports[`regression tests > deselects selected element on pointer down when pointer doesn't hit any element > [end of test] number of renders 1`] = `7`; exports[`regression tests > deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element > [end of test] appState 1`] = ` { @@ -5220,7 +5220,7 @@ History { exports[`regression tests > deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element > [end of test] number of elements 1`] = `0`; -exports[`regression tests > deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element > [end of test] number of renders 1`] = `6`; +exports[`regression tests > deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element > [end of test] number of renders 1`] = `7`; exports[`regression tests > double click to edit a group > [end of test] appState 1`] = ` { @@ -5596,7 +5596,7 @@ History { exports[`regression tests > double click to edit a group > [end of test] number of elements 1`] = `0`; -exports[`regression tests > double click to edit a group > [end of test] number of renders 1`] = `12`; +exports[`regression tests > double click to edit a group > [end of test] number of renders 1`] = `15`; exports[`regression tests > drags selected elements from point inside common bounding box that doesn't hit any element and keeps elements selected after dragging > [end of test] appState 1`] = ` { @@ -5880,7 +5880,7 @@ History { exports[`regression tests > drags selected elements from point inside common bounding box that doesn't hit any element and keeps elements selected after dragging > [end of test] number of elements 1`] = `0`; -exports[`regression tests > drags selected elements from point inside common bounding box that doesn't hit any element and keeps elements selected after dragging > [end of test] number of renders 1`] = `10`; +exports[`regression tests > drags selected elements from point inside common bounding box that doesn't hit any element and keeps elements selected after dragging > [end of test] number of renders 1`] = `12`; exports[`regression tests > draw every type of shape > [end of test] appState 1`] = ` { @@ -6682,7 +6682,7 @@ History { exports[`regression tests > draw every type of shape > [end of test] number of elements 1`] = `0`; -exports[`regression tests > draw every type of shape > [end of test] number of renders 1`] = `23`; +exports[`regression tests > draw every type of shape > [end of test] number of renders 1`] = `31`; exports[`regression tests > given a group of selected elements with an element that is not selected inside the group common bounding box when element that is not selected is clicked should switch selection to not selected element on pointer up > [end of test] appState 1`] = ` { @@ -7006,7 +7006,7 @@ History { exports[`regression tests > given a group of selected elements with an element that is not selected inside the group common bounding box when element that is not selected is clicked should switch selection to not selected element on pointer up > [end of test] number of elements 1`] = `0`; -exports[`regression tests > given a group of selected elements with an element that is not selected inside the group common bounding box when element that is not selected is clicked should switch selection to not selected element on pointer up > [end of test] number of renders 1`] = `11`; +exports[`regression tests > given a group of selected elements with an element that is not selected inside the group common bounding box when element that is not selected is clicked should switch selection to not selected element on pointer up > [end of test] number of renders 1`] = `14`; exports[`regression tests > given a selected element A and a not selected element B with higher z-index than A and given B partially overlaps A when there's a shift-click on the overlapped section B is added to the selection > [end of test] appState 1`] = ` { @@ -7276,7 +7276,7 @@ History { exports[`regression tests > given a selected element A and a not selected element B with higher z-index than A and given B partially overlaps A when there's a shift-click on the overlapped section B is added to the selection > [end of test] number of elements 1`] = `0`; -exports[`regression tests > given a selected element A and a not selected element B with higher z-index than A and given B partially overlaps A when there's a shift-click on the overlapped section B is added to the selection > [end of test] number of renders 1`] = `10`; +exports[`regression tests > given a selected element A and a not selected element B with higher z-index than A and given B partially overlaps A when there's a shift-click on the overlapped section B is added to the selection > [end of test] number of renders 1`] = `12`; exports[`regression tests > given selected element A with lower z-index than unselected element B and given B is partially over A when clicking intersection between A and B B should be selected on pointer up > [end of test] appState 1`] = ` { @@ -7909,7 +7909,7 @@ History { exports[`regression tests > key 2 selects rectangle tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key 2 selects rectangle tool > [end of test] number of renders 1`] = `5`; +exports[`regression tests > key 2 selects rectangle tool > [end of test] number of renders 1`] = `6`; exports[`regression tests > key 3 selects diamond tool > [end of test] appState 1`] = ` { @@ -8083,7 +8083,7 @@ History { exports[`regression tests > key 3 selects diamond tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key 3 selects diamond tool > [end of test] number of renders 1`] = `5`; +exports[`regression tests > key 3 selects diamond tool > [end of test] number of renders 1`] = `6`; exports[`regression tests > key 4 selects ellipse tool > [end of test] appState 1`] = ` { @@ -8257,7 +8257,7 @@ History { exports[`regression tests > key 4 selects ellipse tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key 4 selects ellipse tool > [end of test] number of renders 1`] = `5`; +exports[`regression tests > key 4 selects ellipse tool > [end of test] number of renders 1`] = `6`; exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`] = ` { @@ -8473,7 +8473,7 @@ History { exports[`regression tests > key 5 selects arrow tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key 5 selects arrow tool > [end of test] number of renders 1`] = `5`; +exports[`regression tests > key 5 selects arrow tool > [end of test] number of renders 1`] = `6`; exports[`regression tests > key 6 selects line tool > [end of test] appState 1`] = ` { @@ -8688,7 +8688,7 @@ History { exports[`regression tests > key 6 selects line tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key 6 selects line tool > [end of test] number of renders 1`] = `5`; +exports[`regression tests > key 6 selects line tool > [end of test] number of renders 1`] = `6`; exports[`regression tests > key 7 selects freedraw tool > [end of test] appState 1`] = ` { @@ -8876,7 +8876,7 @@ History { exports[`regression tests > key 7 selects freedraw tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key 7 selects freedraw tool > [end of test] number of renders 1`] = `5`; +exports[`regression tests > key 7 selects freedraw tool > [end of test] number of renders 1`] = `6`; exports[`regression tests > key a selects arrow tool > [end of test] appState 1`] = ` { @@ -9092,7 +9092,7 @@ History { exports[`regression tests > key a selects arrow tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key a selects arrow tool > [end of test] number of renders 1`] = `5`; +exports[`regression tests > key a selects arrow tool > [end of test] number of renders 1`] = `6`; exports[`regression tests > key d selects diamond tool > [end of test] appState 1`] = ` { @@ -9266,7 +9266,7 @@ History { exports[`regression tests > key d selects diamond tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key d selects diamond tool > [end of test] number of renders 1`] = `5`; +exports[`regression tests > key d selects diamond tool > [end of test] number of renders 1`] = `6`; exports[`regression tests > key l selects line tool > [end of test] appState 1`] = ` { @@ -9481,7 +9481,7 @@ History { exports[`regression tests > key l selects line tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key l selects line tool > [end of test] number of renders 1`] = `5`; +exports[`regression tests > key l selects line tool > [end of test] number of renders 1`] = `6`; exports[`regression tests > key o selects ellipse tool > [end of test] appState 1`] = ` { @@ -9655,7 +9655,7 @@ History { exports[`regression tests > key o selects ellipse tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key o selects ellipse tool > [end of test] number of renders 1`] = `5`; +exports[`regression tests > key o selects ellipse tool > [end of test] number of renders 1`] = `6`; exports[`regression tests > key p selects freedraw tool > [end of test] appState 1`] = ` { @@ -9843,7 +9843,7 @@ History { exports[`regression tests > key p selects freedraw tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key p selects freedraw tool > [end of test] number of renders 1`] = `5`; +exports[`regression tests > key p selects freedraw tool > [end of test] number of renders 1`] = `6`; exports[`regression tests > key r selects rectangle tool > [end of test] appState 1`] = ` { @@ -10017,7 +10017,7 @@ History { exports[`regression tests > key r selects rectangle tool > [end of test] number of elements 1`] = `0`; -exports[`regression tests > key r selects rectangle tool > [end of test] number of renders 1`] = `5`; +exports[`regression tests > key r selects rectangle tool > [end of test] number of renders 1`] = `6`; exports[`regression tests > make a group and duplicate it > [end of test] appState 1`] = ` { @@ -10525,7 +10525,7 @@ History { exports[`regression tests > make a group and duplicate it > [end of test] number of elements 1`] = `0`; -exports[`regression tests > make a group and duplicate it > [end of test] number of renders 1`] = `14`; +exports[`regression tests > make a group and duplicate it > [end of test] number of renders 1`] = `17`; exports[`regression tests > noop interaction after undo shouldn't create history entry > [end of test] appState 1`] = ` { @@ -10796,7 +10796,7 @@ History { exports[`regression tests > noop interaction after undo shouldn't create history entry > [end of test] number of elements 1`] = `0`; -exports[`regression tests > noop interaction after undo shouldn't create history entry > [end of test] number of renders 1`] = `12`; +exports[`regression tests > noop interaction after undo shouldn't create history entry > [end of test] number of renders 1`] = `14`; exports[`regression tests > pinch-to-zoom works > [end of test] appState 1`] = ` { @@ -11109,7 +11109,7 @@ History { exports[`regression tests > shift click on selected element should deselect it on pointer up > [end of test] number of elements 1`] = `0`; -exports[`regression tests > shift click on selected element should deselect it on pointer up > [end of test] number of renders 1`] = `6`; +exports[`regression tests > shift click on selected element should deselect it on pointer up > [end of test] number of renders 1`] = `7`; exports[`regression tests > shift-click to multiselect, then drag > [end of test] appState 1`] = ` { @@ -11414,7 +11414,7 @@ History { exports[`regression tests > shift-click to multiselect, then drag > [end of test] number of elements 1`] = `0`; -exports[`regression tests > shift-click to multiselect, then drag > [end of test] number of renders 1`] = `11`; +exports[`regression tests > shift-click to multiselect, then drag > [end of test] number of renders 1`] = `13`; exports[`regression tests > should group elements and ungroup them > [end of test] appState 1`] = ` { @@ -11820,7 +11820,7 @@ History { exports[`regression tests > should group elements and ungroup them > [end of test] number of elements 1`] = `0`; -exports[`regression tests > should group elements and ungroup them > [end of test] number of renders 1`] = `15`; +exports[`regression tests > should group elements and ungroup them > [end of test] number of renders 1`] = `18`; exports[`regression tests > single-clicking on a subgroup of a selected group should not alter selection > [end of test] appState 1`] = ` { @@ -12427,7 +12427,7 @@ History { exports[`regression tests > single-clicking on a subgroup of a selected group should not alter selection > [end of test] number of elements 1`] = `0`; -exports[`regression tests > single-clicking on a subgroup of a selected group should not alter selection > [end of test] number of renders 1`] = `21`; +exports[`regression tests > single-clicking on a subgroup of a selected group should not alter selection > [end of test] number of renders 1`] = `25`; exports[`regression tests > spacebar + drag scrolls the canvas > [end of test] appState 1`] = ` { @@ -13128,7 +13128,7 @@ History { exports[`regression tests > supports nested groups > [end of test] number of elements 1`] = `0`; -exports[`regression tests > supports nested groups > [end of test] number of renders 1`] = `20`; +exports[`regression tests > supports nested groups > [end of test] number of renders 1`] = `23`; exports[`regression tests > switches from group of selected elements to another element on pointer down > [end of test] appState 1`] = ` { @@ -13460,7 +13460,7 @@ History { exports[`regression tests > switches from group of selected elements to another element on pointer down > [end of test] number of elements 1`] = `0`; -exports[`regression tests > switches from group of selected elements to another element on pointer down > [end of test] number of renders 1`] = `11`; +exports[`regression tests > switches from group of selected elements to another element on pointer down > [end of test] number of renders 1`] = `14`; exports[`regression tests > switches selected element on pointer down > [end of test] appState 1`] = ` { @@ -13719,7 +13719,7 @@ History { exports[`regression tests > switches selected element on pointer down > [end of test] number of elements 1`] = `0`; -exports[`regression tests > switches selected element on pointer down > [end of test] number of renders 1`] = `8`; +exports[`regression tests > switches selected element on pointer down > [end of test] number of renders 1`] = `10`; exports[`regression tests > two-finger scroll works > [end of test] appState 1`] = ` { @@ -14212,7 +14212,7 @@ History { exports[`regression tests > undo/redo drawing an element > [end of test] number of elements 1`] = `0`; -exports[`regression tests > undo/redo drawing an element > [end of test] number of renders 1`] = `16`; +exports[`regression tests > undo/redo drawing an element > [end of test] number of renders 1`] = `19`; exports[`regression tests > updates fontSize & fontFamily appState > [end of test] appState 1`] = ` { diff --git a/packages/excalidraw/tests/dragCreate.test.tsx b/packages/excalidraw/tests/dragCreate.test.tsx index 8a1a18173829d..760bf81e5dfe0 100644 --- a/packages/excalidraw/tests/dragCreate.test.tsx +++ b/packages/excalidraw/tests/dragCreate.test.tsx @@ -52,7 +52,7 @@ describe("Test dragCreate", () => { fireEvent.pointerUp(canvas); expect(renderInteractiveScene).toHaveBeenCalledTimes(5); - expect(renderStaticScene).toHaveBeenCalledTimes(4); + expect(renderStaticScene).toHaveBeenCalledTimes(5); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); @@ -84,7 +84,7 @@ describe("Test dragCreate", () => { fireEvent.pointerUp(canvas); expect(renderInteractiveScene).toHaveBeenCalledTimes(5); - expect(renderStaticScene).toHaveBeenCalledTimes(4); + expect(renderStaticScene).toHaveBeenCalledTimes(5); expect(h.state.selectionElement).toBeNull(); @@ -117,7 +117,7 @@ describe("Test dragCreate", () => { fireEvent.pointerUp(canvas); expect(renderInteractiveScene).toHaveBeenCalledTimes(5); - expect(renderStaticScene).toHaveBeenCalledTimes(4); + expect(renderStaticScene).toHaveBeenCalledTimes(5); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); @@ -149,7 +149,7 @@ describe("Test dragCreate", () => { fireEvent.pointerUp(canvas); expect(renderInteractiveScene).toHaveBeenCalledTimes(5); - expect(renderStaticScene).toHaveBeenCalledTimes(4); + expect(renderStaticScene).toHaveBeenCalledTimes(5); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); @@ -185,7 +185,7 @@ describe("Test dragCreate", () => { fireEvent.pointerUp(canvas); expect(renderInteractiveScene).toHaveBeenCalledTimes(5); - expect(renderStaticScene).toHaveBeenCalledTimes(4); + expect(renderStaticScene).toHaveBeenCalledTimes(5); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); @@ -226,7 +226,7 @@ describe("Test dragCreate", () => { fireEvent.pointerUp(canvas); expect(renderInteractiveScene).toHaveBeenCalledTimes(5); - expect(renderStaticScene).toHaveBeenCalledTimes(4); + expect(renderStaticScene).toHaveBeenCalledTimes(5); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(0); }); @@ -246,7 +246,7 @@ describe("Test dragCreate", () => { fireEvent.pointerUp(canvas); expect(renderInteractiveScene).toHaveBeenCalledTimes(5); - expect(renderStaticScene).toHaveBeenCalledTimes(4); + expect(renderStaticScene).toHaveBeenCalledTimes(5); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(0); }); @@ -266,7 +266,7 @@ describe("Test dragCreate", () => { fireEvent.pointerUp(canvas); expect(renderInteractiveScene).toHaveBeenCalledTimes(5); - expect(renderStaticScene).toHaveBeenCalledTimes(4); + expect(renderStaticScene).toHaveBeenCalledTimes(5); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(0); }); @@ -293,7 +293,7 @@ describe("Test dragCreate", () => { }); expect(renderInteractiveScene).toHaveBeenCalledTimes(6); - expect(renderStaticScene).toHaveBeenCalledTimes(4); + expect(renderStaticScene).toHaveBeenCalledTimes(5); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(0); }); @@ -320,7 +320,7 @@ describe("Test dragCreate", () => { }); expect(renderInteractiveScene).toHaveBeenCalledTimes(6); - expect(renderStaticScene).toHaveBeenCalledTimes(4); + expect(renderStaticScene).toHaveBeenCalledTimes(5); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(0); }); diff --git a/packages/excalidraw/tests/move.test.tsx b/packages/excalidraw/tests/move.test.tsx index 692f8cf1efdf4..9cc3e45075fb5 100644 --- a/packages/excalidraw/tests/move.test.tsx +++ b/packages/excalidraw/tests/move.test.tsx @@ -50,7 +50,7 @@ describe("move element", () => { expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot( `5`, ); - expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`4`); + expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`5`); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); @@ -98,7 +98,7 @@ describe("move element", () => { expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot( `17`, ); - expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`10`); + expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`13`); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(3); expect(h.state.selectedElementIds[rectB.id]).toBeTruthy(); @@ -148,7 +148,7 @@ describe("duplicate element on move when ALT is clicked", () => { expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot( `5`, ); - expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`4`); + expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`5`); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); diff --git a/packages/excalidraw/tests/multiPointCreate.test.tsx b/packages/excalidraw/tests/multiPointCreate.test.tsx index ccca6a22e048e..7435a5084cbe1 100644 --- a/packages/excalidraw/tests/multiPointCreate.test.tsx +++ b/packages/excalidraw/tests/multiPointCreate.test.tsx @@ -53,7 +53,7 @@ describe("remove shape in non linear elements", () => { fireEvent.pointerUp(canvas, { clientX: 30, clientY: 30 }); expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`5`); - expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`4`); + expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`5`); expect(h.elements.length).toEqual(0); }); @@ -68,7 +68,7 @@ describe("remove shape in non linear elements", () => { fireEvent.pointerUp(canvas, { clientX: 30, clientY: 30 }); expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`5`); - expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`4`); + expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`5`); expect(h.elements.length).toEqual(0); }); @@ -83,7 +83,7 @@ describe("remove shape in non linear elements", () => { fireEvent.pointerUp(canvas, { clientX: 30, clientY: 30 }); expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`5`); - expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`4`); + expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`5`); expect(h.elements.length).toEqual(0); }); }); @@ -116,7 +116,7 @@ describe("multi point mode in linear elements", () => { }); expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`7`); - expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`5`); + expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`); expect(h.elements.length).toEqual(1); const element = h.elements[0] as ExcalidrawLinearElement; @@ -159,7 +159,7 @@ describe("multi point mode in linear elements", () => { key: KEYS.ENTER, }); expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(`7`); - expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`5`); + expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`); expect(h.elements.length).toEqual(1); const element = h.elements[0] as ExcalidrawLinearElement; diff --git a/packages/excalidraw/tests/selection.test.tsx b/packages/excalidraw/tests/selection.test.tsx index 1ef7955c228e8..bffe375bf5d8c 100644 --- a/packages/excalidraw/tests/selection.test.tsx +++ b/packages/excalidraw/tests/selection.test.tsx @@ -315,7 +315,7 @@ describe("select single element on the scene", () => { fireEvent.pointerUp(canvas); expect(renderInteractiveScene).toHaveBeenCalledTimes(8); - expect(renderStaticScene).toHaveBeenCalledTimes(5); + expect(renderStaticScene).toHaveBeenCalledTimes(6); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); @@ -347,7 +347,7 @@ describe("select single element on the scene", () => { fireEvent.pointerUp(canvas); expect(renderInteractiveScene).toHaveBeenCalledTimes(8); - expect(renderStaticScene).toHaveBeenCalledTimes(5); + expect(renderStaticScene).toHaveBeenCalledTimes(6); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); @@ -379,7 +379,7 @@ describe("select single element on the scene", () => { fireEvent.pointerUp(canvas); expect(renderInteractiveScene).toHaveBeenCalledTimes(8); - expect(renderStaticScene).toHaveBeenCalledTimes(5); + expect(renderStaticScene).toHaveBeenCalledTimes(6); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); @@ -424,7 +424,7 @@ describe("select single element on the scene", () => { fireEvent.pointerUp(canvas); expect(renderInteractiveScene).toHaveBeenCalledTimes(8); - expect(renderStaticScene).toHaveBeenCalledTimes(5); + expect(renderStaticScene).toHaveBeenCalledTimes(6); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); @@ -468,7 +468,7 @@ describe("select single element on the scene", () => { fireEvent.pointerUp(canvas); expect(renderInteractiveScene).toHaveBeenCalledTimes(8); - expect(renderStaticScene).toHaveBeenCalledTimes(5); + expect(renderStaticScene).toHaveBeenCalledTimes(6); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); From 66b73b6ff98db9bef3cfe3cbe938cd6b9ea2b81e Mon Sep 17 00:00:00 2001 From: dwelle <5153846+dwelle@users.noreply.github.com> Date: Thu, 22 Aug 2024 14:58:32 +0200 Subject: [PATCH 11/16] skip update of image statuses if no change --- excalidraw-app/collab/Portal.tsx | 35 +++++++++++++++----------- packages/excalidraw/components/App.tsx | 3 +-- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/excalidraw-app/collab/Portal.tsx b/excalidraw-app/collab/Portal.tsx index 79410cb08e1c4..0a16f9584f91f 100644 --- a/excalidraw-app/collab/Portal.tsx +++ b/excalidraw-app/collab/Portal.tsx @@ -116,21 +116,26 @@ class Portal { } } - this.collab.excalidrawAPI.updateScene({ - elements: this.collab.excalidrawAPI - .getSceneElementsIncludingDeleted() - .map((element) => { - if (this.collab.fileManager.shouldUpdateImageElementStatus(element)) { - // this will signal collaborators to pull image data from server - // (using mutation instead of newElementWith otherwise it'd break - // in-progress dragging) - return newElementWith(element, { status: "saved" }); - } - return element; - }), - storeAction: StoreAction.UPDATE, - triggerUpdate: false, - }); + let isChanged = false; + const newElements = this.collab.excalidrawAPI + .getSceneElementsIncludingDeleted() + .map((element) => { + if (this.collab.fileManager.shouldUpdateImageElementStatus(element)) { + isChanged = true; + // this will signal collaborators to pull image data from server + // (using mutation instead of newElementWith otherwise it'd break + // in-progress dragging) + return newElementWith(element, { status: "saved" }); + } + return element; + }); + + if (isChanged) { + this.collab.excalidrawAPI.updateScene({ + elements: newElements, + storeAction: StoreAction.UPDATE, + }); + } }, FILE_UPLOAD_TIMEOUT); broadcastScene = async ( diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 96c4d0ba0b8a8..385e057f029b8 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -3787,7 +3787,6 @@ class App extends React.Component { collaborators?: SceneData["collaborators"]; /** @default StoreAction.NONE */ storeAction?: SceneData["storeAction"]; - triggerUpdate?: boolean; }) => { const nextElements = syncInvalidIndices(sceneData.elements ?? []); @@ -3826,7 +3825,7 @@ class App extends React.Component { } if (sceneData.elements) { - this.scene.replaceAllElements(nextElements, sceneData.triggerUpdate); + this.scene.replaceAllElements(nextElements); } if (sceneData.collaborators) { From 4100d1165a10cd6d5135bb916029185f7fa6cc0e Mon Sep 17 00:00:00 2001 From: dwelle <5153846+dwelle@users.noreply.github.com> Date: Fri, 23 Aug 2024 00:53:38 +0200 Subject: [PATCH 12/16] throttle NewElementCanvas only if enabled --- .../components/canvases/NewElementCanvas.tsx | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/excalidraw/components/canvases/NewElementCanvas.tsx b/packages/excalidraw/components/canvases/NewElementCanvas.tsx index 351ec53ed5d7d..36f6fd5278393 100644 --- a/packages/excalidraw/components/canvases/NewElementCanvas.tsx +++ b/packages/excalidraw/components/canvases/NewElementCanvas.tsx @@ -8,6 +8,7 @@ import type { } from "../../scene/types"; import type { RoughCanvas } from "roughjs/bin/canvas"; import { renderNewElementScene } from "../../renderer/renderNewElementScene"; +import { isRenderThrottlingEnabled } from "../../reactUtils"; interface NewElementCanvasProps { canvas: HTMLCanvasElement | null; @@ -22,16 +23,19 @@ interface NewElementCanvasProps { const NewElementCanvas = (props: NewElementCanvasProps) => { useEffect(() => { - renderNewElementScene({ - canvas: props.canvas, - scale: props.scale, - newElement: props.appState.newElement, - elementsMap: props.elementsMap, - allElementsMap: props.allElementsMap, - rc: props.rc, - renderConfig: props.renderConfig, - appState: props.appState, - }); + renderNewElementScene( + { + canvas: props.canvas, + scale: props.scale, + newElement: props.appState.newElement, + elementsMap: props.elementsMap, + allElementsMap: props.allElementsMap, + rc: props.rc, + renderConfig: props.renderConfig, + appState: props.appState, + }, + isRenderThrottlingEnabled(), + ); }); return ( From f05daeb629ccd99a978b97628fc5d271873317b7 Mon Sep 17 00:00:00 2001 From: dwelle <5153846+dwelle@users.noreply.github.com> Date: Fri, 23 Aug 2024 00:49:01 +0200 Subject: [PATCH 13/16] handle canvas ref in-component --- packages/excalidraw/components/App.tsx | 9 --------- .../components/canvases/NewElementCanvas.tsx | 17 ++++++++--------- packages/excalidraw/locales/en.json | 1 - packages/excalidraw/types.ts | 1 - 4 files changed, 8 insertions(+), 20 deletions(-) diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 385e057f029b8..56efc190086cc 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -537,7 +537,6 @@ const gesture: Gesture = { class App extends React.Component { canvas: AppClassProperties["canvas"]; interactiveCanvas: AppClassProperties["interactiveCanvas"] = null; - newElementCanvas: AppClassProperties["newElementCanvas"] = null; rc: RoughCanvas; unmounted: boolean = false; actionManager: ActionManager; @@ -1709,8 +1708,6 @@ class App extends React.Component { { } }; - private handleNewElementCanvasRef = (canvas: HTMLCanvasElement | null) => { - if (canvas !== null) { - this.newElementCanvas = canvas; - } - }; - private handleAppOnDrop = async (event: React.DragEvent) => { // must be retrieved first, in the same frame const { file, fileHandle } = await getFileFromEvent(event); diff --git a/packages/excalidraw/components/canvases/NewElementCanvas.tsx b/packages/excalidraw/components/canvases/NewElementCanvas.tsx index 36f6fd5278393..999962f018a54 100644 --- a/packages/excalidraw/components/canvases/NewElementCanvas.tsx +++ b/packages/excalidraw/components/canvases/NewElementCanvas.tsx @@ -1,6 +1,5 @@ -import { useEffect } from "react"; +import { useEffect, useRef } from "react"; import type { NonDeletedSceneElementsMap } from "../../element/types"; -import { t } from "../../i18n"; import type { AppState } from "../../types"; import type { RenderableElementsMap, @@ -11,21 +10,23 @@ import { renderNewElementScene } from "../../renderer/renderNewElementScene"; import { isRenderThrottlingEnabled } from "../../reactUtils"; interface NewElementCanvasProps { - canvas: HTMLCanvasElement | null; appState: AppState; elementsMap: RenderableElementsMap; allElementsMap: NonDeletedSceneElementsMap; scale: number; rc: RoughCanvas; renderConfig: StaticCanvasRenderConfig; - handleCanvasRef: (canvas: HTMLCanvasElement | null) => void; } const NewElementCanvas = (props: NewElementCanvasProps) => { + const canvasRef = useRef(null); useEffect(() => { + if (!canvasRef.current) { + return; + } renderNewElementScene( { - canvas: props.canvas, + canvas: canvasRef.current, scale: props.scale, newElement: props.appState.newElement, elementsMap: props.elementsMap, @@ -46,10 +47,8 @@ const NewElementCanvas = (props: NewElementCanvasProps) => { }} width={props.appState.width * props.scale} height={props.appState.height * props.scale} - ref={props.handleCanvasRef} - > - {t("labels.newElementCanvas")} - + ref={canvasRef} + /> ); }; diff --git a/packages/excalidraw/locales/en.json b/packages/excalidraw/locales/en.json index 1f91e7d3954b2..b67624efe5209 100644 --- a/packages/excalidraw/locales/en.json +++ b/packages/excalidraw/locales/en.json @@ -78,7 +78,6 @@ "canvasColors": "Used on canvas", "canvasBackground": "Canvas background", "drawingCanvas": "Drawing canvas", - "newElementCanvas": "New element canvas", "clearCanvas": "Clear canvas", "layers": "Layers", "actions": "Actions", diff --git a/packages/excalidraw/types.ts b/packages/excalidraw/types.ts index ba00a6bce6d2f..39b1f6be59dc5 100644 --- a/packages/excalidraw/types.ts +++ b/packages/excalidraw/types.ts @@ -617,7 +617,6 @@ export type AppClassProperties = { props: AppProps; state: AppState; interactiveCanvas: HTMLCanvasElement | null; - newElementCanvas: HTMLCanvasElement | null; /** static canvas */ canvas: HTMLCanvasElement; focusContainer(): void; From e243d0a5778ebdf6773d8aad16a08e051bcc5eb5 Mon Sep 17 00:00:00 2001 From: dwelle <5153846+dwelle@users.noreply.github.com> Date: Fri, 23 Aug 2024 00:49:08 +0200 Subject: [PATCH 14/16] cleanup --- packages/excalidraw/actions/actionHistory.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/excalidraw/actions/actionHistory.tsx b/packages/excalidraw/actions/actionHistory.tsx index f8562072b525c..c1e35674adc7c 100644 --- a/packages/excalidraw/actions/actionHistory.tsx +++ b/packages/excalidraw/actions/actionHistory.tsx @@ -21,7 +21,6 @@ const executeHistoryAction = ( if ( !appState.multiElement && !appState.resizingElement && - // MARK: do check this again !appState.editingTextElement && !appState.newElement && !appState.selectedElementsAreBeingDragged && From 7c995c0d23e177f5ce616523c9177797822fb88f Mon Sep 17 00:00:00 2001 From: dwelle <5153846+dwelle@users.noreply.github.com> Date: Fri, 23 Aug 2024 00:49:27 +0200 Subject: [PATCH 15/16] align with prev behavior --- packages/excalidraw/components/Actions.tsx | 6 ++++-- packages/excalidraw/scene/selection.ts | 7 ++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/excalidraw/components/Actions.tsx b/packages/excalidraw/components/Actions.tsx index 2f24d291865e4..96508f9ea84e2 100644 --- a/packages/excalidraw/components/Actions.tsx +++ b/packages/excalidraw/components/Actions.tsx @@ -104,7 +104,9 @@ export const SelectedShapeActions = ({ ) { isSingleElementBoundContainer = true; } - const isEditingText = Boolean(appState.editingTextElement); + const isEditingTextOrNewElement = Boolean( + appState.editingTextElement || appState.newElement, + ); const device = useDevice(); const isRTL = document.documentElement.getAttribute("dir") === "rtl"; @@ -234,7 +236,7 @@ export const SelectedShapeActions = ({
)} - {!isEditingText && targetElements.length > 0 && ( + {!isEditingTextOrNewElement && targetElements.length > 0 && (
{t("labels.actions")}
diff --git a/packages/excalidraw/scene/selection.ts b/packages/excalidraw/scene/selection.ts index 7593cd5d98f25..06fb2c604a578 100644 --- a/packages/excalidraw/scene/selection.ts +++ b/packages/excalidraw/scene/selection.ts @@ -218,10 +218,15 @@ export const getSelectedElements = ( export const getTargetElements = ( elements: ElementsMapOrArray, - appState: Pick, + appState: Pick< + AppState, + "selectedElementIds" | "editingTextElement" | "newElement" + >, ) => appState.editingTextElement ? [appState.editingTextElement] + : appState.newElement + ? [appState.newElement] : getSelectedElements(elements, appState, { includeBoundTextElement: true, }); From 3712e4de50f4b2bcbb2825ffbff9d23435302756 Mon Sep 17 00:00:00 2001 From: dwelle <5153846+dwelle@users.noreply.github.com> Date: Fri, 23 Aug 2024 13:30:01 +0200 Subject: [PATCH 16/16] switch `triggerUpdate` flag to `updateSceneNonce` --- packages/excalidraw/scene/Scene.ts | 31 ++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/excalidraw/scene/Scene.ts b/packages/excalidraw/scene/Scene.ts index 83375e34f82c5..603320a733b64 100644 --- a/packages/excalidraw/scene/Scene.ts +++ b/packages/excalidraw/scene/Scene.ts @@ -285,7 +285,10 @@ class Scene { return didChange; } - replaceAllElements(nextElements: ElementsMapOrArray, triggerUpdate = true) { + replaceAllElements( + nextElements: ElementsMapOrArray, + updateSceneNonce = true, + ) { const _nextElements = // ts doesn't like `Array.isArray` of `instanceof Map` nextElements instanceof Array @@ -311,13 +314,13 @@ class Scene { this.frames = nextFrameLikes; this.nonDeletedFramesLikes = getNonDeletedElements(this.frames).elements; - if (triggerUpdate) { - this.triggerUpdate(); - } + this.triggerUpdate(updateSceneNonce); } - triggerUpdate() { - this.sceneNonce = randomInteger(); + triggerUpdate(updateSceneNonce = true) { + if (updateSceneNonce) { + this.sceneNonce = randomInteger(); + } for (const callback of Array.from(this.callbacks)) { callback(); @@ -363,7 +366,7 @@ class Scene { insertElementAtIndex( element: ExcalidrawElement, index: number, - triggerUpdate = true, + updateSceneNonce = true, ) { if (!Number.isFinite(index) || index < 0) { throw new Error( @@ -379,13 +382,13 @@ class Scene { syncMovedIndices(nextElements, arrayToMap([element])); - this.replaceAllElements(nextElements, triggerUpdate); + this.replaceAllElements(nextElements, updateSceneNonce); } insertElementsAtIndex( elements: ExcalidrawElement[], index: number, - triggerUpdate = true, + updateSceneNonce = true, ) { if (!Number.isFinite(index) || index < 0) { throw new Error( @@ -401,23 +404,23 @@ class Scene { syncMovedIndices(nextElements, arrayToMap(elements)); - this.replaceAllElements(nextElements, triggerUpdate); + this.replaceAllElements(nextElements, updateSceneNonce); } - insertElement = (element: ExcalidrawElement, triggerUpdate = true) => { + insertElement = (element: ExcalidrawElement, updateSceneNonce = true) => { const index = element.frameId ? this.getElementIndex(element.frameId) : this.elements.length; - this.insertElementAtIndex(element, index, triggerUpdate); + this.insertElementAtIndex(element, index, updateSceneNonce); }; - insertElements = (elements: ExcalidrawElement[], triggerUpdate = true) => { + insertElements = (elements: ExcalidrawElement[], updateSceneNonce = true) => { const index = elements[0].frameId ? this.getElementIndex(elements[0].frameId) : this.elements.length; - this.insertElementsAtIndex(elements, index, triggerUpdate); + this.insertElementsAtIndex(elements, index, updateSceneNonce); }; getElementIndex(elementId: string) {