From 6c2f3afa4e77c099cc5b3c76cc7426e0f15cda63 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Tue, 22 Apr 2025 08:19:43 +1000 Subject: [PATCH] add shape switch to command palette --- .../actions/actionToggleShapeSwitch.tsx | 40 +++++++++++++++++++ packages/excalidraw/actions/types.ts | 6 ++- .../CommandPalette/CommandPalette.tsx | 10 +++++ packages/excalidraw/locales/en.json | 3 +- 4 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 packages/excalidraw/actions/actionToggleShapeSwitch.tsx diff --git a/packages/excalidraw/actions/actionToggleShapeSwitch.tsx b/packages/excalidraw/actions/actionToggleShapeSwitch.tsx new file mode 100644 index 000000000..90cae988a --- /dev/null +++ b/packages/excalidraw/actions/actionToggleShapeSwitch.tsx @@ -0,0 +1,40 @@ +import { getSwitchableTypeFromElements } from "@excalidraw/element/typeChecks"; + +import type { ExcalidrawElement } from "@excalidraw/element/types"; + +import { shapeSwitchAtom } from "../components/ShapeSwitch"; +import { editorJotaiStore } from "../editor-jotai"; +import { CaptureUpdateAction } from "../store"; + +import { register } from "./register"; + +export const actionToggleShapeSwitch = register({ + name: "toggleShapeSwitch", + label: "labels.shapeSwitch", + icon: () => null, + viewMode: true, + trackEvent: { + category: "shape_switch", + action: "toggle", + }, + keywords: ["change", "switch", "swap"], + perform(elements, appState, _, app) { + editorJotaiStore.set(shapeSwitchAtom, { + type: "panel", + }); + + return { + appState, + commitToHistory: false, + captureUpdate: CaptureUpdateAction.NEVER, + }; + }, + checked: (appState) => appState.gridModeEnabled, + predicate: (elements, appState, props) => { + const { generic, linear } = getSwitchableTypeFromElements( + elements as ExcalidrawElement[], + ); + + return generic || linear; + }, +}); diff --git a/packages/excalidraw/actions/types.ts b/packages/excalidraw/actions/types.ts index 152b9a0c7..2dec65dca 100644 --- a/packages/excalidraw/actions/types.ts +++ b/packages/excalidraw/actions/types.ts @@ -139,7 +139,8 @@ export type ActionName = | "copyElementLink" | "linkToElement" | "cropEditor" - | "wrapSelectionInFrame"; + | "wrapSelectionInFrame" + | "toggleShapeSwitch"; export type PanelComponentProps = { elements: readonly ExcalidrawElement[]; @@ -194,7 +195,8 @@ export interface Action { | "menu" | "collab" | "hyperlink" - | "search_menu"; + | "search_menu" + | "shape_switch"; action?: string; predicate?: ( appState: Readonly, diff --git a/packages/excalidraw/components/CommandPalette/CommandPalette.tsx b/packages/excalidraw/components/CommandPalette/CommandPalette.tsx index 4391759d9..5508aa235 100644 --- a/packages/excalidraw/components/CommandPalette/CommandPalette.tsx +++ b/packages/excalidraw/components/CommandPalette/CommandPalette.tsx @@ -11,6 +11,8 @@ import { isWritableElement, } from "@excalidraw/common"; +import { actionToggleShapeSwitch } from "@excalidraw/excalidraw/actions/actionToggleShapeSwitch"; + import type { MarkRequired } from "@excalidraw/common/utility-types"; import { @@ -409,6 +411,14 @@ function CommandPaletteInner({ actionManager.executeAction(actionToggleSearchMenu); }, }, + { + label: t("labels.shapeSwitch"), + category: DEFAULT_CATEGORIES.elements, + icon: boltIcon, + perform: () => { + actionManager.executeAction(actionToggleShapeSwitch); + }, + }, { label: t("labels.changeStroke"), keywords: ["color", "outline"], diff --git a/packages/excalidraw/locales/en.json b/packages/excalidraw/locales/en.json index c465b525a..92ab19b05 100644 --- a/packages/excalidraw/locales/en.json +++ b/packages/excalidraw/locales/en.json @@ -166,7 +166,8 @@ "copyElementLink": "Copy link to object", "linkToElement": "Link to object", "wrapSelectionInFrame": "Wrap selection in frame", - "tab": "Tab" + "tab": "Tab", + "shapeSwitch": "Switch shape" }, "elementLink": { "title": "Link to object",