From 3d617958cc194b0e994f65c04bd81427fabc7345 Mon Sep 17 00:00:00 2001 From: David Luzar Date: Tue, 19 Sep 2023 16:01:40 +0200 Subject: [PATCH] fix: improperly disabling UI pointer-events on canvas interaction (#7005) Co-authored-by: Aakansha Doshi --- src/components/App.tsx | 21 +++++++++++++++---- src/components/FixedSideContainer.scss | 2 +- src/components/LayerUI.scss | 10 ++++++--- src/components/LayerUI.tsx | 10 ++------- src/components/Sidebar/Sidebar.scss | 2 ++ src/components/Stats.scss | 2 +- src/components/UserList.scss | 2 +- src/components/footer/Footer.tsx | 2 +- src/components/footer/FooterCenter.scss | 3 ++- .../welcome-screen/WelcomeScreen.scss | 6 +++--- src/constants.ts | 8 +++++++ src/css/styles.scss | 14 ++++++------- .../components/AppWelcomeScreen.tsx | 3 ++- 13 files changed, 54 insertions(+), 31 deletions(-) diff --git a/src/components/App.tsx b/src/components/App.tsx index 373ff7b6..367c8f7f 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -85,6 +85,7 @@ import { VERTICAL_ALIGN, YOUTUBE_STATES, ZOOM_STEP, + POINTER_EVENTS, } from "../constants"; import { exportCanvas, loadFromBlob } from "../data"; import Library, { distributeLibraryItemsOnSquareGrid } from "../data/library"; @@ -857,7 +858,9 @@ class App extends React.Component { width: isVisible ? `${el.width}px` : 0, height: isVisible ? `${el.height}px` : 0, transform: isVisible ? `rotate(${el.angle}rad)` : "none", - pointerEvents: isActive ? "auto" : "none", + pointerEvents: isActive + ? POINTER_EVENTS.enabled + : POINTER_EVENTS.disabled, }} > {isHovered && ( @@ -1081,9 +1084,9 @@ class App extends React.Component { whiteSpace: "nowrap", textOverflow: "ellipsis", cursor: CURSOR_TYPE.MOVE, - // disable all interaction (e.g. cursor change) when in view - // mode - pointerEvents: this.state.viewModeEnabled ? "none" : "all", + pointerEvents: this.state.viewModeEnabled + ? POINTER_EVENTS.disabled + : POINTER_EVENTS.inheritFromUI, }} onPointerDown={(event) => this.handleCanvasPointerDown(event)} onWheel={(event) => this.handleWheel(event)} @@ -1125,6 +1128,16 @@ class App extends React.Component { "excalidraw--view-mode": this.state.viewModeEnabled, "excalidraw--mobile": this.device.isMobile, })} + style={{ + ["--ui-pointerEvents" as any]: + this.state.selectionElement || + this.state.draggingElement || + this.state.resizingElement || + (this.state.editingElement && + !isTextElement(this.state.editingElement)) + ? POINTER_EVENTS.disabled + : POINTER_EVENTS.enabled, + }} ref={this.excalidrawContainerRef} onDrop={this.handleAppOnDrop} tabIndex={0} diff --git a/src/components/FixedSideContainer.scss b/src/components/FixedSideContainer.scss index a485d6d2..62d77d50 100644 --- a/src/components/FixedSideContainer.scss +++ b/src/components/FixedSideContainer.scss @@ -7,7 +7,7 @@ } .FixedSideContainer > * { - pointer-events: all; + pointer-events: var(--ui-pointerEvents); } .FixedSideContainer_side_top { diff --git a/src/components/LayerUI.scss b/src/components/LayerUI.scss index 73e39229..8898b0f8 100644 --- a/src/components/LayerUI.scss +++ b/src/components/LayerUI.scss @@ -91,13 +91,17 @@ visibility: visible; transition: visibility 0s linear 300ms, opacity 0.5s; transition-delay: 0.8s; + + pointer-events: var(--ui-pointerEvents); } } .layer-ui__wrapper__footer-left, - .layer-ui__wrapper__footer-right, - .disable-zen-mode--visible { - pointer-events: all; + .footer-center, + .layer-ui__wrapper__footer-right { + & > * { + pointer-events: var(--ui-pointerEvents); + } } .layer-ui__wrapper__footer-right { diff --git a/src/components/LayerUI.tsx b/src/components/LayerUI.tsx index 26be77ae..02f360e2 100644 --- a/src/components/LayerUI.tsx +++ b/src/components/LayerUI.tsx @@ -2,7 +2,7 @@ import clsx from "clsx"; import React from "react"; import { ActionManager } from "../actions/manager"; import { CLASSES, DEFAULT_SIDEBAR, LIBRARY_SIDEBAR_WIDTH } from "../constants"; -import { isTextElement, showSelectedShapeActions } from "../element"; +import { showSelectedShapeActions } from "../element"; import { NonDeletedExcalidrawElement } from "../element/types"; import { Language, t } from "../i18n"; import { calculateScrollCenter } from "../scene"; @@ -427,13 +427,7 @@ const LayerUI = ({ {!device.isMobile && ( <>
* { - pointer-events: all; + pointer-events: var(--ui-pointerEvents); } .UserList_mobile { diff --git a/src/components/footer/Footer.tsx b/src/components/footer/Footer.tsx index 173ea451..85844aad 100644 --- a/src/components/footer/Footer.tsx +++ b/src/components/footer/Footer.tsx @@ -73,7 +73,7 @@ const Footer = ({
diff --git a/src/components/footer/FooterCenter.scss b/src/components/footer/FooterCenter.scss index 1e17db6c..ce656592 100644 --- a/src/components/footer/FooterCenter.scss +++ b/src/components/footer/FooterCenter.scss @@ -1,10 +1,11 @@ .footer-center { pointer-events: none; & > * { - pointer-events: all; + pointer-events: var(--ui-pointerEvents); } display: flex; width: 100%; justify-content: flex-start; + margin-inline-end: 0.6rem; } diff --git a/src/components/welcome-screen/WelcomeScreen.scss b/src/components/welcome-screen/WelcomeScreen.scss index a1b88d8b..8f1a09bf 100644 --- a/src/components/welcome-screen/WelcomeScreen.scss +++ b/src/components/welcome-screen/WelcomeScreen.scss @@ -161,7 +161,7 @@ .welcome-screen-menu-item { box-sizing: border-box; - pointer-events: all; + pointer-events: var(--ui-pointerEvents); color: var(--color-gray-50); font-size: 0.875rem; @@ -202,7 +202,7 @@ } } - &:not(:active) .welcome-screen-menu-item:hover { + .welcome-screen-menu-item:hover { text-decoration: none; background: var(--color-gray-10); @@ -246,7 +246,7 @@ } } - &:not(:active) .welcome-screen-menu-item:hover { + .welcome-screen-menu-item:hover { background: var(--color-gray-85); .welcome-screen-menu-item__shortcut { diff --git a/src/constants.ts b/src/constants.ts index 46ae25b4..90fc6675 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -41,6 +41,14 @@ export const POINTER_BUTTON = { TOUCH: -1, } as const; +export const POINTER_EVENTS = { + enabled: "all", + disabled: "none", + // asserted as any so it can be freely assigned to React Element + // "pointerEnvets" CSS prop + inheritFromUI: "var(--ui-pointerEvents)" as any, +} as const; + export enum EVENT { COPY = "copy", PASTE = "paste", diff --git a/src/css/styles.scss b/src/css/styles.scss index bb906332..4ca58af4 100644 --- a/src/css/styles.scss +++ b/src/css/styles.scss @@ -253,7 +253,7 @@ max-height: 100%; display: flex; flex-direction: column; - pointer-events: initial; + pointer-events: var(--ui-pointerEvents); .panelColumn { padding: 8px 8px 0 8px; @@ -301,7 +301,7 @@ pointer-events: none !important; & > * { - pointer-events: all; + pointer-events: var(--ui-pointerEvents); } } @@ -312,16 +312,16 @@ cursor: default; pointer-events: none !important; + & > * { + pointer-events: var(--ui-pointerEvents); + } + @media (min-width: 1536px) { grid-template-columns: 1fr 1fr 1fr; grid-gap: 3rem; } } - .layer-ui__wrapper:not(.disable-pointerEvents) .App-menu_top > * { - pointer-events: all; - } - .App-menu_top > *:first-child { justify-self: flex-start; } @@ -436,7 +436,7 @@ left: 50%; bottom: 30px; transform: translateX(-50%); - pointer-events: all; + pointer-events: var(--ui-pointerEvents); font-family: inherit; &:hover { diff --git a/src/excalidraw-app/components/AppWelcomeScreen.tsx b/src/excalidraw-app/components/AppWelcomeScreen.tsx index 699c3ba8..72b688d9 100644 --- a/src/excalidraw-app/components/AppWelcomeScreen.tsx +++ b/src/excalidraw-app/components/AppWelcomeScreen.tsx @@ -3,6 +3,7 @@ import { PlusPromoIcon } from "../../components/icons"; import { useI18n } from "../../i18n"; import { WelcomeScreen } from "../../packages/excalidraw/index"; import { isExcalidrawPlusSignedUser } from "../app_constants"; +import { POINTER_EVENTS } from "../../constants"; export const AppWelcomeScreen: React.FC<{ setCollabDialogShown: (toggle: boolean) => any; @@ -18,7 +19,7 @@ export const AppWelcomeScreen: React.FC<{ if (bit === "Excalidraw+") { return (