refactor(web): extract allocation multi-drag session

This commit is contained in:
2026-04-01 11:22:18 +02:00
parent 5402189158
commit 510459fbff
5 changed files with 249 additions and 37 deletions
@@ -0,0 +1,75 @@
type MutableCurrent<T> = {
current: T;
};
type AttachDocumentMouseDrag = (
documentTarget: Document,
onMove: (event: MouseEvent) => void,
onUp: (event: MouseEvent) => void,
) => () => void;
type MultiDragStateLike<TMode extends string = string> = {
selectedAllocationIds: string[];
multiDragDaysDelta: number;
isMultiDragging: boolean;
multiDragMode: TMode;
};
type BeginAllocationMultiDragSessionParams<TState extends MultiDragStateLike, TMode extends string> = {
startMouseX: number;
dragMode: TMode;
documentTarget: Document;
cleanupRef: MutableCurrent<(() => void) | null>;
stateRef: MutableCurrent<TState>;
setState: (state: TState) => void;
startState: (state: TState, dragMode: TMode) => TState;
updateState: (state: TState, daysDelta: number) => TState | null;
finalizeState: (state: TState) => TState;
toDaysDelta: (deltaX: number) => number;
onComplete: (daysDelta: number, finalState: TState) => void;
attachDrag: AttachDocumentMouseDrag;
};
export function beginAllocationMultiDragSession<TState extends MultiDragStateLike, TMode extends string>({
startMouseX,
dragMode,
documentTarget,
cleanupRef,
stateRef,
setState,
startState,
updateState,
finalizeState,
toDaysDelta,
onComplete,
attachDrag,
}: BeginAllocationMultiDragSessionParams<TState, TMode>) {
const initialState = startState(stateRef.current, dragMode);
stateRef.current = initialState;
setState(initialState);
cleanupRef.current?.();
function handleMove(event: MouseEvent) {
const updated = updateState(stateRef.current, toDaysDelta(event.clientX - startMouseX));
if (!updated) return;
stateRef.current = updated;
setState(updated);
}
function handleUp(event: MouseEvent) {
cleanupRef.current?.();
cleanupRef.current = null;
const finalState = finalizeState(stateRef.current);
stateRef.current = finalState;
setState(finalState);
const finalDelta = toDaysDelta(event.clientX - startMouseX);
if (finalDelta !== 0) {
onComplete(finalDelta, finalState);
}
}
cleanupRef.current = attachDrag(documentTarget, handleMove, handleUp);
}