@msobiecki/react-marauders-path 1.24.3 → 1.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +142 -7
  2. package/dist/index.d.ts +100 -0
  3. package/dist/index.js +29 -17
  4. package/dist/index.js.map +1 -1
  5. package/dist/use-double-tap/invoke-double-tap-action.js +7 -0
  6. package/dist/use-double-tap/invoke-double-tap-action.js.map +1 -0
  7. package/dist/use-double-tap/use-double-tap.js +77 -0
  8. package/dist/use-double-tap/use-double-tap.js.map +1 -0
  9. package/dist/use-double-tap/use-double-tap.types.js +9 -0
  10. package/dist/use-double-tap/use-double-tap.types.js.map +1 -0
  11. package/dist/use-drag/use-drag.js +68 -70
  12. package/dist/use-drag/use-drag.js.map +1 -1
  13. package/dist/use-key/use-key.js +96 -104
  14. package/dist/use-key/use-key.js.map +1 -1
  15. package/dist/use-pinch/use-pinch.js +77 -79
  16. package/dist/use-pinch/use-pinch.js.map +1 -1
  17. package/dist/use-press/invoke-press-action.js +7 -0
  18. package/dist/use-press/invoke-press-action.js.map +1 -0
  19. package/dist/use-press/use-press.js +98 -0
  20. package/dist/use-press/use-press.js.map +1 -0
  21. package/dist/use-press/use-press.types.js +9 -0
  22. package/dist/use-press/use-press.types.js.map +1 -0
  23. package/dist/use-swipe/use-swipe.js +61 -68
  24. package/dist/use-swipe/use-swipe.js.map +1 -1
  25. package/dist/use-tap/invoke-tap-action.js +7 -0
  26. package/dist/use-tap/invoke-tap-action.js.map +1 -0
  27. package/dist/use-tap/use-tap.js +94 -0
  28. package/dist/use-tap/use-tap.js.map +1 -0
  29. package/dist/use-tap/use-tap.types.js +9 -0
  30. package/dist/use-tap/use-tap.types.js.map +1 -0
  31. package/dist/use-wheel/use-wheel.js +33 -47
  32. package/dist/use-wheel/use-wheel.js.map +1 -1
  33. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"use-key.js","sources":["../../src/use-key/use-key.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from \"react\";\n\nimport {\n KeyOptions,\n SequenceState,\n UseKeySchema,\n UseKeyCallback,\n UseKeyOptions,\n CombinationState,\n KeyEventTypes,\n} from \"./use-key.types\";\nimport { parseKeySequences } from \"./parse-key-sequences\";\nimport { advanceSequenceState, resetSequenceState } from \"./sequence-state\";\nimport { invokeKeyAction } from \"./invoke-key-action\";\nimport { shouldHandleKeyboardEvent } from \"./event-guards\";\nimport { SPECIAL_KEYS } from \"./normalize-key\";\n\nconst defaultOptions: KeyOptions = {\n eventType: KeyEventTypes.KeyUp,\n eventRepeat: false,\n eventCapture: false,\n eventOnce: false,\n eventStopImmediatePropagation: false,\n sequenceThreshold: 1000,\n combinationThreshold: 200,\n container: { current: null },\n};\n\n/**\n * React hook for handling keyboard events with support for key sequences and combinations.\n *\n * Enables listening for single key presses, key combinations, and sequential key presses.\n * Supports customizable options like event type, repeat handling, and one-time listeners.\n *\n * @template T - The callback function type\n * @param {UseKeySchema} key - Single key, combination, sequence, or array of patterns to listen for\n * @param {UseKeyCallback} keyCallback - Callback function invoked when key pattern matches\n * @param {UseKeyOptions} [options] - Configuration options for the hook\n * @param {KeyEventType} [options.eventType=KeyEventTypes.KeyUp] - Type of keyboard event ('keydown' or 'keyup')\n * @param {boolean} [options.eventRepeat=false] - Allow repeated key presses to trigger callback\n * @param {boolean} [options.eventCapture=false] - Use event capture phase instead of bubbling\n * @param {boolean} [options.eventOnce=false] - Trigger callback only once\n * @param {boolean} [options.eventStopImmediatePropagation=false] - Stop immediate propagation\n * @param {number} [options.sequenceThreshold=1000] - Timeout in ms between sequence keys\n * @param {number} [options.combinationThreshold=200] - Timeout in ms between combination keys\n * @param {RefObject<HTMLElement>} [options.container] - DOM element to attach listener to (default: window)\n *\n * @example\n * // Single key schema\n * useKey('a', (event, key) => console.log(`Pressed ${key}`));\n *\n * @example\n * // Multiple patterns of single key schema\n * useKey(['a', 'b', 'c'], (event, key) => console.log(`Pressed ${key}`));\n *\n * @example\n * // Combination key schema\n * useKey('a+b', (event, key) => {\n * console.log(`Pressed ${key}`);\n * });\n *\n * @example\n * // Multiple patterns of combination key schema\n * useKey(['a+b', 'c+d'], (event, key) => {\n * console.log(`Pressed ${key}`);\n * });\n *\n * @example\n * // Sequential key schema\n * useKey('ArrowUp ArrowUp ArrowDown ArrowDown', (event, key) => {\n * console.log(`Pressed ${key}`);\n * });\n *\n * @example\n * // Multiple patterns of sequential key schema\n * useKey(['ArrowUp ArrowUp ArrowDown ArrowDown', 'ArrowLeft ArrowRight'], (event, key) => {\n * console.log(`Pressed ${key}`);\n * });\n *\n * @example\n * // Using options to listen for a key on keydown event and stop propagation\n * useKey('Any', handleSubmit, {\n * eventType: KeyEventTypes.KeyDown,\n * eventStopImmediatePropagation: true,\n * container: inputRef\n * });\n *\n */\nconst useKey = (\n key: UseKeySchema,\n keyCallback: UseKeyCallback,\n options: UseKeyOptions = defaultOptions,\n) => {\n const {\n eventType,\n eventRepeat,\n eventCapture,\n eventOnce,\n eventStopImmediatePropagation,\n sequenceThreshold,\n combinationThreshold,\n container,\n } = { ...defaultOptions, ...options };\n\n const targetReference = useRef<EventTarget | null>(null);\n const abortControllerReference = useRef<AbortController | null>(null);\n\n const combinationReference = useRef<CombinationState>({\n activeKeys: new Map(),\n });\n const sequenceReference = useRef<SequenceState[]>([]);\n\n const destroyListener = useCallback(() => {\n if (abortControllerReference.current) {\n abortControllerReference.current.abort();\n }\n }, []);\n\n const resetCombination = useCallback(() => {\n combinationReference.current.activeKeys.clear();\n }, []);\n\n const resetSequence = useCallback((sequence: SequenceState) => {\n sequenceReference.current = resetSequenceState(\n sequence,\n sequenceReference.current,\n );\n }, []);\n\n const shouldProcessEvent = useCallback(\n (event: KeyboardEvent) => {\n return shouldHandleKeyboardEvent(event, {\n repeat: eventRepeat,\n });\n },\n [eventRepeat],\n );\n\n const registerKeyDown = useCallback((event: KeyboardEvent) => {\n const normalizedEventKey =\n event.key === \" \" ? SPECIAL_KEYS.SPACE : event.key;\n combinationReference.current.activeKeys.set(normalizedEventKey, {\n pressedAt: Date.now(),\n });\n }, []);\n\n const registerKeyUp = useCallback((event: KeyboardEvent) => {\n const normalizedEventKey =\n event.key === \" \" ? SPECIAL_KEYS.SPACE : event.key;\n const state =\n combinationReference.current.activeKeys.get(normalizedEventKey);\n if (state) state.releasedAt = Date.now();\n }, []);\n\n const cleanupCombinationKeys = useCallback(() => {\n const now = Date.now();\n const combo = combinationReference.current;\n\n [...combo.activeKeys.entries()].forEach(([key, state]) => {\n if (eventType === KeyEventTypes.KeyDown) {\n if (state.releasedAt) {\n combo.activeKeys.delete(key);\n }\n } else if (\n state.releasedAt &&\n now - state.releasedAt > combinationThreshold\n ) {\n combo.activeKeys.delete(key);\n }\n });\n }, [eventType, combinationThreshold]);\n\n const validateCombination = useCallback(\n (\n expectedKey: string[],\n activeKeys: Map<string, { pressedAt: number; releasedAt?: number }>,\n ): boolean => {\n if (eventType === KeyEventTypes.KeyDown) {\n return (\n activeKeys.size === expectedKey.length &&\n expectedKey.every((key) => {\n if (key === SPECIAL_KEYS.ANY) {\n return activeKeys.size > 0;\n }\n return activeKeys.has(key);\n })\n );\n }\n if (eventType === KeyEventTypes.KeyUp) {\n const keyStates = expectedKey.map((key) => {\n if (key === SPECIAL_KEYS.ANY) {\n const entries = [...activeKeys.entries()];\n const lastEntry = entries.at(-1);\n return lastEntry ? lastEntry[1] : undefined;\n }\n return activeKeys.get(key);\n });\n\n if (keyStates.some((state) => !state?.releasedAt)) {\n return false;\n }\n\n const pressedTimes: number[] = keyStates\n .map((state) => state?.pressedAt)\n .filter((value): value is number => value !== undefined);\n const releasedTimes: number[] = keyStates\n .map((state) => state?.releasedAt)\n .filter((value): value is number => value !== undefined);\n\n const minReleased = Math.min(...releasedTimes);\n const maxReleased = Math.max(...releasedTimes);\n const maxPressed = Math.max(...pressedTimes);\n\n if (maxPressed > minReleased) {\n return false;\n }\n\n if (maxReleased - minReleased > combinationThreshold) {\n return false;\n }\n\n return true;\n }\n\n return false;\n },\n [eventType, combinationThreshold],\n );\n\n const handleSingleKey = useCallback(\n (event: KeyboardEvent, sequence: SequenceState) => {\n const expectedKey = sequence.chord[0];\n\n if (Array.isArray(expectedKey)) {\n const { activeKeys } = combinationReference.current;\n\n if (!validateCombination(expectedKey, activeKeys)) {\n return;\n }\n\n invokeKeyAction(event, sequence.key, keyCallback, {\n stopImmediate: eventStopImmediatePropagation,\n once: eventOnce,\n onOnce: () => {\n destroyListener();\n },\n });\n\n return;\n }\n\n const normalizedEventKey =\n event.key === \" \" ? SPECIAL_KEYS.SPACE : event.key;\n if (\n expectedKey !== SPECIAL_KEYS.ANY &&\n expectedKey !== normalizedEventKey\n ) {\n return;\n }\n\n invokeKeyAction(event, sequence.key, keyCallback, {\n stopImmediate: eventStopImmediatePropagation,\n once: eventOnce,\n onOnce: () => {\n destroyListener();\n },\n });\n },\n [\n eventStopImmediatePropagation,\n eventOnce,\n keyCallback,\n validateCombination,\n destroyListener,\n ],\n );\n\n const handleSequenceStep = useCallback(\n (event: KeyboardEvent, sequence: SequenceState) => {\n const expectedKey = sequence.chord[sequence.index];\n\n if (Array.isArray(expectedKey)) {\n const { activeKeys } = combinationReference.current;\n\n if (!validateCombination(expectedKey, activeKeys)) {\n return;\n }\n\n const [updatedSequence, updatedSequences] = advanceSequenceState(\n sequence,\n sequenceReference.current,\n sequenceThreshold,\n resetSequence,\n );\n sequenceReference.current = updatedSequences;\n\n if (updatedSequence.index === updatedSequence.chord.length) {\n invokeKeyAction(event, updatedSequence.key, keyCallback, {\n stopImmediate: eventStopImmediatePropagation,\n once: eventOnce,\n onOnce: () => {\n destroyListener();\n },\n });\n\n resetSequence(updatedSequence);\n }\n\n return;\n }\n\n const normalizedEventKey =\n event.key === \" \" ? SPECIAL_KEYS.SPACE : event.key;\n if (\n expectedKey !== SPECIAL_KEYS.ANY &&\n expectedKey !== normalizedEventKey\n ) {\n resetSequence(sequence);\n return;\n }\n\n const [updatedSequence, updatedSequences] = advanceSequenceState(\n sequence,\n sequenceReference.current,\n sequenceThreshold,\n resetSequence,\n );\n sequenceReference.current = updatedSequences;\n\n if (updatedSequence.index === updatedSequence.chord.length) {\n invokeKeyAction(event, updatedSequence.key, keyCallback, {\n stopImmediate: eventStopImmediatePropagation,\n once: eventOnce,\n onOnce: () => {\n destroyListener();\n },\n });\n\n resetSequence(updatedSequence);\n }\n },\n [\n eventOnce,\n eventStopImmediatePropagation,\n sequenceThreshold,\n keyCallback,\n resetSequence,\n validateCombination,\n destroyListener,\n ],\n );\n\n const evaluateSequences = useCallback(\n (event: KeyboardEvent) => {\n sequenceReference.current.forEach((sequence) => {\n if (sequence.chord.length === 1) {\n handleSingleKey(event, sequence);\n } else {\n handleSequenceStep(event, sequence);\n }\n });\n },\n [handleSingleKey, handleSequenceStep],\n );\n\n const handleEventListener = useCallback(\n (event: KeyboardEvent) => {\n if (!shouldProcessEvent(event)) {\n return;\n }\n\n cleanupCombinationKeys();\n evaluateSequences(event);\n },\n [shouldProcessEvent, cleanupCombinationKeys, evaluateSequences],\n );\n\n useEffect(() => {\n sequenceReference.current = parseKeySequences(key);\n }, [key]);\n\n useEffect(() => {\n targetReference.current = container?.current ?? globalThis;\n abortControllerReference.current = new AbortController();\n\n const keyDownListener = (event: Event) =>\n registerKeyDown(event as KeyboardEvent);\n targetReference.current.addEventListener(\"keydown\", keyDownListener, {\n capture: eventCapture,\n signal: abortControllerReference.current.signal,\n });\n\n const keyUpListener = (event: Event) =>\n registerKeyUp(event as KeyboardEvent);\n targetReference.current.addEventListener(\"keyup\", keyUpListener, {\n capture: eventCapture,\n signal: abortControllerReference.current.signal,\n });\n\n const eventListener = (event: Event) =>\n handleEventListener(event as KeyboardEvent);\n\n targetReference.current.addEventListener(eventType, eventListener, {\n capture: eventCapture,\n signal: abortControllerReference.current.signal,\n });\n\n return () => {\n abortControllerReference.current?.abort();\n\n resetCombination();\n sequenceReference.current.forEach((sequence) => resetSequence(sequence));\n };\n }, [\n eventType,\n eventCapture,\n container,\n registerKeyDown,\n registerKeyUp,\n handleEventListener,\n resetCombination,\n resetSequence,\n ]);\n};\n\nexport default useKey;\n"],"names":["defaultOptions","KeyEventTypes","useKey","key","keyCallback","options","eventType","eventRepeat","eventCapture","eventOnce","eventStopImmediatePropagation","sequenceThreshold","combinationThreshold","container","targetReference","useRef","abortControllerReference","combinationReference","sequenceReference","destroyListener","useCallback","resetCombination","resetSequence","sequence","resetSequenceState","shouldProcessEvent","event","shouldHandleKeyboardEvent","registerKeyDown","normalizedEventKey","SPECIAL_KEYS","registerKeyUp","state","cleanupCombinationKeys","now","combo","validateCombination","expectedKey","activeKeys","keyStates","lastEntry","pressedTimes","value","releasedTimes","minReleased","maxReleased","handleSingleKey","invokeKeyAction","handleSequenceStep","updatedSequence","updatedSequences","advanceSequenceState","evaluateSequences","handleEventListener","useEffect","parseKeySequences","keyDownListener","keyUpListener","eventListener"],"mappings":"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"}
