{"version":3,"file":"use-long-press-handlers.cjs","names":[],"sources":["../../src/hooks/use-long-press-handlers.ts"],"sourcesContent":["import { useCallback, useRef } from \"react\";\nimport { useLatestRef } from \"./use-latest-ref\";\nimport type { MouseEvent as ReactMouseEvent, TouchEvent as ReactTouchEvent } from \"react\";\n\n/**\n * DOM event handlers produced by {@link useLongPressHandlers}, ready to spread\n * onto a JSX element (`<div {...handlers}>`).\n */\nexport interface LongPressHandlers {\n    /** Starts the hold timer on mouse press. */\n    onMouseDown: (event: ReactMouseEvent) => void;\n    /** Cancels the pending hold when the mouse is released. */\n    onMouseUp: () => void;\n    /** Cancels the pending hold when the pointer leaves the element. */\n    onMouseLeave: () => void;\n    /** Starts the hold timer on touch start. */\n    onTouchStart: (event: ReactTouchEvent) => void;\n    /** Cancels the pending hold when the touch ends. */\n    onTouchEnd: () => void;\n    /** Cancels the pending hold when the finger moves. */\n    onTouchMove: () => void;\n    /** Fires the long-press immediately (desktop right-click parity). */\n    onContextMenu: (event: ReactMouseEvent) => void;\n}\n\n/** Options accepted by {@link useLongPressHandlers}. */\nexport interface UseLongPressHandlersOptions {\n    /** Hold duration in ms before `onLongPress` fires. Defaults to `500`. */\n    delayMs?: number;\n    /** When `true`, the hook is inert and every handler is a no-op. */\n    disabled?: boolean;\n}\n\n/** Return shape of {@link useLongPressHandlers}. */\nexport type UseLongPressHandlersResult = LongPressHandlers & {\n    /**\n     * Reads whether the most recent interaction fired a long-press. Use it in\n     * the element's `onClick` to suppress the click that follows a long-press.\n     */\n    wasLongPress: () => boolean;\n};\n\n/**\n * Returns DOM event handlers that detect a long press (touch or mouse hold)\n * and invoke `onLongPress` once after `delayMs`.\n *\n * Cancels on touch movement or pointer release. Also wires `contextmenu` to\n * fire `onLongPress` immediately so a right-click on desktop opens selection\n * mode the same way an Android long-press does on mobile.\n *\n * The hook does not `preventDefault` on the underlying click — the consumer\n * decides whether the subsequent click should still fire. Track that with the\n * returned `wasLongPress()` guard to tell \"long-press fired\" apart from a\n * \"regular click\".\n *\n * Unlike {@link useLongPress}, which attaches pointer listeners to a `ref`,\n * this variant returns handler props you spread directly onto an element and\n * exposes a `wasLongPress()` guard.\n *\n * @param onLongPress - Callback invoked once the hold threshold is reached.\n * @param options - Optional `delayMs` and `disabled` flags.\n * @returns The spreadable handlers plus a `wasLongPress()` guard.\n *\n * @example\n * const longPress = useLongPressHandlers(() => enterSelectionMode(), { delayMs: 600 });\n * <button {...longPress} onClick={() => { if (!longPress.wasLongPress()) navigate(); }}>\n *   Item\n * </button>\n */\nexport function useLongPressHandlers(\n    onLongPress: () => void,\n    options: UseLongPressHandlersOptions = {},\n): UseLongPressHandlersResult {\n    const { delayMs = 500, disabled = false } = options;\n    const timerRef = useRef<number | null>(null);\n    const firedRef = useRef<boolean>(false);\n    const callbackRef = useLatestRef(onLongPress);\n\n    const clear = useCallback((): void => {\n        if (timerRef.current !== null) {\n            window.clearTimeout(timerRef.current);\n            timerRef.current = null;\n        }\n    }, []);\n\n    const start = useCallback((): void => {\n        if (disabled) return;\n        firedRef.current = false;\n        clear();\n        timerRef.current = window.setTimeout(() => {\n            firedRef.current = true;\n            callbackRef.current();\n        }, delayMs);\n    }, [disabled, clear, delayMs, callbackRef]);\n\n    const onContextMenu = useCallback(\n        (event: ReactMouseEvent): void => {\n            if (disabled) return;\n            event.preventDefault();\n            firedRef.current = true;\n            callbackRef.current();\n        },\n        [disabled, callbackRef],\n    );\n\n    return {\n        onMouseDown: start,\n        onMouseUp: clear,\n        onMouseLeave: clear,\n        onTouchStart: start,\n        onTouchEnd: clear,\n        onTouchMove: clear,\n        onContextMenu,\n        wasLongPress: () => firedRef.current,\n    };\n}\n"],"mappings":"+DAqEA,SAAgB,EACZ,EACA,EAAuC,CAAC,EACd,CAC1B,GAAM,CAAE,UAAU,IAAK,WAAW,IAAU,EACtC,GAAA,EAAW,EAAA,OAAA,CAAsB,IAAI,EACrC,GAAA,EAAW,EAAA,OAAA,CAAgB,EAAK,EAChC,EAAc,EAAA,aAAa,CAAW,EAEtC,GAAA,EAAQ,EAAA,YAAA,KAAwB,CAC9B,EAAS,UAAY,OACrB,OAAO,aAAa,EAAS,OAAO,EACpC,EAAS,QAAU,KAE3B,EAAG,CAAC,CAAC,EAEC,GAAA,EAAQ,EAAA,YAAA,KAAwB,CAC9B,IACJ,EAAS,QAAU,GACnB,EAAM,EACN,EAAS,QAAU,OAAO,eAAiB,CACvC,EAAS,QAAU,GACnB,EAAY,QAAQ,CACxB,EAAG,CAAO,EACd,EAAG,CAAC,EAAU,EAAO,EAAS,CAAW,CAAC,EAY1C,MAAO,CACH,YAAa,EACb,UAAW,EACX,aAAc,EACd,aAAc,EACd,WAAY,EACZ,YAAa,EACb,eAAA,EAjBkB,EAAA,YAAA,CACjB,GAAiC,CAC1B,IACJ,EAAM,eAAe,EACrB,EAAS,QAAU,GACnB,EAAY,QAAQ,EACxB,EACA,CAAC,EAAU,CAAW,CAUtB,EACA,iBAAoB,EAAS,OACjC,CACJ"}