@onesy/ui-react
Version:
UI for React
164 lines (160 loc) • 6.8 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireDefault(require("react"));
var _utils = require("@onesy/utils");
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) { (0, _defineProperty2.default)(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; }
const optionsDefault = {
flick: true,
flickTreshold: 140
};
const useSwipe = (element, options_ = {}) => {
const [response, setResponse] = _react.default.useState();
const [touch, setTouch] = _react.default.useState(false);
const options = (0, _utils.merge)(options_, optionsDefault);
const refs = {
rect: _react.default.useRef(undefined),
element: _react.default.useRef(undefined),
options: _react.default.useRef(options),
response: _react.default.useRef(undefined),
touch: _react.default.useRef(undefined),
previous: _react.default.useRef(undefined),
previousMouseMove: _react.default.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 === null || element === void 0 ? void 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 = (0, _utils.clamp)(value_, min_1, max_1);
newResponse_0.valuePercentage = (0, _utils.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.default.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 === 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_0 = (element === null || element === void 0 ? void 0 : element.ownerDocument) || window.document;
rootDocument_0.removeEventListener('touchend', onTouchEnd);
rootDocument_0.removeEventListener('touchmove', onTouchMoveMethod);
};
}, [element]);
return response;
};
useSwipe.displayName = 'onesy-UseSwipe';
var _default = exports.default = useSwipe;