export type DragState = | { kind: "idle" } | { kind: "previewing"; itemId: ItemId; target: Target | null } | { kind: "committing"; itemId: ItemId; target: Target }; export type DragEvent = | { type: "begin"; itemId: ItemId } | { type: "preview"; target: Target | null } | { type: "commit"; target: Target } | { type: "cancel" }; export function reduceDragState( state: DragState, event: DragEvent, ): DragState { switch (event.type) { case "begin": return { kind: "previewing", itemId: event.itemId, target: null }; case "preview": return state.kind === "previewing" ? { ...state, target: event.target } : state; case "commit": return state.kind === "previewing" && state.target !== null ? { kind: "committing", itemId: state.itemId, target: event.target } : state; case "cancel": return { kind: "idle" }; } } export function createDragState() { let state: DragState = { kind: "idle" }; return { read: () => state, send: (event: DragEvent) => { state = reduceDragState(state, event); return state; }, reset: () => { state = { kind: "idle" }; return state; }, }; }