@amaui/ui-react
Version:
UI for React
139 lines (138 loc) • 6.56 kB
JavaScript
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;
;