fix: improperly disabling UI pointer-events on canvas interaction (#7005)

Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>
This commit is contained in:
David Luzar 2023-09-19 16:01:40 +02:00 committed by GitHub
parent 99dbc0acb9
commit 3d617958cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 54 additions and 31 deletions

View File

@ -85,6 +85,7 @@ import {
VERTICAL_ALIGN, VERTICAL_ALIGN,
YOUTUBE_STATES, YOUTUBE_STATES,
ZOOM_STEP, ZOOM_STEP,
POINTER_EVENTS,
} from "../constants"; } from "../constants";
import { exportCanvas, loadFromBlob } from "../data"; import { exportCanvas, loadFromBlob } from "../data";
import Library, { distributeLibraryItemsOnSquareGrid } from "../data/library"; import Library, { distributeLibraryItemsOnSquareGrid } from "../data/library";
@ -857,7 +858,9 @@ class App extends React.Component<AppProps, AppState> {
width: isVisible ? `${el.width}px` : 0, width: isVisible ? `${el.width}px` : 0,
height: isVisible ? `${el.height}px` : 0, height: isVisible ? `${el.height}px` : 0,
transform: isVisible ? `rotate(${el.angle}rad)` : "none", transform: isVisible ? `rotate(${el.angle}rad)` : "none",
pointerEvents: isActive ? "auto" : "none", pointerEvents: isActive
? POINTER_EVENTS.enabled
: POINTER_EVENTS.disabled,
}} }}
> >
{isHovered && ( {isHovered && (
@ -1081,9 +1084,9 @@ class App extends React.Component<AppProps, AppState> {
whiteSpace: "nowrap", whiteSpace: "nowrap",
textOverflow: "ellipsis", textOverflow: "ellipsis",
cursor: CURSOR_TYPE.MOVE, cursor: CURSOR_TYPE.MOVE,
// disable all interaction (e.g. cursor change) when in view pointerEvents: this.state.viewModeEnabled
// mode ? POINTER_EVENTS.disabled
pointerEvents: this.state.viewModeEnabled ? "none" : "all", : POINTER_EVENTS.inheritFromUI,
}} }}
onPointerDown={(event) => this.handleCanvasPointerDown(event)} onPointerDown={(event) => this.handleCanvasPointerDown(event)}
onWheel={(event) => this.handleWheel(event)} onWheel={(event) => this.handleWheel(event)}
@ -1125,6 +1128,16 @@ class App extends React.Component<AppProps, AppState> {
"excalidraw--view-mode": this.state.viewModeEnabled, "excalidraw--view-mode": this.state.viewModeEnabled,
"excalidraw--mobile": this.device.isMobile, "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} ref={this.excalidrawContainerRef}
onDrop={this.handleAppOnDrop} onDrop={this.handleAppOnDrop}
tabIndex={0} tabIndex={0}

View File

@ -7,7 +7,7 @@
} }
.FixedSideContainer > * { .FixedSideContainer > * {
pointer-events: all; pointer-events: var(--ui-pointerEvents);
} }
.FixedSideContainer_side_top { .FixedSideContainer_side_top {

View File

@ -91,13 +91,17 @@
visibility: visible; visibility: visible;
transition: visibility 0s linear 300ms, opacity 0.5s; transition: visibility 0s linear 300ms, opacity 0.5s;
transition-delay: 0.8s; transition-delay: 0.8s;
pointer-events: var(--ui-pointerEvents);
} }
} }
.layer-ui__wrapper__footer-left, .layer-ui__wrapper__footer-left,
.layer-ui__wrapper__footer-right, .footer-center,
.disable-zen-mode--visible { .layer-ui__wrapper__footer-right {
pointer-events: all; & > * {
pointer-events: var(--ui-pointerEvents);
}
} }
.layer-ui__wrapper__footer-right { .layer-ui__wrapper__footer-right {

View File

@ -2,7 +2,7 @@ import clsx from "clsx";
import React from "react"; import React from "react";
import { ActionManager } from "../actions/manager"; import { ActionManager } from "../actions/manager";
import { CLASSES, DEFAULT_SIDEBAR, LIBRARY_SIDEBAR_WIDTH } from "../constants"; import { CLASSES, DEFAULT_SIDEBAR, LIBRARY_SIDEBAR_WIDTH } from "../constants";
import { isTextElement, showSelectedShapeActions } from "../element"; import { showSelectedShapeActions } from "../element";
import { NonDeletedExcalidrawElement } from "../element/types"; import { NonDeletedExcalidrawElement } from "../element/types";
import { Language, t } from "../i18n"; import { Language, t } from "../i18n";
import { calculateScrollCenter } from "../scene"; import { calculateScrollCenter } from "../scene";
@ -427,13 +427,7 @@ const LayerUI = ({
{!device.isMobile && ( {!device.isMobile && (
<> <>
<div <div
className={clsx("layer-ui__wrapper", { className="layer-ui__wrapper"
"disable-pointerEvents":
appState.draggingElement ||
appState.resizingElement ||
(appState.editingElement &&
!isTextElement(appState.editingElement)),
})}
style={ style={
appState.openSidebar && appState.openSidebar &&
isSidebarDocked && isSidebarDocked &&

View File

@ -17,6 +17,8 @@
background-color: var(--sidebar-bg-color); background-color: var(--sidebar-bg-color);
box-shadow: var(--sidebar-shadow); box-shadow: var(--sidebar-shadow);
pointer-events: var(--ui-pointerEvents);
:root[dir="rtl"] & { :root[dir="rtl"] & {
left: 0; left: 0;
right: auto; right: auto;

View File

@ -7,7 +7,7 @@
right: 12px; right: 12px;
font-size: 12px; font-size: 12px;
z-index: 10; z-index: 10;
pointer-events: all; pointer-events: var(--ui-pointerEvents);
h3 { h3 {
margin: 0 24px 8px 0; margin: 0 24px 8px 0;

View File

@ -26,7 +26,7 @@
} }
.UserList > * { .UserList > * {
pointer-events: all; pointer-events: var(--ui-pointerEvents);
} }
.UserList_mobile { .UserList_mobile {

View File

@ -73,7 +73,7 @@ const Footer = ({
<FooterCenterTunnel.Out /> <FooterCenterTunnel.Out />
<div <div
className={clsx("layer-ui__wrapper__footer-right zen-mode-transition", { className={clsx("layer-ui__wrapper__footer-right zen-mode-transition", {
"transition-right disable-pointerEvents": appState.zenModeEnabled, "transition-right": appState.zenModeEnabled,
})} })}
> >
<div style={{ position: "relative" }}> <div style={{ position: "relative" }}>

View File

@ -1,10 +1,11 @@
.footer-center { .footer-center {
pointer-events: none; pointer-events: none;
& > * { & > * {
pointer-events: all; pointer-events: var(--ui-pointerEvents);
} }
display: flex; display: flex;
width: 100%; width: 100%;
justify-content: flex-start; justify-content: flex-start;
margin-inline-end: 0.6rem;
} }

View File

@ -161,7 +161,7 @@
.welcome-screen-menu-item { .welcome-screen-menu-item {
box-sizing: border-box; box-sizing: border-box;
pointer-events: all; pointer-events: var(--ui-pointerEvents);
color: var(--color-gray-50); color: var(--color-gray-50);
font-size: 0.875rem; font-size: 0.875rem;
@ -202,7 +202,7 @@
} }
} }
&:not(:active) .welcome-screen-menu-item:hover { .welcome-screen-menu-item:hover {
text-decoration: none; text-decoration: none;
background: var(--color-gray-10); 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); background: var(--color-gray-85);
.welcome-screen-menu-item__shortcut { .welcome-screen-menu-item__shortcut {

View File

@ -41,6 +41,14 @@ export const POINTER_BUTTON = {
TOUCH: -1, TOUCH: -1,
} as const; } 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 { export enum EVENT {
COPY = "copy", COPY = "copy",
PASTE = "paste", PASTE = "paste",

View File

@ -253,7 +253,7 @@
max-height: 100%; max-height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
pointer-events: initial; pointer-events: var(--ui-pointerEvents);
.panelColumn { .panelColumn {
padding: 8px 8px 0 8px; padding: 8px 8px 0 8px;
@ -301,7 +301,7 @@
pointer-events: none !important; pointer-events: none !important;
& > * { & > * {
pointer-events: all; pointer-events: var(--ui-pointerEvents);
} }
} }
@ -312,16 +312,16 @@
cursor: default; cursor: default;
pointer-events: none !important; pointer-events: none !important;
& > * {
pointer-events: var(--ui-pointerEvents);
}
@media (min-width: 1536px) { @media (min-width: 1536px) {
grid-template-columns: 1fr 1fr 1fr; grid-template-columns: 1fr 1fr 1fr;
grid-gap: 3rem; grid-gap: 3rem;
} }
} }
.layer-ui__wrapper:not(.disable-pointerEvents) .App-menu_top > * {
pointer-events: all;
}
.App-menu_top > *:first-child { .App-menu_top > *:first-child {
justify-self: flex-start; justify-self: flex-start;
} }
@ -436,7 +436,7 @@
left: 50%; left: 50%;
bottom: 30px; bottom: 30px;
transform: translateX(-50%); transform: translateX(-50%);
pointer-events: all; pointer-events: var(--ui-pointerEvents);
font-family: inherit; font-family: inherit;
&:hover { &:hover {

View File

@ -3,6 +3,7 @@ import { PlusPromoIcon } from "../../components/icons";
import { useI18n } from "../../i18n"; import { useI18n } from "../../i18n";
import { WelcomeScreen } from "../../packages/excalidraw/index"; import { WelcomeScreen } from "../../packages/excalidraw/index";
import { isExcalidrawPlusSignedUser } from "../app_constants"; import { isExcalidrawPlusSignedUser } from "../app_constants";
import { POINTER_EVENTS } from "../../constants";
export const AppWelcomeScreen: React.FC<{ export const AppWelcomeScreen: React.FC<{
setCollabDialogShown: (toggle: boolean) => any; setCollabDialogShown: (toggle: boolean) => any;
@ -18,7 +19,7 @@ export const AppWelcomeScreen: React.FC<{
if (bit === "Excalidraw+") { if (bit === "Excalidraw+") {
return ( return (
<a <a
style={{ pointerEvents: "all" }} style={{ pointerEvents: POINTER_EVENTS.inheritFromUI }}
href={`${ href={`${
import.meta.env.VITE_APP_PLUS_APP import.meta.env.VITE_APP_PLUS_APP
}?utm_source=excalidraw&utm_medium=app&utm_content=welcomeScreenSignedInUser`} }?utm_source=excalidraw&utm_medium=app&utm_content=welcomeScreenSignedInUser`}