1
+ {"version":3,"file":"use-key.js","sources":["../../src/use-key/use-key.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from \"react\";\n\nimport {\n KeyOptions,\n SequenceState,\n UseKeySchema,\n UseKeyCallback,\n UseKeyOptions,\n CombinationState,\n KeyEventTypes,\n} from \"./use-key.types\";\nimport { parseKeySequences } from \"./parse-key-sequences\";\nimport { advanceSequenceState, resetSequenceState } from \"./sequence-state\";\nimport { invokeKeyAction } from \"./invoke-key-action\";\nimport { shouldHandleKeyboardEvent } from \"./event-guards\";\nimport { SPECIAL_KEYS } from \"./normalize-key\";\n\nconst defaultOptions: KeyOptions = {\n eventType: KeyEventTypes.KeyUp,\n eventRepeat: false,\n eventCapture: false,\n eventOnce: false,\n eventStopImmediatePropagation: false,\n sequenceThreshold: 1000,\n combinationThreshold: 200,\n container: { current: null },\n};\n\n/**\n * React hook for handling keyboard events with support for key sequences and combinations.\n *\n * Enables listening for single key presses, key combinations, and sequential key presses.\n * Supports customizable options like event type, repeat handling, and one-time listeners.\n *\n * @template T - The callback function type\n * @param {UseKeySchema} key - Single key, combination, sequence, or array of patterns to listen for\n * @param {UseKeyCallback} keyCallback - Callback function invoked when key pattern matches\n * @param {UseKeyOptions} [options] - Configuration options for the hook\n * @param {KeyEventType} [options.eventType=KeyEventTypes.KeyUp] - Type of keyboard event ('keydown' or 'keyup')\n * @param {boolean} [options.eventRepeat=false] - Allow repeated key presses to trigger callback\n * @param {boolean} [options.eventCapture=false] - Use event capture phase instead of bubbling\n * @param {boolean} [options.eventOnce=false] - Trigger callback only once\n * @param {boolean} [options.eventStopImmediatePropagation=false] - Stop immediate propagation\n * @param {number} [options.sequenceThreshold=1000] - Timeout in ms between sequence keys\n * @param {number} [options.combinationThreshold=200] - Timeout in ms between combination keys\n * @param {RefObject<HTMLElement>} [options.container] - DOM element to attach listener to (default: window)\n *\n * @example\n * // Single key schema\n * useKey('a', (event, key) => console.log(`Pressed ${key}`));\n *\n * @example\n * // Multiple patterns of single key schema\n * useKey(['a', 'b', 'c'], (event, key) => console.log(`Pressed ${key}`));\n *\n * @example\n * // Combination key schema\n * useKey('a+b', (event, key) => {\n * console.log(`Pressed ${key}`);\n * });\n *\n * @example\n * // Multiple patterns of combination key schema\n * useKey(['a+b', 'c+d'], (event, key) => {\n * console.log(`Pressed ${key}`);\n * });\n *\n * @example\n * // Sequential key schema\n * useKey('ArrowUp ArrowUp ArrowDown ArrowDown', (event, key) => {\n * console.log(`Pressed ${key}`);\n * });\n *\n * @example\n * // Multiple patterns of sequential key schema\n * useKey(['ArrowUp ArrowUp ArrowDown ArrowDown', 'ArrowLeft ArrowRight'], (event, key) => {\n * console.log(`Pressed ${key}`);\n * });\n *\n * @example\n * // Using options to listen for a key on keydown event and stop propagation\n * useKey('Any', handleSubmit, {\n * eventType: KeyEventTypes.KeyDown,\n * eventStopImmediatePropagation: true,\n * container: inputRef\n * });\n *\n */\nconst useKey = (\n key: UseKeySchema,\n keyCallback: UseKeyCallback,\n options: UseKeyOptions = defaultOptions,\n) => {\n const {\n eventType,\n eventRepeat,\n eventCapture,\n eventOnce,\n eventStopImmediatePropagation,\n sequenceThreshold,\n combinationThreshold,\n container,\n } = { ...defaultOptions, ...options };\n\n const targetReference = useRef<EventTarget | null>(null);\n const abortControllerReference = useRef<AbortController | null>(null);\n\n const combinationReference = useRef<CombinationState>({\n activeKeys: new Map(),\n });\n const sequenceReference = useRef<SequenceState[]>([]);\n\n const resetCombination = useCallback(() => {\n combinationReference.current.activeKeys.clear();\n }, []);\n\n const resetSequence = useCallback((sequence: SequenceState) => {\n sequenceReference.current = resetSequenceState(\n sequence,\n sequenceReference.current,\n );\n }, []);\n\n const shouldProcessEvent = useCallback(\n (event: KeyboardEvent) => {\n return shouldHandleKeyboardEvent(event, {\n repeat: eventRepeat,\n });\n },\n [eventRepeat],\n );\n\n const registerKeyDown = useCallback((event: KeyboardEvent) => {\n const normalizedEventKey =\n event.key === \" \" ? SPECIAL_KEYS.SPACE : event.key;\n combinationReference.current.activeKeys.set(normalizedEventKey, {\n pressedAt: Date.now(),\n });\n }, []);\n\n const registerKeyUp = useCallback((event: KeyboardEvent) => {\n const normalizedEventKey =\n event.key === \" \" ? SPECIAL_KEYS.SPACE : event.key;\n const state =\n combinationReference.current.activeKeys.get(normalizedEventKey);\n if (state) state.releasedAt = Date.now();\n }, []);\n\n const cleanupCombinationKeys = useCallback(() => {\n const now = Date.now();\n const combo = combinationReference.current;\n\n [...combo.activeKeys.entries()].forEach(([key, state]) => {\n if (eventType === KeyEventTypes.KeyDown) {\n if (state.releasedAt) {\n combo.activeKeys.delete(key);\n }\n } else if (\n state.releasedAt &&\n now - state.releasedAt > combinationThreshold\n ) {\n combo.activeKeys.delete(key);\n }\n });\n }, [eventType, combinationThreshold]);\n\n const validateCombination = useCallback(\n (\n expectedKey: string[],\n activeKeys: Map<string, { pressedAt: number; releasedAt?: number }>,\n ): boolean => {\n if (eventType === KeyEventTypes.KeyDown) {\n return (\n activeKeys.size === expectedKey.length &&\n expectedKey.every((key) => {\n if (key === SPECIAL_KEYS.ANY) {\n return activeKeys.size > 0;\n }\n return activeKeys.has(key);\n })\n );\n }\n if (eventType === KeyEventTypes.KeyUp) {\n const keyStates = expectedKey.map((key) => {\n if (key === SPECIAL_KEYS.ANY) {\n const entries = [...activeKeys.entries()];\n const lastEntry = entries.at(-1);\n return lastEntry ? lastEntry[1] : undefined;\n }\n return activeKeys.get(key);\n });\n\n if (keyStates.some((state) => !state?.releasedAt)) {\n return false;\n }\n\n const pressedTimes: number[] = keyStates\n .map((state) => state?.pressedAt)\n .filter((value): value is number => value !== undefined);\n const releasedTimes: number[] = keyStates\n .map((state) => state?.releasedAt)\n .filter((value): value is number => value !== undefined);\n\n const minReleased = Math.min(...releasedTimes);\n const maxReleased = Math.max(...releasedTimes);\n const maxPressed = Math.max(...pressedTimes);\n\n if (maxPressed > minReleased) {\n return false;\n }\n\n if (maxReleased - minReleased > combinationThreshold) {\n return false;\n }\n\n return true;\n }\n\n return false;\n },\n [eventType, combinationThreshold],\n );\n\n const handleSingleKey = useCallback(\n (event: KeyboardEvent, sequence: SequenceState) => {\n const expectedKey = sequence.chord[0];\n\n if (Array.isArray(expectedKey)) {\n const { activeKeys } = combinationReference.current;\n\n if (!validateCombination(expectedKey, activeKeys)) {\n return;\n }\n\n invokeKeyAction(event, sequence.key, keyCallback, {\n stopImmediate: eventStopImmediatePropagation,\n once: eventOnce,\n onOnce: () => {\n abortControllerReference.current?.abort();\n },\n });\n\n return;\n }\n\n const normalizedEventKey =\n event.key === \" \" ? SPECIAL_KEYS.SPACE : event.key;\n if (\n expectedKey !== SPECIAL_KEYS.ANY &&\n expectedKey !== normalizedEventKey\n ) {\n return;\n }\n\n invokeKeyAction(event, sequence.key, keyCallback, {\n stopImmediate: eventStopImmediatePropagation,\n once: eventOnce,\n onOnce: () => {\n abortControllerReference.current?.abort();\n },\n });\n },\n [\n eventStopImmediatePropagation,\n eventOnce,\n keyCallback,\n validateCombination,\n ],\n );\n\n const handleSequenceStep = useCallback(\n (event: KeyboardEvent, sequence: SequenceState) => {\n const expectedKey = sequence.chord[sequence.index];\n\n if (Array.isArray(expectedKey)) {\n const { activeKeys } = combinationReference.current;\n\n if (!validateCombination(expectedKey, activeKeys)) {\n return;\n }\n\n const [updatedSequence, updatedSequences] = advanceSequenceState(\n sequence,\n sequenceReference.current,\n sequenceThreshold,\n resetSequence,\n );\n sequenceReference.current = updatedSequences;\n\n if (updatedSequence.index === updatedSequence.chord.length) {\n invokeKeyAction(event, updatedSequence.key, keyCallback, {\n stopImmediate: eventStopImmediatePropagation,\n once: eventOnce,\n onOnce: () => {\n abortControllerReference.current?.abort();\n },\n });\n\n resetSequence(updatedSequence);\n }\n\n return;\n }\n\n const normalizedEventKey =\n event.key === \" \" ? SPECIAL_KEYS.SPACE : event.key;\n if (\n expectedKey !== SPECIAL_KEYS.ANY &&\n expectedKey !== normalizedEventKey\n ) {\n resetSequence(sequence);\n return;\n }\n\n const [updatedSequence, updatedSequences] = advanceSequenceState(\n sequence,\n sequenceReference.current,\n sequenceThreshold,\n resetSequence,\n );\n sequenceReference.current = updatedSequences;\n\n if (updatedSequence.index === updatedSequence.chord.length) {\n invokeKeyAction(event, updatedSequence.key, keyCallback, {\n stopImmediate: eventStopImmediatePropagation,\n once: eventOnce,\n onOnce: () => {\n abortControllerReference.current?.abort();\n },\n });\n\n resetSequence(updatedSequence);\n }\n },\n [\n eventOnce,\n eventStopImmediatePropagation,\n sequenceThreshold,\n keyCallback,\n resetSequence,\n validateCombination,\n ],\n );\n\n const evaluateSequences = useCallback(\n (event: KeyboardEvent) => {\n sequenceReference.current.forEach((sequence) => {\n if (sequence.chord.length === 1) {\n handleSingleKey(event, sequence);\n } else {\n handleSequenceStep(event, sequence);\n }\n });\n },\n [handleSingleKey, handleSequenceStep],\n );\n\n const handleEventListener = useCallback(\n (event: KeyboardEvent) => {\n if (!shouldProcessEvent(event)) {\n return;\n }\n\n cleanupCombinationKeys();\n evaluateSequences(event);\n },\n [shouldProcessEvent, cleanupCombinationKeys, evaluateSequences],\n );\n\n useEffect(() => {\n sequenceReference.current = parseKeySequences(key);\n }, [key]);\n\n useEffect(() => {\n targetReference.current = container?.current ?? globalThis;\n abortControllerReference.current = new AbortController();\n const { signal } = abortControllerReference.current;\n\n const keyDownListener = (event: Event) =>\n registerKeyDown(event as KeyboardEvent);\n\n const keyUpListener = (event: Event) =>\n registerKeyUp(event as KeyboardEvent);\n\n const eventListener = (event: Event) =>\n handleEventListener(event as KeyboardEvent);\n\n targetReference.current.addEventListener(\"keydown\", keyDownListener, {\n capture: eventCapture,\n signal,\n });\n\n targetReference.current.addEventListener(\"keyup\", keyUpListener, {\n capture: eventCapture,\n signal,\n });\n\n targetReference.current.addEventListener(eventType, eventListener, {\n capture: eventCapture,\n signal,\n });\n\n return () => {\n abortControllerReference.current?.abort();\n\n resetCombination();\n sequenceReference.current.forEach((sequence) => resetSequence(sequence));\n };\n }, [\n eventType,\n eventCapture,\n container,\n registerKeyDown,\n registerKeyUp,\n handleEventListener,\n resetCombination,\n resetSequence,\n ]);\n};\n\nexport default useKey;\n"],"names":["defaultOptions","KeyEventTypes","useKey","key","keyCallback","options","eventType","eventRepeat","eventCapture","eventOnce","eventStopImmediatePropagation","sequenceThreshold","combinationThreshold","container","targetReference","useRef","abortControllerReference","combinationReference","sequenceReference","resetCombination","useCallback","resetSequence","sequence","resetSequenceState","shouldProcessEvent","event","shouldHandleKeyboardEvent","registerKeyDown","normalizedEventKey","SPECIAL_KEYS","registerKeyUp","state","cleanupCombinationKeys","now","combo","validateCombination","expectedKey","activeKeys","keyStates","lastEntry","pressedTimes","value","releasedTimes","minReleased","maxReleased","handleSingleKey","invokeKeyAction","handleSequenceStep","updatedSequence","updatedSequences","advanceSequenceState","evaluateSequences","handleEventListener","useEffect","parseKeySequences","signal","keyDownListener","keyUpListener","eventListener"],"mappings":";;;;;;;AAiBA,MAAMA,IAA6B;AAAA,EACjC,WAAWC,EAAc;AAAA,EACzB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,WAAW;AAAA,EACX,+BAA+B;AAAA,EAC/B,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,WAAW,EAAE,SAAS,KAAA;AACxB,GA8DMC,KAAS,CACbC,GACAC,GACAC,IAAyBL,MACtB;AACH,QAAM;AAAA,IACJ,WAAAM;AAAA,IACA,aAAAC;AAAA,IACA,cAAAC;AAAA,IACA,WAAAC;AAAA,IACA,+BAAAC;AAAA,IACA,mBAAAC;AAAA,IACA,sBAAAC;AAAA,IACA,WAAAC;AAAA,EAAA,IACE,EAAE,GAAGb,GAAgB,GAAGK,EAAA,GAEtBS,IAAkBC,EAA2B,IAAI,GACjDC,IAA2BD,EAA+B,IAAI,GAE9DE,IAAuBF,EAAyB;AAAA,IACpD,gCAAgB,IAAA;AAAA,EAAI,CACrB,GACKG,IAAoBH,EAAwB,EAAE,GAE9CI,IAAmBC,EAAY,MAAM;AACzC,IAAAH,EAAqB,QAAQ,WAAW,MAAA;AAAA,EAC1C,GAAG,CAAA,CAAE,GAECI,IAAgBD,EAAY,CAACE,MAA4B;AAC7D,IAAAJ,EAAkB,UAAUK;AAAA,MAC1BD;AAAA,MACAJ,EAAkB;AAAA,IAAA;AAAA,EAEtB,GAAG,CAAA,CAAE,GAECM,IAAqBJ;AAAA,IACzB,CAACK,MACQC,EAA0BD,GAAO;AAAA,MACtC,QAAQlB;AAAA,IAAA,CACT;AAAA,IAEH,CAACA,CAAW;AAAA,EAAA,GAGRoB,IAAkBP,EAAY,CAACK,MAAyB;AAC5D,UAAMG,IACJH,EAAM,QAAQ,MAAMI,EAAa,QAAQJ,EAAM;AACjD,IAAAR,EAAqB,QAAQ,WAAW,IAAIW,GAAoB;AAAA,MAC9D,WAAW,KAAK,IAAA;AAAA,IAAI,CACrB;AAAA,EACH,GAAG,CAAA,CAAE,GAECE,IAAgBV,EAAY,CAACK,MAAyB;AAC1D,UAAMG,IACJH,EAAM,QAAQ,MAAMI,EAAa,QAAQJ,EAAM,KAC3CM,IACJd,EAAqB,QAAQ,WAAW,IAAIW,CAAkB;AAChE,IAAIG,MAAOA,EAAM,aAAa,KAAK,IAAA;AAAA,EACrC,GAAG,CAAA,CAAE,GAECC,IAAyBZ,EAAY,MAAM;AAC/C,UAAMa,IAAM,KAAK,IAAA,GACXC,IAAQjB,EAAqB;AAEnC,KAAC,GAAGiB,EAAM,WAAW,QAAA,CAAS,EAAE,QAAQ,CAAC,CAAC/B,GAAK4B,CAAK,MAAM;AACxD,MAAIzB,MAAcL,EAAc,UAC1B8B,EAAM,cACRG,EAAM,WAAW,OAAO/B,CAAG,IAG7B4B,EAAM,cACNE,IAAMF,EAAM,aAAanB,KAEzBsB,EAAM,WAAW,OAAO/B,CAAG;AAAA,IAE/B,CAAC;AAAA,EACH,GAAG,CAACG,GAAWM,CAAoB,CAAC,GAE9BuB,IAAsBf;AAAA,IAC1B,CACEgB,GACAC,MACY;AACZ,UAAI/B,MAAcL,EAAc;AAC9B,eACEoC,EAAW,SAASD,EAAY,UAChCA,EAAY,MAAM,CAACjC,MACbA,MAAQ0B,EAAa,MAChBQ,EAAW,OAAO,IAEpBA,EAAW,IAAIlC,CAAG,CAC1B;AAGL,UAAIG,MAAcL,EAAc,OAAO;AACrC,cAAMqC,IAAYF,EAAY,IAAI,CAACjC,MAAQ;AACzC,cAAIA,MAAQ0B,EAAa,KAAK;AAE5B,kBAAMU,IADU,CAAC,GAAGF,EAAW,SAAS,EACd,GAAG,EAAE;AAC/B,mBAAOE,IAAYA,EAAU,CAAC,IAAI;AAAA,UACpC;AACA,iBAAOF,EAAW,IAAIlC,CAAG;AAAA,QAC3B,CAAC;AAED,YAAImC,EAAU,KAAK,CAACP,MAAU,CAACA,GAAO,UAAU;AAC9C,iBAAO;AAGT,cAAMS,IAAyBF,EAC5B,IAAI,CAACP,MAAUA,GAAO,SAAS,EAC/B,OAAO,CAACU,MAA2BA,MAAU,MAAS,GACnDC,IAA0BJ,EAC7B,IAAI,CAACP,MAAUA,GAAO,UAAU,EAChC,OAAO,CAACU,MAA2BA,MAAU,MAAS,GAEnDE,IAAc,KAAK,IAAI,GAAGD,CAAa,GACvCE,IAAc,KAAK,IAAI,GAAGF,CAAa;AAO7C,eAJI,EAFe,KAAK,IAAI,GAAGF,CAAY,IAE1BG,KAIbC,IAAcD,IAAc/B;AAAA,MAKlC;AAEA,aAAO;AAAA,IACT;AAAA,IACA,CAACN,GAAWM,CAAoB;AAAA,EAAA,GAG5BiC,IAAkBzB;AAAA,IACtB,CAACK,GAAsBH,MAA4B;AACjD,YAAMc,IAAcd,EAAS,MAAM,CAAC;AAEpC,UAAI,MAAM,QAAQc,CAAW,GAAG;AAC9B,cAAM,EAAE,YAAAC,MAAepB,EAAqB;AAE5C,YAAI,CAACkB,EAAoBC,GAAaC,CAAU;AAC9C;AAGF,QAAAS,EAAgBrB,GAAOH,EAAS,KAAKlB,GAAa;AAAA,UAChD,eAAeM;AAAA,UACf,MAAMD;AAAA,UACN,QAAQ,MAAM;AACZ,YAAAO,EAAyB,SAAS,MAAA;AAAA,UACpC;AAAA,QAAA,CACD;AAED;AAAA,MACF;AAEA,YAAMY,IACJH,EAAM,QAAQ,MAAMI,EAAa,QAAQJ,EAAM;AACjD,MACEW,MAAgBP,EAAa,OAC7BO,MAAgBR,KAKlBkB,EAAgBrB,GAAOH,EAAS,KAAKlB,GAAa;AAAA,QAChD,eAAeM;AAAA,QACf,MAAMD;AAAA,QACN,QAAQ,MAAM;AACZ,UAAAO,EAAyB,SAAS,MAAA;AAAA,QACpC;AAAA,MAAA,CACD;AAAA,IACH;AAAA,IACA;AAAA,MACEN;AAAA,MACAD;AAAA,MACAL;AAAA,MACA+B;AAAA,IAAA;AAAA,EACF,GAGIY,IAAqB3B;AAAA,IACzB,CAACK,GAAsBH,MAA4B;AACjD,YAAMc,IAAcd,EAAS,MAAMA,EAAS,KAAK;AAEjD,UAAI,MAAM,QAAQc,CAAW,GAAG;AAC9B,cAAM,EAAE,YAAAC,MAAepB,EAAqB;AAE5C,YAAI,CAACkB,EAAoBC,GAAaC,CAAU;AAC9C;AAGF,cAAM,CAACW,GAAiBC,CAAgB,IAAIC;AAAA,UAC1C5B;AAAA,UACAJ,EAAkB;AAAA,UAClBP;AAAA,UACAU;AAAA,QAAA;AAEF,QAAAH,EAAkB,UAAU+B,GAExBD,EAAgB,UAAUA,EAAgB,MAAM,WAClDF,EAAgBrB,GAAOuB,EAAgB,KAAK5C,GAAa;AAAA,UACvD,eAAeM;AAAA,UACf,MAAMD;AAAA,UACN,QAAQ,MAAM;AACZ,YAAAO,EAAyB,SAAS,MAAA;AAAA,UACpC;AAAA,QAAA,CACD,GAEDK,EAAc2B,CAAe;AAG/B;AAAA,MACF;AAEA,YAAMpB,IACJH,EAAM,QAAQ,MAAMI,EAAa,QAAQJ,EAAM;AACjD,UACEW,MAAgBP,EAAa,OAC7BO,MAAgBR,GAChB;AACA,QAAAP,EAAcC,CAAQ;AACtB;AAAA,MACF;AAEA,YAAM,CAAC0B,GAAiBC,CAAgB,IAAIC;AAAA,QAC1C5B;AAAA,QACAJ,EAAkB;AAAA,QAClBP;AAAA,QACAU;AAAA,MAAA;AAEF,MAAAH,EAAkB,UAAU+B,GAExBD,EAAgB,UAAUA,EAAgB,MAAM,WAClDF,EAAgBrB,GAAOuB,EAAgB,KAAK5C,GAAa;AAAA,QACvD,eAAeM;AAAA,QACf,MAAMD;AAAA,QACN,QAAQ,MAAM;AACZ,UAAAO,EAAyB,SAAS,MAAA;AAAA,QACpC;AAAA,MAAA,CACD,GAEDK,EAAc2B,CAAe;AAAA,IAEjC;AAAA,IACA;AAAA,MACEvC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAP;AAAA,MACAiB;AAAA,MACAc;AAAA,IAAA;AAAA,EACF,GAGIgB,IAAoB/B;AAAA,IACxB,CAACK,MAAyB;AACxB,MAAAP,EAAkB,QAAQ,QAAQ,CAACI,MAAa;AAC9C,QAAIA,EAAS,MAAM,WAAW,IAC5BuB,EAAgBpB,GAAOH,CAAQ,IAE/ByB,EAAmBtB,GAAOH,CAAQ;AAAA,MAEtC,CAAC;AAAA,IACH;AAAA,IACA,CAACuB,GAAiBE,CAAkB;AAAA,EAAA,GAGhCK,IAAsBhC;AAAA,IAC1B,CAACK,MAAyB;AACxB,MAAKD,EAAmBC,CAAK,MAI7BO,EAAA,GACAmB,EAAkB1B,CAAK;AAAA,IACzB;AAAA,IACA,CAACD,GAAoBQ,GAAwBmB,CAAiB;AAAA,EAAA;AAGhE,EAAAE,EAAU,MAAM;AACd,IAAAnC,EAAkB,UAAUoC,EAAkBnD,CAAG;AAAA,EACnD,GAAG,CAACA,CAAG,CAAC,GAERkD,EAAU,MAAM;AACd,IAAAvC,EAAgB,UAAUD,GAAW,WAAW,YAChDG,EAAyB,UAAU,IAAI,gBAAA;AACvC,UAAM,EAAE,QAAAuC,MAAWvC,EAAyB,SAEtCwC,IAAkB,CAAC/B,MACvBE,EAAgBF,CAAsB,GAElCgC,IAAgB,CAAChC,MACrBK,EAAcL,CAAsB,GAEhCiC,IAAgB,CAACjC,MACrB2B,EAAoB3B,CAAsB;AAE5C,WAAAX,EAAgB,QAAQ,iBAAiB,WAAW0C,GAAiB;AAAA,MACnE,SAAShD;AAAA,MACT,QAAA+C;AAAA,IAAA,CACD,GAEDzC,EAAgB,QAAQ,iBAAiB,SAAS2C,GAAe;AAAA,MAC/D,SAASjD;AAAA,MACT,QAAA+C;AAAA,IAAA,CACD,GAEDzC,EAAgB,QAAQ,iBAAiBR,GAAWoD,GAAe;AAAA,MACjE,SAASlD;AAAA,MACT,QAAA+C;AAAA,IAAA,CACD,GAEM,MAAM;AACX,MAAAvC,EAAyB,SAAS,MAAA,GAElCG,EAAA,GACAD,EAAkB,QAAQ,QAAQ,CAACI,MAAaD,EAAcC,CAAQ,CAAC;AAAA,IACzE;AAAA,EACF,GAAG;AAAA,IACDhB;AAAA,IACAE;AAAA,IACAK;AAAA,IACAc;AAAA,IACAG;AAAA,IACAsB;AAAA,IACAjC;AAAA,IACAE;AAAA,EAAA,CACD;AACH;"}
@@ -1,6 +1,6 @@
1
- import { useRef as a, useCallback as l, useEffect as F } from "react";
2
- import { invokePinchAction as A } from "./invoke-pinch-action.js";
3
- const S = {
1
+ import { useRef as i, useCallback as f, useEffect as z } from "react";
2
+ import { invokePinchAction as O } from "./invoke-pinch-action.js";
3
+ const F = {
4
4
  eventPointerTypes: ["touch"],
5
5
  eventCapture: !1,
6
6
  eventOnce: !1,
@@ -8,124 +8,122 @@ const S = {
8
8
  threshold: 0,
9
9
  container: { current: null },
10
10
  raf: !1
11
- }, x = (f, C = {}) => {
11
+ }, q = (v, A = {}) => {
12
12
  const {
13
- eventPointerTypes: I,
14
- eventCapture: u,
15
- eventOnce: v,
16
- eventStopImmediatePropagation: m,
17
- threshold: L,
18
- container: R,
19
- raf: y
20
- } = { ...S, ...C }, p = a(null), s = a(null), d = a(null), g = a(null), D = a(null), i = a({
13
+ eventPointerTypes: E,
14
+ eventCapture: a,
15
+ eventOnce: m,
16
+ eventStopImmediatePropagation: h,
17
+ threshold: I,
18
+ container: L,
19
+ raf: g
20
+ } = { ...F, ...A }, l = i(null), u = i(null), p = i(null), D = i(null), P = i(null), s = i({
21
21
  pointers: /* @__PURE__ */ new Map(),
22
22
  startDistance: 0,
23
23
  lastDistance: 0,
24
24
  active: !1
25
- }), h = l(() => {
26
- s.current?.abort();
27
- }, []), E = l(() => {
28
- d.current = null;
29
- const t = g.current, e = D.current;
30
- !t || !e || (A(e, t, f, {
31
- stopImmediate: m,
32
- once: v,
33
- onOnce: () => h()
34
- }), g.current = null, D.current = null);
35
- }, [
36
- f,
37
- m,
38
- v,
39
- h
40
- ]), M = l(
25
+ }), R = f(() => {
26
+ p.current = null;
27
+ const t = D.current, e = P.current;
28
+ !t || !e || (O(e, t, v, {
29
+ stopImmediate: h,
30
+ once: m,
31
+ onOnce: () => {
32
+ u.current?.abort();
33
+ }
34
+ }), D.current = null, P.current = null);
35
+ }, [v, h, m]), M = f(
41
36
  (t) => {
42
- if (!I.includes(t.pointerType))
37
+ if (!E.includes(t.pointerType))
43
38
  return;
44
- const e = i.current;
39
+ const e = s.current;
45
40
  if (e.pointers.set(t.pointerId, t), e.pointers.size === 2) {
46
- const [c, o] = [...e.pointers.values()], n = o.clientX - c.clientX, P = o.clientY - c.clientY, r = Math.hypot(n, P);
41
+ const [o, c] = [...e.pointers.values()], d = c.clientX - o.clientX, n = c.clientY - o.clientY, r = Math.hypot(d, n);
47
42
  e.startDistance = r, e.lastDistance = r, e.active = !0;
48
43
  }
49
44
  },
50
- [I]
51
- ), X = l(
45
+ [E]
46
+ ), X = f(
52
47
  (t) => {
53
- const e = i.current;
54
- if (!e.active || !e.pointers.has(t.pointerId) || (e.pointers.set(t.pointerId, t), e.pointers.size < 2)) return;
55
- const [c, o] = [...e.pointers.values()], n = o.clientX - c.clientX, P = o.clientY - c.clientY, r = Math.hypot(n, P), T = r - e.lastDistance, O = r - e.startDistance;
56
- if (Math.abs(O) < L) return;
57
- const z = r / e.startDistance, b = {
48
+ const e = s.current;
49
+ if (!e.active || !e.pointers.has(t.pointerId) || (e.pointers.set(t.pointerId, t), e.pointers.size < 2))
50
+ return;
51
+ const [o, c] = [...e.pointers.values()], d = c.clientX - o.clientX, n = c.clientY - o.clientY, r = Math.hypot(d, n), C = r - e.lastDistance, w = r - e.startDistance;
52
+ if (Math.abs(w) < I)
53
+ return;
54
+ const T = r / e.startDistance, y = {
58
55
  distance: r,
59
- delta: T,
60
- totalDelta: O,
61
- scale: z
56
+ delta: C,
57
+ totalDelta: w,
58
+ scale: T
62
59
  };
63
- if (e.lastDistance = r, !y) {
64
- A(t, b, f, {
65
- stopImmediate: m,
66
- once: v,
67
- onOnce: () => h()
60
+ if (e.lastDistance = r, !g) {
61
+ O(t, y, v, {
62
+ stopImmediate: h,
63
+ once: m,
64
+ onOnce: () => {
65
+ u.current?.abort();
66
+ }
68
67
  });
69
68
  return;
70
69
  }
71
- g.current = b, D.current = t, d.current === null && (d.current = requestAnimationFrame(E));
70
+ D.current = y, P.current = t, p.current === null && (p.current = requestAnimationFrame(R));
72
71
  },
73
72
  [
74
- L,
75
- y,
76
- f,
77
- m,
73
+ I,
74
+ g,
78
75
  v,
79
76
  h,
80
- E
77
+ m,
78
+ R
81
79
  ]
82
- ), Y = l((t) => {
83
- const e = i.current;
80
+ ), Y = f((t) => {
81
+ const e = s.current;
84
82
  e.pointers.delete(t.pointerId), e.pointers.size < 2 && (e.active = !1, e.startDistance = 0, e.lastDistance = 0);
85
- }, []), w = l((t) => {
86
- const e = i.current;
83
+ }, []), b = f((t) => {
84
+ const e = s.current;
87
85
  e.pointers.delete(t.pointerId), e.active = !1;
88
86
  }, []);
89
- F(() => {
90
- p.current = R?.current ?? globalThis, s.current = new AbortController();
91
- const t = (n) => M(n), e = (n) => X(n), c = (n) => Y(n), o = (n) => w(n);
92
- return p.current.addEventListener(
87
+ z(() => {
88
+ l.current = L?.current ?? globalThis, u.current = new AbortController();
89
+ const { signal: t } = u.current, e = (n) => n instanceof PointerEvent && M(n), o = (n) => n instanceof PointerEvent && X(n), c = (n) => n instanceof PointerEvent && Y(n), d = (n) => n instanceof PointerEvent && b(n);
90
+ return l.current.addEventListener(
93
91
  "pointerdown",
94
- t,
92
+ e,
95
93
  {
96
- capture: u,
97
- signal: s.current.signal
94
+ capture: a,
95
+ signal: t
98
96
  }
99
- ), p.current.addEventListener(
97
+ ), l.current.addEventListener(
100
98
  "pointermove",
101
- e,
99
+ o,
102
100
  {
103
- capture: u,
104
- signal: s.current.signal
101
+ capture: a,
102
+ signal: t
105
103
  }
106
- ), p.current.addEventListener("pointerup", c, {
107
- capture: u,
108
- signal: s.current.signal
109
- }), p.current.addEventListener(
104
+ ), l.current.addEventListener("pointerup", c, {
105
+ capture: a,
106
+ signal: t
107
+ }), l.current.addEventListener(
110
108
  "pointercancel",
111
- o,
109
+ d,
112
110
  {
113
- capture: u,
114
- signal: s.current.signal
111
+ capture: a,
112
+ signal: t
115
113
  }
116
114
  ), () => {
117
- s.current?.abort(), i.current.active = !1, i.current.pointers.clear(), d.current !== null && cancelAnimationFrame(d.current);
115
+ u.current?.abort(), s.current.active = !1, s.current.pointers.clear(), p.current !== null && cancelAnimationFrame(p.current);
118
116
  };
119
117
  }, [
120
- R,
121
- u,
118
+ L,
119
+ a,
122
120
  M,
123
121
  X,
124
122
  Y,
125
- w
123
+ b
126
124
  ]);
127
125
  };
128
126
  export {
129
- x as default
127
+ q as default
130
128
  };
131
129
  //# sourceMappingURL=use-pinch.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-pinch.js","sources":["../../src/use-pinch/use-pinch.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from \"react\";\nimport {\n PinchState,\n PinchData,\n UsePinchCallback,\n UsePinchOptions,\n PinchOptions,\n PinchEventPointerType,\n} from \"./use-pinch.types\";\nimport { invokePinchAction } from \"./invoke-pinch-action\";\n\nconst defaultOptions: PinchOptions = {\n eventPointerTypes: [\"touch\"],\n eventCapture: false,\n eventOnce: false,\n eventStopImmediatePropagation: false,\n threshold: 0,\n container: { current: null },\n raf: false,\n};\n\nconst usePinch = (\n pinchCallback: UsePinchCallback,\n options: UsePinchOptions = {},\n) => {\n const {\n eventPointerTypes,\n eventCapture,\n eventOnce,\n eventStopImmediatePropagation,\n threshold,\n container,\n raf,\n } = { ...defaultOptions, ...options };\n\n const targetReference = useRef<EventTarget | null>(null);\n const abortControllerReference = useRef<AbortController | null>(null);\n\n const frameReference = useRef<number | null>(null);\n const pendingDataReference = useRef<PinchData | null>(null);\n const pendingEventReference = useRef<PointerEvent | null>(null);\n\n const pinchStateReference = useRef<PinchState>({\n pointers: new Map(),\n startDistance: 0,\n lastDistance: 0,\n active: false,\n });\n\n const destroyListener = useCallback(() => {\n abortControllerReference.current?.abort();\n }, []);\n\n const flushFrame = useCallback(() => {\n frameReference.current = null;\n\n const data = pendingDataReference.current;\n const event = pendingEventReference.current;\n\n if (!data || !event) return;\n\n invokePinchAction(event, data, pinchCallback, {\n stopImmediate: eventStopImmediatePropagation,\n once: eventOnce,\n onOnce: () => destroyListener(),\n });\n\n pendingDataReference.current = null;\n pendingEventReference.current = null;\n }, [\n pinchCallback,\n eventStopImmediatePropagation,\n eventOnce,\n destroyListener,\n ]);\n\n const handlePointerDown = useCallback(\n (event: PointerEvent) => {\n if (\n !eventPointerTypes.includes(event.pointerType as PinchEventPointerType)\n ) {\n return;\n }\n\n const state = pinchStateReference.current;\n\n state.pointers.set(event.pointerId, event);\n\n if (state.pointers.size === 2) {\n const [pointer1, pointer2] = [...state.pointers.values()];\n\n const deltaX = pointer2.clientX - pointer1.clientX;\n const deltaY = pointer2.clientY - pointer1.clientY;\n\n const distance = Math.hypot(deltaX, deltaY);\n\n state.startDistance = distance;\n state.lastDistance = distance;\n state.active = true;\n }\n },\n [eventPointerTypes],\n );\n\n const handlePointerMove = useCallback(\n (event: PointerEvent) => {\n const state = pinchStateReference.current;\n if (!state.active) return;\n\n if (!state.pointers.has(event.pointerId)) return;\n\n state.pointers.set(event.pointerId, event);\n\n if (state.pointers.size < 2) return;\n\n const [pointer1, pointer2] = [...state.pointers.values()];\n\n const deltaX = pointer2.clientX - pointer1.clientX;\n const deltaY = pointer2.clientY - pointer1.clientY;\n\n const distance = Math.hypot(deltaX, deltaY);\n\n const delta = distance - state.lastDistance;\n const totalDelta = distance - state.startDistance;\n\n if (Math.abs(totalDelta) < threshold) return;\n\n const scale = distance / state.startDistance;\n\n const data: PinchData = {\n distance,\n delta,\n totalDelta,\n scale,\n };\n\n state.lastDistance = distance;\n\n if (!raf) {\n invokePinchAction(event, data, pinchCallback, {\n stopImmediate: eventStopImmediatePropagation,\n once: eventOnce,\n onOnce: () => destroyListener(),\n });\n return;\n }\n\n pendingDataReference.current = data;\n pendingEventReference.current = event;\n\n if (frameReference.current === null) {\n frameReference.current = requestAnimationFrame(flushFrame);\n }\n },\n [\n threshold,\n raf,\n pinchCallback,\n eventStopImmediatePropagation,\n eventOnce,\n destroyListener,\n flushFrame,\n ],\n );\n\n const handlePointerUp = useCallback((event: PointerEvent) => {\n const state = pinchStateReference.current;\n\n state.pointers.delete(event.pointerId);\n\n if (state.pointers.size < 2) {\n state.active = false;\n state.startDistance = 0;\n state.lastDistance = 0;\n }\n }, []);\n\n const handlePointerCancel = useCallback((event: PointerEvent) => {\n const state = pinchStateReference.current;\n\n state.pointers.delete(event.pointerId);\n state.active = false;\n }, []);\n\n useEffect(() => {\n targetReference.current = container?.current ?? globalThis;\n abortControllerReference.current = new AbortController();\n\n const pointerDownListener = (event: Event) =>\n handlePointerDown(event as PointerEvent);\n\n const pointerMoveListener = (event: Event) =>\n handlePointerMove(event as PointerEvent);\n\n const pointerUpListener = (event: Event) =>\n handlePointerUp(event as PointerEvent);\n\n const pointerCancelListener = (event: Event) =>\n handlePointerCancel(event as PointerEvent);\n\n targetReference.current.addEventListener(\n \"pointerdown\",\n pointerDownListener,\n {\n capture: eventCapture,\n signal: abortControllerReference.current.signal,\n },\n );\n\n targetReference.current.addEventListener(\n \"pointermove\",\n pointerMoveListener,\n {\n capture: eventCapture,\n signal: abortControllerReference.current.signal,\n },\n );\n\n targetReference.current.addEventListener(\"pointerup\", pointerUpListener, {\n capture: eventCapture,\n signal: abortControllerReference.current.signal,\n });\n\n targetReference.current.addEventListener(\n \"pointercancel\",\n pointerCancelListener,\n {\n capture: eventCapture,\n signal: abortControllerReference.current.signal,\n },\n );\n\n return () => {\n abortControllerReference.current?.abort();\n pinchStateReference.current.active = false;\n pinchStateReference.current.pointers.clear();\n\n if (frameReference.current !== null) {\n cancelAnimationFrame(frameReference.current);\n }\n };\n }, [\n container,\n eventCapture,\n handlePointerDown,\n handlePointerMove,\n handlePointerUp,\n handlePointerCancel,\n ]);\n};\n\nexport default usePinch;\n"],"names":["defaultOptions","usePinch","pinchCallback","options","eventPointerTypes","eventCapture","eventOnce","eventStopImmediatePropagation","threshold","container","raf","targetReference","useRef","abortControllerReference","frameReference","pendingDataReference","pendingEventReference","pinchStateReference","destroyListener","useCallback","flushFrame","data","event","invokePinchAction","handlePointerDown","state","pointer1","pointer2","deltaX","deltaY","distance","handlePointerMove","delta","totalDelta","scale","handlePointerUp","handlePointerCancel","useEffect","pointerDownListener","pointerMoveListener","pointerUpListener","pointerCancelListener"],"mappings":"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"}
1
+ {"version":3,"file":"use-pinch.js","sources":["../../src/use-pinch/use-pinch.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from \"react\";\nimport {\n PinchState,\n PinchData,\n UsePinchCallback,\n UsePinchOptions,\n PinchOptions,\n PinchEventPointerType,\n} from \"./use-pinch.types\";\nimport { invokePinchAction } from \"./invoke-pinch-action\";\n\nconst defaultOptions: PinchOptions = {\n eventPointerTypes: [\"touch\"],\n eventCapture: false,\n eventOnce: false,\n eventStopImmediatePropagation: false,\n threshold: 0,\n container: { current: null },\n raf: false,\n};\n\nconst usePinch = (\n pinchCallback: UsePinchCallback,\n options: UsePinchOptions = {},\n) => {\n const {\n eventPointerTypes,\n eventCapture,\n eventOnce,\n eventStopImmediatePropagation,\n threshold,\n container,\n raf,\n } = { ...defaultOptions, ...options };\n\n const targetReference = useRef<EventTarget | null>(null);\n const abortControllerReference = useRef<AbortController | null>(null);\n\n const frameReference = useRef<number | null>(null);\n const pendingDataReference = useRef<PinchData | null>(null);\n const pendingEventReference = useRef<PointerEvent | null>(null);\n\n const pinchStateReference = useRef<PinchState>({\n pointers: new Map(),\n startDistance: 0,\n lastDistance: 0,\n active: false,\n });\n\n const flushFrame = useCallback(() => {\n frameReference.current = null;\n\n const data = pendingDataReference.current;\n const event = pendingEventReference.current;\n\n if (!data || !event) {\n return;\n }\n\n invokePinchAction(event, data, pinchCallback, {\n stopImmediate: eventStopImmediatePropagation,\n once: eventOnce,\n onOnce: () => {\n abortControllerReference.current?.abort();\n },\n });\n\n pendingDataReference.current = null;\n pendingEventReference.current = null;\n }, [pinchCallback, eventStopImmediatePropagation, eventOnce]);\n\n const handlePointerDown = useCallback(\n (event: PointerEvent) => {\n if (\n !eventPointerTypes.includes(event.pointerType as PinchEventPointerType)\n ) {\n return;\n }\n\n const state = pinchStateReference.current;\n\n state.pointers.set(event.pointerId, event);\n\n if (state.pointers.size === 2) {\n const [pointer1, pointer2] = [...state.pointers.values()];\n\n const deltaX = pointer2.clientX - pointer1.clientX;\n const deltaY = pointer2.clientY - pointer1.clientY;\n\n const distance = Math.hypot(deltaX, deltaY);\n\n state.startDistance = distance;\n state.lastDistance = distance;\n state.active = true;\n }\n },\n [eventPointerTypes],\n );\n\n const handlePointerMove = useCallback(\n (event: PointerEvent) => {\n const state = pinchStateReference.current;\n if (!state.active) {\n return;\n }\n\n if (!state.pointers.has(event.pointerId)) {\n return;\n }\n\n state.pointers.set(event.pointerId, event);\n\n if (state.pointers.size < 2) {\n return;\n }\n\n const [pointer1, pointer2] = [...state.pointers.values()];\n\n const deltaX = pointer2.clientX - pointer1.clientX;\n const deltaY = pointer2.clientY - pointer1.clientY;\n\n const distance = Math.hypot(deltaX, deltaY);\n\n const delta = distance - state.lastDistance;\n const totalDelta = distance - state.startDistance;\n\n if (Math.abs(totalDelta) < threshold) {\n return;\n }\n\n const scale = distance / state.startDistance;\n\n const data: PinchData = {\n distance,\n delta,\n totalDelta,\n scale,\n };\n\n state.lastDistance = distance;\n\n if (!raf) {\n invokePinchAction(event, data, pinchCallback, {\n stopImmediate: eventStopImmediatePropagation,\n once: eventOnce,\n onOnce: () => {\n abortControllerReference.current?.abort();\n },\n });\n return;\n }\n\n pendingDataReference.current = data;\n pendingEventReference.current = event;\n\n if (frameReference.current === null) {\n frameReference.current = requestAnimationFrame(flushFrame);\n }\n },\n [\n threshold,\n raf,\n pinchCallback,\n eventStopImmediatePropagation,\n eventOnce,\n flushFrame,\n ],\n );\n\n const handlePointerUp = useCallback((event: PointerEvent) => {\n const state = pinchStateReference.current;\n\n state.pointers.delete(event.pointerId);\n\n if (state.pointers.size < 2) {\n state.active = false;\n state.startDistance = 0;\n state.lastDistance = 0;\n }\n }, []);\n\n const handlePointerCancel = useCallback((event: PointerEvent) => {\n const state = pinchStateReference.current;\n\n state.pointers.delete(event.pointerId);\n state.active = false;\n }, []);\n\n useEffect(() => {\n targetReference.current = container?.current ?? globalThis;\n abortControllerReference.current = new AbortController();\n const { signal } = abortControllerReference.current;\n\n const pointerDownListener = (event: Event) =>\n event instanceof PointerEvent && handlePointerDown(event);\n\n const pointerMoveListener = (event: Event) =>\n event instanceof PointerEvent && handlePointerMove(event);\n\n const pointerUpListener = (event: Event) =>\n event instanceof PointerEvent && handlePointerUp(event);\n\n const pointerCancelListener = (event: Event) =>\n event instanceof PointerEvent && handlePointerCancel(event);\n\n targetReference.current.addEventListener(\n \"pointerdown\",\n pointerDownListener,\n {\n capture: eventCapture,\n signal,\n },\n );\n\n targetReference.current.addEventListener(\n \"pointermove\",\n pointerMoveListener,\n {\n capture: eventCapture,\n signal,\n },\n );\n\n targetReference.current.addEventListener(\"pointerup\", pointerUpListener, {\n capture: eventCapture,\n signal,\n });\n\n targetReference.current.addEventListener(\n \"pointercancel\",\n pointerCancelListener,\n {\n capture: eventCapture,\n signal,\n },\n );\n\n return () => {\n abortControllerReference.current?.abort();\n\n pinchStateReference.current.active = false;\n pinchStateReference.current.pointers.clear();\n\n if (frameReference.current !== null) {\n cancelAnimationFrame(frameReference.current);\n }\n };\n }, [\n container,\n eventCapture,\n handlePointerDown,\n handlePointerMove,\n handlePointerUp,\n handlePointerCancel,\n ]);\n};\n\nexport default usePinch;\n"],"names":["defaultOptions","usePinch","pinchCallback","options","eventPointerTypes","eventCapture","eventOnce","eventStopImmediatePropagation","threshold","container","raf","targetReference","useRef","abortControllerReference","frameReference","pendingDataReference","pendingEventReference","pinchStateReference","flushFrame","useCallback","data","event","invokePinchAction","handlePointerDown","state","pointer1","pointer2","deltaX","deltaY","distance","handlePointerMove","delta","totalDelta","scale","handlePointerUp","handlePointerCancel","useEffect","signal","pointerDownListener","pointerMoveListener","pointerUpListener","pointerCancelListener"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ const r = (e, t, n, o) => {
2
+ o.stopImmediate && e.stopImmediatePropagation(), n(e, t) && e.preventDefault(), o.once && o.onOnce?.();
3
+ };
4
+ export {
5
+ r as invokePressAction
6
+ };
7
+ //# sourceMappingURL=invoke-press-action.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invoke-press-action.js","sources":["../../src/use-press/invoke-press-action.ts"],"sourcesContent":["import { PressData } from \"./use-press.types\";\n\n/**\n * Invokes a press action callback with optional event modifications.\n *\n * Handles press event processing including preventing default behavior,\n * stopping immediate propagation, and managing one-time event handlers.\n *\n * @param {PointerEvent} event - The press event\n * @param {PressData} data - The normalized press data\n * @param {Function} callback - Function to invoke with (event, data). Return true to prevent default.\n * @param {Object} options - Action options\n * @param {boolean} [options.stopImmediate=false] - Whether to stop immediate propagation\n * @param {boolean} [options.once=false] - Whether this is a one-time event\n * @param {Function} [options.onOnce] - Callback to invoke when one-time event fires\n *\n * @example\n * invokePressAction(event, data, (e, d) => {\n * console.log(`Press at: ${d.x}, ${d.y}`);\n * return true; // Prevent default\n * }, { stopImmediate: true });\n */\nexport const invokePressAction = (\n event: PointerEvent,\n data: PressData,\n callback:\n | ((event: PointerEvent, data: PressData) => boolean)\n | ((event: PointerEvent, data: PressData) => void),\n options: {\n stopImmediate?: boolean;\n once?: boolean;\n onOnce?: () => void;\n },\n) => {\n if (options.stopImmediate) {\n event.stopImmediatePropagation();\n }\n\n const shouldPrevent = callback(event, data);\n if (shouldPrevent) {\n event.preventDefault();\n }\n\n if (options.once) {\n options.onOnce?.();\n }\n};\n"],"names":["invokePressAction","event","data","callback","options"],"mappings":"AAsBO,MAAMA,IAAoB,CAC/BC,GACAC,GACAC,GAGAC,MAKG;AACH,EAAIA,EAAQ,iBACVH,EAAM,yBAAA,GAGcE,EAASF,GAAOC,CAAI,KAExCD,EAAM,eAAA,GAGJG,EAAQ,QACVA,EAAQ,SAAA;AAEZ;"}
@@ -0,0 +1,98 @@
1
+ import { useRef as l, useCallback as i, useEffect as R } from "react";
2
+ import { invokePressAction as w } from "./invoke-press-action.js";
3
+ const O = {
4
+ eventPointerTypes: ["touch", "mouse", "pen"],
5
+ eventCapture: !1,
6
+ eventOnce: !1,
7
+ eventStopImmediatePropagation: !1,
8
+ delay: 500,
9
+ threshold: 8,
10
+ container: { current: null }
11
+ }, I = (f, g = {}) => {
12
+ const {
13
+ eventPointerTypes: m,
14
+ eventCapture: o,
15
+ eventOnce: P,
16
+ eventStopImmediatePropagation: v,
17
+ delay: h,
18
+ threshold: y,
19
+ container: E
20
+ } = { ...O, ...g }, c = l(null), s = l(null), u = l({
21
+ x: 0,
22
+ y: 0,
23
+ active: !1
24
+ }), a = l(null), t = i(() => {
25
+ a.current !== null && (clearTimeout(a.current), a.current = null), u.current.active = !1;
26
+ }, []), L = i(
27
+ (e) => {
28
+ e.isPrimary && m.includes(e.pointerType) && (u.current = {
29
+ x: e.clientX,
30
+ y: e.clientY,
31
+ active: !0
32
+ }, a.current = setTimeout(() => {
33
+ const r = {
34
+ x: e.clientX,
35
+ y: e.clientY
36
+ };
37
+ w(e, r, f, {
38
+ stopImmediate: v,
39
+ once: P,
40
+ onOnce: () => {
41
+ s.current?.abort();
42
+ }
43
+ }), t();
44
+ }, h));
45
+ },
46
+ [
47
+ f,
48
+ h,
49
+ m,
50
+ P,
51
+ v,
52
+ t
53
+ ]
54
+ ), C = i(
55
+ (e) => {
56
+ const r = u.current;
57
+ if (!r.active)
58
+ return;
59
+ const p = e.clientX - r.x, d = e.clientY - r.y;
60
+ Math.hypot(p, d) > y && t();
61
+ },
62
+ [y, t]
63
+ ), T = i(() => t(), [t]), b = i(() => t(), [t]);
64
+ R(() => {
65
+ c.current = E?.current ?? globalThis, s.current = new AbortController();
66
+ const { signal: e } = s.current, r = (n) => n instanceof PointerEvent && L(n), p = (n) => n instanceof PointerEvent && C(n), d = (n) => n instanceof PointerEvent && T(), x = (n) => n instanceof PointerEvent && b();
67
+ return c.current.addEventListener(
68
+ "pointerdown",
69
+ r,
70
+ { capture: o, signal: e }
71
+ ), c.current.addEventListener(
72
+ "pointermove",
73
+ p,
74
+ { capture: o, signal: e }
75
+ ), c.current.addEventListener("pointerup", d, {
76
+ capture: o,
77
+ signal: e
78
+ }), c.current.addEventListener(
79
+ "pointercancel",
80
+ x,
81
+ { capture: o, signal: e }
82
+ ), () => {
83
+ s.current?.abort(), t();
84
+ };
85
+ }, [
86
+ E,
87
+ o,
88
+ L,
89
+ C,
90
+ T,
91
+ b,
92
+ t
93
+ ]);
94
+ };
95
+ export {
96
+ I as default
97
+ };
98
+ //# sourceMappingURL=use-press.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-press.js","sources":["../../src/use-press/use-press.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from \"react\";\nimport {\n PressOptions,\n UsePressCallback,\n UsePressOptions,\n PressEventPointerType,\n PressData,\n} from \"./use-press.types\";\nimport { invokePressAction } from \"./invoke-press-action\";\n\nconst defaultOptions: PressOptions = {\n eventPointerTypes: [\"touch\", \"mouse\", \"pen\"],\n eventCapture: false,\n eventOnce: false,\n eventStopImmediatePropagation: false,\n delay: 500,\n threshold: 8,\n container: { current: null },\n};\n\nconst usePress = (\n pressCallback: UsePressCallback,\n options: UsePressOptions = {},\n) => {\n const {\n eventPointerTypes,\n eventCapture,\n eventOnce,\n eventStopImmediatePropagation,\n delay,\n threshold,\n container,\n } = { ...defaultOptions, ...options };\n\n const targetReference = useRef<EventTarget | null>(null);\n const abortControllerReference = useRef<AbortController | null>(null);\n\n const pressStateReference = useRef<{\n x: number;\n y: number;\n active: boolean;\n }>({\n x: 0,\n y: 0,\n active: false,\n });\n\n const timerReference = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearPress = useCallback(() => {\n if (timerReference.current !== null) {\n clearTimeout(timerReference.current);\n timerReference.current = null;\n }\n pressStateReference.current.active = false;\n }, []);\n\n const handlePointerDown = useCallback(\n (event: PointerEvent) => {\n if (!event.isPrimary) {\n return;\n }\n if (\n !eventPointerTypes.includes(event.pointerType as PressEventPointerType)\n ) {\n return;\n }\n\n pressStateReference.current = {\n x: event.clientX,\n y: event.clientY,\n active: true,\n };\n\n timerReference.current = setTimeout(() => {\n const data: PressData = {\n x: event.clientX,\n y: event.clientY,\n };\n invokePressAction(event, data, pressCallback, {\n stopImmediate: eventStopImmediatePropagation,\n once: eventOnce,\n onOnce: () => {\n abortControllerReference.current?.abort();\n },\n });\n\n clearPress();\n }, delay);\n },\n [\n pressCallback,\n delay,\n eventPointerTypes,\n eventOnce,\n eventStopImmediatePropagation,\n clearPress,\n ],\n );\n\n const handlePointerMove = useCallback(\n (event: PointerEvent) => {\n const state = pressStateReference.current;\n if (!state.active) {\n return;\n }\n\n const deltaX = event.clientX - state.x;\n const deltaY = event.clientY - state.y;\n\n if (Math.hypot(deltaX, deltaY) > threshold) {\n clearPress();\n }\n },\n [threshold, clearPress],\n );\n\n const handlePointerUp = useCallback(() => clearPress(), [clearPress]);\n const handlePointerCancel = useCallback(() => clearPress(), [clearPress]);\n\n useEffect(() => {\n targetReference.current = container?.current ?? globalThis;\n abortControllerReference.current = new AbortController();\n const { signal } = abortControllerReference.current;\n\n const pointerDownListener = (event: Event) =>\n event instanceof PointerEvent && handlePointerDown(event);\n\n const pointerMoveListener = (event: Event) =>\n event instanceof PointerEvent && handlePointerMove(event);\n\n const pointerUpListener = (event: Event) =>\n event instanceof PointerEvent && handlePointerUp();\n\n const pointerCancelListener = (event: Event) =>\n event instanceof PointerEvent && handlePointerCancel();\n\n targetReference.current.addEventListener(\n \"pointerdown\",\n pointerDownListener,\n { capture: eventCapture, signal },\n );\n\n targetReference.current.addEventListener(\n \"pointermove\",\n pointerMoveListener,\n { capture: eventCapture, signal },\n );\n\n targetReference.current.addEventListener(\"pointerup\", pointerUpListener, {\n capture: eventCapture,\n signal,\n });\n\n targetReference.current.addEventListener(\n \"pointercancel\",\n pointerCancelListener,\n { capture: eventCapture, signal },\n );\n\n return () => {\n abortControllerReference.current?.abort();\n clearPress();\n };\n }, [\n container,\n eventCapture,\n handlePointerDown,\n handlePointerMove,\n handlePointerUp,\n handlePointerCancel,\n clearPress,\n ]);\n};\n\nexport default usePress;\n"],"names":["defaultOptions","usePress","pressCallback","options","eventPointerTypes","eventCapture","eventOnce","eventStopImmediatePropagation","delay","threshold","container","targetReference","useRef","abortControllerReference","pressStateReference","timerReference","clearPress","useCallback","handlePointerDown","event","data","invokePressAction","handlePointerMove","state","deltaX","deltaY","handlePointerUp","handlePointerCancel","useEffect","signal","pointerDownListener","pointerMoveListener","pointerUpListener","pointerCancelListener"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ const e = {
2
+ Touch: "touch",
3
+ Mouse: "mouse",
4
+ Pen: "pen"
5
+ };
6
+ export {
7
+ e as PressEventPointerTypes
8
+ };
9
+ //# sourceMappingURL=use-press.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-press.types.js","sources":["../../src/use-press/use-press.types.ts"],"sourcesContent":["export const PressEventPointerTypes = {\n Touch: \"touch\",\n Mouse: \"mouse\",\n Pen: \"pen\",\n} as const;\n\nexport type PressEventPointerType =\n (typeof PressEventPointerTypes)[keyof typeof PressEventPointerTypes];\n\nexport interface PressData {\n x: number;\n y: number;\n}\n\nexport interface PressOptions {\n eventPointerTypes: PressEventPointerType[];\n eventCapture: boolean;\n eventOnce: boolean;\n eventStopImmediatePropagation: boolean;\n delay: number;\n threshold: number;\n container: { current: EventTarget | null };\n}\n\nexport type UsePressCallback =\n | ((event: PointerEvent, data: PressData) => void)\n | ((event: PointerEvent, data: PressData) => boolean);\n\nexport type UsePressOptions = Partial<PressOptions>;\n"],"names":["PressEventPointerTypes"],"mappings":"AAAO,MAAMA,IAAyB;AAAA,EACpC,OAAO;AAAA,EACP,OAAO;AAAA,EACP,KAAK;AACP;"}