From b89fa184899155bf8db495d5835312ca1d3495d5 Mon Sep 17 00:00:00 2001 From: dwelle Date: Thu, 18 May 2023 11:46:39 +0200 Subject: [PATCH] support tool locking --- src/components/App.tsx | 11 +++-- src/excalidraw-app/index.tsx | 95 ++++++++++++++++++++++++++++++++++-- src/utils.ts | 27 +++++++++- 3 files changed, 124 insertions(+), 9 deletions(-) diff --git a/src/components/App.tsx b/src/components/App.tsx index b2baeba87abf..630df2465659 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -2887,8 +2887,11 @@ class App extends React.Component { private setActiveTool = ( tool: - | { type: typeof SHAPES[number]["value"] | "eraser" | "hand" | "frame" } - | { type: "custom"; customType: string }, + | { + type: typeof SHAPES[number]["value"] | "eraser" | "hand" | "frame"; + locked?: boolean; + } + | { type: "custom"; customType: string; locked?: boolean }, ) => { const nextActiveTool = updateActiveTool(this.state, tool); if (nextActiveTool.type === "hand") { @@ -4265,7 +4268,9 @@ class App extends React.Component { pointerDownState, ); } else if (this.state.activeTool.type === "custom") { - setCursor(this.canvas, CURSOR_TYPE.AUTO); + if (this.state.activeTool.customType === "comment") { + setCursorForShape(this.canvas, this.state); + } } else if (this.state.activeTool.type === "frame") { this.createFrameElementOnPointerDown(pointerDownState); } else if ( diff --git a/src/excalidraw-app/index.tsx b/src/excalidraw-app/index.tsx index 8f8ba3dcc94e..d39070ff47b3 100644 --- a/src/excalidraw-app/index.tsx +++ b/src/excalidraw-app/index.tsx @@ -1,6 +1,6 @@ import polyfill from "../polyfill"; import LanguageDetector from "i18next-browser-languagedetector"; -import { useEffect, useRef, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; import { trackEvent } from "../analytics"; import { getDefaultAppState } from "../appState"; import { ErrorDialog } from "../components/ErrorDialog"; @@ -21,7 +21,13 @@ import { } from "../element/types"; import { useCallbackRefState } from "../hooks/useCallbackRefState"; import { t } from "../i18n"; -import { Excalidraw, defaultLang } from "../packages/excalidraw/index"; +import { + Excalidraw, + defaultLang, + Footer, + Button, + Sidebar, +} from "../packages/excalidraw/index"; import { AppState, LibraryItems, @@ -80,7 +86,6 @@ import { reconcileElements } from "./collab/reconciliation"; import { parseLibraryTokensFromUrl, useHandleLibrary } from "../data/library"; import { AppMainMenu } from "./components/AppMainMenu"; import { AppWelcomeScreen } from "./components/AppWelcomeScreen"; -import { AppFooter } from "./components/AppFooter"; import { atom, Provider, useAtom, useAtomValue } from "jotai"; import { useAtomWithInitialValue } from "../jotai"; import { appJotaiStore } from "./app-jotai"; @@ -637,6 +642,70 @@ const ExcalidrawWrapper = () => { const isOffline = useAtomValue(isOfflineAtom); + const [activeToolType, setActiveToolType] = useState(null); + const prevActiveTool = useRef<{ + type: string; + locked?: boolean; + prevLockState?: boolean; + }>(); + + const toggleCommentTool = useCallback(() => { + const nextType = + excalidrawAPI?.getAppState().activeTool?.customType === "comment" + ? "selection" + : "comment"; + excalidrawAPI?.setActiveTool( + nextType === "comment" + ? { + type: "custom", + customType: "comment", + locked: true, + } + : { type: "selection" }, + ); + }, [excalidrawAPI]); + + useEffect(() => { + if (excalidrawAPI) { + const unsubOnChange = excalidrawAPI.onChange((_, appState) => { + const type = appState.activeTool.customType || appState.activeTool.type; + if ( + prevActiveTool.current?.type === "comment" && + type !== "comment" && + !prevActiveTool.current?.prevLockState + ) { + excalidrawAPI.setActiveTool({ + ...appState.activeTool, + locked: false, + }); + } + setActiveToolType(type); + prevActiveTool.current = { + type, + locked: appState.activeTool.locked, + prevLockState: + prevActiveTool.current?.type !== "comment" + ? prevActiveTool.current?.locked + : prevActiveTool.current?.prevLockState, + }; + }); + + // on C keypress + const onKeyDown = (event: KeyboardEvent) => { + if (event.code === "KeyC") { + toggleCommentTool(); + } + }; + + window.addEventListener("keydown", onKeyDown); + + return () => { + window.removeEventListener("keydown", onKeyDown); + unsubOnChange(); + }; + } + }, [excalidrawAPI, toggleCommentTool]); + return (
{ )} - + test +
+
+ sidebar + +
+
{isCollaborating && isOffline && (
{t("alerts.collabOfflineWarning")} diff --git a/src/utils.ts b/src/utils.ts index c644efd81e14..0a9c5f4ed279 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -369,8 +369,11 @@ export const distance = (x: number, y: number) => Math.abs(x - y); export const updateActiveTool = ( appState: Pick, data: ( - | { type: typeof SHAPES[number]["value"] | "eraser" | "hand" | "frame" } - | { type: "custom"; customType: string } + | { + type: typeof SHAPES[number]["value"] | "eraser" | "hand" | "frame"; + locked?: boolean; + } + | { type: "custom"; customType: string; locked?: boolean } ) & { lastActiveToolBeforeEraser?: LastActiveTool }, ): AppState["activeTool"] => { if (data.type === "custom") { @@ -378,6 +381,7 @@ export const updateActiveTool = ( ...appState.activeTool, type: "custom", customType: data.customType, + locked: data.locked ?? appState.activeTool.locked, }; } @@ -389,6 +393,7 @@ export const updateActiveTool = ( : data.lastActiveToolBeforeEraser, type: data.type, customType: null, + locked: data.locked ?? appState.activeTool.locked, }; }; @@ -464,6 +469,24 @@ export const setCursorForShape = ( // Ignore custom type as well and let host decide } else if (!["image", "custom"].includes(appState.activeTool.type)) { canvas.style.cursor = CURSOR_TYPE.CROSSHAIR; + } else if ( + appState.activeTool.type === "custom" && + appState.activeTool.customType === "comment" + ) { + const cursorIconUrl = `data:${MIME_TYPES.svg},${encodeURIComponent(` + + + + `)}`; + canvas.style.cursor = `url(${cursorIconUrl}) 5 20, auto`; } };