fix(app): make sidebar reordering respond immediately

Mouse input inherited the touch hold delay. Split activation by input so mouse dragging begins after deliberate movement while touch retains long-press arbitration.
This commit is contained in:
Mohamed Boudra
2026-07-17 13:00:47 +02:00
parent 266d54463b
commit a7cbf4f61d
7 changed files with 124 additions and 254 deletions
@@ -1,8 +1,9 @@
export { reorderItemsOnDragEnd } from "./reorder-items";
export type { DragEndInput } from "./reorder-items";
export {
getPointerActivationConstraint,
type PointerActivationConfig,
getDragActivationConstraints,
type DragActivationConfig,
type DragActivationConstraints,
type PointerActivationConstraint,
} from "./pointer-activation";
export {
@@ -1,14 +1,21 @@
import { describe, expect, it } from "vitest";
import { getPointerActivationConstraint } from "./pointer-activation";
import { getDragActivationConstraints } from "./pointer-activation";
const config = { defaultDistance: 6, holdDelayMs: 250, holdTolerance: 8 };
const config = { movementDistance: 6, touchHoldDelayMs: 180, touchHoldTolerance: 8 };
describe("getPointerActivationConstraint", () => {
it("uses distance activation for default draggable rows", () => {
expect(getPointerActivationConstraint(false, config)).toEqual({ distance: 6 });
describe("getDragActivationConstraints", () => {
it("starts mouse drags after deliberate pointer movement", () => {
expect(getDragActivationConstraints(true, config).mouse).toEqual({ distance: 6 });
});
it("requires a held pointer before activating handle-based drags", () => {
expect(getPointerActivationConstraint(true, config)).toEqual({ delay: 250, tolerance: 8 });
it("requires a short hold before starting touch drags", () => {
expect(getDragActivationConstraints(true, config).touch).toEqual({
delay: 180,
tolerance: 8,
});
});
it("starts ordinary touch rows after deliberate movement", () => {
expect(getDragActivationConstraints(false, config).touch).toEqual({ distance: 6 });
});
});
@@ -2,18 +2,25 @@ export type PointerActivationConstraint =
| { distance: number }
| { delay: number; tolerance: number };
export interface PointerActivationConfig {
defaultDistance: number;
holdDelayMs: number;
holdTolerance: number;
export interface DragActivationConfig {
movementDistance: number;
touchHoldDelayMs: number;
touchHoldTolerance: number;
}
export function getPointerActivationConstraint(
export interface DragActivationConstraints {
mouse: PointerActivationConstraint;
touch: PointerActivationConstraint;
}
export function getDragActivationConstraints(
useDragHandle: boolean,
config: PointerActivationConfig,
): PointerActivationConstraint {
if (useDragHandle) {
return { delay: config.holdDelayMs, tolerance: config.holdTolerance };
}
return { distance: config.defaultDistance };
config: DragActivationConfig,
): DragActivationConstraints {
const movement = { distance: config.movementDistance };
const touch = useDragHandle
? { delay: config.touchHoldDelayMs, tolerance: config.touchHoldTolerance }
: movement;
return { mouse: movement, touch };
}