type MutableCurrent = { current: T; }; type AttachDocumentMouseDrag = ( documentTarget: Document, onMove: (event: MouseEvent) => void, onUp: (event: MouseEvent) => void, ) => () => void; type BeginAllocationDragSessionParams = { state: TState; cleanupRef: MutableCurrent<(() => void) | null>; stateRef: MutableCurrent; setState: (state: TState) => void; documentTarget: Document; attachDrag: AttachDocumentMouseDrag; updatePosition: (clientX: number) => void; finalize: (clientX: number) => Promise | void; }; export function beginAllocationDragSession({ state, cleanupRef, stateRef, setState, documentTarget, attachDrag, updatePosition, finalize, }: BeginAllocationDragSessionParams) { stateRef.current = state; setState(state); cleanupRef.current?.(); function handleMove(event: MouseEvent) { updatePosition(event.clientX); } function handleUp(event: MouseEvent) { cleanupRef.current?.(); cleanupRef.current = null; void finalize(event.clientX); event.preventDefault(); } cleanupRef.current = attachDrag(documentTarget, handleMove, handleUp); }