From e9fa0cd53010967c1b3b3dffaa0434a96d64e6d9 Mon Sep 17 00:00:00 2001 From: Ivan Starkov Date: Sun, 5 Jan 2025 14:39:23 +0300 Subject: [PATCH] fix: Deleting in the code editor causes the instance on the canvas to be removed. (#4717) ## Description Removed logic based on preventDefault ## Steps for reproduction 1. click button 2. expect xyz ## Code Review - [ ] hi @kof, I need you to do - conceptual review (architecture, feature-correctness) - detailed review (read every line) - test it on preview ## Before requesting a review - [ ] made a self-review - [ ] added inline comments where things may be not obvious (the "why", not "what") ## Before merging - [ ] tested locally and on preview environment (preview dev login: 0000) - [ ] updated [test cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md) document - [ ] added tests - [ ] if any new env variables are added, added them to `.env` file --- .../app/builder/features/topbar/menu/menu.tsx | 4 ++- apps/builder/app/builder/shared/commands.ts | 9 ++---- apps/builder/app/canvas/shared/commands.ts | 10 ++++++ apps/builder/app/shared/commands-emitter.ts | 32 ++++++++----------- 4 files changed, 30 insertions(+), 25 deletions(-) diff --git a/apps/builder/app/builder/features/topbar/menu/menu.tsx b/apps/builder/app/builder/features/topbar/menu/menu.tsx index fc4e36df47..e7fa1756ea 100644 --- a/apps/builder/app/builder/features/topbar/menu/menu.tsx +++ b/apps/builder/app/builder/features/topbar/menu/menu.tsx @@ -140,7 +140,9 @@ export const Menu = () => { */} - emitCommand("deleteInstance")}> + emitCommand("deleteInstanceBuilder")} + > Delete diff --git a/apps/builder/app/builder/shared/commands.ts b/apps/builder/app/builder/shared/commands.ts index 6c2a0c4147..4a56d26e89 100644 --- a/apps/builder/app/builder/shared/commands.ts +++ b/apps/builder/app/builder/shared/commands.ts @@ -59,7 +59,6 @@ const makeBreakpointCommand = ( export const deleteSelectedInstance = () => { if ($isPreviewMode.get()) { - builderApi.toast.info("Deleting is not allowed in preview mode."); return; } const textEditingInstanceSelector = $textEditingInstanceSelector.get(); @@ -375,13 +374,11 @@ export const { emitCommand, subscribeCommands } = createCommandsEmitter({ }, */ - // instances - { - name: "deleteInstance", + name: "deleteInstanceBuilder", defaultHotkeys: ["backspace", "delete"], - // this disables hotkey for inputs on style panel - // but still work for input on canvas which call event.preventDefault() in keydown handler + // See "deleteInstanceCanvas" for details on why the command is separated for the canvas and builder. + disableHotkeyOutsideApp: true, disableOnInputLikeControls: true, handler: deleteSelectedInstance, }, diff --git a/apps/builder/app/canvas/shared/commands.ts b/apps/builder/app/canvas/shared/commands.ts index 840fe6ffff..214c028636 100644 --- a/apps/builder/app/canvas/shared/commands.ts +++ b/apps/builder/app/canvas/shared/commands.ts @@ -21,11 +21,21 @@ import { } from "../features/text-editor/toolbar-connector"; import { selectInstance } from "~/shared/awareness"; import { isDescendantOrSelf, type InstanceSelector } from "~/shared/tree-utils"; +import { deleteSelectedInstance } from "~/builder/shared/commands"; export const { emitCommand, subscribeCommands } = createCommandsEmitter({ source: "canvas", externalCommands: ["clickCanvas"], commands: [ + { + name: "deleteInstanceCanvas", + defaultHotkeys: ["backspace", "delete"], + disableHotkeyOutsideApp: true, + // We are not disabling "Backspace" or "Delete" on the canvas. This is the main reason we have separate functions: deleteInstanceCanvas and deleteInstanceBuilder. + disableOnInputLikeControls: false, + handler: deleteSelectedInstance, + }, + { name: "editInstanceText", hidden: true, diff --git a/apps/builder/app/shared/commands-emitter.ts b/apps/builder/app/shared/commands-emitter.ts index 7396b3f23e..991394df52 100644 --- a/apps/builder/app/shared/commands-emitter.ts +++ b/apps/builder/app/shared/commands-emitter.ts @@ -148,26 +148,22 @@ export const createCommandsEmitter = ({ ) { continue; } - const element = event.target as HTMLElement; - const isOnInputLikeControl = - ["input", "select", "textarea"].includes( - element.tagName.toLowerCase() - ) || - element.isContentEditable || - // Detect Radix select, dropdown and co. - element.getAttribute("role") === "option"; + const { disableOnInputLikeControls } = commandMeta; - // in some cases hotkey override default behavior - // on form tags and contentEditable - // though still proceed when default behavior is prevented - // this hack makes hotkeys work on canvas instances of input etc. - if ( - isOnInputLikeControl && - disableOnInputLikeControls && - event.defaultPrevented === false - ) { - continue; + if (disableOnInputLikeControls) { + const element = event.target as HTMLElement; + const isOnInputLikeControl = + ["input", "select", "textarea"].includes( + element.tagName.toLowerCase() + ) || + element.isContentEditable || + // Detect Radix select, dropdown and co. + element.getAttribute("role") === "option"; + + if (isOnInputLikeControl) { + continue; + } } emitted = true;