UNPKG

preact-gestures

Version:

Preact compatible HOCs for gesture detection

298 lines (247 loc) 8.57 kB
import { h } from 'preact'; function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } function _toArray(arr) { return _arrayWithHoles(arr) || _iterableToArray(arr) || _nonIterableRest(); } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } var gestureTriggers = (function () { let _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, _ref$touchMenuHoldTim = _ref.touchMenuHoldTime, touchMenuHoldTime = _ref$touchMenuHoldTim === void 0 ? 600 : _ref$touchMenuHoldTim, _ref$touchDragDelay = _ref.touchDragDelay, touchDragDelay = _ref$touchDragDelay === void 0 ? 500 : _ref$touchDragDelay; return { onClick: { onClick: (fireEvent, event) => fireEvent(event) }, onDblclick: { onDblclick: (fireEvent, event) => fireEvent(event) }, onMenu: { onMousedown(fireEvent, event) { if (event.button === 2) fireEvent(event); }, onTouchstart(fireEvent, event) { const target = event.target; let canFire = false; const holdTimer = setTimeout(() => canFire = true, touchMenuHoldTime); const handleCancel = () => { target.removeEventListener('touchend', handleEnd); target.removeEventListener('touchcancel', handleCancel); }; const handleEnd = () => { if (canFire) { fireEvent(event); } else { clearTimeout(holdTimer); } handleCancel(); }; target.addEventListener('touchend', handleEnd); target.addEventListener('touchcancel', handleCancel); } }, onDrag: { onMousedown(fireEvent, startEvent) { if (startEvent.button !== 0) return; const target = startEvent.target; let isFirstMove = true; const handleMove = moveEvent => { if (isFirstMove) { fireEvent(startEvent, 'start'); isFirstMove = false; } fireEvent(moveEvent, 'move'); }; const handleEnd = endEvent => { fireEvent(endEvent, 'end'); target.removeEventListener('mousemove', handleMove); target.removeEventListener('mouseup', handleEnd); }; target.addEventListener('mousemove', handleMove); target.addEventListener('mouseup', handleEnd); }, onTouchstart(fireEvent, startEvent) { const target = startEvent.target; const startingTouch = startEvent.changedTouches[0]; let isDragging = false; let isFirstMove = true; const handleMove = moveEvent => { if (isFirstMove) { fireEvent(startEvent, 'start'); isFirstMove = false; } for (let i = 0; i < moveEvent.changedTouches.length; i++) { const touch = moveEvent.changedTouches[i]; if (touch.identifier === startingTouch.identifier) { fireEvent(moveEvent, 'move'); } } }; const handleStart = () => { isDragging = true; target.addEventListener('touchmove', handleMove); }; const holdTimer = setTimeout(handleStart, touchDragDelay); const handleEnd = endEvent => { debugger; if (isDragging) { fireEvent(endEvent, 'end'); target.removeEventListener('touchmove', handleMove); } else { clearTimeout(holdTimer); } isDragging = false; target.removeEventListener('touchend', handleEnd); target.removeEventListener('touchcancel', handleEnd); }; target.addEventListener('touchend', handleEnd); target.addEventListener('touchcancel', handleEnd); } } }; }); function series(funcs) { return function () { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return funcs.forEach(f => f(...args)); }; } function splitCamelCase(string) { return string.split(/(?=[A-Z])/g); } function safeAppend(target, value) { if (Array.isArray(target)) return target.concat([value]);else return [target, value]; } function mergeWith(resolver, objA, objB) { let result = Object.assign({}, objA); Object.entries(objB).forEach((_ref) => { let _ref2 = _slicedToArray(_ref, 2), key = _ref2[0], value = _ref2[1]; if (key in result) { result[key] = safeAppend(result[key], value); } else { result[key] = [value]; } }); Object.entries(result).forEach((_ref3) => { let _ref4 = _slicedToArray(_ref3, 2), key = _ref4[0], values = _ref4[1]; if (values.length === 1) result[key] = values[0];else result[key] = resolver(values, key); }); return result; } // export function filterObj (obj, pred) { // let result = {} // Object.entries(obj) // .forEach(([key, val]) => pred(key, val) ? result[key] = val : undefined) // return result // } function mapObj(obj, mapper) { let result = {}; Object.entries(obj).forEach((_ref5) => { let _ref6 = _slicedToArray(_ref5, 2), key = _ref6[0], val = _ref6[1]; return result[key] = mapper(key, val); }); return result; } function setPath(obj, path, value) { const pathParts = path.slice(); const propToSet = pathParts.pop(); let current = obj; pathParts.forEach(p => { if (typeof current[p] !== 'object') current[p] = {}; current = current[p]; }); current[propToSet] = value; } const splitHandlerName = name => { let _splitCamelCase = splitCamelCase(name), _splitCamelCase2 = _toArray(_splitCamelCase), on = _splitCamelCase2[0], gestureName = _splitCamelCase2[1], eventName = _splitCamelCase2.slice(2); eventName = eventName.length === 0 ? ['default'] : eventName; return [on + gestureName, eventName.join('')]; }; function withGestures(Wrapped, config) { const handledEvents = []; const configuredTriggers = gestureTriggers(config); const bindTriggerToCallbacks = (triggerFunc, callbacks) => { const fireEvent = function fireEvent(event) { let name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'default'; if (!handledEvents.includes(event)) { handledEvents.push(event); if (name in callbacks) callbacks[name](event); } }; return triggerFunc.bind(null, fireEvent); }; return function (props) { let passtroughProps = {}; let gestureTriggers = {}; let gestureCallbacks = {}; Object.entries(props).forEach((_ref) => { let _ref2 = _slicedToArray(_ref, 2), propName = _ref2[0], prop = _ref2[1]; let _splitHandlerName = splitHandlerName(propName), _splitHandlerName2 = _slicedToArray(_splitHandlerName, 2), gestureName = _splitHandlerName2[0], gestureEventName = _splitHandlerName2[1]; gestureEventName = gestureEventName.toLowerCase(); if (gestureName in configuredTriggers) { let gestureCallback = prop; setPath(gestureCallbacks, [gestureName, gestureEventName], gestureCallback); } else { passtroughProps[propName] = prop; } }); Object.entries(gestureCallbacks).forEach((_ref3) => { let _ref4 = _slicedToArray(_ref3, 2), gestureName = _ref4[0], callbacks = _ref4[1]; let currentTriggers = mapObj(configuredTriggers[gestureName], (name, triggerFunc) => bindTriggerToCallbacks(triggerFunc, callbacks)); gestureTriggers = mergeWith(series, gestureTriggers, currentTriggers); }); return h("span", gestureTriggers, h(Wrapped, passtroughProps)); }; } export { withGestures };