UNPKG

@amaui/ui-react

Version:
139 lines (138 loc) 6.56 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const react_1 = __importDefault(require("react")); const utils_1 = require("@amaui/utils"); const optionsDefault = { flick: true, flickTreshold: 140 }; const useSwipe = (element, options_ = {}) => { const [response, setResponse] = react_1.default.useState(); const [touch, setTouch] = react_1.default.useState(false); const options = (0, utils_1.merge)(options_, optionsDefault); const refs = { rect: react_1.default.useRef(undefined), element: react_1.default.useRef(undefined), options: react_1.default.useRef(options), response: react_1.default.useRef(undefined), touch: react_1.default.useRef(undefined), previous: react_1.default.useRef(undefined), previousMouseMove: react_1.default.useRef(undefined) }; refs.options.current = options; refs.response.current = response; refs.touch.current = touch; const onTouchStart = react_1.default.useCallback((event) => setTouch(event), []); const getMinMax = react_1.default.useCallback(() => { 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 = react_1.default.useCallback(() => { const newResponse = Object.assign({}, refs.response.current); const { min, max } = 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 : max; newResponse.position = (newResponse.valuePercentage < 50 || isFlick) ? 'min' : 'max'; newResponse.min = min; newResponse.max = max; newResponse.flick = isFlick; refs.previous.current = undefined; setTouch(false); setResponse(newResponse); }, [response]); const onTouchMove = react_1.default.useCallback((event) => { const newResponse = Object.assign({}, refs.response.current); const { clientX: x_, clientY: y_ } = event.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 === null || element === void 0 ? void 0 : element.getBoundingClientRect()) || {}; // value let value_; const { min, max } = 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.min = min; newResponse.max = max; newResponse.value = (0, utils_1.clamp)(value_, min, max); newResponse.valuePercentage = (0, utils_1.percentageFromValueWithinRange)(newResponse.value, min, max); if (['bottom', 'right'].includes(refs.options.current.direction)) newResponse.valuePercentage = 100 - newResponse.valuePercentage; // Only value move at touchmove newResponse.position = undefined; // previous mouse move refs.previousMouseMove.current = new Date().getTime(); setResponse(newResponse); }, [element, response]); react_1.default.useEffect(() => { const onTouchMoveMethod = (event) => { // 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.touches[0].clientX, event.touches[0].clientY)))) { if (!refs.touch.current) setTouch(true); onTouchMove(event); } refs.previous.current = event; }; if (element) { refs.element.current = element; refs.rect.current = element.getBoundingClientRect(); element.addEventListener('touchstart', onTouchStart, { passive: true }); const rootDocument = (element === null || element === void 0 ? void 0 : 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 = (element === null || element === void 0 ? void 0 : element.ownerDocument) || window.document; rootDocument.removeEventListener('touchend', onTouchEnd); rootDocument.removeEventListener('touchmove', onTouchMoveMethod); }; }, [element]); return response; }; useSwipe.displayName = 'amaui-UseSwipe'; exports.default = useSwipe;