fix: improperly disabling UI pointer-events on canvas interaction (#7005)
Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>
This commit is contained in:
parent
99dbc0acb9
commit
3d617958cc
@ -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}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.FixedSideContainer > * {
|
.FixedSideContainer > * {
|
||||||
pointer-events: all;
|
pointer-events: var(--ui-pointerEvents);
|
||||||
}
|
}
|
||||||
|
|
||||||
.FixedSideContainer_side_top {
|
.FixedSideContainer_side_top {
|
||||||
|
@ -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 {
|
||||||
|
@ -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 &&
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.UserList > * {
|
.UserList > * {
|
||||||
pointer-events: all;
|
pointer-events: var(--ui-pointerEvents);
|
||||||
}
|
}
|
||||||
|
|
||||||
.UserList_mobile {
|
.UserList_mobile {
|
||||||
|
@ -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" }}>
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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",
|
||||||
|
@ -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 {
|
||||||
|
@ -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`}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user