mirror of
https://github.com/excalidraw/excalidraw.git
synced 2026-10-19 16:15:56 +00:00
feat(editor): disable arrowhead toggle via dblclick (#11822)
This commit is contained in:
@@ -335,36 +335,14 @@ describe("Test Linear Elements", () => {
|
||||
await getTextEditor();
|
||||
});
|
||||
|
||||
describe("Arrowhead toggle on endpoint dblclick", () => {
|
||||
// the toggle replaces the element (immutable update), so always re-read
|
||||
// the arrow from the scene instead of holding on to a stale reference
|
||||
const getArrow = () => h.elements[0] as ExcalidrawArrowElement;
|
||||
|
||||
it("should toggle end arrowhead between default and none", () => {
|
||||
createTwoPointerLinearElement("arrow");
|
||||
expect(getArrow().endArrowhead).toBe(null);
|
||||
|
||||
mouse.doubleClickAt(p2[0], p2[1]);
|
||||
expect(getArrow().endArrowhead).toBe("arrow");
|
||||
expect(document.querySelector(TEXT_EDITOR_SELECTOR)).toBe(null);
|
||||
|
||||
mouse.doubleClickAt(p2[0], p2[1]);
|
||||
expect(getArrow().endArrowhead).toBe(null);
|
||||
});
|
||||
|
||||
it("should toggle start arrowhead between default and none", () => {
|
||||
createTwoPointerLinearElement("arrow");
|
||||
expect(getArrow().startArrowhead).toBe(null);
|
||||
|
||||
mouse.doubleClickAt(p1[0], p1[1]);
|
||||
expect(getArrow().startArrowhead).toBe("arrow");
|
||||
expect(document.querySelector(TEXT_EDITOR_SELECTOR)).toBe(null);
|
||||
|
||||
mouse.doubleClickAt(p1[0], p1[1]);
|
||||
expect(getArrow().startArrowhead).toBe(null);
|
||||
});
|
||||
|
||||
it("should restore the arrowhead removed by the previous toggle", () => {
|
||||
it.each([
|
||||
["start", null],
|
||||
["start", "triangle"],
|
||||
["end", null],
|
||||
["end", "triangle"],
|
||||
] as const)(
|
||||
"should not toggle the %s arrowhead from %s on endpoint dblclick",
|
||||
async (side, arrowhead) => {
|
||||
const arrow = API.createElement({
|
||||
type: "arrow",
|
||||
x: p1[0],
|
||||
@@ -372,26 +350,25 @@ describe("Test Linear Elements", () => {
|
||||
width: p2[0] - p1[0],
|
||||
height: 0,
|
||||
points: [pointFrom(0, 0), pointFrom(p2[0] - p1[0], p2[1] - p1[1])],
|
||||
endArrowhead: "triangle",
|
||||
startArrowhead: side === "start" ? arrowhead : null,
|
||||
endArrowhead: side === "end" ? arrowhead : null,
|
||||
});
|
||||
API.setElements([arrow]);
|
||||
mouse.clickAt(midpoint[0], midpoint[1]);
|
||||
|
||||
mouse.doubleClickAt(p2[0], p2[1]);
|
||||
expect(getArrow().endArrowhead).toBe(null);
|
||||
const endpoint = side === "start" ? p1 : p2;
|
||||
mouse.doubleClickAt(endpoint[0], endpoint[1]);
|
||||
|
||||
mouse.doubleClickAt(p2[0], p2[1]);
|
||||
expect(getArrow().endArrowhead).toBe("triangle");
|
||||
});
|
||||
const updatedArrow = h.elements[0] as ExcalidrawArrowElement;
|
||||
expect(
|
||||
side === "start"
|
||||
? updatedArrow.startArrowhead
|
||||
: updatedArrow.endArrowhead,
|
||||
).toBe(arrowhead);
|
||||
|
||||
it("should not toggle arrowheads on dblclick outside endpoints", () => {
|
||||
createTwoPointerLinearElement("arrow");
|
||||
|
||||
mouse.doubleClickAt(midpoint[0], midpoint[1]);
|
||||
expect(getArrow().startArrowhead).toBe(null);
|
||||
expect(getArrow().endArrowhead).toBe(null);
|
||||
});
|
||||
});
|
||||
await getTextEditor();
|
||||
},
|
||||
);
|
||||
|
||||
it("shouldn't create text element on double click in line editor (arrow)", async () => {
|
||||
createTwoPointerLinearElement("arrow");
|
||||
|
||||
@@ -282,7 +282,6 @@ import type {
|
||||
ExcalidrawEmbeddableElement,
|
||||
Ordered,
|
||||
MagicGenerationData,
|
||||
Arrowhead,
|
||||
ExcalidrawArrowElement,
|
||||
ExcalidrawElbowArrowElement,
|
||||
SceneElementsMap,
|
||||
@@ -708,9 +707,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
/** current frame pointer cords */
|
||||
lastPointerMoveCoords: { x: number; y: number } | null = null;
|
||||
private lastCompletedCanvasClicks: { x: number; y: number }[] = [];
|
||||
/** arrowheads removed via endpoint double-click toggle, so a subsequent
|
||||
* toggle can restore the original arrowhead (keyed by `elementId:side`) */
|
||||
private removedArrowheads = new Map<string, Arrowhead>();
|
||||
/** previous frame pointer coords */
|
||||
previousPointerMoveCoords: { x: number; y: number } | null = null;
|
||||
|
||||
@@ -6940,49 +6936,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggles the arrowhead at the given endpoint between no arrowhead and the
|
||||
* arrowhead it had before the last toggle (falling back to the current
|
||||
* default arrowhead).
|
||||
*/
|
||||
private toggleArrowheadAtEndpoint = (
|
||||
element: ExcalidrawArrowElement,
|
||||
side: "start" | "end",
|
||||
) => {
|
||||
const currentArrowhead =
|
||||
side === "start" ? element.startArrowhead : element.endArrowhead;
|
||||
|
||||
this.store.scheduleCapture();
|
||||
|
||||
let arrowheadUpdate:
|
||||
| { startArrowhead: Arrowhead | null }
|
||||
| { endArrowhead: Arrowhead | null };
|
||||
|
||||
if (currentArrowhead) {
|
||||
this.removedArrowheads.set(`${element.id}:${side}`, currentArrowhead);
|
||||
arrowheadUpdate =
|
||||
side === "start" ? { startArrowhead: null } : { endArrowhead: null };
|
||||
} else {
|
||||
const arrowhead =
|
||||
this.removedArrowheads.get(`${element.id}:${side}`) ??
|
||||
(side === "start"
|
||||
? this.state.currentItemStartArrowhead
|
||||
: this.state.currentItemEndArrowhead) ??
|
||||
"arrow";
|
||||
arrowheadUpdate =
|
||||
side === "start"
|
||||
? { startArrowhead: arrowhead }
|
||||
: { endArrowhead: arrowhead };
|
||||
}
|
||||
|
||||
this.scene.mapElements((_element) => {
|
||||
if (_element.id === element.id && isArrowElement(_element)) {
|
||||
return newElementWith(_element, arrowheadUpdate);
|
||||
}
|
||||
return _element;
|
||||
});
|
||||
};
|
||||
|
||||
private handleCanvasDoubleClick = (
|
||||
event: Pick<
|
||||
React.MouseEvent<HTMLCanvasElement>,
|
||||
@@ -7029,30 +6982,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
const selectedLinearElement: ExcalidrawLinearElement =
|
||||
selectedElements[0];
|
||||
|
||||
if (
|
||||
!event[KEYS.CTRL_OR_CMD] &&
|
||||
isArrowElement(selectedLinearElement) &&
|
||||
this.state.selectedLinearElement?.elementId === selectedLinearElement.id
|
||||
) {
|
||||
const clickedPointIndex = LinearElementEditor.getPointIndexUnderCursor(
|
||||
selectedLinearElement,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
this.state.zoom,
|
||||
sceneX,
|
||||
sceneY,
|
||||
);
|
||||
if (
|
||||
clickedPointIndex === 0 ||
|
||||
clickedPointIndex === selectedLinearElement.points.length - 1
|
||||
) {
|
||||
this.toggleArrowheadAtEndpoint(
|
||||
selectedLinearElement,
|
||||
clickedPointIndex === 0 ? "start" : "end",
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
((event[KEYS.CTRL_OR_CMD] && isSimpleArrow(selectedLinearElement)) ||
|
||||
isLineElement(selectedLinearElement)) &&
|
||||
|
||||
Reference in New Issue
Block a user