fix: prevent double-click to edit/create text scenarios on line (#9597)
* fix : double click on line enables line editor * fix : prevent double-click to edit/create text when inside line editor * refactor: use lineCheck instead of arrowCheck in doubleClick handler to align with updated logic * fix: replace negative arrowCheck with lineCheck in dbl click handler and fix double-click bind text test in linearElementEditor tests * clean up test * simplify check * add tests * prevent text editing on dblclick when inside arrow editor --------- Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
parent
ca1a4f25e7
commit
469caadb87
@ -129,6 +129,15 @@ export const isElbowArrow = (
|
|||||||
return isArrowElement(element) && element.elbowed;
|
return isArrowElement(element) && element.elbowed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sharp or curved arrow, but not elbow
|
||||||
|
*/
|
||||||
|
export const isSimpleArrow = (
|
||||||
|
element?: ExcalidrawElement,
|
||||||
|
): element is ExcalidrawArrowElement => {
|
||||||
|
return isArrowElement(element) && !element.elbowed;
|
||||||
|
};
|
||||||
|
|
||||||
export const isSharpArrow = (
|
export const isSharpArrow = (
|
||||||
element?: ExcalidrawElement,
|
element?: ExcalidrawElement,
|
||||||
): element is ExcalidrawArrowElement => {
|
): element is ExcalidrawArrowElement => {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { pointCenter, pointFrom } from "@excalidraw/math";
|
import { pointCenter, pointFrom } from "@excalidraw/math";
|
||||||
import { act, queryByTestId, queryByText } from "@testing-library/react";
|
import { act, queryByTestId, queryByText } from "@testing-library/react";
|
||||||
import React from "react";
|
|
||||||
import { vi } from "vitest";
|
import { vi } from "vitest";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -33,6 +32,8 @@ import { getBoundTextElementPosition, getBoundTextMaxWidth } from "../src";
|
|||||||
import { LinearElementEditor } from "../src";
|
import { LinearElementEditor } from "../src";
|
||||||
import { newArrowElement } from "../src";
|
import { newArrowElement } from "../src";
|
||||||
|
|
||||||
|
import { getTextEditor } from "../../excalidraw/tests/queries/dom";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ExcalidrawElement,
|
ExcalidrawElement,
|
||||||
ExcalidrawLinearElement,
|
ExcalidrawLinearElement,
|
||||||
@ -252,7 +253,17 @@ describe("Test Linear Elements", () => {
|
|||||||
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
|
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should enter line editor when using double clicked with ctrl key", () => {
|
it("should enter line editor on ctrl+dblclick (simple arrow)", () => {
|
||||||
|
createTwoPointerLinearElement("arrow");
|
||||||
|
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
|
||||||
|
|
||||||
|
Keyboard.withModifierKeys({ ctrl: true }, () => {
|
||||||
|
mouse.doubleClick();
|
||||||
|
});
|
||||||
|
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should enter line editor on ctrl+dblclick (line)", () => {
|
||||||
createTwoPointerLinearElement("line");
|
createTwoPointerLinearElement("line");
|
||||||
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
|
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
|
||||||
|
|
||||||
@ -262,6 +273,39 @@ describe("Test Linear Elements", () => {
|
|||||||
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
|
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should enter line editor on dblclick (line)", () => {
|
||||||
|
createTwoPointerLinearElement("line");
|
||||||
|
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
|
||||||
|
|
||||||
|
mouse.doubleClick();
|
||||||
|
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not enter line editor on dblclick (arrow)", async () => {
|
||||||
|
createTwoPointerLinearElement("arrow");
|
||||||
|
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
|
||||||
|
|
||||||
|
mouse.doubleClick();
|
||||||
|
expect(h.state.editingLinearElement).toEqual(null);
|
||||||
|
await getTextEditor(".excalidraw-textEditorContainer > textarea");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shouldn't create text element on double click in line editor (arrow)", async () => {
|
||||||
|
createTwoPointerLinearElement("arrow");
|
||||||
|
const arrow = h.elements[0] as ExcalidrawLinearElement;
|
||||||
|
enterLineEditingMode(arrow);
|
||||||
|
|
||||||
|
expect(h.state.editingLinearElement?.elementId).toEqual(arrow.id);
|
||||||
|
|
||||||
|
mouse.doubleClick();
|
||||||
|
expect(h.state.editingLinearElement?.elementId).toEqual(arrow.id);
|
||||||
|
expect(h.elements.length).toEqual(1);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
document.querySelector(".excalidraw-textEditorContainer > textarea"),
|
||||||
|
).toBe(null);
|
||||||
|
});
|
||||||
|
|
||||||
describe("Inside editor", () => {
|
describe("Inside editor", () => {
|
||||||
it("should not drag line and add midpoint when dragged irrespective of threshold", () => {
|
it("should not drag line and add midpoint when dragged irrespective of threshold", () => {
|
||||||
createTwoPointerLinearElement("line");
|
createTwoPointerLinearElement("line");
|
||||||
@ -1063,13 +1107,7 @@ describe("Test Linear Elements", () => {
|
|||||||
|
|
||||||
expect(h.elements.length).toBe(1);
|
expect(h.elements.length).toBe(1);
|
||||||
mouse.doubleClickAt(line.x, line.y);
|
mouse.doubleClickAt(line.x, line.y);
|
||||||
|
expect(h.elements.length).toBe(1);
|
||||||
expect(h.elements.length).toBe(2);
|
|
||||||
|
|
||||||
const text = h.elements[1] as ExcalidrawTextElementWithContainer;
|
|
||||||
expect(text.type).toBe("text");
|
|
||||||
expect(text.containerId).toBeNull();
|
|
||||||
expect(line.boundElements).toBeNull();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO fix #7029 and rewrite this test
|
// TODO fix #7029 and rewrite this test
|
||||||
|
@ -230,6 +230,8 @@ import {
|
|||||||
CaptureUpdateAction,
|
CaptureUpdateAction,
|
||||||
type ElementUpdate,
|
type ElementUpdate,
|
||||||
hitElementBoundingBox,
|
hitElementBoundingBox,
|
||||||
|
isLineElement,
|
||||||
|
isSimpleArrow,
|
||||||
} from "@excalidraw/element";
|
} from "@excalidraw/element";
|
||||||
|
|
||||||
import type { LocalPoint, Radians } from "@excalidraw/math";
|
import type { LocalPoint, Radians } from "@excalidraw/math";
|
||||||
@ -5438,17 +5440,17 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (selectedElements.length === 1 && isLinearElement(selectedElements[0])) {
|
if (selectedElements.length === 1 && isLinearElement(selectedElements[0])) {
|
||||||
|
const selectedLinearElement: ExcalidrawLinearElement =
|
||||||
|
selectedElements[0];
|
||||||
if (
|
if (
|
||||||
event[KEYS.CTRL_OR_CMD] &&
|
((event[KEYS.CTRL_OR_CMD] && isSimpleArrow(selectedLinearElement)) ||
|
||||||
(!this.state.editingLinearElement ||
|
isLineElement(selectedLinearElement)) &&
|
||||||
this.state.editingLinearElement.elementId !==
|
this.state.editingLinearElement?.elementId !== selectedLinearElement.id
|
||||||
selectedElements[0].id) &&
|
|
||||||
!isElbowArrow(selectedElements[0])
|
|
||||||
) {
|
) {
|
||||||
this.store.scheduleCapture();
|
this.store.scheduleCapture();
|
||||||
this.setState({
|
this.setState({
|
||||||
editingLinearElement: new LinearElementEditor(
|
editingLinearElement: new LinearElementEditor(
|
||||||
selectedElements[0],
|
selectedLinearElement,
|
||||||
this.scene.getNonDeletedElementsMap(),
|
this.scene.getNonDeletedElementsMap(),
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
@ -5515,6 +5517,13 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (
|
||||||
|
this.state.editingLinearElement &&
|
||||||
|
this.state.editingLinearElement.elementId ===
|
||||||
|
selectedLinearElement.id &&
|
||||||
|
isLineElement(selectedLinearElement)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5563,7 +5572,13 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const container = this.getTextBindableContainerAtPosition(sceneX, sceneY);
|
// shouldn't edit/create text when inside line editor (often false positive)
|
||||||
|
|
||||||
|
if (!this.state.editingLinearElement) {
|
||||||
|
const container = this.getTextBindableContainerAtPosition(
|
||||||
|
sceneX,
|
||||||
|
sceneY,
|
||||||
|
);
|
||||||
|
|
||||||
if (container) {
|
if (container) {
|
||||||
if (
|
if (
|
||||||
@ -5594,6 +5609,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
container,
|
container,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private getElementLinkAtPosition = (
|
private getElementLinkAtPosition = (
|
||||||
|
Loading…
x
Reference in New Issue
Block a user