@mantine/hooks
Version:
A collection of 50+ hooks for state and UI management
1 lines • 6.65 kB
Source Map (JSON)
{"version":3,"file":"use-move.cjs","names":["clamp"],"sources":["../../src/use-move/use-move.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport { clamp } from '../utils';\n\nexport interface UseMovePosition {\n x: number;\n y: number;\n}\n\nexport function clampUseMovePosition(position: UseMovePosition) {\n return {\n x: clamp(position.x, 0, 1),\n y: clamp(position.y, 0, 1),\n };\n}\n\nexport interface UseMoveHandlers {\n onScrubStart?: () => void;\n onScrubEnd?: () => void;\n}\n\nexport interface UseMoveReturnValue<T extends HTMLElement = any> {\n ref: React.RefCallback<T | null>;\n active: boolean;\n}\n\nexport function useMove<T extends HTMLElement = any>(\n onChange: (value: UseMovePosition) => void,\n handlers?: UseMoveHandlers,\n dir: 'ltr' | 'rtl' = 'ltr'\n): UseMoveReturnValue<T> {\n const mounted = useRef<boolean>(false);\n const isSliding = useRef(false);\n const frame = useRef(0);\n const cleanupRef = useRef<(() => void) | null>(null);\n const [active, setActive] = useState(false);\n\n useEffect(() => {\n mounted.current = true;\n return () => {\n cleanupRef.current?.();\n };\n }, []);\n\n const refCallback: React.RefCallback<T | null> = useCallback(\n (node) => {\n const onScrub = ({ x, y }: UseMovePosition) => {\n cancelAnimationFrame(frame.current);\n\n frame.current = requestAnimationFrame(() => {\n if (mounted.current && node) {\n node.style.userSelect = 'none';\n const rect = node.getBoundingClientRect();\n\n if (rect.width && rect.height) {\n const _x = clamp((x - rect.left) / rect.width, 0, 1);\n onChange({\n x: dir === 'ltr' ? _x : 1 - _x,\n y: clamp((y - rect.top) / rect.height, 0, 1),\n });\n }\n }\n });\n };\n\n const bindEvents = () => {\n document.addEventListener('mousemove', onMouseMove);\n document.addEventListener('mouseup', stopScrubbing);\n document.addEventListener('touchmove', onTouchMove, { passive: false });\n document.addEventListener('touchend', stopScrubbing);\n };\n\n const unbindEvents = () => {\n document.removeEventListener('mousemove', onMouseMove);\n document.removeEventListener('mouseup', stopScrubbing);\n document.removeEventListener('touchmove', onTouchMove);\n document.removeEventListener('touchend', stopScrubbing);\n };\n\n const startScrubbing = () => {\n if (!isSliding.current && mounted.current) {\n isSliding.current = true;\n typeof handlers?.onScrubStart === 'function' && handlers.onScrubStart();\n setActive(true);\n bindEvents();\n }\n };\n\n const stopScrubbing = () => {\n if (isSliding.current && mounted.current) {\n isSliding.current = false;\n setActive(false);\n unbindEvents();\n setTimeout(() => {\n typeof handlers?.onScrubEnd === 'function' && handlers.onScrubEnd();\n }, 0);\n }\n };\n\n const onMouseDown = (event: MouseEvent) => {\n startScrubbing();\n event.preventDefault();\n onMouseMove(event);\n };\n\n const onMouseMove = (event: MouseEvent) => onScrub({ x: event.clientX, y: event.clientY });\n\n const onTouchStart = (event: TouchEvent) => {\n if (event.cancelable) {\n event.preventDefault();\n }\n\n startScrubbing();\n onTouchMove(event);\n };\n\n const onTouchMove = (event: TouchEvent) => {\n if (event.cancelable) {\n event.preventDefault();\n }\n\n onScrub({ x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY });\n };\n\n node?.addEventListener('mousedown', onMouseDown);\n node?.addEventListener('touchstart', onTouchStart, { passive: false });\n\n cleanupRef.current = () => {\n unbindEvents();\n cancelAnimationFrame(frame.current);\n };\n\n return () => {\n if (node) {\n node.removeEventListener('mousedown', onMouseDown);\n node.removeEventListener('touchstart', onTouchStart);\n }\n };\n },\n [dir, onChange]\n );\n\n return { ref: refCallback, active };\n}\n\nexport namespace useMove {\n export type Handlers = UseMoveHandlers;\n export type ReturnValue<T extends HTMLElement> = UseMoveReturnValue<T>;\n}\n"],"mappings":"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"}