UNPKG

@onesy/ui-react

Version:
157 lines (154 loc) 6.28 kB
import _defineProperty from "@babel/runtime/helpers/defineProperty"; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } import React from 'react'; import { clamp, merge, percentageFromValueWithinRange } from '@onesy/utils'; const optionsDefault = { flick: true, flickTreshold: 140 }; const useSwipe = (element, options_ = {}) => { const [response, setResponse] = React.useState(); const [touch, setTouch] = React.useState(false); const options = merge(options_, optionsDefault); const refs = { rect: React.useRef(undefined), element: React.useRef(undefined), options: React.useRef(options), response: React.useRef(undefined), touch: React.useRef(undefined), previous: React.useRef(undefined), previousMouseMove: React.useRef(undefined) }; refs.options.current = options; refs.response.current = response; refs.touch.current = touch; const onTouchStart = event => setTouch(event); const getMinMax = () => { let min; let max; const optionsMin = refs.options.current.min || 0; if (refs.options.current.direction === 'top') { min = refs.rect.current.top; max = refs.rect.current.bottom - optionsMin; } if (refs.options.current.direction === 'left') { min = refs.rect.current.left; max = refs.rect.current.right - optionsMin; } if (refs.options.current.direction === 'right') { min = window.innerWidth - refs.rect.current.left - optionsMin; max = min + refs.rect.current.width - optionsMin; } if (refs.options.current.direction === 'bottom') { min = window.innerHeight - refs.rect.current.top - optionsMin; max = min + refs.rect.current.height - optionsMin; } return { min, max }; }; const onTouchEnd = () => { const newResponse = _objectSpread({}, refs.response.current); const { min: min_0, max: max_0 } = getMinMax(); let isFlick = false; if (refs.options.current.flick) { const now = new Date().getTime(); const flick = now - refs.previousMouseMove.current <= refs.options.current.flickTreshold && newResponse.valuePercentage < 100; if (flick) isFlick = true; } newResponse.value = ['left', 'top'].includes(refs.options.current.direction) && (newResponse.valuePercentage < 50 || isFlick) || ['right', 'bottom'].includes(refs.options.current.direction) && newResponse.valuePercentage > 50 && !isFlick ? min_0 : max_0; newResponse.position = newResponse.valuePercentage < 50 || isFlick ? 'min' : 'max'; newResponse.min = min_0; newResponse.max = max_0; newResponse.flick = isFlick; refs.previous.current = undefined; setTouch(false); setResponse(newResponse); }; const onTouchMove = event_0 => { const newResponse_0 = _objectSpread({}, refs.response.current); const { clientX: x_, clientY: y_ } = event_0.touches[0]; const { clientX: pX, clientY: pY } = refs.previous.current.touches[0]; const x = pX - x_; const y = pY - y_; const { top = 0, left = 0, width = 0, height = 0 } = element?.getBoundingClientRect() || {}; // value let value_; const { min: min_1, max: max_1 } = getMinMax(); if (refs.options.current.direction === 'top') { value_ = top - y; } if (refs.options.current.direction === 'left') { value_ = left - x; } if (refs.options.current.direction === 'right') { value_ = width - (window.innerWidth - left) - x; } if (refs.options.current.direction === 'bottom') { value_ = height - (window.innerHeight - top) - y; } newResponse_0.min = min_1; newResponse_0.max = max_1; newResponse_0.value = clamp(value_, min_1, max_1); newResponse_0.valuePercentage = percentageFromValueWithinRange(newResponse_0.value, min_1, max_1); if (['bottom', 'right'].includes(refs.options.current.direction)) newResponse_0.valuePercentage = 100 - newResponse_0.valuePercentage; // Only value move at touchmove newResponse_0.position = undefined; // previous mouse move refs.previousMouseMove.current = new Date().getTime(); setResponse(newResponse_0); }; React.useEffect(() => { const onTouchMoveMethod = event_1 => { // Workaround for proper element for touchmove if (refs.options.current.open && refs.previous.current && (refs.options.current.touchAnywhere || refs.touch.current || element.contains(document.elementFromPoint(event_1.touches[0].clientX, event_1.touches[0].clientY)))) { if (!refs.touch.current) setTouch(true); onTouchMove(event_1); } refs.previous.current = event_1; }; if (element) { refs.element.current = element; refs.rect.current = element.getBoundingClientRect(); element.addEventListener('touchstart', onTouchStart, { passive: true }); const rootDocument = element?.ownerDocument || window.document; rootDocument.addEventListener('touchend', onTouchEnd, { passive: true }); rootDocument.addEventListener('touchmove', onTouchMoveMethod, { passive: true }); } return () => { // Remove previous event listeners if (element) element.removeEventListener('touchstart', onTouchStart); const rootDocument_0 = element?.ownerDocument || window.document; rootDocument_0.removeEventListener('touchend', onTouchEnd); rootDocument_0.removeEventListener('touchmove', onTouchMoveMethod); }; }, [element]); return response; }; useSwipe.displayName = 'onesy-UseSwipe'; export default useSwipe;