mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-24 11:25:50 -06:00
fix(ui): keep resize drag owned by one pointer (#127760)
Amp-Thread-ID: https://ampcode.com/threads/T-01a021f4-b547-7788-a916-d4a94cbd3e3b Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
committed by
GitHub
parent
6cb08cb8ee
commit
1bd5f22b13
@@ -74,14 +74,14 @@ async function renderDivider() {
|
||||
return divider;
|
||||
}
|
||||
|
||||
function dispatchPointer(target: EventTarget, type: string, clientX: number) {
|
||||
function dispatchPointer(target: EventTarget, type: string, clientX: number, pointerId = 7) {
|
||||
target.dispatchEvent(
|
||||
new PointerEvent(type, {
|
||||
bubbles: true,
|
||||
button: 0,
|
||||
cancelable: true,
|
||||
clientX,
|
||||
pointerId: 7,
|
||||
pointerId,
|
||||
pointerType: "touch",
|
||||
}),
|
||||
);
|
||||
@@ -204,7 +204,7 @@ describe("resizable-divider", () => {
|
||||
expectLastResizeRatio(resized, 0.65);
|
||||
});
|
||||
|
||||
it("uses pointer events for mouse, pen, and touch dragging", async () => {
|
||||
it("keeps dragging owned by the initiating pointer", async () => {
|
||||
const divider = await renderDivider();
|
||||
const resized = vi.fn();
|
||||
const resizeEnded = vi.fn();
|
||||
@@ -222,17 +222,29 @@ describe("resizable-divider", () => {
|
||||
expect([...divider.classList]).toEqual(["dragging"]);
|
||||
expect(setPointerCapture).toHaveBeenCalledWith(7);
|
||||
|
||||
dispatchPointer(document, "pointermove", 220);
|
||||
dispatchPointer(divider, "pointerdown", 180, 8);
|
||||
dispatchPointer(document, "pointermove", 220, 8);
|
||||
dispatchPointer(document, "pointercancel", 220, 8);
|
||||
dispatchPointer(document, "pointerup", 220, 8);
|
||||
|
||||
expect(setPointerCapture).toHaveBeenCalledTimes(1);
|
||||
expect(resized).not.toHaveBeenCalled();
|
||||
expect(resizeEnded).not.toHaveBeenCalled();
|
||||
expect([...divider.classList]).toEqual(["dragging"]);
|
||||
|
||||
dispatchPointer(document, "pointermove", 220, 7);
|
||||
expectLastResizeRatio(resized, 0.7);
|
||||
expect(resizeEnded).not.toHaveBeenCalled();
|
||||
|
||||
dispatchPointer(document, "pointerup", 220);
|
||||
dispatchPointer(document, "pointerup", 220, 7);
|
||||
const endEvent = resizeEnded.mock.lastCall?.[0] as
|
||||
| CustomEvent<{ splitRatio: number }>
|
||||
| undefined;
|
||||
expect(endEvent?.detail).toEqual({ splitRatio: 0.7 });
|
||||
expect(resizeEnded).toHaveBeenCalledTimes(1);
|
||||
expect([...divider.classList]).toEqual([]);
|
||||
expect(releasePointerCapture).toHaveBeenCalledWith(7);
|
||||
expect(releasePointerCapture).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("stops dragging when the window loses focus", async () => {
|
||||
|
||||
@@ -126,7 +126,7 @@ class ResizableDivider extends OpenClawLitElement {
|
||||
}
|
||||
|
||||
private handlePointerDown = (e: PointerEvent) => {
|
||||
if (e.button !== 0) {
|
||||
if (e.button !== 0 || this.activePointerId !== null) {
|
||||
return;
|
||||
}
|
||||
this.startPosition = this.orientation === "horizontal" ? e.clientY : e.clientX;
|
||||
@@ -144,7 +144,7 @@ class ResizableDivider extends OpenClawLitElement {
|
||||
};
|
||||
|
||||
private handlePointerMove = (e: PointerEvent) => {
|
||||
if (this.activePointerId === null) {
|
||||
if (e.pointerId !== this.activePointerId) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -205,7 +205,10 @@ class ResizableDivider extends OpenClawLitElement {
|
||||
this.emitResizeEnd(nextRatio);
|
||||
};
|
||||
|
||||
private readonly finishDragging = () => {
|
||||
private readonly finishDragging = (event: Event) => {
|
||||
if ("pointerId" in event && event.pointerId !== this.activePointerId) {
|
||||
return;
|
||||
}
|
||||
if (this.activePointerId !== null) {
|
||||
this.emitResizeEnd(this.dragRatio);
|
||||
}
|
||||
@@ -213,11 +216,12 @@ class ResizableDivider extends OpenClawLitElement {
|
||||
};
|
||||
|
||||
private stopDragging() {
|
||||
if (this.activePointerId === null) {
|
||||
const pointerId = this.activePointerId;
|
||||
if (pointerId === null) {
|
||||
return;
|
||||
}
|
||||
this.classList.remove("dragging");
|
||||
this.releaseActivePointer();
|
||||
this.releaseActivePointer(pointerId);
|
||||
|
||||
window.removeEventListener("pointermove", this.handlePointerMove);
|
||||
for (const type of DRAG_END_EVENTS) {
|
||||
@@ -281,10 +285,9 @@ class ResizableDivider extends OpenClawLitElement {
|
||||
this.setPointerCapture(pointerId);
|
||||
}
|
||||
|
||||
private releaseActivePointer() {
|
||||
const pointerId = this.activePointerId;
|
||||
private releaseActivePointer(pointerId: number) {
|
||||
this.activePointerId = null;
|
||||
if (pointerId == null || typeof this.releasePointerCapture !== "function") {
|
||||
if (typeof this.releasePointerCapture !== "function") {
|
||||
return;
|
||||
}
|
||||
if (typeof this.hasPointerCapture === "function" && !this.hasPointerCapture(pointerId)) {
|
||||
|
||||
Reference in New Issue
Block a user