Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 28cbe82a86 |
@@ -692,6 +692,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
lastPointerMoveEvent: PointerEvent | null = null;
|
lastPointerMoveEvent: PointerEvent | null = null;
|
||||||
/** current frame pointer cords */
|
/** current frame pointer cords */
|
||||||
lastPointerMoveCoords: { x: number; y: number } | null = null;
|
lastPointerMoveCoords: { x: number; y: number } | null = null;
|
||||||
|
private lastCompletedCanvasClicks: { x: number; y: number }[] = [];
|
||||||
/** previous frame pointer coords */
|
/** previous frame pointer coords */
|
||||||
previousPointerMoveCoords: { x: number; y: number } | null = null;
|
previousPointerMoveCoords: { x: number; y: number } | null = null;
|
||||||
lastViewportPosition = { x: 0, y: 0 };
|
lastViewportPosition = { x: 0, y: 0 };
|
||||||
@@ -2341,6 +2342,7 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}
|
}
|
||||||
handleCanvasRef={this.handleInteractiveCanvasRef}
|
handleCanvasRef={this.handleInteractiveCanvasRef}
|
||||||
onContextMenu={this.handleCanvasContextMenu}
|
onContextMenu={this.handleCanvasContextMenu}
|
||||||
|
onClick={this.handleCanvasClick}
|
||||||
onPointerMove={this.handleCanvasPointerMove}
|
onPointerMove={this.handleCanvasPointerMove}
|
||||||
onPointerUp={this.handleCanvasPointerUp}
|
onPointerUp={this.handleCanvasPointerUp}
|
||||||
onPointerCancel={this.removePointer}
|
onPointerCancel={this.removePointer}
|
||||||
@@ -3594,10 +3596,14 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
this.lassoTrail.endPath();
|
this.lassoTrail.endPath();
|
||||||
this.deselectElements();
|
this.deselectElements();
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
this.handleCanvasDoubleClick({
|
this.handleCanvasDoubleClick({
|
||||||
clientX: touch.clientX,
|
clientX: touch.clientX,
|
||||||
clientY: touch.clientY,
|
clientY: touch.clientY,
|
||||||
|
type: "touch",
|
||||||
|
altKey: false,
|
||||||
|
ctrlKey: false,
|
||||||
|
metaKey: false,
|
||||||
|
shiftKey: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
didTapTwice = false;
|
didTapTwice = false;
|
||||||
@@ -6220,10 +6226,46 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private shouldHandleBrowserCanvasDoubleClick = (type: string) => {
|
||||||
|
// TODO remove this once we consolidate double-click logic and handle
|
||||||
|
// ourselves for all event types together
|
||||||
|
if (type === "touch") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (this.lastCompletedCanvasClicks.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.lastCompletedCanvasClicks.length < 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [firstClick, secondClick] = this.lastCompletedCanvasClicks;
|
||||||
|
|
||||||
|
return (
|
||||||
|
pointDistance(
|
||||||
|
pointFrom(firstClick.x, firstClick.y),
|
||||||
|
pointFrom(secondClick.x, secondClick.y),
|
||||||
|
) <= DOUBLE_TAP_POSITION_THRESHOLD
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
private handleCanvasDoubleClick = (
|
private handleCanvasDoubleClick = (
|
||||||
event: React.MouseEvent<HTMLCanvasElement>,
|
event: Pick<
|
||||||
|
React.MouseEvent<HTMLCanvasElement>,
|
||||||
|
| "type"
|
||||||
|
| "clientX"
|
||||||
|
| "clientY"
|
||||||
|
| "altKey"
|
||||||
|
| "ctrlKey"
|
||||||
|
| "metaKey"
|
||||||
|
| "shiftKey"
|
||||||
|
>,
|
||||||
) => {
|
) => {
|
||||||
if (this.state.editingTextElement) {
|
if (
|
||||||
|
this.state.editingTextElement ||
|
||||||
|
!this.shouldHandleBrowserCanvasDoubleClick(event.type)
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// case: double-clicking with arrow/line tool selected would both create
|
// case: double-clicking with arrow/line tool selected would both create
|
||||||
@@ -6413,6 +6455,21 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private handleCanvasClick = (event: React.MouseEvent<HTMLCanvasElement>) => {
|
||||||
|
if (event.button !== POINTER_BUTTON.MAIN) {
|
||||||
|
this.lastCompletedCanvasClicks = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lastCompletedCanvasClicks = [
|
||||||
|
...this.lastCompletedCanvasClicks.slice(-1),
|
||||||
|
{
|
||||||
|
x: event.clientX,
|
||||||
|
y: event.clientY,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
private getElementLinkAtPosition = (
|
private getElementLinkAtPosition = (
|
||||||
scenePointer: Readonly<{ x: number; y: number }>,
|
scenePointer: Readonly<{ x: number; y: number }>,
|
||||||
hitElementMightBeLocked: NonDeletedExcalidrawElement | null,
|
hitElementMightBeLocked: NonDeletedExcalidrawElement | null,
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ type InteractiveCanvasProps = {
|
|||||||
DOMAttributes<HTMLCanvasElement | HTMLDivElement>["onContextMenu"],
|
DOMAttributes<HTMLCanvasElement | HTMLDivElement>["onContextMenu"],
|
||||||
undefined
|
undefined
|
||||||
>;
|
>;
|
||||||
|
onClick: Exclude<DOMAttributes<HTMLCanvasElement>["onClick"], undefined>;
|
||||||
onPointerMove: Exclude<
|
onPointerMove: Exclude<
|
||||||
DOMAttributes<HTMLCanvasElement>["onPointerMove"],
|
DOMAttributes<HTMLCanvasElement>["onPointerMove"],
|
||||||
undefined
|
undefined
|
||||||
@@ -213,6 +214,7 @@ const InteractiveCanvas = (props: InteractiveCanvasProps) => {
|
|||||||
height={props.appState.height * props.scale}
|
height={props.appState.height * props.scale}
|
||||||
ref={props.handleCanvasRef}
|
ref={props.handleCanvasRef}
|
||||||
onContextMenu={props.onContextMenu}
|
onContextMenu={props.onContextMenu}
|
||||||
|
onClick={props.onClick}
|
||||||
onPointerMove={props.onPointerMove}
|
onPointerMove={props.onPointerMove}
|
||||||
onPointerUp={props.onPointerUp}
|
onPointerUp={props.onPointerUp}
|
||||||
onPointerCancel={props.onPointerCancel}
|
onPointerCancel={props.onPointerCancel}
|
||||||
|
|||||||
@@ -293,6 +293,39 @@ describe("textWysiwyg", () => {
|
|||||||
expect(await getTextEditor({ waitForEditor: false })).toBe(null);
|
expect(await getTextEditor({ waitForEditor: false })).toBe(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should ignore double-click when the second click ends away from where it started", async () => {
|
||||||
|
UI.clickTool("selection");
|
||||||
|
|
||||||
|
mouse.downAt(40, 40);
|
||||||
|
mouse.upAt(40, 40);
|
||||||
|
fireEvent.click(GlobalTestState.interactiveCanvas, {
|
||||||
|
button: 0,
|
||||||
|
clientX: 40,
|
||||||
|
clientY: 40,
|
||||||
|
});
|
||||||
|
|
||||||
|
mouse.downAt(40, 40);
|
||||||
|
mouse.moveTo(200, 200);
|
||||||
|
mouse.upAt(200, 200);
|
||||||
|
fireEvent.click(GlobalTestState.interactiveCanvas, {
|
||||||
|
button: 0,
|
||||||
|
clientX: 200,
|
||||||
|
clientY: 200,
|
||||||
|
});
|
||||||
|
|
||||||
|
fireEvent.doubleClick(GlobalTestState.interactiveCanvas, {
|
||||||
|
button: 0,
|
||||||
|
clientX: 200,
|
||||||
|
clientY: 200,
|
||||||
|
});
|
||||||
|
|
||||||
|
const editor = await getTextEditor({ waitForEditor: false });
|
||||||
|
|
||||||
|
expect(editor).toBe(null);
|
||||||
|
expect(h.state.editingTextElement).toBe(null);
|
||||||
|
expect(h.elements.length).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
// FIXME too flaky. No one knows why.
|
// FIXME too flaky. No one knows why.
|
||||||
it.skip("should bump the version of a labeled arrow when the label is updated", async () => {
|
it.skip("should bump the version of a labeled arrow when the label is updated", async () => {
|
||||||
const arrow = UI.createElement("arrow", {
|
const arrow = UI.createElement("arrow", {
|
||||||
|
|||||||
Reference in New Issue
Block a user