fix: improve line creation ux on touch screens (#9740)
* fix: awkward point adding and removing on touch device * feat: move finalize to next to last point * feat: on touch screen, click would create a default line/arrow * fix: make default adaptive to zoom * fix: increase padding to avoid cutoffs * refactor: simplify * fix: only use bigger padding when needed * center arrow horizontally on pointer * increase min drag distance before we start 2-point-arrow-drag-creating * do not render 0-width arrow while creating * dead code * fix tests * fix: remove redundant code * do not enter line editor on creation --------- Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
@@ -505,15 +505,3 @@ export const ExitZenModeAction = ({
|
||||
{t("buttons.exitZenMode")}
|
||||
</button>
|
||||
);
|
||||
|
||||
export const FinalizeAction = ({
|
||||
renderAction,
|
||||
className,
|
||||
}: {
|
||||
renderAction: ActionManager["renderAction"];
|
||||
className?: string;
|
||||
}) => (
|
||||
<div className={`finalize-button ${className}`}>
|
||||
{renderAction("finalize", { size: "small" })}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -100,6 +100,7 @@ import {
|
||||
randomInteger,
|
||||
CLASSES,
|
||||
Emitter,
|
||||
MINIMUM_ARROW_SIZE,
|
||||
} from "@excalidraw/common";
|
||||
|
||||
import {
|
||||
@@ -8162,7 +8163,9 @@ class App extends React.Component<AppProps, AppState> {
|
||||
pointDistance(
|
||||
pointFrom(pointerCoords.x, pointerCoords.y),
|
||||
pointFrom(pointerDownState.origin.x, pointerDownState.origin.y),
|
||||
) < DRAGGING_THRESHOLD
|
||||
) *
|
||||
this.state.zoom.value <
|
||||
MINIMUM_ARROW_SIZE
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@@ -9113,25 +9116,54 @@ class App extends React.Component<AppProps, AppState> {
|
||||
this.state,
|
||||
);
|
||||
|
||||
if (!pointerDownState.drag.hasOccurred && newElement && !multiElement) {
|
||||
this.scene.mutateElement(
|
||||
newElement,
|
||||
{
|
||||
points: [
|
||||
...newElement.points,
|
||||
pointFrom<LocalPoint>(
|
||||
pointerCoords.x - newElement.x,
|
||||
pointerCoords.y - newElement.y,
|
||||
),
|
||||
],
|
||||
},
|
||||
{ informMutation: false, isDragging: false },
|
||||
);
|
||||
const dragDistance =
|
||||
pointDistance(
|
||||
pointFrom(pointerCoords.x, pointerCoords.y),
|
||||
pointFrom(pointerDownState.origin.x, pointerDownState.origin.y),
|
||||
) * this.state.zoom.value;
|
||||
|
||||
this.setState({
|
||||
multiElement: newElement,
|
||||
newElement,
|
||||
});
|
||||
if (
|
||||
(!pointerDownState.drag.hasOccurred ||
|
||||
dragDistance < MINIMUM_ARROW_SIZE) &&
|
||||
newElement &&
|
||||
!multiElement
|
||||
) {
|
||||
if (this.device.isTouchScreen) {
|
||||
const FIXED_DELTA_X = Math.min(
|
||||
(this.state.width * 0.7) / this.state.zoom.value,
|
||||
100,
|
||||
);
|
||||
|
||||
this.scene.mutateElement(
|
||||
newElement,
|
||||
{
|
||||
x: newElement.x - FIXED_DELTA_X / 2,
|
||||
points: [
|
||||
pointFrom<LocalPoint>(0, 0),
|
||||
pointFrom<LocalPoint>(FIXED_DELTA_X, 0),
|
||||
],
|
||||
},
|
||||
{ informMutation: false, isDragging: false },
|
||||
);
|
||||
|
||||
this.actionManager.executeAction(actionFinalize);
|
||||
} else {
|
||||
const dx = pointerCoords.x - newElement.x;
|
||||
const dy = pointerCoords.y - newElement.y;
|
||||
|
||||
this.scene.mutateElement(
|
||||
newElement,
|
||||
{
|
||||
points: [...newElement.points, pointFrom<LocalPoint>(dx, dy)],
|
||||
},
|
||||
{ informMutation: false, isDragging: false },
|
||||
);
|
||||
|
||||
this.setState({
|
||||
multiElement: newElement,
|
||||
newElement,
|
||||
});
|
||||
}
|
||||
} else if (pointerDownState.drag.hasOccurred && !multiElement) {
|
||||
if (
|
||||
isBindingEnabled(this.state) &&
|
||||
|
||||
@@ -2,13 +2,7 @@ import clsx from "clsx";
|
||||
|
||||
import { actionShortcuts } from "../../actions";
|
||||
import { useTunnels } from "../../context/tunnels";
|
||||
import {
|
||||
ExitZenModeAction,
|
||||
FinalizeAction,
|
||||
UndoRedoActions,
|
||||
ZoomActions,
|
||||
} from "../Actions";
|
||||
import { useDevice } from "../App";
|
||||
import { ExitZenModeAction, UndoRedoActions, ZoomActions } from "../Actions";
|
||||
import { HelpButton } from "../HelpButton";
|
||||
import { Section } from "../Section";
|
||||
import Stack from "../Stack";
|
||||
@@ -29,10 +23,6 @@ const Footer = ({
|
||||
}) => {
|
||||
const { FooterCenterTunnel, WelcomeScreenHelpHintTunnel } = useTunnels();
|
||||
|
||||
const device = useDevice();
|
||||
const showFinalize =
|
||||
!appState.viewModeEnabled && appState.multiElement && device.isTouchScreen;
|
||||
|
||||
return (
|
||||
<footer
|
||||
role="contentinfo"
|
||||
@@ -60,15 +50,6 @@ const Footer = ({
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
{showFinalize && (
|
||||
<FinalizeAction
|
||||
renderAction={actionManager.renderAction}
|
||||
className={clsx("zen-mode-transition", {
|
||||
"layer-ui__wrapper__footer-left--transition-left":
|
||||
appState.zenModeEnabled,
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</Section>
|
||||
</Stack.Col>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user