76 lines
2.1 KiB
TypeScript
76 lines
2.1 KiB
TypeScript
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);
|
|
}
|