1
0
mirror of https://github.com/excalidraw/excalidraw.git synced 2025-02-18 13:29:36 +01:00

Add loading state (#1027)

* add loading state

* update snapshots

* add border radius

* fix comment breaking build jsx
This commit is contained in:
David Luzar 2020-03-26 18:28:26 +01:00 committed by GitHub
parent d8708cb14f
commit cac2dda5ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 214 additions and 85 deletions

@ -130,6 +130,26 @@
media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2)"
rel="apple-touch-startup-image"
/>
<style>
.LoadingMessage {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 999;
display: flex;
align-items: center;
justify-content: center;
pointer-events: none;
}
.LoadingMessage span {
background-color: rgba(255, 255, 255, 0.8);
border-radius: 5px;
padding: 0.8em 1.2em;
font-size: 1.3em;
}
</style>
<script
async
src="https://www.googletagmanager.com/gtag/js?id=UA-387204-13"
@ -151,7 +171,11 @@
<header>
<h1 class="visually-hidden">Excalidraw</h1>
</header>
<div id="root"></div>
<div id="root">
<div class="LoadingMessage">
<span>Loading scene...</span>
</div>
</div>
<aside>
<!-- https://github.com/tholman/github-corners -->
<svg

@ -5,6 +5,7 @@ export const DEFAULT_FONT = "20px Virgil";
export function getDefaultAppState(): AppState {
return {
isLoading: false,
draggingElement: null,
resizingElement: null,
multiElement: null,
@ -47,6 +48,7 @@ export function clearAppStateForLocalStorage(appState: AppState) {
isResizing,
collaborators,
isCollaborating,
isLoading,
...exportedState
} = appState;
return exportedState;

@ -154,6 +154,12 @@ export class App extends React.Component<any, AppState> {
actionManager: ActionManager;
canvasOnlyActions = ["selectAll"];
public state: AppState = {
...getDefaultAppState(),
isLoading: true,
};
constructor(props: any) {
super(props);
this.actionManager = new ActionManager(
@ -226,15 +232,22 @@ export class App extends React.Component<any, AppState> {
file?.type === "application/json" ||
file?.name.endsWith(".excalidraw")
) {
this.setState({ isLoading: true });
loadFromBlob(file)
.then(({ elements, appState }) =>
this.syncActionResult({
elements,
appState,
appState: {
...(appState || this.state),
isLoading: false,
},
commitToHistory: false,
}),
)
.catch((error) => console.error(error));
.catch((error) => {
console.error(error);
this.setState({ isLoading: false });
});
}
}}
>
@ -270,15 +283,55 @@ export class App extends React.Component<any, AppState> {
// Lifecycle
private onUnload = withBatchedUpdates(() => {
private onBlur = withBatchedUpdates(() => {
isHoldingSpace = false;
this.saveDebounced();
this.saveDebounced.flush();
});
private onUnload = () => {
this.destroySocketClient();
this.onBlur();
};
private disableEvent: EventHandlerNonNull = (event) => {
event.preventDefault();
};
private initializeScene = async () => {
const searchParams = new URLSearchParams(window.location.search);
const id = searchParams.get("id");
const jsonMatch = window.location.hash.match(
/^#json=([0-9]+),([a-zA-Z0-9_-]+)$/,
);
const isCollaborationScene = getCollaborationLinkData(window.location.href);
if (!isCollaborationScene) {
let scene: ResolutionType<typeof loadScene> | undefined;
// Backwards compatibility with legacy url format
if (id) {
scene = await loadScene(id);
} else if (jsonMatch) {
scene = await loadScene(jsonMatch[1], jsonMatch[2]);
} else {
scene = await loadScene(null);
}
if (scene) {
this.syncActionResult(scene);
}
}
if (this.state.isLoading) {
this.setState({ isLoading: false });
}
// run this last else the `isLoading` state
if (isCollaborationScene) {
this.initializeSocketClient({ showLoadingState: true });
}
};
private unmounted = false;
public async componentDidMount() {
@ -320,7 +373,7 @@ export class App extends React.Component<any, AppState> {
document.addEventListener("mousemove", this.updateCurrentCursorPosition);
window.addEventListener("resize", this.onResize, false);
window.addEventListener("unload", this.onUnload, false);
window.addEventListener("blur", this.onUnload, false);
window.addEventListener("blur", this.onBlur, false);
window.addEventListener("dragover", this.disableEvent, false);
window.addEventListener("drop", this.disableEvent, false);
@ -338,32 +391,7 @@ export class App extends React.Component<any, AppState> {
document.addEventListener("gestureend", this.onGestureEnd as any, false);
window.addEventListener("beforeunload", this.beforeUnload);
const searchParams = new URLSearchParams(window.location.search);
const id = searchParams.get("id");
if (id) {
// Backwards compatibility with legacy url format
const scene = await loadScene(id);
this.syncActionResult(scene);
}
const jsonMatch = window.location.hash.match(
/^#json=([0-9]+),([a-zA-Z0-9_-]+)$/,
);
if (jsonMatch) {
const scene = await loadScene(jsonMatch[1], jsonMatch[2]);
this.syncActionResult(scene);
return;
}
const roomMatch = getCollaborationLinkData(window.location.href);
if (roomMatch) {
this.initializeSocketClient();
return;
}
const scene = await loadScene(null);
this.syncActionResult(scene);
this.initializeScene();
}
public componentWillUnmount() {
@ -383,7 +411,7 @@ export class App extends React.Component<any, AppState> {
document.removeEventListener("keyup", this.onKeyUp);
window.removeEventListener("resize", this.onResize, false);
window.removeEventListener("unload", this.onUnload, false);
window.removeEventListener("blur", this.onUnload, false);
window.removeEventListener("blur", this.onBlur, false);
window.removeEventListener("dragover", this.disableEvent, false);
window.removeEventListener("drop", this.disableEvent, false);
@ -420,7 +448,7 @@ export class App extends React.Component<any, AppState> {
componentDidUpdate() {
if (this.state.isCollaborating && !this.socket) {
this.initializeSocketClient();
this.initializeSocketClient({ showLoadingState: true });
}
const pointerViewportCoords: {
[id: string]: { x: number; y: number };
@ -625,7 +653,7 @@ export class App extends React.Component<any, AppState> {
"Excalidraw",
await generateCollaborationLink(),
);
this.initializeSocketClient();
this.initializeSocketClient({ showLoadingState: false });
};
destroyRoom = () => {
@ -655,15 +683,23 @@ export class App extends React.Component<any, AppState> {
}
};
private initializeSocketClient = () => {
private initializeSocketClient = (opts: { showLoadingState: boolean }) => {
if (this.socket) {
return;
}
const roomMatch = getCollaborationLinkData(window.location.href);
if (roomMatch) {
this.setState({
isCollaborating: true,
});
const initialize = () => {
this.socketInitialized = true;
clearTimeout(initializationTimer);
if (this.state.isLoading && !this.unmounted) {
this.setState({ isLoading: false });
}
};
// fallback in case you're not alone in the room but still don't receive
// initial SCENE_UPDATE message
const initializationTimer = setTimeout(initialize, 5000);
this.socket = socketIOClient(SOCKET_SERVER);
this.roomID = roomMatch[1];
this.roomKey = roomMatch[2];
@ -685,7 +721,7 @@ export class App extends React.Component<any, AppState> {
switch (decryptedData.type) {
case "INVALID_RESPONSE":
return;
case "SCENE_UPDATE":
case "SCENE_UPDATE": {
const { elements: remoteElements } = decryptedData.payload;
const restoredState = restore(remoteElements || [], null, {
scrollToContent: true,
@ -765,10 +801,11 @@ export class App extends React.Component<any, AppState> {
// right now we think this is the right tradeoff.
history.clear();
if (this.socketInitialized === false) {
this.socketInitialized = true;
initialize();
}
break;
case "MOUSE_LOCATION":
}
case "MOUSE_LOCATION": {
const { socketID, pointerCoords } = decryptedData.payload;
this.setState((state) => {
if (!state.collaborators.has(socketID)) {
@ -780,6 +817,7 @@ export class App extends React.Component<any, AppState> {
return state;
});
break;
}
}
},
);
@ -787,7 +825,7 @@ export class App extends React.Component<any, AppState> {
if (this.socket) {
this.socket.off("first-in-room");
}
this.socketInitialized = true;
initialize();
});
this.socket.on("room-user-change", (clients: string[]) => {
this.setState((state) => {
@ -808,6 +846,11 @@ export class App extends React.Component<any, AppState> {
this.socket.on("new-user", async (socketID: string) => {
this.broadcastSceneUpdate();
});
this.setState({
isCollaborating: true,
isLoading: opts.showLoadingState ? true : this.state.isLoading,
});
}
};
@ -867,8 +910,6 @@ export class App extends React.Component<any, AppState> {
this.setState({});
};
public state: AppState = getDefaultAppState();
private updateCurrentCursorPosition = withBatchedUpdates(
(event: MouseEvent) => {
cursorX = event.x;

@ -22,6 +22,7 @@ import { MobileMenu } from "./MobileMenu";
import { ZoomActions, SelectedShapeActions, ShapesSwitcher } from "./Actions";
import { Section } from "./Section";
import { RoomDialog } from "./RoomDialog";
import { LoadingMessage } from "./LoadingMessage";
interface LayerUIProps {
actionManager: ActionManager;
@ -105,6 +106,7 @@ export const LayerUI = React.memo(
/>
) : (
<>
{appState.isLoading && <LoadingMessage />}
<FixedSideContainer side="top">
<HintViewer appState={appState} elements={elements} />
<div className="App-menu App-menu_top">

@ -0,0 +1,10 @@
import React from "react";
export const LoadingMessage = () => {
// !! KEEP THIS IN SYNC WITH index.html !!
return (
<div className="LoadingMessage">
<span>Loading scene...</span>
</div>
);
};

@ -15,6 +15,7 @@ import { Section } from "./Section";
import { RoomDialog } from "./RoomDialog";
import { SCROLLBAR_WIDTH, SCROLLBAR_MARGIN } from "../scene/scrollbars";
import { LockIcon } from "./LockIcon";
import { LoadingMessage } from "./LoadingMessage";
type MobileMenuProps = {
appState: AppState;
@ -41,6 +42,7 @@ export function MobileMenu({
}: MobileMenuProps) {
return (
<>
{appState.isLoading && <LoadingMessage />}
<FixedSideContainer side="top">
<Section heading="shapes">
{(heading) => (

6
src/global.d.ts vendored

@ -9,3 +9,9 @@ interface Clipboard extends EventTarget {
type Mutable<T> = {
-readonly [P in keyof T]: T[P];
};
type ResolutionType<T extends (...args: any) => any> = T extends (
...args: any
) => Promise<infer R>
? R
: any;

@ -18,6 +18,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -176,7 +177,7 @@ Object {
exports[`regression tests alt-drag duplicates an element: [end of test] number of elements 1`] = `2`;
exports[`regression tests alt-drag duplicates an element: [end of test] number of renders 1`] = `8`;
exports[`regression tests alt-drag duplicates an element: [end of test] number of renders 1`] = `9`;
exports[`regression tests arrow keys: [end of test] appState 1`] = `
Object {
@ -196,6 +197,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -280,7 +282,7 @@ Object {
exports[`regression tests arrow keys: [end of test] number of elements 1`] = `1`;
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 change the properties of a shape: [end of test] appState 1`] = `
Object {
@ -300,6 +302,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -520,7 +523,7 @@ Object {
exports[`regression tests change the properties of a shape: [end of test] number of elements 1`] = `1`;
exports[`regression tests change the properties of a shape: [end of test] number of renders 1`] = `9`;
exports[`regression tests change the properties of a shape: [end of test] number of renders 1`] = `10`;
exports[`regression tests click on an element and drag it: [dragged] appState 1`] = `
Object {
@ -540,6 +543,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -659,7 +663,7 @@ Object {
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`] = `8`;
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: [end of test] appState 1`] = `
Object {
@ -679,6 +683,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -833,7 +838,7 @@ Object {
exports[`regression tests click on an element and drag it: [end of test] number of elements 1`] = `1`;
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`] = `12`;
exports[`regression tests click to select a shape: [end of test] appState 1`] = `
Object {
@ -853,6 +858,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -1011,7 +1017,7 @@ Object {
exports[`regression tests click to select a shape: [end of test] number of elements 1`] = `2`;
exports[`regression tests click to select a shape: [end of test] number of renders 1`] = `11`;
exports[`regression tests click to select a shape: [end of test] number of renders 1`] = `12`;
exports[`regression tests click-drag to select a group: [end of test] appState 1`] = `
Object {
@ -1031,6 +1037,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -1281,7 +1288,7 @@ Object {
exports[`regression tests click-drag to select a group: [end of test] number of elements 1`] = `3`;
exports[`regression tests click-drag to select a group: [end of test] number of renders 1`] = `16`;
exports[`regression tests click-drag to select a group: [end of test] number of renders 1`] = `17`;
exports[`regression tests draw every type of shape: [end of test] appState 1`] = `
Object {
@ -1301,6 +1308,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -1853,7 +1861,7 @@ Object {
exports[`regression tests draw every type of shape: [end of test] number of elements 1`] = `5`;
exports[`regression tests draw every type of shape: [end of test] number of renders 1`] = `33`;
exports[`regression tests draw every type of shape: [end of test] number of renders 1`] = `34`;
exports[`regression tests hotkey 2 selects rectangle tool: [end of test] appState 1`] = `
Object {
@ -1873,6 +1881,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -1957,7 +1966,7 @@ Object {
exports[`regression tests hotkey 2 selects rectangle tool: [end of test] number of elements 1`] = `1`;
exports[`regression tests hotkey 2 selects rectangle tool: [end of test] number of renders 1`] = `5`;
exports[`regression tests hotkey 2 selects rectangle tool: [end of test] number of renders 1`] = `6`;
exports[`regression tests hotkey 3 selects diamond tool: [end of test] appState 1`] = `
Object {
@ -1977,6 +1986,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -2061,7 +2071,7 @@ Object {
exports[`regression tests hotkey 3 selects diamond tool: [end of test] number of elements 1`] = `1`;
exports[`regression tests hotkey 3 selects diamond tool: [end of test] number of renders 1`] = `5`;
exports[`regression tests hotkey 3 selects diamond tool: [end of test] number of renders 1`] = `6`;
exports[`regression tests hotkey 4 selects ellipse tool: [end of test] appState 1`] = `
Object {
@ -2081,6 +2091,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -2165,7 +2176,7 @@ Object {
exports[`regression tests hotkey 4 selects ellipse tool: [end of test] number of elements 1`] = `1`;
exports[`regression tests hotkey 4 selects ellipse tool: [end of test] number of renders 1`] = `5`;
exports[`regression tests hotkey 4 selects ellipse tool: [end of test] number of renders 1`] = `6`;
exports[`regression tests hotkey 5 selects arrow tool: [end of test] appState 1`] = `
Object {
@ -2185,6 +2196,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -2291,7 +2303,7 @@ Object {
exports[`regression tests hotkey 5 selects arrow tool: [end of test] number of elements 1`] = `1`;
exports[`regression tests hotkey 5 selects arrow tool: [end of test] number of renders 1`] = `5`;
exports[`regression tests hotkey 5 selects arrow tool: [end of test] number of renders 1`] = `6`;
exports[`regression tests hotkey 6 selects line tool: [end of test] appState 1`] = `
Object {
@ -2311,6 +2323,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -2417,7 +2430,7 @@ Object {
exports[`regression tests hotkey 6 selects line tool: [end of test] number of elements 1`] = `1`;
exports[`regression tests hotkey 6 selects line tool: [end of test] number of renders 1`] = `5`;
exports[`regression tests hotkey 6 selects line tool: [end of test] number of renders 1`] = `6`;
exports[`regression tests hotkey a selects arrow tool: [end of test] appState 1`] = `
Object {
@ -2437,6 +2450,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -2543,7 +2557,7 @@ Object {
exports[`regression tests hotkey a selects arrow tool: [end of test] number of elements 1`] = `1`;
exports[`regression tests hotkey a selects arrow tool: [end of test] number of renders 1`] = `5`;
exports[`regression tests hotkey a selects arrow tool: [end of test] number of renders 1`] = `6`;
exports[`regression tests hotkey d selects diamond tool: [end of test] appState 1`] = `
Object {
@ -2563,6 +2577,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -2647,7 +2662,7 @@ Object {
exports[`regression tests hotkey d selects diamond tool: [end of test] number of elements 1`] = `1`;
exports[`regression tests hotkey d selects diamond tool: [end of test] number of renders 1`] = `5`;
exports[`regression tests hotkey d selects diamond tool: [end of test] number of renders 1`] = `6`;
exports[`regression tests hotkey e selects ellipse tool: [end of test] appState 1`] = `
Object {
@ -2667,6 +2682,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -2751,7 +2767,7 @@ Object {
exports[`regression tests hotkey e selects ellipse tool: [end of test] number of elements 1`] = `1`;
exports[`regression tests hotkey e selects ellipse tool: [end of test] number of renders 1`] = `5`;
exports[`regression tests hotkey e selects ellipse tool: [end of test] number of renders 1`] = `6`;
exports[`regression tests hotkey l selects line tool: [end of test] appState 1`] = `
Object {
@ -2771,6 +2787,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -2877,7 +2894,7 @@ Object {
exports[`regression tests hotkey l selects line tool: [end of test] number of elements 1`] = `1`;
exports[`regression tests hotkey l selects line tool: [end of test] number of renders 1`] = `5`;
exports[`regression tests hotkey l selects line tool: [end of test] number of renders 1`] = `6`;
exports[`regression tests hotkey r selects rectangle tool: [end of test] appState 1`] = `
Object {
@ -2897,6 +2914,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -2981,7 +2999,7 @@ Object {
exports[`regression tests hotkey r selects rectangle tool: [end of test] number of elements 1`] = `1`;
exports[`regression tests hotkey r selects rectangle tool: [end of test] number of renders 1`] = `5`;
exports[`regression tests hotkey r selects rectangle tool: [end of test] number of renders 1`] = `6`;
exports[`regression tests pinch-to-zoom works: [end of test] appState 1`] = `
Object {
@ -3001,6 +3019,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "touch",
"multiElement": null,
@ -3029,7 +3048,7 @@ Object {
exports[`regression tests pinch-to-zoom works: [end of test] number of elements 1`] = `0`;
exports[`regression tests pinch-to-zoom works: [end of test] number of renders 1`] = `7`;
exports[`regression tests pinch-to-zoom works: [end of test] number of renders 1`] = `8`;
exports[`regression tests resize an element, trying every resize handle: [end of test] appState 1`] = `
Object {
@ -3049,6 +3068,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -3693,7 +3713,7 @@ Object {
exports[`regression tests resize an element, trying every resize handle: [end of test] number of elements 1`] = `1`;
exports[`regression tests resize an element, trying every resize handle: [end of test] number of renders 1`] = `53`;
exports[`regression tests resize an element, trying every resize handle: [end of test] number of renders 1`] = `54`;
exports[`regression tests resize an element, trying every resize handle: [resize handle ne (+5, +5)] appState 1`] = `
Object {
@ -3713,6 +3733,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -4042,7 +4063,7 @@ Object {
exports[`regression tests resize an element, trying every resize handle: [resize handle ne (+5, +5)] number of elements 1`] = `1`;
exports[`regression tests resize an element, trying every resize handle: [resize handle ne (+5, +5)] number of renders 1`] = `26`;
exports[`regression tests resize an element, trying every resize handle: [resize handle ne (+5, +5)] number of renders 1`] = `27`;
exports[`regression tests resize an element, trying every resize handle: [resize handle ne (-5, -5)] appState 1`] = `
Object {
@ -4062,6 +4083,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -4321,7 +4343,7 @@ Object {
exports[`regression tests resize an element, trying every resize handle: [resize handle ne (-5, -5)] number of elements 1`] = `1`;
exports[`regression tests resize an element, trying every resize handle: [resize handle ne (-5, -5)] number of renders 1`] = `20`;
exports[`regression tests resize an element, trying every resize handle: [resize handle ne (-5, -5)] number of renders 1`] = `21`;
exports[`regression tests resize an element, trying every resize handle: [resize handle nw (+5, +5)] appState 1`] = `
Object {
@ -4341,6 +4363,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -4530,7 +4553,7 @@ Object {
exports[`regression tests resize an element, trying every resize handle: [resize handle nw (+5, +5)] number of elements 1`] = `1`;
exports[`regression tests resize an element, trying every resize handle: [resize handle nw (+5, +5)] number of renders 1`] = `14`;
exports[`regression tests resize an element, trying every resize handle: [resize handle nw (+5, +5)] number of renders 1`] = `15`;
exports[`regression tests resize an element, trying every resize handle: [resize handle nw (-5, -5)] appState 1`] = `
Object {
@ -4550,6 +4573,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -4669,7 +4693,7 @@ Object {
exports[`regression tests resize an element, trying every resize handle: [resize handle nw (-5, -5)] number of elements 1`] = `1`;
exports[`regression tests resize an element, trying every resize handle: [resize handle nw (-5, -5)] number of renders 1`] = `8`;
exports[`regression tests resize an element, trying every resize handle: [resize handle nw (-5, -5)] number of renders 1`] = `9`;
exports[`regression tests resize an element, trying every resize handle: [resize handle se (+5, +5)] appState 1`] = `
Object {
@ -4689,6 +4713,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -5298,7 +5323,7 @@ Object {
exports[`regression tests resize an element, trying every resize handle: [resize handle se (+5, +5)] number of elements 1`] = `1`;
exports[`regression tests resize an element, trying every resize handle: [resize handle se (+5, +5)] number of renders 1`] = `50`;
exports[`regression tests resize an element, trying every resize handle: [resize handle se (+5, +5)] number of renders 1`] = `51`;
exports[`regression tests resize an element, trying every resize handle: [resize handle se (-5, -5)] appState 1`] = `
Object {
@ -5318,6 +5343,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -5857,7 +5883,7 @@ Object {
exports[`regression tests resize an element, trying every resize handle: [resize handle se (-5, -5)] number of elements 1`] = `1`;
exports[`regression tests resize an element, trying every resize handle: [resize handle se (-5, -5)] number of renders 1`] = `44`;
exports[`regression tests resize an element, trying every resize handle: [resize handle se (-5, -5)] number of renders 1`] = `45`;
exports[`regression tests resize an element, trying every resize handle: [resize handle sw (+5, +5)] appState 1`] = `
Object {
@ -5877,6 +5903,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -6346,7 +6373,7 @@ Object {
exports[`regression tests resize an element, trying every resize handle: [resize handle sw (+5, +5)] number of elements 1`] = `1`;
exports[`regression tests resize an element, trying every resize handle: [resize handle sw (+5, +5)] number of renders 1`] = `38`;
exports[`regression tests resize an element, trying every resize handle: [resize handle sw (+5, +5)] number of renders 1`] = `39`;
exports[`regression tests resize an element, trying every resize handle: [resize handle sw (-5, -5)] appState 1`] = `
Object {
@ -6366,6 +6393,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -6765,7 +6793,7 @@ Object {
exports[`regression tests resize an element, trying every resize handle: [resize handle sw (-5, -5)] number of elements 1`] = `1`;
exports[`regression tests resize an element, trying every resize handle: [resize handle sw (-5, -5)] number of renders 1`] = `32`;
exports[`regression tests resize an element, trying every resize handle: [resize handle sw (-5, -5)] number of renders 1`] = `33`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle ne (+5, +5)] appState 1`] = `
Object {
@ -6785,6 +6813,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -7149,7 +7178,7 @@ Object {
exports[`regression tests resize an element, trying every resize handle: [unresize handle ne (+5, +5)] number of elements 1`] = `1`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle ne (+5, +5)] number of renders 1`] = `29`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle ne (+5, +5)] number of renders 1`] = `30`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle ne (-5, -5)] appState 1`] = `
Object {
@ -7169,6 +7198,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -7463,7 +7493,7 @@ Object {
exports[`regression tests resize an element, trying every resize handle: [unresize handle ne (-5, -5)] number of elements 1`] = `1`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle ne (-5, -5)] number of renders 1`] = `23`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle ne (-5, -5)] number of renders 1`] = `24`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle nw (+5, +5)] appState 1`] = `
Object {
@ -7483,6 +7513,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -7707,7 +7738,7 @@ Object {
exports[`regression tests resize an element, trying every resize handle: [unresize handle nw (+5, +5)] number of elements 1`] = `1`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle nw (+5, +5)] number of renders 1`] = `17`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle nw (+5, +5)] number of renders 1`] = `18`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle nw (-5, -5)] appState 1`] = `
Object {
@ -7727,6 +7758,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -7881,7 +7913,7 @@ Object {
exports[`regression tests resize an element, trying every resize handle: [unresize handle nw (-5, -5)] number of elements 1`] = `1`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle nw (-5, -5)] number of renders 1`] = `11`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle nw (-5, -5)] number of renders 1`] = `12`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle se (+5, +5)] appState 1`] = `
Object {
@ -7901,6 +7933,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -8545,7 +8578,7 @@ Object {
exports[`regression tests resize an element, trying every resize handle: [unresize handle se (+5, +5)] number of elements 1`] = `1`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle se (+5, +5)] number of renders 1`] = `53`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle se (+5, +5)] number of renders 1`] = `54`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle se (-5, -5)] appState 1`] = `
Object {
@ -8565,6 +8598,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -9139,7 +9173,7 @@ Object {
exports[`regression tests resize an element, trying every resize handle: [unresize handle se (-5, -5)] number of elements 1`] = `1`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle se (-5, -5)] number of renders 1`] = `47`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle se (-5, -5)] number of renders 1`] = `48`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle sw (+5, +5)] appState 1`] = `
Object {
@ -9159,6 +9193,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -9663,7 +9698,7 @@ Object {
exports[`regression tests resize an element, trying every resize handle: [unresize handle sw (+5, +5)] number of elements 1`] = `1`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle sw (+5, +5)] number of renders 1`] = `41`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle sw (+5, +5)] number of renders 1`] = `42`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle sw (-5, -5)] appState 1`] = `
Object {
@ -9683,6 +9718,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -10117,7 +10153,7 @@ Object {
exports[`regression tests resize an element, trying every resize handle: [unresize handle sw (-5, -5)] number of elements 1`] = `1`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle sw (-5, -5)] number of renders 1`] = `35`;
exports[`regression tests resize an element, trying every resize handle: [unresize handle sw (-5, -5)] number of renders 1`] = `36`;
exports[`regression tests shift-click to select a group, then drag: [end of test] appState 1`] = `
Object {
@ -10137,6 +10173,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -10350,7 +10387,7 @@ Object {
exports[`regression tests shift-click to select a group, then drag: [end of test] number of elements 1`] = `2`;
exports[`regression tests shift-click to select a group, then drag: [end of test] number of renders 1`] = `16`;
exports[`regression tests shift-click to select a group, then drag: [end of test] number of renders 1`] = `17`;
exports[`regression tests spacebar + drag scrolls the canvas: [end of test] appState 1`] = `
Object {
@ -10370,6 +10407,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -10396,7 +10434,7 @@ Object {
exports[`regression tests spacebar + drag scrolls the canvas: [end of test] number of elements 1`] = `0`;
exports[`regression tests spacebar + drag scrolls the canvas: [end of test] number of renders 1`] = `3`;
exports[`regression tests spacebar + drag scrolls the canvas: [end of test] number of renders 1`] = `4`;
exports[`regression tests two-finger scroll works: [end of test] appState 1`] = `
Object {
@ -10416,6 +10454,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -10444,7 +10483,7 @@ Object {
exports[`regression tests two-finger scroll works: [end of test] number of elements 1`] = `0`;
exports[`regression tests two-finger scroll works: [end of test] number of renders 1`] = `9`;
exports[`regression tests two-finger scroll works: [end of test] number of renders 1`] = `10`;
exports[`regression tests undo/redo drawing an element: [end of test] appState 1`] = `
Object {
@ -10464,6 +10503,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -10713,7 +10753,7 @@ Object {
exports[`regression tests undo/redo drawing an element: [end of test] number of elements 1`] = `3`;
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`] = `17`;
exports[`regression tests zoom hotkeys: [end of test] appState 1`] = `
Object {
@ -10733,6 +10773,7 @@ Object {
"elementType": "selection",
"exportBackground": true,
"isCollaborating": false,
"isLoading": false,
"isResizing": false,
"lastPointerDownWith": "mouse",
"multiElement": null,
@ -10759,4 +10800,4 @@ Object {
exports[`regression tests zoom hotkeys: [end of test] number of elements 1`] = `0`;
exports[`regression tests zoom hotkeys: [end of test] number of renders 1`] = `3`;
exports[`regression tests zoom hotkeys: [end of test] number of renders 1`] = `4`;

@ -10,6 +10,7 @@ export type FlooredNumber = number & { _brand: "FlooredNumber" };
export type Point = Readonly<RoughPoint>;
export type AppState = {
isLoading: boolean;
draggingElement: ExcalidrawElement | null;
resizingElement: ExcalidrawElement | null;
multiElement: ExcalidrawLinearElement | null;