@use-gesture/core
Advanced tools
Comparing version 10.0.0-beta.10 to 10.0.0-beta.11
export { Controller } from './Controller'; | ||
export { DragEngine } from './engines/DragEngine'; | ||
export { dragConfigResolver } from './config/dragConfigResolver'; | ||
export { PinchEngine } from './engines/PinchEngine'; | ||
export { pinchConfigResolver } from './config/pinchConfigResolver'; | ||
export { WheelEngine } from './engines/WheelEngine'; | ||
export { wheelConfigResolver } from './config/wheelConfigResolver'; | ||
export { ScrollEngine } from './engines/ScrollEngine'; | ||
export { scrollConfigResolver } from './config/scrollConfigResolver'; | ||
export { MoveEngine } from './engines/MoveEngine'; | ||
export { moveConfigResolver } from './config/moveConfigResolver'; | ||
export { HoverEngine } from './engines/HoverEngine'; | ||
export { hoverConfigResolver } from './config/hoverConfigResolver'; | ||
export { registerEngine, parseMergedHandlers } from './imports'; | ||
export { parseMergedHandlers } from './parser'; |
@@ -6,1 +6,2 @@ export * from './config'; | ||
export * from './handlers'; | ||
export * from './action'; |
@@ -5,115 +5,5 @@ 'use strict'; | ||
var maths = require('./maths-125ca19a.cjs.dev.js'); | ||
var actions_dist_useGestureCoreActions = require('./actions-50385b2b.cjs.dev.js'); | ||
require('./maths-125ca19a.cjs.dev.js'); | ||
function _defineProperty(obj, key, value) { | ||
if (key in obj) { | ||
Object.defineProperty(obj, key, { | ||
value: value, | ||
enumerable: true, | ||
configurable: true, | ||
writable: true | ||
}); | ||
} else { | ||
obj[key] = value; | ||
} | ||
return obj; | ||
} | ||
function ownKeys(object, enumerableOnly) { | ||
var keys = Object.keys(object); | ||
if (Object.getOwnPropertySymbols) { | ||
var symbols = Object.getOwnPropertySymbols(object); | ||
if (enumerableOnly) { | ||
symbols = symbols.filter(function (sym) { | ||
return Object.getOwnPropertyDescriptor(object, sym).enumerable; | ||
}); | ||
} | ||
keys.push.apply(keys, symbols); | ||
} | ||
return keys; | ||
} | ||
function _objectSpread2(target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i] != null ? arguments[i] : {}; | ||
if (i % 2) { | ||
ownKeys(Object(source), true).forEach(function (key) { | ||
_defineProperty(target, key, source[key]); | ||
}); | ||
} else if (Object.getOwnPropertyDescriptors) { | ||
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); | ||
} else { | ||
ownKeys(Object(source)).forEach(function (key) { | ||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); | ||
}); | ||
} | ||
} | ||
return target; | ||
} | ||
const EngineMap = new Map(); | ||
const ConfigResolverMap = new Map(); | ||
function registerEngine(action, Engine, resolver) { | ||
EngineMap.set(action, Engine); | ||
ConfigResolverMap.set(action, resolver); | ||
} | ||
const RE_NOT_NATIVE = /^on(Drag|Wheel|Scroll|Move|Pinch|Hover)/; | ||
function sortHandlers(_handlers) { | ||
const native = {}; | ||
const handlers = {}; | ||
const actions = new Set(); | ||
for (let key in _handlers) { | ||
if (RE_NOT_NATIVE.test(key)) { | ||
actions.add(RegExp.lastMatch); | ||
handlers[key] = _handlers[key]; | ||
} else { | ||
native[key] = _handlers[key]; | ||
} | ||
} | ||
return [handlers, native, actions]; | ||
} | ||
function registerGesture(actions, handlers, handlerKey, key, internalHandlers, config) { | ||
if (!actions.has(handlerKey)) return; | ||
const startKey = handlerKey + 'Start'; | ||
const endKey = handlerKey + 'End'; | ||
const fn = state => { | ||
let memo = undefined; | ||
if (state.first && startKey in handlers) handlers[startKey](state); | ||
if (handlerKey in handlers) memo = handlers[handlerKey](state); | ||
if (state.last && endKey in handlers) handlers[endKey](state); | ||
return memo; | ||
}; | ||
internalHandlers[key] = fn; | ||
config[key] = config[key] || {}; | ||
} | ||
function parseMergedHandlers(mergedHandlers, mergedConfig) { | ||
const [handlers, nativeHandlers, actions] = sortHandlers(mergedHandlers); | ||
const internalHandlers = {}; | ||
registerGesture(actions, handlers, 'onDrag', 'drag', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onWheel', 'wheel', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onScroll', 'scroll', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onPinch', 'pinch', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onMove', 'move', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onHover', 'hover', internalHandlers, mergedConfig); | ||
return { | ||
handlers: internalHandlers, | ||
config: mergedConfig, | ||
nativeHandlers | ||
}; | ||
} | ||
function _objectWithoutPropertiesLoose(source, excluded) { | ||
@@ -153,32 +43,2 @@ if (source == null) return {}; | ||
const isBrowser = typeof window !== 'undefined' && window.document && window.document.createElement; | ||
function supportsTouchEvents() { | ||
return isBrowser && 'ontouchstart' in window; | ||
} | ||
function supportsPointerEvents() { | ||
return isBrowser && 'onpointerdown' in window; | ||
} | ||
function supportsPointerLock() { | ||
return isBrowser && 'exitPointerLock' in window.document; | ||
} | ||
function supportsGestureEvents() { | ||
try { | ||
return 'constructor' in GestureEvent; | ||
} catch (e) { | ||
return false; | ||
} | ||
} | ||
const SUPPORT = { | ||
isBrowser, | ||
gesture: supportsGestureEvents(), | ||
touch: supportsTouchEvents(), | ||
pointer: supportsPointerEvents(), | ||
pointerLock: supportsPointerLock() | ||
}; | ||
const identity = v => v; | ||
@@ -198,3 +58,3 @@ const sharedConfigResolver = { | ||
window(value = SUPPORT.isBrowser ? window : undefined) { | ||
window(value = actions_dist_useGestureCoreActions.SUPPORT.isBrowser ? window : undefined) { | ||
return value; | ||
@@ -259,4 +119,4 @@ }, | ||
if (gestureKey) { | ||
const resolver = ConfigResolverMap.get(gestureKey); | ||
_config[gestureKey] = resolveWith(_objectSpread2({ | ||
const resolver = actions_dist_useGestureCoreActions.ConfigResolverMap.get(gestureKey); | ||
_config[gestureKey] = resolveWith(actions_dist_useGestureCoreActions._objectSpread2({ | ||
shared: _config.shared | ||
@@ -266,4 +126,9 @@ }, rest), resolver); | ||
for (const key in rest) { | ||
const resolver = ConfigResolverMap.get(key); | ||
_config[key] = resolveWith(_objectSpread2({ | ||
const resolver = actions_dist_useGestureCoreActions.ConfigResolverMap.get(key); | ||
if (process.env.NODE_ENV === 'development') { | ||
if (!resolver) console.warn(`[@use-gesture]: You've created a custom handler that that uses the \`${key}\` gesture but isn't properly configured.\n\nPlease add \`${key}Action\` when creating your handler.`); | ||
} | ||
_config[key] = resolveWith(actions_dist_useGestureCoreActions._objectSpread2({ | ||
shared: _config.shared | ||
@@ -277,144 +142,5 @@ }, rest[key]), resolver); | ||
const EVENT_TYPE_MAP = { | ||
pointer: { | ||
start: 'down', | ||
change: 'move', | ||
end: 'up' | ||
}, | ||
mouse: { | ||
start: 'down', | ||
change: 'move', | ||
end: 'up' | ||
}, | ||
touch: { | ||
start: 'start', | ||
change: 'move', | ||
end: 'end' | ||
}, | ||
gesture: { | ||
start: 'start', | ||
change: 'change', | ||
end: 'end' | ||
} | ||
}; | ||
function capitalize(string) { | ||
if (!string) return ''; | ||
return string[0].toUpperCase() + string.slice(1); | ||
} | ||
function toReactHandlerProp(device, action = '', capture = false) { | ||
const deviceProps = EVENT_TYPE_MAP[device]; | ||
const actionKey = deviceProps ? deviceProps[action] || action : action; | ||
return 'on' + capitalize(device) + capitalize(actionKey) + (capture ? 'Capture' : ''); | ||
} | ||
function toDomEventType(device, action = '') { | ||
const deviceProps = EVENT_TYPE_MAP[device]; | ||
const actionKey = deviceProps ? deviceProps[action] || action : action; | ||
return device + actionKey; | ||
} | ||
function isTouch(event) { | ||
return 'touches' in event; | ||
} | ||
function getCurrentTargetTouchList(event) { | ||
return Array.from(event.touches).filter(e => { | ||
var _event$currentTarget; | ||
return (_event$currentTarget = event.currentTarget) === null || _event$currentTarget === void 0 ? void 0 : _event$currentTarget.contains(e.target); | ||
}); | ||
} | ||
function getTouchList(event) { | ||
return event.type === 'touchend' ? event.changedTouches : event.targetTouches; | ||
} | ||
function getValueEvent(event) { | ||
return isTouch(event) ? getTouchList(event)[0] : event; | ||
} | ||
function distanceAngle(P1, P2) { | ||
const dx = P2.clientX - P1.clientX; | ||
const dy = P2.clientY - P1.clientY; | ||
const cx = (P2.clientX + P1.clientX) / 2; | ||
const cy = (P2.clientY + P1.clientY) / 2; | ||
const distance = Math.hypot(dx, dy); | ||
const angle = -(Math.atan2(dx, dy) * 180) / Math.PI; | ||
const origin = [cx, cy]; | ||
return { | ||
angle, | ||
distance, | ||
origin | ||
}; | ||
} | ||
function touchIds(event) { | ||
return getCurrentTargetTouchList(event).map(touch => touch.identifier); | ||
} | ||
function touchDistanceAngle(event, ids) { | ||
const [P1, P2] = Array.from(event.touches).filter(touch => ids.includes(touch.identifier)); | ||
return distanceAngle(P1, P2); | ||
} | ||
function pointerId(event) { | ||
const valueEvent = getValueEvent(event); | ||
return isTouch(event) ? valueEvent.identifier : valueEvent.pointerId; | ||
} | ||
function pointerValues(event) { | ||
const valueEvent = getValueEvent(event); | ||
return [valueEvent.clientX, valueEvent.clientY]; | ||
} | ||
const LINE_HEIGHT = 40; | ||
const PAGE_HEIGHT = 800; | ||
function wheelValues(event) { | ||
let { | ||
deltaX, | ||
deltaY, | ||
deltaMode | ||
} = event; | ||
if (deltaMode === 1) { | ||
deltaX *= LINE_HEIGHT; | ||
deltaY *= LINE_HEIGHT; | ||
} else if (deltaMode === 2) { | ||
deltaX *= PAGE_HEIGHT; | ||
deltaY *= PAGE_HEIGHT; | ||
} | ||
return [deltaX, deltaY]; | ||
} | ||
function scrollValues(event) { | ||
var _ref, _ref2; | ||
const { | ||
scrollX, | ||
scrollY, | ||
scrollLeft, | ||
scrollTop | ||
} = event.currentTarget; | ||
return [(_ref = scrollX !== null && scrollX !== void 0 ? scrollX : scrollLeft) !== null && _ref !== void 0 ? _ref : 0, (_ref2 = scrollY !== null && scrollY !== void 0 ? scrollY : scrollTop) !== null && _ref2 !== void 0 ? _ref2 : 0]; | ||
} | ||
function getEventDetails(event) { | ||
const payload = {}; | ||
if ('buttons' in event) payload.buttons = event.buttons; | ||
if ('shiftKey' in event) { | ||
const { | ||
shiftKey, | ||
altKey, | ||
metaKey, | ||
ctrlKey | ||
} = event; | ||
Object.assign({ | ||
shiftKey, | ||
altKey, | ||
metaKey, | ||
ctrlKey | ||
}); | ||
} | ||
return payload; | ||
} | ||
class EventStore { | ||
constructor(ctrl) { | ||
_defineProperty(this, "_listeners", []); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "_listeners", []); | ||
@@ -425,3 +151,3 @@ this._ctrl = ctrl; | ||
add(element, device, action, handler, options) { | ||
const type = toDomEventType(device, action); | ||
const type = actions_dist_useGestureCoreActions.toDomEventType(device, action); | ||
const eventOptions = options || this._ctrl.config.shared.eventOptions; | ||
@@ -443,3 +169,3 @@ element.addEventListener(type, handler, eventOptions); | ||
constructor() { | ||
_defineProperty(this, "_timeouts", new Map()); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "_timeouts", new Map()); | ||
} | ||
@@ -467,46 +193,21 @@ | ||
function call(v, ...args) { | ||
if (typeof v === 'function') { | ||
return v(...args); | ||
} else { | ||
return v; | ||
} | ||
} | ||
function noop() {} | ||
function chain(...fns) { | ||
if (fns.length === 0) return noop; | ||
if (fns.length === 1) return fns[0]; | ||
return function () { | ||
let result; | ||
for (const fn of fns) { | ||
result = fn.apply(this, arguments) || result; | ||
} | ||
return result; | ||
}; | ||
} | ||
function assignDefault(value, fallback) { | ||
return Object.assign({}, fallback, value || {}); | ||
} | ||
class Controller { | ||
constructor(handlers) { | ||
_defineProperty(this, "gestures", new Set()); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "gestures", new Set()); | ||
_defineProperty(this, "_targetEventStore", new EventStore(this)); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "_targetEventStore", new EventStore(this)); | ||
_defineProperty(this, "gestureEventStores", {}); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "gestureEventStores", {}); | ||
_defineProperty(this, "gestureTimeoutStores", {}); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "gestureTimeoutStores", {}); | ||
_defineProperty(this, "handlers", {}); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "handlers", {}); | ||
_defineProperty(this, "config", {}); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "config", {}); | ||
_defineProperty(this, "pointerIds", new Set()); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "pointerIds", new Set()); | ||
_defineProperty(this, "touchIds", new Set()); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "touchIds", new Set()); | ||
_defineProperty(this, "state", { | ||
actions_dist_useGestureCoreActions._defineProperty(this, "state", { | ||
shared: { | ||
@@ -524,4 +225,4 @@ shiftKey: false, | ||
setEventIds(event) { | ||
if (isTouch(event)) { | ||
this.touchIds = new Set(touchIds(event)); | ||
if (actions_dist_useGestureCoreActions.isTouch(event)) { | ||
this.touchIds = new Set(actions_dist_useGestureCoreActions.touchIds(event)); | ||
} else if ('pointerId' in event) { | ||
@@ -570,3 +271,3 @@ if (event.type === 'pointerup') this.pointerIds.delete(event.pointerId);else this.pointerIds.add(event.pointerId); | ||
for (const eventKey in this.nativeHandlers) { | ||
bindFunction(eventKey, '', event => this.nativeHandlers[eventKey](_objectSpread2(_objectSpread2({}, this.state.shared), {}, { | ||
bindFunction(eventKey, '', event => this.nativeHandlers[eventKey](actions_dist_useGestureCoreActions._objectSpread2(actions_dist_useGestureCoreActions._objectSpread2({}, this.state.shared), {}, { | ||
event, | ||
@@ -579,3 +280,3 @@ args | ||
if (this.config[gestureKey].enabled) { | ||
const Engine = EngineMap.get(gestureKey); | ||
const Engine = actions_dist_useGestureCoreActions.EngineMap.get(gestureKey); | ||
new Engine(this, args, gestureKey).bind(bindFunction); | ||
@@ -588,3 +289,3 @@ } | ||
for (const handlerProp in props) { | ||
props[handlerProp] = chain(...props[handlerProp]); | ||
props[handlerProp] = actions_dist_useGestureCoreActions.chain(...props[handlerProp]); | ||
} | ||
@@ -622,3 +323,3 @@ | ||
const capture = (_options$capture = options.capture) !== null && _options$capture !== void 0 ? _options$capture : eventOptions.capture; | ||
const handlerProp = isNative ? device : toReactHandlerProp(device, action, capture); | ||
const handlerProp = isNative ? device : actions_dist_useGestureCoreActions.toReactHandlerProp(device, action, capture); | ||
props[handlerProp] = props[handlerProp] || []; | ||
@@ -628,1234 +329,55 @@ props[handlerProp].push(handler); | ||
class Engine { | ||
constructor(ctrl, args, key) { | ||
this.ctrl = ctrl; | ||
this.args = args; | ||
this.key = key; | ||
const RE_NOT_NATIVE = /^on(Drag|Wheel|Scroll|Move|Pinch|Hover)/; | ||
if (!this.state) { | ||
this.state = { | ||
values: [0, 0], | ||
initial: [0, 0] | ||
}; | ||
if (this.init) this.init(); | ||
this.reset(); | ||
} | ||
} | ||
function sortHandlers(_handlers) { | ||
const native = {}; | ||
const handlers = {}; | ||
const actions = new Set(); | ||
get state() { | ||
return this.ctrl.state[this.key]; | ||
} | ||
set state(state) { | ||
this.ctrl.state[this.key] = state; | ||
} | ||
get shared() { | ||
return this.ctrl.state.shared; | ||
} | ||
get eventStore() { | ||
return this.ctrl.gestureEventStores[this.key]; | ||
} | ||
get timeoutStore() { | ||
return this.ctrl.gestureTimeoutStores[this.key]; | ||
} | ||
get config() { | ||
return this.ctrl.config[this.key]; | ||
} | ||
get sharedConfig() { | ||
return this.ctrl.config.shared; | ||
} | ||
get handler() { | ||
return this.ctrl.handlers[this.key]; | ||
} | ||
reset() { | ||
const { | ||
state, | ||
shared, | ||
config, | ||
ingKey, | ||
args | ||
} = this; | ||
const { | ||
transform, | ||
threshold = [0, 0] | ||
} = config; | ||
shared[ingKey] = state._active = state.active = state._blocked = state._force = false; | ||
state._step = [false, false]; | ||
state.intentional = false; | ||
state._movement = [0, 0]; | ||
state._distance = [0, 0]; | ||
state._delta = [0, 0]; | ||
state._threshold = maths.V.sub(transform(threshold), transform([0, 0])).map(Math.abs); | ||
state._bounds = [[-Infinity, Infinity], [-Infinity, Infinity]]; | ||
state.args = args; | ||
state.axis = undefined; | ||
state.memo = undefined; | ||
state.elapsedTime = 0; | ||
state.direction = [0, 0]; | ||
state.distance = [0, 0]; | ||
state.velocity = [0, 0]; | ||
state.movement = [0, 0]; | ||
state.delta = [0, 0]; | ||
state.timeStamp = 0; | ||
} | ||
start(event) { | ||
const state = this.state; | ||
const config = this.config; | ||
if (!state._active) { | ||
this.reset(); | ||
state._active = true; | ||
state.target = event.currentTarget; | ||
state.initial = state.values; | ||
state.lastOffset = config.from ? call(config.from, state) : state.offset; | ||
state.offset = state.lastOffset; | ||
} | ||
state.startTime = state.timeStamp = event.timeStamp; | ||
} | ||
compute(event) { | ||
const { | ||
state, | ||
config, | ||
shared | ||
} = this; | ||
state.args = this.args; | ||
let dt = 0; | ||
if (event) { | ||
state.event = event; | ||
shared.touches = this.ctrl.pointerIds.size || this.ctrl.touchIds.size; | ||
shared.locked = !!document.pointerLockElement; | ||
Object.assign(shared, getEventDetails(event)); | ||
shared.down = shared.pressed = shared.buttons % 2 === 1 || shared.touches > 0; | ||
dt = event.timeStamp - state.timeStamp; | ||
state.timeStamp = event.timeStamp; | ||
state.elapsedTime = state.timeStamp - state.startTime; | ||
} | ||
if (state._active) { | ||
const _absoluteDelta = state._delta.map(Math.abs); | ||
maths.V.addTo(state._distance, _absoluteDelta); | ||
} | ||
const [_m0, _m1] = config.transform(state._movement); | ||
const [_t0, _t1] = state._threshold; | ||
let [_s0, _s1] = state._step; | ||
if (_s0 === false) _s0 = Math.abs(_m0) >= _t0 && Math.sign(_m0) * _t0; | ||
if (_s1 === false) _s1 = Math.abs(_m1) >= _t1 && Math.sign(_m1) * _t1; | ||
state.intentional = _s0 !== false || _s1 !== false; | ||
if (!state.intentional) return; | ||
state._step = [_s0, _s1]; | ||
const movement = [0, 0]; | ||
movement[0] = _s0 !== false ? _m0 - _s0 : 0; | ||
movement[1] = _s1 !== false ? _m1 - _s1 : 0; | ||
if (this.intent) this.intent(movement); | ||
if (state._active && !state._blocked || state.active) { | ||
state.first = state._active && !state.active; | ||
state.last = !state._active && state.active; | ||
state.active = shared[this.ingKey] = state._active; | ||
if (event) { | ||
if (state.first) { | ||
if ('bounds' in config) state._bounds = call(config.bounds, state); | ||
if (this.setup) this.setup(); | ||
} | ||
const previousMovement = state.movement; | ||
state.movement = movement; | ||
this.computeOffset(); | ||
if (!state.last) { | ||
state.delta = maths.V.sub(movement, previousMovement); | ||
const absoluteDelta = state.delta.map(Math.abs); | ||
maths.V.addTo(state.distance, absoluteDelta); | ||
state.direction = state.delta.map(Math.sign); | ||
if (!state.first && dt > 0) { | ||
state.velocity = [absoluteDelta[0] / dt, absoluteDelta[1] / dt]; | ||
} | ||
} | ||
} | ||
} | ||
const rubberband = state._active ? config.rubberband || [0, 0] : [0, 0]; | ||
state.offset = maths.computeRubberband(state._bounds, state.offset, rubberband); | ||
this.computeMovement(); | ||
} | ||
emit() { | ||
const state = this.state; | ||
const shared = this.shared; | ||
const config = this.config; | ||
if (!state._active) this.clean(); | ||
if ((state._blocked || !state.intentional) && !state._force && !config.triggerAllEvents) return; | ||
const memo = this.handler(_objectSpread2(_objectSpread2({}, shared), state)); | ||
if (memo !== undefined) state.memo = memo; | ||
} | ||
clean() { | ||
this.eventStore.clean(); | ||
this.timeoutStore.clean(); | ||
} | ||
} | ||
function selectAxis([dx, dy]) { | ||
const d = Math.abs(dx) - Math.abs(dy); | ||
if (d > 0) return 'x'; | ||
if (d < 0) return 'y'; | ||
return undefined; | ||
} | ||
function restrictVectorToAxis(v, axis) { | ||
switch (axis) { | ||
case 'x': | ||
v[1] = 0; | ||
break; | ||
case 'y': | ||
v[0] = 0; | ||
break; | ||
} | ||
} | ||
class CoordinatesEngine extends Engine { | ||
reset() { | ||
super.reset(); | ||
this.state.axis = undefined; | ||
} | ||
init() { | ||
this.state.offset = [0, 0]; | ||
this.state.lastOffset = [0, 0]; | ||
} | ||
computeOffset() { | ||
this.state.offset = maths.V.add(this.state.lastOffset, this.state.movement); | ||
} | ||
computeMovement() { | ||
this.state.movement = maths.V.sub(this.state.offset, this.state.lastOffset); | ||
this.state.xy = this.state.values; | ||
} | ||
intent(v) { | ||
this.state.axis = this.state.axis || selectAxis(v); | ||
this.state._blocked = (this.config.lockDirection || !!this.config.axis) && !this.state.axis || !!this.config.axis && this.config.axis !== this.state.axis; | ||
if (this.state._blocked) return; | ||
if (this.config.axis || this.config.lockDirection) { | ||
restrictVectorToAxis(v, this.state.axis); | ||
} | ||
} | ||
} | ||
const DEFAULT_RUBBERBAND = 0.15; | ||
const commonConfigResolver = { | ||
enabled(value = true) { | ||
return value; | ||
}, | ||
triggerAllEvents(value = false) { | ||
return value; | ||
}, | ||
rubberband(value = 0) { | ||
switch (value) { | ||
case true: | ||
return [DEFAULT_RUBBERBAND, DEFAULT_RUBBERBAND]; | ||
case false: | ||
return [0, 0]; | ||
default: | ||
return maths.V.toVector(value); | ||
} | ||
}, | ||
from(value) { | ||
if (typeof value === 'function') return value; | ||
if (value != null) return maths.V.toVector(value); | ||
}, | ||
transform(value, _k, config) { | ||
return value || config.shared.transform; | ||
} | ||
}; | ||
if (process.env.NODE_ENV === 'development') { | ||
Object.assign(commonConfigResolver, { | ||
domTarget(value) { | ||
if (value !== undefined) { | ||
throw Error(`[@use-gesture]: \`domTarget\` option has been renamed to \`target\`.`); | ||
} | ||
}, | ||
lockDirection(value) { | ||
if (value !== undefined) { | ||
throw Error(`[@use-gesture]: \`lockDirection\` option has been merged with \`axis\`. Use it as in \`{ axis: 'lock' }\``); | ||
} | ||
}, | ||
initial(value) { | ||
if (value !== undefined) { | ||
throw Error(`[@use-gesture]: \`initial\` option has been renamed to \`from\`.`); | ||
} | ||
} | ||
}); | ||
} | ||
const coordinatesConfigResolver = _objectSpread2(_objectSpread2({}, commonConfigResolver), {}, { | ||
axis(_v, _k, { | ||
axis | ||
}) { | ||
this.lockDirection = axis === 'lock'; | ||
if (!this.lockDirection) return axis; | ||
}, | ||
bounds(value = {}) { | ||
if (typeof value === 'function') { | ||
return state => coordinatesConfigResolver.bounds(value(state)); | ||
} | ||
if ('current' in value) { | ||
return () => value.current; | ||
} | ||
if (typeof HTMLElement === 'function' && value instanceof HTMLElement) { | ||
return value; | ||
} | ||
const { | ||
left = -Infinity, | ||
right = Infinity, | ||
top = -Infinity, | ||
bottom = Infinity | ||
} = value; | ||
return [[left, right], [top, bottom]]; | ||
} | ||
}); | ||
const DISPLACEMENT = 10; | ||
const KEYS_DELTA_MAP = { | ||
ArrowRight: (factor = 1) => [DISPLACEMENT * factor, 0], | ||
ArrowLeft: (factor = 1) => [-DISPLACEMENT * factor, 0], | ||
ArrowUp: (factor = 1) => [0, -DISPLACEMENT * factor], | ||
ArrowDown: (factor = 1) => [0, DISPLACEMENT * factor] | ||
}; | ||
class DragEngine extends CoordinatesEngine { | ||
constructor(...args) { | ||
super(...args); | ||
_defineProperty(this, "ingKey", 'dragging'); | ||
} | ||
reset() { | ||
super.reset(); | ||
const state = this.state; | ||
state._pointerId = undefined; | ||
state._pointerActive = false; | ||
state._keyboardActive = false; | ||
state._preventScroll = false; | ||
state._delayed = false; | ||
state.swipe = [0, 0]; | ||
state.tap = false; | ||
state.canceled = false; | ||
state.cancel = this.cancel.bind(this); | ||
} | ||
setup() { | ||
const state = this.state; | ||
if (state._bounds instanceof HTMLElement) { | ||
const boundRect = state._bounds.getBoundingClientRect(); | ||
const targetRect = state.target.getBoundingClientRect(); | ||
const _bounds = { | ||
left: boundRect.left - targetRect.left + state.offset[0], | ||
right: boundRect.right - targetRect.right + state.offset[0], | ||
top: boundRect.top - targetRect.top + state.offset[1], | ||
bottom: boundRect.bottom - targetRect.bottom + state.offset[1] | ||
}; | ||
state._bounds = coordinatesConfigResolver.bounds(_bounds); | ||
} | ||
} | ||
cancel() { | ||
const state = this.state; | ||
if (state.canceled) return; | ||
setTimeout(() => { | ||
state.canceled = true; | ||
state._active = false; | ||
this.compute(); | ||
this.emit(); | ||
}, 0); | ||
} | ||
setActive() { | ||
this.state._active = this.state._pointerActive || this.state._keyboardActive; | ||
} | ||
clean() { | ||
this.pointerClean(); | ||
this.state._pointerActive = false; | ||
this.state._keyboardActive = false; | ||
super.clean(); | ||
} | ||
pointerDown(event) { | ||
if (event.buttons != null && event.buttons % 2 !== 1) return; | ||
this.ctrl.setEventIds(event); | ||
if (this.config.pointerCapture) { | ||
event.target.setPointerCapture(event.pointerId); | ||
} | ||
const state = this.state; | ||
const config = this.config; | ||
if (state._pointerActive) return; | ||
this.start(event); | ||
this.setupPointer(event); | ||
state._pointerId = pointerId(event); | ||
state._pointerActive = true; | ||
state.values = pointerValues(event); | ||
state.initial = state.values; | ||
if (config.preventScroll) { | ||
this.setupScrollPrevention(event); | ||
} else if (config.delay > 0) { | ||
this.setupDelayTrigger(event); | ||
for (let key in _handlers) { | ||
if (RE_NOT_NATIVE.test(key)) { | ||
actions.add(RegExp.lastMatch); | ||
handlers[key] = _handlers[key]; | ||
} else { | ||
this.startPointerDrag(event); | ||
native[key] = _handlers[key]; | ||
} | ||
} | ||
startPointerDrag(event) { | ||
const state = this.state; | ||
state._active = true; | ||
state._preventScroll = true; | ||
state._delayed = false; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
pointerMove(event) { | ||
const state = this.state; | ||
const config = this.config; | ||
if (!state._pointerActive) return; | ||
const id = pointerId(event); | ||
if (state._pointerId && id !== state._pointerId) return; | ||
const values = pointerValues(event); | ||
if (document.pointerLockElement === event.target) { | ||
state._delta = [event.movementX, event.movementY]; | ||
} else { | ||
state._delta = maths.V.sub(values, state.values); | ||
state.values = values; | ||
} | ||
maths.V.addTo(state._movement, state._delta); | ||
this.compute(event); | ||
if (state._delayed) { | ||
this.timeoutStore.remove('dragDelay'); | ||
this.startPointerDrag(event); | ||
return; | ||
} | ||
if (config.preventScroll && !state._preventScroll) { | ||
if (state.axis) { | ||
if (state.axis === config.preventScrollAxis || config.preventScrollAxis === 'xy') { | ||
state._active = false; | ||
this.clean(); | ||
return; | ||
} else { | ||
this.timeoutStore.remove('startPointerDrag'); | ||
this.startPointerDrag(event); | ||
return; | ||
} | ||
} else { | ||
return; | ||
} | ||
} | ||
this.emit(); | ||
} | ||
pointerUp(event) { | ||
this.ctrl.setEventIds(event); | ||
try { | ||
if (this.config.pointerCapture && event.target.hasPointerCapture(event.pointerId)) { | ||
; | ||
event.target.releasePointerCapture(event.pointerId); | ||
} | ||
} catch (_unused) { | ||
if (process.env.NODE_ENV === 'development') { | ||
console.warn(`[@use-gesture]: If you see this message, it's likely that you're using an outdated version of \`@react-three/fiber\`. \n\nPlease upgrade to the latest version.`); | ||
} | ||
} | ||
const state = this.state; | ||
const config = this.config; | ||
if (!state._pointerActive) return; | ||
const id = pointerId(event); | ||
if (state._pointerId && id !== state._pointerId) return; | ||
this.state._pointerActive = false; | ||
this.setActive(); | ||
this.compute(event); | ||
const [dx, dy] = state._distance; | ||
state.tap = dx <= 3 && dy <= 3; | ||
if (state.tap && config.filterTaps) { | ||
state._force = true; | ||
} else { | ||
const [dirx, diry] = state.direction; | ||
const [vx, vy] = state.velocity; | ||
const [mx, my] = state.movement; | ||
const [svx, svy] = config.swipe.velocity; | ||
const [sx, sy] = config.swipe.distance; | ||
const sdt = config.swipe.duration; | ||
if (state.elapsedTime < sdt) { | ||
if (Math.abs(vx) > svx && Math.abs(mx) > sx) state.swipe[0] = dirx; | ||
if (Math.abs(vy) > svy && Math.abs(my) > sy) state.swipe[1] = diry; | ||
} | ||
} | ||
this.emit(); | ||
} | ||
pointerClick(event) { | ||
if (!this.state.tap) { | ||
event.preventDefault(); | ||
event.stopPropagation(); | ||
} | ||
} | ||
setupPointer(event) { | ||
const config = this.config; | ||
let device = config.device; | ||
if (process.env.NODE_ENV === 'development') { | ||
try { | ||
if (device === 'pointer') { | ||
const currentTarget = 'uv' in event ? event.sourceEvent.currentTarget : event.currentTarget; | ||
const style = window.getComputedStyle(currentTarget); | ||
if (style.touchAction === 'auto') { | ||
console.warn(`[@use-gesture]: The drag target has its \`touch-action\` style property set to \`auto\`. It is recommended to add \`touch-action: 'none'\` so that the drag gesture behaves correctly on touch-enabled devices. For more information read this: https://use-gesture.netlify.app/docs/extras/#touch-action.\n\nThis message will only show in development mode. It won't appear in production. If this is intended, you can ignore it.`, currentTarget); | ||
} | ||
} | ||
} catch (_unused2) {} | ||
} | ||
if (config.pointerLock) { | ||
event.currentTarget.requestPointerLock(); | ||
} | ||
if (!config.pointerCapture) { | ||
this.eventStore.add(this.sharedConfig.window, device, 'change', this.pointerMove.bind(this)); | ||
this.eventStore.add(this.sharedConfig.window, device, 'end', this.pointerUp.bind(this)); | ||
} | ||
} | ||
pointerClean() { | ||
if (this.config.pointerLock && document.pointerLockElement === this.state.target) { | ||
document.exitPointerLock(); | ||
} | ||
} | ||
preventScroll(event) { | ||
if (this.state._preventScroll && event.cancelable) { | ||
event.preventDefault(); | ||
} | ||
} | ||
setupScrollPrevention(event) { | ||
persistEvent(event); | ||
this.eventStore.add(this.sharedConfig.window, 'touch', 'change', this.preventScroll.bind(this), { | ||
passive: false | ||
}); | ||
this.eventStore.add(this.sharedConfig.window, 'touch', 'end', this.clean.bind(this), { | ||
passive: false | ||
}); | ||
this.eventStore.add(this.sharedConfig.window, 'touch', 'cancel', this.clean.bind(this), { | ||
passive: false | ||
}); | ||
this.timeoutStore.add('startPointerDrag', this.startPointerDrag.bind(this), this.config.preventScroll, event); | ||
} | ||
setupDelayTrigger(event) { | ||
this.state._delayed = true; | ||
this.timeoutStore.add('dragDelay', this.startPointerDrag.bind(this), this.config.delay, event); | ||
} | ||
keyDown(event) { | ||
const deltaFn = KEYS_DELTA_MAP[event.key]; | ||
const state = this.state; | ||
if (deltaFn) { | ||
const factor = event.shiftKey ? 10 : event.altKey ? 0.1 : 1; | ||
state._delta = deltaFn(factor); | ||
this.start(event); | ||
state._keyboardActive = true; | ||
maths.V.addTo(state._movement, state._delta); | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
} | ||
keyUp(event) { | ||
if (!(event.key in KEYS_DELTA_MAP)) return; | ||
this.state._keyboardActive = false; | ||
this.setActive(); | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
bind(bindFunction) { | ||
const device = this.config.device; | ||
bindFunction(device, 'start', this.pointerDown.bind(this)); | ||
if (this.config.pointerCapture) { | ||
bindFunction(device, 'change', this.pointerMove.bind(this)); | ||
bindFunction(device, 'end', this.pointerUp.bind(this)); | ||
bindFunction(device, 'cancel', this.pointerUp.bind(this)); | ||
} | ||
bindFunction('key', 'down', this.keyDown.bind(this)); | ||
bindFunction('key', 'up', this.keyUp.bind(this)); | ||
if (this.config.filterTaps) { | ||
bindFunction('click', '', this.pointerClick.bind(this), { | ||
capture: true | ||
}); | ||
} | ||
} | ||
return [handlers, native, actions]; | ||
} | ||
function persistEvent(event) { | ||
'persist' in event && typeof event.persist === 'function' && event.persist(); | ||
} | ||
function registerGesture(actions, handlers, handlerKey, key, internalHandlers, config) { | ||
if (!actions.has(handlerKey)) return; | ||
const startKey = handlerKey + 'Start'; | ||
const endKey = handlerKey + 'End'; | ||
const DEFAULT_PREVENT_SCROLL_DELAY = 250; | ||
const DEFAULT_DRAG_DELAY = 180; | ||
const DEFAULT_SWIPE_VELOCITY = 0.5; | ||
const DEFAULT_SWIPE_DISTANCE = 50; | ||
const DEFAULT_SWIPE_DURATION = 250; | ||
const dragConfigResolver = _objectSpread2(_objectSpread2({}, coordinatesConfigResolver), {}, { | ||
pointerLock(_v, _k, { | ||
pointer: { | ||
lock = false, | ||
touch = false | ||
} = {} | ||
}) { | ||
this.useTouch = SUPPORT.touch && touch; | ||
return SUPPORT.pointerLock && lock; | ||
}, | ||
const fn = state => { | ||
let memo = undefined; | ||
if (state.first && startKey in handlers) handlers[startKey](state); | ||
if (handlerKey in handlers) memo = handlers[handlerKey](state); | ||
if (state.last && endKey in handlers) handlers[endKey](state); | ||
return memo; | ||
}; | ||
device(_v, _k) { | ||
if (this.useTouch) return 'touch'; | ||
if (this.pointerLock) return 'mouse'; | ||
if (SUPPORT.pointer) return 'pointer'; | ||
if (SUPPORT.touch) return 'touch'; | ||
return 'mouse'; | ||
}, | ||
preventScroll(value = false, _k, { | ||
preventScrollAxis = 'y' | ||
}) { | ||
if (preventScrollAxis) this.preventScrollAxis = preventScrollAxis; | ||
if (!SUPPORT.touch) return false; | ||
if (typeof value === 'number') return value; | ||
return value ? DEFAULT_PREVENT_SCROLL_DELAY : false; | ||
}, | ||
pointerCapture(_v, _k, { | ||
pointer: { | ||
capture = true | ||
} = {} | ||
}) { | ||
return !this.pointerLock && this.device === 'pointer' && capture; | ||
}, | ||
threshold(value, _k, { | ||
filterTaps = false, | ||
axis = undefined | ||
}) { | ||
const threshold = maths.V.toVector(value, filterTaps ? 3 : axis ? 1 : 0); | ||
this.filterTaps = filterTaps; | ||
return threshold; | ||
}, | ||
swipe({ | ||
velocity = DEFAULT_SWIPE_VELOCITY, | ||
distance = DEFAULT_SWIPE_DISTANCE, | ||
duration = DEFAULT_SWIPE_DURATION | ||
} = {}) { | ||
return { | ||
velocity: this.transform(maths.V.toVector(velocity)), | ||
distance: this.transform(maths.V.toVector(distance)), | ||
duration | ||
}; | ||
}, | ||
delay(value = 0) { | ||
switch (value) { | ||
case true: | ||
return DEFAULT_DRAG_DELAY; | ||
case false: | ||
return 0; | ||
default: | ||
return value; | ||
} | ||
} | ||
}); | ||
if (process.env.NODE_ENV === 'development') { | ||
Object.assign(dragConfigResolver, { | ||
useTouch(value) { | ||
if (value !== undefined) { | ||
throw Error(`[@use-gesture]: \`useTouch\` option has been renamed to \`pointer.touch\`. Use it as in \`{ pointer: { touch: true } }\`.`); | ||
} | ||
}, | ||
experimental_preventWindowScrollY(value) { | ||
if (value !== undefined) { | ||
throw Error(`[@use-gesture]: \`experimental_preventWindowScrollY\` option has been renamed to \`preventScroll\`.`); | ||
} | ||
}, | ||
swipeVelocity(value) { | ||
if (value !== undefined) { | ||
throw Error(`[@use-gesture]: \`swipeVelocity\` option has been renamed to \`swipe.velocity\`. Use it as in \`{ swipe: { velocity: 0.5 } }\`.`); | ||
} | ||
}, | ||
swipeDistance(value) { | ||
if (value !== undefined) { | ||
throw Error(`[@use-gesture]: \`swipeDistance\` option has been renamed to \`swipe.distance\`. Use it as in \`{ swipe: { distance: 50 } }\`.`); | ||
} | ||
}, | ||
swipeDuration(value) { | ||
if (value !== undefined) { | ||
throw Error(`[@use-gesture]: \`swipeDuration\` option has been renamed to \`swipe.duration\`. Use it as in \`{ swipe: { duration: 250 } }\`.`); | ||
} | ||
} | ||
}); | ||
internalHandlers[key] = fn; | ||
config[key] = config[key] || {}; | ||
} | ||
const SCALE_ANGLE_RATIO_INTENT_DEG = 30; | ||
const PINCH_WHEEL_RATIO = 60; | ||
class PinchEngine extends Engine { | ||
constructor(...args) { | ||
super(...args); | ||
_defineProperty(this, "ingKey", 'pinching'); | ||
} | ||
init() { | ||
this.state.offset = [1, 0]; | ||
this.state.lastOffset = [1, 0]; | ||
this.state._pointerEvents = new Map(); | ||
} | ||
reset() { | ||
super.reset(); | ||
const state = this.state; | ||
state._touchIds = []; | ||
state.canceled = false; | ||
state.cancel = this.cancel.bind(this); | ||
state.turns = 0; | ||
} | ||
computeOffset() { | ||
const { | ||
movement, | ||
lastOffset | ||
} = this.state; | ||
this.state.offset = [(1 + movement[0]) * lastOffset[0], movement[1] + lastOffset[1]]; | ||
} | ||
computeMovement() { | ||
const { | ||
offset, | ||
lastOffset | ||
} = this.state; | ||
this.state.movement = [offset[0] / lastOffset[0] - 1, offset[1] - lastOffset[1]]; | ||
this.state.da = this.state.values; | ||
} | ||
intent(v) { | ||
const state = this.state; | ||
if (!state.axis) { | ||
const axisMovementDifference = Math.abs(v[0]) * SCALE_ANGLE_RATIO_INTENT_DEG - Math.abs(v[1]); | ||
if (axisMovementDifference < 0) state.axis = 'angle';else if (axisMovementDifference > 0) state.axis = 'scale'; | ||
} | ||
if (this.config.lockDirection) { | ||
if (state.axis === 'scale') v[1] = 0;else if (state.axis === 'angle') v[0] = 0; | ||
} | ||
} | ||
cancel() { | ||
const state = this.state; | ||
if (state.canceled) return; | ||
setTimeout(() => { | ||
state.canceled = true; | ||
state._active = false; | ||
this.compute(); | ||
this.emit(); | ||
}, 0); | ||
} | ||
touchStart(event) { | ||
this.ctrl.setEventIds(event); | ||
const state = this.state; | ||
const ctrlTouchIds = this.ctrl.touchIds; | ||
if (state._active) { | ||
if (state._touchIds.every(id => ctrlTouchIds.has(id))) return; | ||
} | ||
if (ctrlTouchIds.size < 2) return; | ||
this.start(event); | ||
state._touchIds = Array.from(ctrlTouchIds).slice(0, 2); | ||
const payload = touchDistanceAngle(event, state._touchIds); | ||
this.pinchStart(event, payload); | ||
} | ||
pointerStart(event) { | ||
if (event.buttons != null && event.buttons % 2 !== 1) return; | ||
this.ctrl.setEventIds(event); | ||
event.target.setPointerCapture(event.pointerId); | ||
const state = this.state; | ||
const _pointerEvents = state._pointerEvents; | ||
const ctrlPointerIds = this.ctrl.pointerIds; | ||
if (state._active) { | ||
if (Array.from(_pointerEvents.keys()).every(id => ctrlPointerIds.has(id))) return; | ||
} | ||
if (_pointerEvents.size < 2) { | ||
_pointerEvents.set(event.pointerId, event); | ||
} | ||
if (state._pointerEvents.size < 2) return; | ||
this.start(event); | ||
const payload = distanceAngle(...Array.from(_pointerEvents.values())); | ||
this.pinchStart(event, payload); | ||
} | ||
pinchStart(event, payload) { | ||
const state = this.state; | ||
state.origin = payload.origin; | ||
state.values = [payload.distance, payload.angle]; | ||
state.initial = state.values; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
touchMove(event) { | ||
if (!this.state._active) return; | ||
const payload = touchDistanceAngle(event, this.state._touchIds); | ||
this.pinchMove(event, payload); | ||
} | ||
pointerMove(event) { | ||
const _pointerEvents = this.state._pointerEvents; | ||
if (_pointerEvents.has(event.pointerId)) { | ||
_pointerEvents.set(event.pointerId, event); | ||
} | ||
if (!this.state._active) return; | ||
const payload = distanceAngle(...Array.from(_pointerEvents.values())); | ||
this.pinchMove(event, payload); | ||
} | ||
pinchMove(event, payload) { | ||
const state = this.state; | ||
const prev_a = state.values[1]; | ||
const delta_a = payload.angle - prev_a; | ||
let delta_turns = 0; | ||
if (Math.abs(delta_a) > 270) delta_turns += Math.sign(delta_a); | ||
state.values = [payload.distance, payload.angle - 360 * delta_turns]; | ||
state.origin = payload.origin; | ||
state.turns = delta_turns; | ||
state._movement = [state.values[0] / state.initial[0] - 1, state.values[1] - state.initial[1]]; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
touchEnd(event) { | ||
this.ctrl.setEventIds(event); | ||
if (!this.state._active) return; | ||
if (this.state._touchIds.some(id => !this.ctrl.touchIds.has(id))) { | ||
this.state._active = false; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
} | ||
pointerEnd(event) { | ||
const state = this.state; | ||
this.ctrl.setEventIds(event); | ||
try { | ||
event.target.releasePointerCapture(event.pointerId); | ||
} catch (_unused) {} | ||
if (state._pointerEvents.has(event.pointerId)) { | ||
state._pointerEvents.delete(event.pointerId); | ||
} | ||
if (!state._active) return; | ||
if (state._pointerEvents.size < 2) { | ||
state._active = false; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
} | ||
gestureStart(event) { | ||
if (event.cancelable) event.preventDefault(); | ||
const state = this.state; | ||
if (state._active) return; | ||
this.start(event); | ||
state.values = [event.scale, event.rotation]; | ||
state.origin = [event.clientX, event.clientY]; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
gestureMove(event) { | ||
if (event.cancelable) event.preventDefault(); | ||
if (!this.state._active) return; | ||
const state = this.state; | ||
state.values = [event.scale, event.rotation]; | ||
state.origin = [event.clientX, event.clientY]; | ||
const _previousMovement = state._movement; | ||
state._movement = [event.scale - 1, event.rotation]; | ||
state._delta = maths.V.sub(state._movement, _previousMovement); | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
gestureEnd(event) { | ||
if (!this.state._active) return; | ||
this.state._active = false; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
wheel(event) { | ||
if (!event.ctrlKey) return; | ||
if (!this.state._active) this.wheelStart(event);else this.wheelChange(event); | ||
this.timeoutStore.add('wheelEnd', this.wheelEnd.bind(this)); | ||
} | ||
wheelStart(event) { | ||
this.start(event); | ||
this.wheelChange(event); | ||
} | ||
wheelChange(event) { | ||
const isR3f = ('uv' in event); | ||
if (!isR3f) { | ||
if (event.cancelable) { | ||
event.preventDefault(); | ||
} | ||
if (process.env.NODE_ENV === 'development' && !event.defaultPrevented) { | ||
console.warn(`[@use-gesture]: To properly support zoom on trackpads, try using the \`target\` option.\n\nThis message will only appear in development mode.`); | ||
} | ||
} | ||
const state = this.state; | ||
state._delta = [-wheelValues(event)[1] / PINCH_WHEEL_RATIO, 0]; | ||
maths.V.addTo(state._movement, state._delta); | ||
this.state.origin = [event.clientX, event.clientY]; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
wheelEnd() { | ||
if (!this.state._active) return; | ||
this.state._active = false; | ||
this.compute(); | ||
this.emit(); | ||
} | ||
bind(bindFunction) { | ||
const device = this.config.device; | ||
if (!!device) { | ||
bindFunction(device, 'start', this[device + 'Start'].bind(this)); | ||
bindFunction(device, 'change', this[device + 'Move'].bind(this)); | ||
bindFunction(device, 'end', this[device + 'End'].bind(this)); | ||
} else { | ||
bindFunction('wheel', '', this.wheel.bind(this), { | ||
passive: false | ||
}); | ||
} | ||
} | ||
function parseMergedHandlers(mergedHandlers, mergedConfig) { | ||
const [handlers, nativeHandlers, actions] = sortHandlers(mergedHandlers); | ||
const internalHandlers = {}; | ||
registerGesture(actions, handlers, 'onDrag', 'drag', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onWheel', 'wheel', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onScroll', 'scroll', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onPinch', 'pinch', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onMove', 'move', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onHover', 'hover', internalHandlers, mergedConfig); | ||
return { | ||
handlers: internalHandlers, | ||
config: mergedConfig, | ||
nativeHandlers | ||
}; | ||
} | ||
const pinchConfigResolver = _objectSpread2(_objectSpread2({}, commonConfigResolver), {}, { | ||
useTouch(_v, _k, { | ||
pointer: { | ||
touch = false | ||
} = {} | ||
}) { | ||
return SUPPORT.touch && touch; | ||
}, | ||
device(_v, _k, config) { | ||
const sharedConfig = config.shared; | ||
if (sharedConfig.target && !SUPPORT.touch && SUPPORT.gesture) return 'gesture'; | ||
if (this.useTouch) return 'touch'; | ||
if (SUPPORT.touch && SUPPORT.pointer) return 'pointer'; | ||
if (SUPPORT.touch) return 'touch'; | ||
}, | ||
bounds(_v, _k, { | ||
scaleBounds = {}, | ||
angleBounds = {} | ||
}) { | ||
const _scaleBounds = state => { | ||
const D = assignDefault(call(scaleBounds, state), { | ||
min: -Infinity, | ||
max: Infinity | ||
}); | ||
return [D.min, D.max]; | ||
}; | ||
const _angleBounds = state => { | ||
const A = assignDefault(call(angleBounds, state), { | ||
min: -Infinity, | ||
max: Infinity | ||
}); | ||
return [A.min, A.max]; | ||
}; | ||
if (typeof scaleBounds !== 'function' && typeof angleBounds !== 'function') return [_scaleBounds(), _angleBounds()]; | ||
return state => [_scaleBounds(state), _angleBounds(state)]; | ||
}, | ||
threshold(value, _k, config) { | ||
this.lockDirection = config.axis === 'lock'; | ||
const threshold = maths.V.toVector(value, this.lockDirection ? [0.1, 3] : 0); | ||
return threshold; | ||
} | ||
}); | ||
class WheelEngine extends CoordinatesEngine { | ||
constructor(...args) { | ||
super(...args); | ||
_defineProperty(this, "ingKey", 'wheeling'); | ||
} | ||
wheel(event) { | ||
if (!this.state._active) this.start(event); | ||
this.wheelChange(event); | ||
this.timeoutStore.add('wheelEnd', this.wheelEnd.bind(this)); | ||
} | ||
wheelChange(event) { | ||
if (event.cancelable) event.preventDefault(); | ||
const state = this.state; | ||
state._delta = wheelValues(event); | ||
maths.V.addTo(this.state._movement, state._delta); | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
wheelEnd() { | ||
if (!this.state._active) return; | ||
this.state._active = false; | ||
this.compute(); | ||
this.emit(); | ||
} | ||
bind(bindFunction) { | ||
bindFunction('wheel', '', this.wheel.bind(this)); | ||
} | ||
} | ||
const wheelConfigResolver = coordinatesConfigResolver; | ||
class ScrollEngine extends CoordinatesEngine { | ||
constructor(...args) { | ||
super(...args); | ||
_defineProperty(this, "ingKey", 'scrolling'); | ||
} | ||
scroll(event) { | ||
if (!this.state._active) this.start(event); | ||
this.scrollChange(event); | ||
this.timeoutStore.add('scrollEnd', this.scrollEnd.bind(this)); | ||
} | ||
scrollChange(event) { | ||
if (event.cancelable) event.preventDefault(); | ||
const state = this.state; | ||
const values = scrollValues(event); | ||
state._delta = maths.V.sub(values, state.values); | ||
maths.V.addTo(state._movement, state._delta); | ||
state.values = values; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
scrollEnd() { | ||
if (!this.state._active) return; | ||
this.state._active = false; | ||
this.compute(); | ||
this.emit(); | ||
} | ||
bind(bindFunction) { | ||
bindFunction('scroll', '', this.scroll.bind(this)); | ||
} | ||
} | ||
const scrollConfigResolver = coordinatesConfigResolver; | ||
class MoveEngine extends CoordinatesEngine { | ||
constructor(...args) { | ||
super(...args); | ||
_defineProperty(this, "ingKey", 'moving'); | ||
} | ||
move(event) { | ||
if (this.config.mouseOnly && event.pointerType !== 'mouse') return; | ||
if (!this.state._active) this.moveStart(event);else this.moveChange(event); | ||
this.timeoutStore.add('moveEnd', this.moveEnd.bind(this)); | ||
} | ||
moveStart(event) { | ||
this.start(event); | ||
const state = this.state; | ||
state.values = pointerValues(event); | ||
this.compute(event); | ||
state.initial = state.values; | ||
this.emit(); | ||
} | ||
moveChange(event) { | ||
if (!this.state._active) return; | ||
const values = pointerValues(event); | ||
const state = this.state; | ||
state._delta = maths.V.sub(values, state.values); | ||
maths.V.addTo(state._movement, state._delta); | ||
state.values = values; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
moveEnd(event) { | ||
if (!this.state._active) return; | ||
this.state._active = false; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
bind(bindFunction) { | ||
bindFunction('pointer', 'change', this.move.bind(this)); | ||
bindFunction('pointer', 'leave', this.moveEnd.bind(this)); | ||
} | ||
} | ||
const moveConfigResolver = _objectSpread2(_objectSpread2({}, coordinatesConfigResolver), {}, { | ||
mouseOnly: (value = true) => value | ||
}); | ||
class HoverEngine extends CoordinatesEngine { | ||
constructor(...args) { | ||
super(...args); | ||
_defineProperty(this, "ingKey", 'hovering'); | ||
} | ||
enter(event) { | ||
if (this.config.mouseOnly && event.pointerType !== 'mouse') return; | ||
this.start(event); | ||
this.state.values = pointerValues(event); | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
leave(event) { | ||
if (this.config.mouseOnly && event.pointerType !== 'mouse') return; | ||
const state = this.state; | ||
if (!state._active) return; | ||
state._active = false; | ||
const values = pointerValues(event); | ||
state._movement = state._delta = maths.V.sub(values, state.values); | ||
state.values = values; | ||
this.compute(event); | ||
state.delta = state.movement; | ||
this.emit(); | ||
} | ||
bind(bindFunction) { | ||
bindFunction('pointer', 'enter', this.enter.bind(this)); | ||
bindFunction('pointer', 'leave', this.leave.bind(this)); | ||
} | ||
} | ||
const hoverConfigResolver = _objectSpread2(_objectSpread2({}, coordinatesConfigResolver), {}, { | ||
mouseOnly: (value = true) => value | ||
}); | ||
exports.Controller = Controller; | ||
exports.DragEngine = DragEngine; | ||
exports.HoverEngine = HoverEngine; | ||
exports.MoveEngine = MoveEngine; | ||
exports.PinchEngine = PinchEngine; | ||
exports.ScrollEngine = ScrollEngine; | ||
exports.WheelEngine = WheelEngine; | ||
exports.dragConfigResolver = dragConfigResolver; | ||
exports.hoverConfigResolver = hoverConfigResolver; | ||
exports.moveConfigResolver = moveConfigResolver; | ||
exports.parseMergedHandlers = parseMergedHandlers; | ||
exports.pinchConfigResolver = pinchConfigResolver; | ||
exports.registerEngine = registerEngine; | ||
exports.scrollConfigResolver = scrollConfigResolver; | ||
exports.wheelConfigResolver = wheelConfigResolver; |
@@ -5,115 +5,5 @@ 'use strict'; | ||
var maths = require('./maths-a42ecce1.cjs.prod.js'); | ||
var actions_dist_useGestureCoreActions = require('./actions-69908e5f.cjs.prod.js'); | ||
require('./maths-a42ecce1.cjs.prod.js'); | ||
function _defineProperty(obj, key, value) { | ||
if (key in obj) { | ||
Object.defineProperty(obj, key, { | ||
value: value, | ||
enumerable: true, | ||
configurable: true, | ||
writable: true | ||
}); | ||
} else { | ||
obj[key] = value; | ||
} | ||
return obj; | ||
} | ||
function ownKeys(object, enumerableOnly) { | ||
var keys = Object.keys(object); | ||
if (Object.getOwnPropertySymbols) { | ||
var symbols = Object.getOwnPropertySymbols(object); | ||
if (enumerableOnly) { | ||
symbols = symbols.filter(function (sym) { | ||
return Object.getOwnPropertyDescriptor(object, sym).enumerable; | ||
}); | ||
} | ||
keys.push.apply(keys, symbols); | ||
} | ||
return keys; | ||
} | ||
function _objectSpread2(target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i] != null ? arguments[i] : {}; | ||
if (i % 2) { | ||
ownKeys(Object(source), true).forEach(function (key) { | ||
_defineProperty(target, key, source[key]); | ||
}); | ||
} else if (Object.getOwnPropertyDescriptors) { | ||
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); | ||
} else { | ||
ownKeys(Object(source)).forEach(function (key) { | ||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); | ||
}); | ||
} | ||
} | ||
return target; | ||
} | ||
const EngineMap = new Map(); | ||
const ConfigResolverMap = new Map(); | ||
function registerEngine(action, Engine, resolver) { | ||
EngineMap.set(action, Engine); | ||
ConfigResolverMap.set(action, resolver); | ||
} | ||
const RE_NOT_NATIVE = /^on(Drag|Wheel|Scroll|Move|Pinch|Hover)/; | ||
function sortHandlers(_handlers) { | ||
const native = {}; | ||
const handlers = {}; | ||
const actions = new Set(); | ||
for (let key in _handlers) { | ||
if (RE_NOT_NATIVE.test(key)) { | ||
actions.add(RegExp.lastMatch); | ||
handlers[key] = _handlers[key]; | ||
} else { | ||
native[key] = _handlers[key]; | ||
} | ||
} | ||
return [handlers, native, actions]; | ||
} | ||
function registerGesture(actions, handlers, handlerKey, key, internalHandlers, config) { | ||
if (!actions.has(handlerKey)) return; | ||
const startKey = handlerKey + 'Start'; | ||
const endKey = handlerKey + 'End'; | ||
const fn = state => { | ||
let memo = undefined; | ||
if (state.first && startKey in handlers) handlers[startKey](state); | ||
if (handlerKey in handlers) memo = handlers[handlerKey](state); | ||
if (state.last && endKey in handlers) handlers[endKey](state); | ||
return memo; | ||
}; | ||
internalHandlers[key] = fn; | ||
config[key] = config[key] || {}; | ||
} | ||
function parseMergedHandlers(mergedHandlers, mergedConfig) { | ||
const [handlers, nativeHandlers, actions] = sortHandlers(mergedHandlers); | ||
const internalHandlers = {}; | ||
registerGesture(actions, handlers, 'onDrag', 'drag', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onWheel', 'wheel', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onScroll', 'scroll', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onPinch', 'pinch', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onMove', 'move', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onHover', 'hover', internalHandlers, mergedConfig); | ||
return { | ||
handlers: internalHandlers, | ||
config: mergedConfig, | ||
nativeHandlers | ||
}; | ||
} | ||
function _objectWithoutPropertiesLoose(source, excluded) { | ||
@@ -153,32 +43,2 @@ if (source == null) return {}; | ||
const isBrowser = typeof window !== 'undefined' && window.document && window.document.createElement; | ||
function supportsTouchEvents() { | ||
return isBrowser && 'ontouchstart' in window; | ||
} | ||
function supportsPointerEvents() { | ||
return isBrowser && 'onpointerdown' in window; | ||
} | ||
function supportsPointerLock() { | ||
return isBrowser && 'exitPointerLock' in window.document; | ||
} | ||
function supportsGestureEvents() { | ||
try { | ||
return 'constructor' in GestureEvent; | ||
} catch (e) { | ||
return false; | ||
} | ||
} | ||
const SUPPORT = { | ||
isBrowser, | ||
gesture: supportsGestureEvents(), | ||
touch: supportsTouchEvents(), | ||
pointer: supportsPointerEvents(), | ||
pointerLock: supportsPointerLock() | ||
}; | ||
const identity = v => v; | ||
@@ -198,3 +58,3 @@ const sharedConfigResolver = { | ||
window(value = SUPPORT.isBrowser ? window : undefined) { | ||
window(value = actions_dist_useGestureCoreActions.SUPPORT.isBrowser ? window : undefined) { | ||
return value; | ||
@@ -259,4 +119,4 @@ }, | ||
if (gestureKey) { | ||
const resolver = ConfigResolverMap.get(gestureKey); | ||
_config[gestureKey] = resolveWith(_objectSpread2({ | ||
const resolver = actions_dist_useGestureCoreActions.ConfigResolverMap.get(gestureKey); | ||
_config[gestureKey] = resolveWith(actions_dist_useGestureCoreActions._objectSpread2({ | ||
shared: _config.shared | ||
@@ -266,4 +126,5 @@ }, rest), resolver); | ||
for (const key in rest) { | ||
const resolver = ConfigResolverMap.get(key); | ||
_config[key] = resolveWith(_objectSpread2({ | ||
const resolver = actions_dist_useGestureCoreActions.ConfigResolverMap.get(key); | ||
_config[key] = resolveWith(actions_dist_useGestureCoreActions._objectSpread2({ | ||
shared: _config.shared | ||
@@ -277,144 +138,5 @@ }, rest[key]), resolver); | ||
const EVENT_TYPE_MAP = { | ||
pointer: { | ||
start: 'down', | ||
change: 'move', | ||
end: 'up' | ||
}, | ||
mouse: { | ||
start: 'down', | ||
change: 'move', | ||
end: 'up' | ||
}, | ||
touch: { | ||
start: 'start', | ||
change: 'move', | ||
end: 'end' | ||
}, | ||
gesture: { | ||
start: 'start', | ||
change: 'change', | ||
end: 'end' | ||
} | ||
}; | ||
function capitalize(string) { | ||
if (!string) return ''; | ||
return string[0].toUpperCase() + string.slice(1); | ||
} | ||
function toReactHandlerProp(device, action = '', capture = false) { | ||
const deviceProps = EVENT_TYPE_MAP[device]; | ||
const actionKey = deviceProps ? deviceProps[action] || action : action; | ||
return 'on' + capitalize(device) + capitalize(actionKey) + (capture ? 'Capture' : ''); | ||
} | ||
function toDomEventType(device, action = '') { | ||
const deviceProps = EVENT_TYPE_MAP[device]; | ||
const actionKey = deviceProps ? deviceProps[action] || action : action; | ||
return device + actionKey; | ||
} | ||
function isTouch(event) { | ||
return 'touches' in event; | ||
} | ||
function getCurrentTargetTouchList(event) { | ||
return Array.from(event.touches).filter(e => { | ||
var _event$currentTarget; | ||
return (_event$currentTarget = event.currentTarget) === null || _event$currentTarget === void 0 ? void 0 : _event$currentTarget.contains(e.target); | ||
}); | ||
} | ||
function getTouchList(event) { | ||
return event.type === 'touchend' ? event.changedTouches : event.targetTouches; | ||
} | ||
function getValueEvent(event) { | ||
return isTouch(event) ? getTouchList(event)[0] : event; | ||
} | ||
function distanceAngle(P1, P2) { | ||
const dx = P2.clientX - P1.clientX; | ||
const dy = P2.clientY - P1.clientY; | ||
const cx = (P2.clientX + P1.clientX) / 2; | ||
const cy = (P2.clientY + P1.clientY) / 2; | ||
const distance = Math.hypot(dx, dy); | ||
const angle = -(Math.atan2(dx, dy) * 180) / Math.PI; | ||
const origin = [cx, cy]; | ||
return { | ||
angle, | ||
distance, | ||
origin | ||
}; | ||
} | ||
function touchIds(event) { | ||
return getCurrentTargetTouchList(event).map(touch => touch.identifier); | ||
} | ||
function touchDistanceAngle(event, ids) { | ||
const [P1, P2] = Array.from(event.touches).filter(touch => ids.includes(touch.identifier)); | ||
return distanceAngle(P1, P2); | ||
} | ||
function pointerId(event) { | ||
const valueEvent = getValueEvent(event); | ||
return isTouch(event) ? valueEvent.identifier : valueEvent.pointerId; | ||
} | ||
function pointerValues(event) { | ||
const valueEvent = getValueEvent(event); | ||
return [valueEvent.clientX, valueEvent.clientY]; | ||
} | ||
const LINE_HEIGHT = 40; | ||
const PAGE_HEIGHT = 800; | ||
function wheelValues(event) { | ||
let { | ||
deltaX, | ||
deltaY, | ||
deltaMode | ||
} = event; | ||
if (deltaMode === 1) { | ||
deltaX *= LINE_HEIGHT; | ||
deltaY *= LINE_HEIGHT; | ||
} else if (deltaMode === 2) { | ||
deltaX *= PAGE_HEIGHT; | ||
deltaY *= PAGE_HEIGHT; | ||
} | ||
return [deltaX, deltaY]; | ||
} | ||
function scrollValues(event) { | ||
var _ref, _ref2; | ||
const { | ||
scrollX, | ||
scrollY, | ||
scrollLeft, | ||
scrollTop | ||
} = event.currentTarget; | ||
return [(_ref = scrollX !== null && scrollX !== void 0 ? scrollX : scrollLeft) !== null && _ref !== void 0 ? _ref : 0, (_ref2 = scrollY !== null && scrollY !== void 0 ? scrollY : scrollTop) !== null && _ref2 !== void 0 ? _ref2 : 0]; | ||
} | ||
function getEventDetails(event) { | ||
const payload = {}; | ||
if ('buttons' in event) payload.buttons = event.buttons; | ||
if ('shiftKey' in event) { | ||
const { | ||
shiftKey, | ||
altKey, | ||
metaKey, | ||
ctrlKey | ||
} = event; | ||
Object.assign({ | ||
shiftKey, | ||
altKey, | ||
metaKey, | ||
ctrlKey | ||
}); | ||
} | ||
return payload; | ||
} | ||
class EventStore { | ||
constructor(ctrl) { | ||
_defineProperty(this, "_listeners", []); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "_listeners", []); | ||
@@ -425,3 +147,3 @@ this._ctrl = ctrl; | ||
add(element, device, action, handler, options) { | ||
const type = toDomEventType(device, action); | ||
const type = actions_dist_useGestureCoreActions.toDomEventType(device, action); | ||
const eventOptions = options || this._ctrl.config.shared.eventOptions; | ||
@@ -443,3 +165,3 @@ element.addEventListener(type, handler, eventOptions); | ||
constructor() { | ||
_defineProperty(this, "_timeouts", new Map()); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "_timeouts", new Map()); | ||
} | ||
@@ -467,46 +189,21 @@ | ||
function call(v, ...args) { | ||
if (typeof v === 'function') { | ||
return v(...args); | ||
} else { | ||
return v; | ||
} | ||
} | ||
function noop() {} | ||
function chain(...fns) { | ||
if (fns.length === 0) return noop; | ||
if (fns.length === 1) return fns[0]; | ||
return function () { | ||
let result; | ||
for (const fn of fns) { | ||
result = fn.apply(this, arguments) || result; | ||
} | ||
return result; | ||
}; | ||
} | ||
function assignDefault(value, fallback) { | ||
return Object.assign({}, fallback, value || {}); | ||
} | ||
class Controller { | ||
constructor(handlers) { | ||
_defineProperty(this, "gestures", new Set()); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "gestures", new Set()); | ||
_defineProperty(this, "_targetEventStore", new EventStore(this)); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "_targetEventStore", new EventStore(this)); | ||
_defineProperty(this, "gestureEventStores", {}); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "gestureEventStores", {}); | ||
_defineProperty(this, "gestureTimeoutStores", {}); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "gestureTimeoutStores", {}); | ||
_defineProperty(this, "handlers", {}); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "handlers", {}); | ||
_defineProperty(this, "config", {}); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "config", {}); | ||
_defineProperty(this, "pointerIds", new Set()); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "pointerIds", new Set()); | ||
_defineProperty(this, "touchIds", new Set()); | ||
actions_dist_useGestureCoreActions._defineProperty(this, "touchIds", new Set()); | ||
_defineProperty(this, "state", { | ||
actions_dist_useGestureCoreActions._defineProperty(this, "state", { | ||
shared: { | ||
@@ -524,4 +221,4 @@ shiftKey: false, | ||
setEventIds(event) { | ||
if (isTouch(event)) { | ||
this.touchIds = new Set(touchIds(event)); | ||
if (actions_dist_useGestureCoreActions.isTouch(event)) { | ||
this.touchIds = new Set(actions_dist_useGestureCoreActions.touchIds(event)); | ||
} else if ('pointerId' in event) { | ||
@@ -570,3 +267,3 @@ if (event.type === 'pointerup') this.pointerIds.delete(event.pointerId);else this.pointerIds.add(event.pointerId); | ||
for (const eventKey in this.nativeHandlers) { | ||
bindFunction(eventKey, '', event => this.nativeHandlers[eventKey](_objectSpread2(_objectSpread2({}, this.state.shared), {}, { | ||
bindFunction(eventKey, '', event => this.nativeHandlers[eventKey](actions_dist_useGestureCoreActions._objectSpread2(actions_dist_useGestureCoreActions._objectSpread2({}, this.state.shared), {}, { | ||
event, | ||
@@ -579,3 +276,3 @@ args | ||
if (this.config[gestureKey].enabled) { | ||
const Engine = EngineMap.get(gestureKey); | ||
const Engine = actions_dist_useGestureCoreActions.EngineMap.get(gestureKey); | ||
new Engine(this, args, gestureKey).bind(bindFunction); | ||
@@ -588,3 +285,3 @@ } | ||
for (const handlerProp in props) { | ||
props[handlerProp] = chain(...props[handlerProp]); | ||
props[handlerProp] = actions_dist_useGestureCoreActions.chain(...props[handlerProp]); | ||
} | ||
@@ -622,3 +319,3 @@ | ||
const capture = (_options$capture = options.capture) !== null && _options$capture !== void 0 ? _options$capture : eventOptions.capture; | ||
const handlerProp = isNative ? device : toReactHandlerProp(device, action, capture); | ||
const handlerProp = isNative ? device : actions_dist_useGestureCoreActions.toReactHandlerProp(device, action, capture); | ||
props[handlerProp] = props[handlerProp] || []; | ||
@@ -628,1156 +325,55 @@ props[handlerProp].push(handler); | ||
class Engine { | ||
constructor(ctrl, args, key) { | ||
this.ctrl = ctrl; | ||
this.args = args; | ||
this.key = key; | ||
const RE_NOT_NATIVE = /^on(Drag|Wheel|Scroll|Move|Pinch|Hover)/; | ||
if (!this.state) { | ||
this.state = { | ||
values: [0, 0], | ||
initial: [0, 0] | ||
}; | ||
if (this.init) this.init(); | ||
this.reset(); | ||
} | ||
} | ||
function sortHandlers(_handlers) { | ||
const native = {}; | ||
const handlers = {}; | ||
const actions = new Set(); | ||
get state() { | ||
return this.ctrl.state[this.key]; | ||
} | ||
set state(state) { | ||
this.ctrl.state[this.key] = state; | ||
} | ||
get shared() { | ||
return this.ctrl.state.shared; | ||
} | ||
get eventStore() { | ||
return this.ctrl.gestureEventStores[this.key]; | ||
} | ||
get timeoutStore() { | ||
return this.ctrl.gestureTimeoutStores[this.key]; | ||
} | ||
get config() { | ||
return this.ctrl.config[this.key]; | ||
} | ||
get sharedConfig() { | ||
return this.ctrl.config.shared; | ||
} | ||
get handler() { | ||
return this.ctrl.handlers[this.key]; | ||
} | ||
reset() { | ||
const { | ||
state, | ||
shared, | ||
config, | ||
ingKey, | ||
args | ||
} = this; | ||
const { | ||
transform, | ||
threshold = [0, 0] | ||
} = config; | ||
shared[ingKey] = state._active = state.active = state._blocked = state._force = false; | ||
state._step = [false, false]; | ||
state.intentional = false; | ||
state._movement = [0, 0]; | ||
state._distance = [0, 0]; | ||
state._delta = [0, 0]; | ||
state._threshold = maths.V.sub(transform(threshold), transform([0, 0])).map(Math.abs); | ||
state._bounds = [[-Infinity, Infinity], [-Infinity, Infinity]]; | ||
state.args = args; | ||
state.axis = undefined; | ||
state.memo = undefined; | ||
state.elapsedTime = 0; | ||
state.direction = [0, 0]; | ||
state.distance = [0, 0]; | ||
state.velocity = [0, 0]; | ||
state.movement = [0, 0]; | ||
state.delta = [0, 0]; | ||
state.timeStamp = 0; | ||
} | ||
start(event) { | ||
const state = this.state; | ||
const config = this.config; | ||
if (!state._active) { | ||
this.reset(); | ||
state._active = true; | ||
state.target = event.currentTarget; | ||
state.initial = state.values; | ||
state.lastOffset = config.from ? call(config.from, state) : state.offset; | ||
state.offset = state.lastOffset; | ||
} | ||
state.startTime = state.timeStamp = event.timeStamp; | ||
} | ||
compute(event) { | ||
const { | ||
state, | ||
config, | ||
shared | ||
} = this; | ||
state.args = this.args; | ||
let dt = 0; | ||
if (event) { | ||
state.event = event; | ||
shared.touches = this.ctrl.pointerIds.size || this.ctrl.touchIds.size; | ||
shared.locked = !!document.pointerLockElement; | ||
Object.assign(shared, getEventDetails(event)); | ||
shared.down = shared.pressed = shared.buttons % 2 === 1 || shared.touches > 0; | ||
dt = event.timeStamp - state.timeStamp; | ||
state.timeStamp = event.timeStamp; | ||
state.elapsedTime = state.timeStamp - state.startTime; | ||
} | ||
if (state._active) { | ||
const _absoluteDelta = state._delta.map(Math.abs); | ||
maths.V.addTo(state._distance, _absoluteDelta); | ||
} | ||
const [_m0, _m1] = config.transform(state._movement); | ||
const [_t0, _t1] = state._threshold; | ||
let [_s0, _s1] = state._step; | ||
if (_s0 === false) _s0 = Math.abs(_m0) >= _t0 && Math.sign(_m0) * _t0; | ||
if (_s1 === false) _s1 = Math.abs(_m1) >= _t1 && Math.sign(_m1) * _t1; | ||
state.intentional = _s0 !== false || _s1 !== false; | ||
if (!state.intentional) return; | ||
state._step = [_s0, _s1]; | ||
const movement = [0, 0]; | ||
movement[0] = _s0 !== false ? _m0 - _s0 : 0; | ||
movement[1] = _s1 !== false ? _m1 - _s1 : 0; | ||
if (this.intent) this.intent(movement); | ||
if (state._active && !state._blocked || state.active) { | ||
state.first = state._active && !state.active; | ||
state.last = !state._active && state.active; | ||
state.active = shared[this.ingKey] = state._active; | ||
if (event) { | ||
if (state.first) { | ||
if ('bounds' in config) state._bounds = call(config.bounds, state); | ||
if (this.setup) this.setup(); | ||
} | ||
const previousMovement = state.movement; | ||
state.movement = movement; | ||
this.computeOffset(); | ||
if (!state.last) { | ||
state.delta = maths.V.sub(movement, previousMovement); | ||
const absoluteDelta = state.delta.map(Math.abs); | ||
maths.V.addTo(state.distance, absoluteDelta); | ||
state.direction = state.delta.map(Math.sign); | ||
if (!state.first && dt > 0) { | ||
state.velocity = [absoluteDelta[0] / dt, absoluteDelta[1] / dt]; | ||
} | ||
} | ||
} | ||
} | ||
const rubberband = state._active ? config.rubberband || [0, 0] : [0, 0]; | ||
state.offset = maths.computeRubberband(state._bounds, state.offset, rubberband); | ||
this.computeMovement(); | ||
} | ||
emit() { | ||
const state = this.state; | ||
const shared = this.shared; | ||
const config = this.config; | ||
if (!state._active) this.clean(); | ||
if ((state._blocked || !state.intentional) && !state._force && !config.triggerAllEvents) return; | ||
const memo = this.handler(_objectSpread2(_objectSpread2({}, shared), state)); | ||
if (memo !== undefined) state.memo = memo; | ||
} | ||
clean() { | ||
this.eventStore.clean(); | ||
this.timeoutStore.clean(); | ||
} | ||
} | ||
function selectAxis([dx, dy]) { | ||
const d = Math.abs(dx) - Math.abs(dy); | ||
if (d > 0) return 'x'; | ||
if (d < 0) return 'y'; | ||
return undefined; | ||
} | ||
function restrictVectorToAxis(v, axis) { | ||
switch (axis) { | ||
case 'x': | ||
v[1] = 0; | ||
break; | ||
case 'y': | ||
v[0] = 0; | ||
break; | ||
} | ||
} | ||
class CoordinatesEngine extends Engine { | ||
reset() { | ||
super.reset(); | ||
this.state.axis = undefined; | ||
} | ||
init() { | ||
this.state.offset = [0, 0]; | ||
this.state.lastOffset = [0, 0]; | ||
} | ||
computeOffset() { | ||
this.state.offset = maths.V.add(this.state.lastOffset, this.state.movement); | ||
} | ||
computeMovement() { | ||
this.state.movement = maths.V.sub(this.state.offset, this.state.lastOffset); | ||
this.state.xy = this.state.values; | ||
} | ||
intent(v) { | ||
this.state.axis = this.state.axis || selectAxis(v); | ||
this.state._blocked = (this.config.lockDirection || !!this.config.axis) && !this.state.axis || !!this.config.axis && this.config.axis !== this.state.axis; | ||
if (this.state._blocked) return; | ||
if (this.config.axis || this.config.lockDirection) { | ||
restrictVectorToAxis(v, this.state.axis); | ||
} | ||
} | ||
} | ||
const DEFAULT_RUBBERBAND = 0.15; | ||
const commonConfigResolver = { | ||
enabled(value = true) { | ||
return value; | ||
}, | ||
triggerAllEvents(value = false) { | ||
return value; | ||
}, | ||
rubberband(value = 0) { | ||
switch (value) { | ||
case true: | ||
return [DEFAULT_RUBBERBAND, DEFAULT_RUBBERBAND]; | ||
case false: | ||
return [0, 0]; | ||
default: | ||
return maths.V.toVector(value); | ||
} | ||
}, | ||
from(value) { | ||
if (typeof value === 'function') return value; | ||
if (value != null) return maths.V.toVector(value); | ||
}, | ||
transform(value, _k, config) { | ||
return value || config.shared.transform; | ||
} | ||
}; | ||
const coordinatesConfigResolver = _objectSpread2(_objectSpread2({}, commonConfigResolver), {}, { | ||
axis(_v, _k, { | ||
axis | ||
}) { | ||
this.lockDirection = axis === 'lock'; | ||
if (!this.lockDirection) return axis; | ||
}, | ||
bounds(value = {}) { | ||
if (typeof value === 'function') { | ||
return state => coordinatesConfigResolver.bounds(value(state)); | ||
} | ||
if ('current' in value) { | ||
return () => value.current; | ||
} | ||
if (typeof HTMLElement === 'function' && value instanceof HTMLElement) { | ||
return value; | ||
} | ||
const { | ||
left = -Infinity, | ||
right = Infinity, | ||
top = -Infinity, | ||
bottom = Infinity | ||
} = value; | ||
return [[left, right], [top, bottom]]; | ||
} | ||
}); | ||
const DISPLACEMENT = 10; | ||
const KEYS_DELTA_MAP = { | ||
ArrowRight: (factor = 1) => [DISPLACEMENT * factor, 0], | ||
ArrowLeft: (factor = 1) => [-DISPLACEMENT * factor, 0], | ||
ArrowUp: (factor = 1) => [0, -DISPLACEMENT * factor], | ||
ArrowDown: (factor = 1) => [0, DISPLACEMENT * factor] | ||
}; | ||
class DragEngine extends CoordinatesEngine { | ||
constructor(...args) { | ||
super(...args); | ||
_defineProperty(this, "ingKey", 'dragging'); | ||
} | ||
reset() { | ||
super.reset(); | ||
const state = this.state; | ||
state._pointerId = undefined; | ||
state._pointerActive = false; | ||
state._keyboardActive = false; | ||
state._preventScroll = false; | ||
state._delayed = false; | ||
state.swipe = [0, 0]; | ||
state.tap = false; | ||
state.canceled = false; | ||
state.cancel = this.cancel.bind(this); | ||
} | ||
setup() { | ||
const state = this.state; | ||
if (state._bounds instanceof HTMLElement) { | ||
const boundRect = state._bounds.getBoundingClientRect(); | ||
const targetRect = state.target.getBoundingClientRect(); | ||
const _bounds = { | ||
left: boundRect.left - targetRect.left + state.offset[0], | ||
right: boundRect.right - targetRect.right + state.offset[0], | ||
top: boundRect.top - targetRect.top + state.offset[1], | ||
bottom: boundRect.bottom - targetRect.bottom + state.offset[1] | ||
}; | ||
state._bounds = coordinatesConfigResolver.bounds(_bounds); | ||
} | ||
} | ||
cancel() { | ||
const state = this.state; | ||
if (state.canceled) return; | ||
setTimeout(() => { | ||
state.canceled = true; | ||
state._active = false; | ||
this.compute(); | ||
this.emit(); | ||
}, 0); | ||
} | ||
setActive() { | ||
this.state._active = this.state._pointerActive || this.state._keyboardActive; | ||
} | ||
clean() { | ||
this.pointerClean(); | ||
this.state._pointerActive = false; | ||
this.state._keyboardActive = false; | ||
super.clean(); | ||
} | ||
pointerDown(event) { | ||
if (event.buttons != null && event.buttons % 2 !== 1) return; | ||
this.ctrl.setEventIds(event); | ||
if (this.config.pointerCapture) { | ||
event.target.setPointerCapture(event.pointerId); | ||
} | ||
const state = this.state; | ||
const config = this.config; | ||
if (state._pointerActive) return; | ||
this.start(event); | ||
this.setupPointer(event); | ||
state._pointerId = pointerId(event); | ||
state._pointerActive = true; | ||
state.values = pointerValues(event); | ||
state.initial = state.values; | ||
if (config.preventScroll) { | ||
this.setupScrollPrevention(event); | ||
} else if (config.delay > 0) { | ||
this.setupDelayTrigger(event); | ||
for (let key in _handlers) { | ||
if (RE_NOT_NATIVE.test(key)) { | ||
actions.add(RegExp.lastMatch); | ||
handlers[key] = _handlers[key]; | ||
} else { | ||
this.startPointerDrag(event); | ||
native[key] = _handlers[key]; | ||
} | ||
} | ||
startPointerDrag(event) { | ||
const state = this.state; | ||
state._active = true; | ||
state._preventScroll = true; | ||
state._delayed = false; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
pointerMove(event) { | ||
const state = this.state; | ||
const config = this.config; | ||
if (!state._pointerActive) return; | ||
const id = pointerId(event); | ||
if (state._pointerId && id !== state._pointerId) return; | ||
const values = pointerValues(event); | ||
if (document.pointerLockElement === event.target) { | ||
state._delta = [event.movementX, event.movementY]; | ||
} else { | ||
state._delta = maths.V.sub(values, state.values); | ||
state.values = values; | ||
} | ||
maths.V.addTo(state._movement, state._delta); | ||
this.compute(event); | ||
if (state._delayed) { | ||
this.timeoutStore.remove('dragDelay'); | ||
this.startPointerDrag(event); | ||
return; | ||
} | ||
if (config.preventScroll && !state._preventScroll) { | ||
if (state.axis) { | ||
if (state.axis === config.preventScrollAxis || config.preventScrollAxis === 'xy') { | ||
state._active = false; | ||
this.clean(); | ||
return; | ||
} else { | ||
this.timeoutStore.remove('startPointerDrag'); | ||
this.startPointerDrag(event); | ||
return; | ||
} | ||
} else { | ||
return; | ||
} | ||
} | ||
this.emit(); | ||
} | ||
pointerUp(event) { | ||
this.ctrl.setEventIds(event); | ||
try { | ||
if (this.config.pointerCapture && event.target.hasPointerCapture(event.pointerId)) { | ||
; | ||
event.target.releasePointerCapture(event.pointerId); | ||
} | ||
} catch (_unused) { | ||
} | ||
const state = this.state; | ||
const config = this.config; | ||
if (!state._pointerActive) return; | ||
const id = pointerId(event); | ||
if (state._pointerId && id !== state._pointerId) return; | ||
this.state._pointerActive = false; | ||
this.setActive(); | ||
this.compute(event); | ||
const [dx, dy] = state._distance; | ||
state.tap = dx <= 3 && dy <= 3; | ||
if (state.tap && config.filterTaps) { | ||
state._force = true; | ||
} else { | ||
const [dirx, diry] = state.direction; | ||
const [vx, vy] = state.velocity; | ||
const [mx, my] = state.movement; | ||
const [svx, svy] = config.swipe.velocity; | ||
const [sx, sy] = config.swipe.distance; | ||
const sdt = config.swipe.duration; | ||
if (state.elapsedTime < sdt) { | ||
if (Math.abs(vx) > svx && Math.abs(mx) > sx) state.swipe[0] = dirx; | ||
if (Math.abs(vy) > svy && Math.abs(my) > sy) state.swipe[1] = diry; | ||
} | ||
} | ||
this.emit(); | ||
} | ||
pointerClick(event) { | ||
if (!this.state.tap) { | ||
event.preventDefault(); | ||
event.stopPropagation(); | ||
} | ||
} | ||
setupPointer(event) { | ||
const config = this.config; | ||
let device = config.device; | ||
if (config.pointerLock) { | ||
event.currentTarget.requestPointerLock(); | ||
} | ||
if (!config.pointerCapture) { | ||
this.eventStore.add(this.sharedConfig.window, device, 'change', this.pointerMove.bind(this)); | ||
this.eventStore.add(this.sharedConfig.window, device, 'end', this.pointerUp.bind(this)); | ||
} | ||
} | ||
pointerClean() { | ||
if (this.config.pointerLock && document.pointerLockElement === this.state.target) { | ||
document.exitPointerLock(); | ||
} | ||
} | ||
preventScroll(event) { | ||
if (this.state._preventScroll && event.cancelable) { | ||
event.preventDefault(); | ||
} | ||
} | ||
setupScrollPrevention(event) { | ||
persistEvent(event); | ||
this.eventStore.add(this.sharedConfig.window, 'touch', 'change', this.preventScroll.bind(this), { | ||
passive: false | ||
}); | ||
this.eventStore.add(this.sharedConfig.window, 'touch', 'end', this.clean.bind(this), { | ||
passive: false | ||
}); | ||
this.eventStore.add(this.sharedConfig.window, 'touch', 'cancel', this.clean.bind(this), { | ||
passive: false | ||
}); | ||
this.timeoutStore.add('startPointerDrag', this.startPointerDrag.bind(this), this.config.preventScroll, event); | ||
} | ||
setupDelayTrigger(event) { | ||
this.state._delayed = true; | ||
this.timeoutStore.add('dragDelay', this.startPointerDrag.bind(this), this.config.delay, event); | ||
} | ||
keyDown(event) { | ||
const deltaFn = KEYS_DELTA_MAP[event.key]; | ||
const state = this.state; | ||
if (deltaFn) { | ||
const factor = event.shiftKey ? 10 : event.altKey ? 0.1 : 1; | ||
state._delta = deltaFn(factor); | ||
this.start(event); | ||
state._keyboardActive = true; | ||
maths.V.addTo(state._movement, state._delta); | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
} | ||
keyUp(event) { | ||
if (!(event.key in KEYS_DELTA_MAP)) return; | ||
this.state._keyboardActive = false; | ||
this.setActive(); | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
bind(bindFunction) { | ||
const device = this.config.device; | ||
bindFunction(device, 'start', this.pointerDown.bind(this)); | ||
if (this.config.pointerCapture) { | ||
bindFunction(device, 'change', this.pointerMove.bind(this)); | ||
bindFunction(device, 'end', this.pointerUp.bind(this)); | ||
bindFunction(device, 'cancel', this.pointerUp.bind(this)); | ||
} | ||
bindFunction('key', 'down', this.keyDown.bind(this)); | ||
bindFunction('key', 'up', this.keyUp.bind(this)); | ||
if (this.config.filterTaps) { | ||
bindFunction('click', '', this.pointerClick.bind(this), { | ||
capture: true | ||
}); | ||
} | ||
} | ||
return [handlers, native, actions]; | ||
} | ||
function persistEvent(event) { | ||
'persist' in event && typeof event.persist === 'function' && event.persist(); | ||
} | ||
function registerGesture(actions, handlers, handlerKey, key, internalHandlers, config) { | ||
if (!actions.has(handlerKey)) return; | ||
const startKey = handlerKey + 'Start'; | ||
const endKey = handlerKey + 'End'; | ||
const DEFAULT_PREVENT_SCROLL_DELAY = 250; | ||
const DEFAULT_DRAG_DELAY = 180; | ||
const DEFAULT_SWIPE_VELOCITY = 0.5; | ||
const DEFAULT_SWIPE_DISTANCE = 50; | ||
const DEFAULT_SWIPE_DURATION = 250; | ||
const dragConfigResolver = _objectSpread2(_objectSpread2({}, coordinatesConfigResolver), {}, { | ||
pointerLock(_v, _k, { | ||
pointer: { | ||
lock = false, | ||
touch = false | ||
} = {} | ||
}) { | ||
this.useTouch = SUPPORT.touch && touch; | ||
return SUPPORT.pointerLock && lock; | ||
}, | ||
const fn = state => { | ||
let memo = undefined; | ||
if (state.first && startKey in handlers) handlers[startKey](state); | ||
if (handlerKey in handlers) memo = handlers[handlerKey](state); | ||
if (state.last && endKey in handlers) handlers[endKey](state); | ||
return memo; | ||
}; | ||
device(_v, _k) { | ||
if (this.useTouch) return 'touch'; | ||
if (this.pointerLock) return 'mouse'; | ||
if (SUPPORT.pointer) return 'pointer'; | ||
if (SUPPORT.touch) return 'touch'; | ||
return 'mouse'; | ||
}, | ||
preventScroll(value = false, _k, { | ||
preventScrollAxis = 'y' | ||
}) { | ||
if (preventScrollAxis) this.preventScrollAxis = preventScrollAxis; | ||
if (!SUPPORT.touch) return false; | ||
if (typeof value === 'number') return value; | ||
return value ? DEFAULT_PREVENT_SCROLL_DELAY : false; | ||
}, | ||
pointerCapture(_v, _k, { | ||
pointer: { | ||
capture = true | ||
} = {} | ||
}) { | ||
return !this.pointerLock && this.device === 'pointer' && capture; | ||
}, | ||
threshold(value, _k, { | ||
filterTaps = false, | ||
axis = undefined | ||
}) { | ||
const threshold = maths.V.toVector(value, filterTaps ? 3 : axis ? 1 : 0); | ||
this.filterTaps = filterTaps; | ||
return threshold; | ||
}, | ||
swipe({ | ||
velocity = DEFAULT_SWIPE_VELOCITY, | ||
distance = DEFAULT_SWIPE_DISTANCE, | ||
duration = DEFAULT_SWIPE_DURATION | ||
} = {}) { | ||
return { | ||
velocity: this.transform(maths.V.toVector(velocity)), | ||
distance: this.transform(maths.V.toVector(distance)), | ||
duration | ||
}; | ||
}, | ||
delay(value = 0) { | ||
switch (value) { | ||
case true: | ||
return DEFAULT_DRAG_DELAY; | ||
case false: | ||
return 0; | ||
default: | ||
return value; | ||
} | ||
} | ||
}); | ||
const SCALE_ANGLE_RATIO_INTENT_DEG = 30; | ||
const PINCH_WHEEL_RATIO = 60; | ||
class PinchEngine extends Engine { | ||
constructor(...args) { | ||
super(...args); | ||
_defineProperty(this, "ingKey", 'pinching'); | ||
} | ||
init() { | ||
this.state.offset = [1, 0]; | ||
this.state.lastOffset = [1, 0]; | ||
this.state._pointerEvents = new Map(); | ||
} | ||
reset() { | ||
super.reset(); | ||
const state = this.state; | ||
state._touchIds = []; | ||
state.canceled = false; | ||
state.cancel = this.cancel.bind(this); | ||
state.turns = 0; | ||
} | ||
computeOffset() { | ||
const { | ||
movement, | ||
lastOffset | ||
} = this.state; | ||
this.state.offset = [(1 + movement[0]) * lastOffset[0], movement[1] + lastOffset[1]]; | ||
} | ||
computeMovement() { | ||
const { | ||
offset, | ||
lastOffset | ||
} = this.state; | ||
this.state.movement = [offset[0] / lastOffset[0] - 1, offset[1] - lastOffset[1]]; | ||
this.state.da = this.state.values; | ||
} | ||
intent(v) { | ||
const state = this.state; | ||
if (!state.axis) { | ||
const axisMovementDifference = Math.abs(v[0]) * SCALE_ANGLE_RATIO_INTENT_DEG - Math.abs(v[1]); | ||
if (axisMovementDifference < 0) state.axis = 'angle';else if (axisMovementDifference > 0) state.axis = 'scale'; | ||
} | ||
if (this.config.lockDirection) { | ||
if (state.axis === 'scale') v[1] = 0;else if (state.axis === 'angle') v[0] = 0; | ||
} | ||
} | ||
cancel() { | ||
const state = this.state; | ||
if (state.canceled) return; | ||
setTimeout(() => { | ||
state.canceled = true; | ||
state._active = false; | ||
this.compute(); | ||
this.emit(); | ||
}, 0); | ||
} | ||
touchStart(event) { | ||
this.ctrl.setEventIds(event); | ||
const state = this.state; | ||
const ctrlTouchIds = this.ctrl.touchIds; | ||
if (state._active) { | ||
if (state._touchIds.every(id => ctrlTouchIds.has(id))) return; | ||
} | ||
if (ctrlTouchIds.size < 2) return; | ||
this.start(event); | ||
state._touchIds = Array.from(ctrlTouchIds).slice(0, 2); | ||
const payload = touchDistanceAngle(event, state._touchIds); | ||
this.pinchStart(event, payload); | ||
} | ||
pointerStart(event) { | ||
if (event.buttons != null && event.buttons % 2 !== 1) return; | ||
this.ctrl.setEventIds(event); | ||
event.target.setPointerCapture(event.pointerId); | ||
const state = this.state; | ||
const _pointerEvents = state._pointerEvents; | ||
const ctrlPointerIds = this.ctrl.pointerIds; | ||
if (state._active) { | ||
if (Array.from(_pointerEvents.keys()).every(id => ctrlPointerIds.has(id))) return; | ||
} | ||
if (_pointerEvents.size < 2) { | ||
_pointerEvents.set(event.pointerId, event); | ||
} | ||
if (state._pointerEvents.size < 2) return; | ||
this.start(event); | ||
const payload = distanceAngle(...Array.from(_pointerEvents.values())); | ||
this.pinchStart(event, payload); | ||
} | ||
pinchStart(event, payload) { | ||
const state = this.state; | ||
state.origin = payload.origin; | ||
state.values = [payload.distance, payload.angle]; | ||
state.initial = state.values; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
touchMove(event) { | ||
if (!this.state._active) return; | ||
const payload = touchDistanceAngle(event, this.state._touchIds); | ||
this.pinchMove(event, payload); | ||
} | ||
pointerMove(event) { | ||
const _pointerEvents = this.state._pointerEvents; | ||
if (_pointerEvents.has(event.pointerId)) { | ||
_pointerEvents.set(event.pointerId, event); | ||
} | ||
if (!this.state._active) return; | ||
const payload = distanceAngle(...Array.from(_pointerEvents.values())); | ||
this.pinchMove(event, payload); | ||
} | ||
pinchMove(event, payload) { | ||
const state = this.state; | ||
const prev_a = state.values[1]; | ||
const delta_a = payload.angle - prev_a; | ||
let delta_turns = 0; | ||
if (Math.abs(delta_a) > 270) delta_turns += Math.sign(delta_a); | ||
state.values = [payload.distance, payload.angle - 360 * delta_turns]; | ||
state.origin = payload.origin; | ||
state.turns = delta_turns; | ||
state._movement = [state.values[0] / state.initial[0] - 1, state.values[1] - state.initial[1]]; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
touchEnd(event) { | ||
this.ctrl.setEventIds(event); | ||
if (!this.state._active) return; | ||
if (this.state._touchIds.some(id => !this.ctrl.touchIds.has(id))) { | ||
this.state._active = false; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
} | ||
pointerEnd(event) { | ||
const state = this.state; | ||
this.ctrl.setEventIds(event); | ||
try { | ||
event.target.releasePointerCapture(event.pointerId); | ||
} catch (_unused) {} | ||
if (state._pointerEvents.has(event.pointerId)) { | ||
state._pointerEvents.delete(event.pointerId); | ||
} | ||
if (!state._active) return; | ||
if (state._pointerEvents.size < 2) { | ||
state._active = false; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
} | ||
gestureStart(event) { | ||
if (event.cancelable) event.preventDefault(); | ||
const state = this.state; | ||
if (state._active) return; | ||
this.start(event); | ||
state.values = [event.scale, event.rotation]; | ||
state.origin = [event.clientX, event.clientY]; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
gestureMove(event) { | ||
if (event.cancelable) event.preventDefault(); | ||
if (!this.state._active) return; | ||
const state = this.state; | ||
state.values = [event.scale, event.rotation]; | ||
state.origin = [event.clientX, event.clientY]; | ||
const _previousMovement = state._movement; | ||
state._movement = [event.scale - 1, event.rotation]; | ||
state._delta = maths.V.sub(state._movement, _previousMovement); | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
gestureEnd(event) { | ||
if (!this.state._active) return; | ||
this.state._active = false; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
wheel(event) { | ||
if (!event.ctrlKey) return; | ||
if (!this.state._active) this.wheelStart(event);else this.wheelChange(event); | ||
this.timeoutStore.add('wheelEnd', this.wheelEnd.bind(this)); | ||
} | ||
wheelStart(event) { | ||
this.start(event); | ||
this.wheelChange(event); | ||
} | ||
wheelChange(event) { | ||
const isR3f = ('uv' in event); | ||
if (!isR3f) { | ||
if (event.cancelable) { | ||
event.preventDefault(); | ||
} | ||
} | ||
const state = this.state; | ||
state._delta = [-wheelValues(event)[1] / PINCH_WHEEL_RATIO, 0]; | ||
maths.V.addTo(state._movement, state._delta); | ||
this.state.origin = [event.clientX, event.clientY]; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
wheelEnd() { | ||
if (!this.state._active) return; | ||
this.state._active = false; | ||
this.compute(); | ||
this.emit(); | ||
} | ||
bind(bindFunction) { | ||
const device = this.config.device; | ||
if (!!device) { | ||
bindFunction(device, 'start', this[device + 'Start'].bind(this)); | ||
bindFunction(device, 'change', this[device + 'Move'].bind(this)); | ||
bindFunction(device, 'end', this[device + 'End'].bind(this)); | ||
} else { | ||
bindFunction('wheel', '', this.wheel.bind(this), { | ||
passive: false | ||
}); | ||
} | ||
} | ||
internalHandlers[key] = fn; | ||
config[key] = config[key] || {}; | ||
} | ||
const pinchConfigResolver = _objectSpread2(_objectSpread2({}, commonConfigResolver), {}, { | ||
useTouch(_v, _k, { | ||
pointer: { | ||
touch = false | ||
} = {} | ||
}) { | ||
return SUPPORT.touch && touch; | ||
}, | ||
device(_v, _k, config) { | ||
const sharedConfig = config.shared; | ||
if (sharedConfig.target && !SUPPORT.touch && SUPPORT.gesture) return 'gesture'; | ||
if (this.useTouch) return 'touch'; | ||
if (SUPPORT.touch && SUPPORT.pointer) return 'pointer'; | ||
if (SUPPORT.touch) return 'touch'; | ||
}, | ||
bounds(_v, _k, { | ||
scaleBounds = {}, | ||
angleBounds = {} | ||
}) { | ||
const _scaleBounds = state => { | ||
const D = assignDefault(call(scaleBounds, state), { | ||
min: -Infinity, | ||
max: Infinity | ||
}); | ||
return [D.min, D.max]; | ||
}; | ||
const _angleBounds = state => { | ||
const A = assignDefault(call(angleBounds, state), { | ||
min: -Infinity, | ||
max: Infinity | ||
}); | ||
return [A.min, A.max]; | ||
}; | ||
if (typeof scaleBounds !== 'function' && typeof angleBounds !== 'function') return [_scaleBounds(), _angleBounds()]; | ||
return state => [_scaleBounds(state), _angleBounds(state)]; | ||
}, | ||
threshold(value, _k, config) { | ||
this.lockDirection = config.axis === 'lock'; | ||
const threshold = maths.V.toVector(value, this.lockDirection ? [0.1, 3] : 0); | ||
return threshold; | ||
} | ||
}); | ||
class WheelEngine extends CoordinatesEngine { | ||
constructor(...args) { | ||
super(...args); | ||
_defineProperty(this, "ingKey", 'wheeling'); | ||
} | ||
wheel(event) { | ||
if (!this.state._active) this.start(event); | ||
this.wheelChange(event); | ||
this.timeoutStore.add('wheelEnd', this.wheelEnd.bind(this)); | ||
} | ||
wheelChange(event) { | ||
if (event.cancelable) event.preventDefault(); | ||
const state = this.state; | ||
state._delta = wheelValues(event); | ||
maths.V.addTo(this.state._movement, state._delta); | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
wheelEnd() { | ||
if (!this.state._active) return; | ||
this.state._active = false; | ||
this.compute(); | ||
this.emit(); | ||
} | ||
bind(bindFunction) { | ||
bindFunction('wheel', '', this.wheel.bind(this)); | ||
} | ||
function parseMergedHandlers(mergedHandlers, mergedConfig) { | ||
const [handlers, nativeHandlers, actions] = sortHandlers(mergedHandlers); | ||
const internalHandlers = {}; | ||
registerGesture(actions, handlers, 'onDrag', 'drag', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onWheel', 'wheel', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onScroll', 'scroll', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onPinch', 'pinch', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onMove', 'move', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onHover', 'hover', internalHandlers, mergedConfig); | ||
return { | ||
handlers: internalHandlers, | ||
config: mergedConfig, | ||
nativeHandlers | ||
}; | ||
} | ||
const wheelConfigResolver = coordinatesConfigResolver; | ||
class ScrollEngine extends CoordinatesEngine { | ||
constructor(...args) { | ||
super(...args); | ||
_defineProperty(this, "ingKey", 'scrolling'); | ||
} | ||
scroll(event) { | ||
if (!this.state._active) this.start(event); | ||
this.scrollChange(event); | ||
this.timeoutStore.add('scrollEnd', this.scrollEnd.bind(this)); | ||
} | ||
scrollChange(event) { | ||
if (event.cancelable) event.preventDefault(); | ||
const state = this.state; | ||
const values = scrollValues(event); | ||
state._delta = maths.V.sub(values, state.values); | ||
maths.V.addTo(state._movement, state._delta); | ||
state.values = values; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
scrollEnd() { | ||
if (!this.state._active) return; | ||
this.state._active = false; | ||
this.compute(); | ||
this.emit(); | ||
} | ||
bind(bindFunction) { | ||
bindFunction('scroll', '', this.scroll.bind(this)); | ||
} | ||
} | ||
const scrollConfigResolver = coordinatesConfigResolver; | ||
class MoveEngine extends CoordinatesEngine { | ||
constructor(...args) { | ||
super(...args); | ||
_defineProperty(this, "ingKey", 'moving'); | ||
} | ||
move(event) { | ||
if (this.config.mouseOnly && event.pointerType !== 'mouse') return; | ||
if (!this.state._active) this.moveStart(event);else this.moveChange(event); | ||
this.timeoutStore.add('moveEnd', this.moveEnd.bind(this)); | ||
} | ||
moveStart(event) { | ||
this.start(event); | ||
const state = this.state; | ||
state.values = pointerValues(event); | ||
this.compute(event); | ||
state.initial = state.values; | ||
this.emit(); | ||
} | ||
moveChange(event) { | ||
if (!this.state._active) return; | ||
const values = pointerValues(event); | ||
const state = this.state; | ||
state._delta = maths.V.sub(values, state.values); | ||
maths.V.addTo(state._movement, state._delta); | ||
state.values = values; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
moveEnd(event) { | ||
if (!this.state._active) return; | ||
this.state._active = false; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
bind(bindFunction) { | ||
bindFunction('pointer', 'change', this.move.bind(this)); | ||
bindFunction('pointer', 'leave', this.moveEnd.bind(this)); | ||
} | ||
} | ||
const moveConfigResolver = _objectSpread2(_objectSpread2({}, coordinatesConfigResolver), {}, { | ||
mouseOnly: (value = true) => value | ||
}); | ||
class HoverEngine extends CoordinatesEngine { | ||
constructor(...args) { | ||
super(...args); | ||
_defineProperty(this, "ingKey", 'hovering'); | ||
} | ||
enter(event) { | ||
if (this.config.mouseOnly && event.pointerType !== 'mouse') return; | ||
this.start(event); | ||
this.state.values = pointerValues(event); | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
leave(event) { | ||
if (this.config.mouseOnly && event.pointerType !== 'mouse') return; | ||
const state = this.state; | ||
if (!state._active) return; | ||
state._active = false; | ||
const values = pointerValues(event); | ||
state._movement = state._delta = maths.V.sub(values, state.values); | ||
state.values = values; | ||
this.compute(event); | ||
state.delta = state.movement; | ||
this.emit(); | ||
} | ||
bind(bindFunction) { | ||
bindFunction('pointer', 'enter', this.enter.bind(this)); | ||
bindFunction('pointer', 'leave', this.leave.bind(this)); | ||
} | ||
} | ||
const hoverConfigResolver = _objectSpread2(_objectSpread2({}, coordinatesConfigResolver), {}, { | ||
mouseOnly: (value = true) => value | ||
}); | ||
exports.Controller = Controller; | ||
exports.DragEngine = DragEngine; | ||
exports.HoverEngine = HoverEngine; | ||
exports.MoveEngine = MoveEngine; | ||
exports.PinchEngine = PinchEngine; | ||
exports.ScrollEngine = ScrollEngine; | ||
exports.WheelEngine = WheelEngine; | ||
exports.dragConfigResolver = dragConfigResolver; | ||
exports.hoverConfigResolver = hoverConfigResolver; | ||
exports.moveConfigResolver = moveConfigResolver; | ||
exports.parseMergedHandlers = parseMergedHandlers; | ||
exports.pinchConfigResolver = pinchConfigResolver; | ||
exports.registerEngine = registerEngine; | ||
exports.scrollConfigResolver = scrollConfigResolver; | ||
exports.wheelConfigResolver = wheelConfigResolver; |
@@ -1,114 +0,4 @@ | ||
import { V, c as computeRubberband } from './maths-b2a210f4.esm.js'; | ||
import { S as SUPPORT, C as ConfigResolverMap, _ as _objectSpread2, a as _defineProperty, t as toDomEventType, i as isTouch, b as touchIds, c as toReactHandlerProp, E as EngineMap, d as chain } from './actions-811d5746.esm.js'; | ||
import './maths-b2a210f4.esm.js'; | ||
function _defineProperty(obj, key, value) { | ||
if (key in obj) { | ||
Object.defineProperty(obj, key, { | ||
value: value, | ||
enumerable: true, | ||
configurable: true, | ||
writable: true | ||
}); | ||
} else { | ||
obj[key] = value; | ||
} | ||
return obj; | ||
} | ||
function ownKeys(object, enumerableOnly) { | ||
var keys = Object.keys(object); | ||
if (Object.getOwnPropertySymbols) { | ||
var symbols = Object.getOwnPropertySymbols(object); | ||
if (enumerableOnly) { | ||
symbols = symbols.filter(function (sym) { | ||
return Object.getOwnPropertyDescriptor(object, sym).enumerable; | ||
}); | ||
} | ||
keys.push.apply(keys, symbols); | ||
} | ||
return keys; | ||
} | ||
function _objectSpread2(target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i] != null ? arguments[i] : {}; | ||
if (i % 2) { | ||
ownKeys(Object(source), true).forEach(function (key) { | ||
_defineProperty(target, key, source[key]); | ||
}); | ||
} else if (Object.getOwnPropertyDescriptors) { | ||
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); | ||
} else { | ||
ownKeys(Object(source)).forEach(function (key) { | ||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); | ||
}); | ||
} | ||
} | ||
return target; | ||
} | ||
const EngineMap = new Map(); | ||
const ConfigResolverMap = new Map(); | ||
function registerEngine(action, Engine, resolver) { | ||
EngineMap.set(action, Engine); | ||
ConfigResolverMap.set(action, resolver); | ||
} | ||
const RE_NOT_NATIVE = /^on(Drag|Wheel|Scroll|Move|Pinch|Hover)/; | ||
function sortHandlers(_handlers) { | ||
const native = {}; | ||
const handlers = {}; | ||
const actions = new Set(); | ||
for (let key in _handlers) { | ||
if (RE_NOT_NATIVE.test(key)) { | ||
actions.add(RegExp.lastMatch); | ||
handlers[key] = _handlers[key]; | ||
} else { | ||
native[key] = _handlers[key]; | ||
} | ||
} | ||
return [handlers, native, actions]; | ||
} | ||
function registerGesture(actions, handlers, handlerKey, key, internalHandlers, config) { | ||
if (!actions.has(handlerKey)) return; | ||
const startKey = handlerKey + 'Start'; | ||
const endKey = handlerKey + 'End'; | ||
const fn = state => { | ||
let memo = undefined; | ||
if (state.first && startKey in handlers) handlers[startKey](state); | ||
if (handlerKey in handlers) memo = handlers[handlerKey](state); | ||
if (state.last && endKey in handlers) handlers[endKey](state); | ||
return memo; | ||
}; | ||
internalHandlers[key] = fn; | ||
config[key] = config[key] || {}; | ||
} | ||
function parseMergedHandlers(mergedHandlers, mergedConfig) { | ||
const [handlers, nativeHandlers, actions] = sortHandlers(mergedHandlers); | ||
const internalHandlers = {}; | ||
registerGesture(actions, handlers, 'onDrag', 'drag', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onWheel', 'wheel', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onScroll', 'scroll', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onPinch', 'pinch', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onMove', 'move', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onHover', 'hover', internalHandlers, mergedConfig); | ||
return { | ||
handlers: internalHandlers, | ||
config: mergedConfig, | ||
nativeHandlers | ||
}; | ||
} | ||
function _objectWithoutPropertiesLoose(source, excluded) { | ||
@@ -148,32 +38,2 @@ if (source == null) return {}; | ||
const isBrowser = typeof window !== 'undefined' && window.document && window.document.createElement; | ||
function supportsTouchEvents() { | ||
return isBrowser && 'ontouchstart' in window; | ||
} | ||
function supportsPointerEvents() { | ||
return isBrowser && 'onpointerdown' in window; | ||
} | ||
function supportsPointerLock() { | ||
return isBrowser && 'exitPointerLock' in window.document; | ||
} | ||
function supportsGestureEvents() { | ||
try { | ||
return 'constructor' in GestureEvent; | ||
} catch (e) { | ||
return false; | ||
} | ||
} | ||
const SUPPORT = { | ||
isBrowser, | ||
gesture: supportsGestureEvents(), | ||
touch: supportsTouchEvents(), | ||
pointer: supportsPointerEvents(), | ||
pointerLock: supportsPointerLock() | ||
}; | ||
const identity = v => v; | ||
@@ -260,2 +120,7 @@ const sharedConfigResolver = { | ||
const resolver = ConfigResolverMap.get(key); | ||
if (process.env.NODE_ENV === 'development') { | ||
if (!resolver) console.warn(`[@use-gesture]: You've created a custom handler that that uses the \`${key}\` gesture but isn't properly configured.\n\nPlease add \`${key}Action\` when creating your handler.`); | ||
} | ||
_config[key] = resolveWith(_objectSpread2({ | ||
@@ -270,141 +135,2 @@ shared: _config.shared | ||
const EVENT_TYPE_MAP = { | ||
pointer: { | ||
start: 'down', | ||
change: 'move', | ||
end: 'up' | ||
}, | ||
mouse: { | ||
start: 'down', | ||
change: 'move', | ||
end: 'up' | ||
}, | ||
touch: { | ||
start: 'start', | ||
change: 'move', | ||
end: 'end' | ||
}, | ||
gesture: { | ||
start: 'start', | ||
change: 'change', | ||
end: 'end' | ||
} | ||
}; | ||
function capitalize(string) { | ||
if (!string) return ''; | ||
return string[0].toUpperCase() + string.slice(1); | ||
} | ||
function toReactHandlerProp(device, action = '', capture = false) { | ||
const deviceProps = EVENT_TYPE_MAP[device]; | ||
const actionKey = deviceProps ? deviceProps[action] || action : action; | ||
return 'on' + capitalize(device) + capitalize(actionKey) + (capture ? 'Capture' : ''); | ||
} | ||
function toDomEventType(device, action = '') { | ||
const deviceProps = EVENT_TYPE_MAP[device]; | ||
const actionKey = deviceProps ? deviceProps[action] || action : action; | ||
return device + actionKey; | ||
} | ||
function isTouch(event) { | ||
return 'touches' in event; | ||
} | ||
function getCurrentTargetTouchList(event) { | ||
return Array.from(event.touches).filter(e => { | ||
var _event$currentTarget; | ||
return (_event$currentTarget = event.currentTarget) === null || _event$currentTarget === void 0 ? void 0 : _event$currentTarget.contains(e.target); | ||
}); | ||
} | ||
function getTouchList(event) { | ||
return event.type === 'touchend' ? event.changedTouches : event.targetTouches; | ||
} | ||
function getValueEvent(event) { | ||
return isTouch(event) ? getTouchList(event)[0] : event; | ||
} | ||
function distanceAngle(P1, P2) { | ||
const dx = P2.clientX - P1.clientX; | ||
const dy = P2.clientY - P1.clientY; | ||
const cx = (P2.clientX + P1.clientX) / 2; | ||
const cy = (P2.clientY + P1.clientY) / 2; | ||
const distance = Math.hypot(dx, dy); | ||
const angle = -(Math.atan2(dx, dy) * 180) / Math.PI; | ||
const origin = [cx, cy]; | ||
return { | ||
angle, | ||
distance, | ||
origin | ||
}; | ||
} | ||
function touchIds(event) { | ||
return getCurrentTargetTouchList(event).map(touch => touch.identifier); | ||
} | ||
function touchDistanceAngle(event, ids) { | ||
const [P1, P2] = Array.from(event.touches).filter(touch => ids.includes(touch.identifier)); | ||
return distanceAngle(P1, P2); | ||
} | ||
function pointerId(event) { | ||
const valueEvent = getValueEvent(event); | ||
return isTouch(event) ? valueEvent.identifier : valueEvent.pointerId; | ||
} | ||
function pointerValues(event) { | ||
const valueEvent = getValueEvent(event); | ||
return [valueEvent.clientX, valueEvent.clientY]; | ||
} | ||
const LINE_HEIGHT = 40; | ||
const PAGE_HEIGHT = 800; | ||
function wheelValues(event) { | ||
let { | ||
deltaX, | ||
deltaY, | ||
deltaMode | ||
} = event; | ||
if (deltaMode === 1) { | ||
deltaX *= LINE_HEIGHT; | ||
deltaY *= LINE_HEIGHT; | ||
} else if (deltaMode === 2) { | ||
deltaX *= PAGE_HEIGHT; | ||
deltaY *= PAGE_HEIGHT; | ||
} | ||
return [deltaX, deltaY]; | ||
} | ||
function scrollValues(event) { | ||
var _ref, _ref2; | ||
const { | ||
scrollX, | ||
scrollY, | ||
scrollLeft, | ||
scrollTop | ||
} = event.currentTarget; | ||
return [(_ref = scrollX !== null && scrollX !== void 0 ? scrollX : scrollLeft) !== null && _ref !== void 0 ? _ref : 0, (_ref2 = scrollY !== null && scrollY !== void 0 ? scrollY : scrollTop) !== null && _ref2 !== void 0 ? _ref2 : 0]; | ||
} | ||
function getEventDetails(event) { | ||
const payload = {}; | ||
if ('buttons' in event) payload.buttons = event.buttons; | ||
if ('shiftKey' in event) { | ||
const { | ||
shiftKey, | ||
altKey, | ||
metaKey, | ||
ctrlKey | ||
} = event; | ||
Object.assign({ | ||
shiftKey, | ||
altKey, | ||
metaKey, | ||
ctrlKey | ||
}); | ||
} | ||
return payload; | ||
} | ||
class EventStore { | ||
@@ -458,27 +184,2 @@ constructor(ctrl) { | ||
function call(v, ...args) { | ||
if (typeof v === 'function') { | ||
return v(...args); | ||
} else { | ||
return v; | ||
} | ||
} | ||
function noop() {} | ||
function chain(...fns) { | ||
if (fns.length === 0) return noop; | ||
if (fns.length === 1) return fns[0]; | ||
return function () { | ||
let result; | ||
for (const fn of fns) { | ||
result = fn.apply(this, arguments) || result; | ||
} | ||
return result; | ||
}; | ||
} | ||
function assignDefault(value, fallback) { | ||
return Object.assign({}, fallback, value || {}); | ||
} | ||
class Controller { | ||
@@ -614,1220 +315,54 @@ constructor(handlers) { | ||
class Engine { | ||
constructor(ctrl, args, key) { | ||
this.ctrl = ctrl; | ||
this.args = args; | ||
this.key = key; | ||
const RE_NOT_NATIVE = /^on(Drag|Wheel|Scroll|Move|Pinch|Hover)/; | ||
if (!this.state) { | ||
this.state = { | ||
values: [0, 0], | ||
initial: [0, 0] | ||
}; | ||
if (this.init) this.init(); | ||
this.reset(); | ||
} | ||
} | ||
function sortHandlers(_handlers) { | ||
const native = {}; | ||
const handlers = {}; | ||
const actions = new Set(); | ||
get state() { | ||
return this.ctrl.state[this.key]; | ||
} | ||
set state(state) { | ||
this.ctrl.state[this.key] = state; | ||
} | ||
get shared() { | ||
return this.ctrl.state.shared; | ||
} | ||
get eventStore() { | ||
return this.ctrl.gestureEventStores[this.key]; | ||
} | ||
get timeoutStore() { | ||
return this.ctrl.gestureTimeoutStores[this.key]; | ||
} | ||
get config() { | ||
return this.ctrl.config[this.key]; | ||
} | ||
get sharedConfig() { | ||
return this.ctrl.config.shared; | ||
} | ||
get handler() { | ||
return this.ctrl.handlers[this.key]; | ||
} | ||
reset() { | ||
const { | ||
state, | ||
shared, | ||
config, | ||
ingKey, | ||
args | ||
} = this; | ||
const { | ||
transform, | ||
threshold = [0, 0] | ||
} = config; | ||
shared[ingKey] = state._active = state.active = state._blocked = state._force = false; | ||
state._step = [false, false]; | ||
state.intentional = false; | ||
state._movement = [0, 0]; | ||
state._distance = [0, 0]; | ||
state._delta = [0, 0]; | ||
state._threshold = V.sub(transform(threshold), transform([0, 0])).map(Math.abs); | ||
state._bounds = [[-Infinity, Infinity], [-Infinity, Infinity]]; | ||
state.args = args; | ||
state.axis = undefined; | ||
state.memo = undefined; | ||
state.elapsedTime = 0; | ||
state.direction = [0, 0]; | ||
state.distance = [0, 0]; | ||
state.velocity = [0, 0]; | ||
state.movement = [0, 0]; | ||
state.delta = [0, 0]; | ||
state.timeStamp = 0; | ||
} | ||
start(event) { | ||
const state = this.state; | ||
const config = this.config; | ||
if (!state._active) { | ||
this.reset(); | ||
state._active = true; | ||
state.target = event.currentTarget; | ||
state.initial = state.values; | ||
state.lastOffset = config.from ? call(config.from, state) : state.offset; | ||
state.offset = state.lastOffset; | ||
} | ||
state.startTime = state.timeStamp = event.timeStamp; | ||
} | ||
compute(event) { | ||
const { | ||
state, | ||
config, | ||
shared | ||
} = this; | ||
state.args = this.args; | ||
let dt = 0; | ||
if (event) { | ||
state.event = event; | ||
shared.touches = this.ctrl.pointerIds.size || this.ctrl.touchIds.size; | ||
shared.locked = !!document.pointerLockElement; | ||
Object.assign(shared, getEventDetails(event)); | ||
shared.down = shared.pressed = shared.buttons % 2 === 1 || shared.touches > 0; | ||
dt = event.timeStamp - state.timeStamp; | ||
state.timeStamp = event.timeStamp; | ||
state.elapsedTime = state.timeStamp - state.startTime; | ||
} | ||
if (state._active) { | ||
const _absoluteDelta = state._delta.map(Math.abs); | ||
V.addTo(state._distance, _absoluteDelta); | ||
} | ||
const [_m0, _m1] = config.transform(state._movement); | ||
const [_t0, _t1] = state._threshold; | ||
let [_s0, _s1] = state._step; | ||
if (_s0 === false) _s0 = Math.abs(_m0) >= _t0 && Math.sign(_m0) * _t0; | ||
if (_s1 === false) _s1 = Math.abs(_m1) >= _t1 && Math.sign(_m1) * _t1; | ||
state.intentional = _s0 !== false || _s1 !== false; | ||
if (!state.intentional) return; | ||
state._step = [_s0, _s1]; | ||
const movement = [0, 0]; | ||
movement[0] = _s0 !== false ? _m0 - _s0 : 0; | ||
movement[1] = _s1 !== false ? _m1 - _s1 : 0; | ||
if (this.intent) this.intent(movement); | ||
if (state._active && !state._blocked || state.active) { | ||
state.first = state._active && !state.active; | ||
state.last = !state._active && state.active; | ||
state.active = shared[this.ingKey] = state._active; | ||
if (event) { | ||
if (state.first) { | ||
if ('bounds' in config) state._bounds = call(config.bounds, state); | ||
if (this.setup) this.setup(); | ||
} | ||
const previousMovement = state.movement; | ||
state.movement = movement; | ||
this.computeOffset(); | ||
if (!state.last) { | ||
state.delta = V.sub(movement, previousMovement); | ||
const absoluteDelta = state.delta.map(Math.abs); | ||
V.addTo(state.distance, absoluteDelta); | ||
state.direction = state.delta.map(Math.sign); | ||
if (!state.first && dt > 0) { | ||
state.velocity = [absoluteDelta[0] / dt, absoluteDelta[1] / dt]; | ||
} | ||
} | ||
} | ||
} | ||
const rubberband = state._active ? config.rubberband || [0, 0] : [0, 0]; | ||
state.offset = computeRubberband(state._bounds, state.offset, rubberband); | ||
this.computeMovement(); | ||
} | ||
emit() { | ||
const state = this.state; | ||
const shared = this.shared; | ||
const config = this.config; | ||
if (!state._active) this.clean(); | ||
if ((state._blocked || !state.intentional) && !state._force && !config.triggerAllEvents) return; | ||
const memo = this.handler(_objectSpread2(_objectSpread2({}, shared), state)); | ||
if (memo !== undefined) state.memo = memo; | ||
} | ||
clean() { | ||
this.eventStore.clean(); | ||
this.timeoutStore.clean(); | ||
} | ||
} | ||
function selectAxis([dx, dy]) { | ||
const d = Math.abs(dx) - Math.abs(dy); | ||
if (d > 0) return 'x'; | ||
if (d < 0) return 'y'; | ||
return undefined; | ||
} | ||
function restrictVectorToAxis(v, axis) { | ||
switch (axis) { | ||
case 'x': | ||
v[1] = 0; | ||
break; | ||
case 'y': | ||
v[0] = 0; | ||
break; | ||
} | ||
} | ||
class CoordinatesEngine extends Engine { | ||
reset() { | ||
super.reset(); | ||
this.state.axis = undefined; | ||
} | ||
init() { | ||
this.state.offset = [0, 0]; | ||
this.state.lastOffset = [0, 0]; | ||
} | ||
computeOffset() { | ||
this.state.offset = V.add(this.state.lastOffset, this.state.movement); | ||
} | ||
computeMovement() { | ||
this.state.movement = V.sub(this.state.offset, this.state.lastOffset); | ||
this.state.xy = this.state.values; | ||
} | ||
intent(v) { | ||
this.state.axis = this.state.axis || selectAxis(v); | ||
this.state._blocked = (this.config.lockDirection || !!this.config.axis) && !this.state.axis || !!this.config.axis && this.config.axis !== this.state.axis; | ||
if (this.state._blocked) return; | ||
if (this.config.axis || this.config.lockDirection) { | ||
restrictVectorToAxis(v, this.state.axis); | ||
} | ||
} | ||
} | ||
const DEFAULT_RUBBERBAND = 0.15; | ||
const commonConfigResolver = { | ||
enabled(value = true) { | ||
return value; | ||
}, | ||
triggerAllEvents(value = false) { | ||
return value; | ||
}, | ||
rubberband(value = 0) { | ||
switch (value) { | ||
case true: | ||
return [DEFAULT_RUBBERBAND, DEFAULT_RUBBERBAND]; | ||
case false: | ||
return [0, 0]; | ||
default: | ||
return V.toVector(value); | ||
} | ||
}, | ||
from(value) { | ||
if (typeof value === 'function') return value; | ||
if (value != null) return V.toVector(value); | ||
}, | ||
transform(value, _k, config) { | ||
return value || config.shared.transform; | ||
} | ||
}; | ||
if (process.env.NODE_ENV === 'development') { | ||
Object.assign(commonConfigResolver, { | ||
domTarget(value) { | ||
if (value !== undefined) { | ||
throw Error(`[@use-gesture]: \`domTarget\` option has been renamed to \`target\`.`); | ||
} | ||
}, | ||
lockDirection(value) { | ||
if (value !== undefined) { | ||
throw Error(`[@use-gesture]: \`lockDirection\` option has been merged with \`axis\`. Use it as in \`{ axis: 'lock' }\``); | ||
} | ||
}, | ||
initial(value) { | ||
if (value !== undefined) { | ||
throw Error(`[@use-gesture]: \`initial\` option has been renamed to \`from\`.`); | ||
} | ||
} | ||
}); | ||
} | ||
const coordinatesConfigResolver = _objectSpread2(_objectSpread2({}, commonConfigResolver), {}, { | ||
axis(_v, _k, { | ||
axis | ||
}) { | ||
this.lockDirection = axis === 'lock'; | ||
if (!this.lockDirection) return axis; | ||
}, | ||
bounds(value = {}) { | ||
if (typeof value === 'function') { | ||
return state => coordinatesConfigResolver.bounds(value(state)); | ||
} | ||
if ('current' in value) { | ||
return () => value.current; | ||
} | ||
if (typeof HTMLElement === 'function' && value instanceof HTMLElement) { | ||
return value; | ||
} | ||
const { | ||
left = -Infinity, | ||
right = Infinity, | ||
top = -Infinity, | ||
bottom = Infinity | ||
} = value; | ||
return [[left, right], [top, bottom]]; | ||
} | ||
}); | ||
const DISPLACEMENT = 10; | ||
const KEYS_DELTA_MAP = { | ||
ArrowRight: (factor = 1) => [DISPLACEMENT * factor, 0], | ||
ArrowLeft: (factor = 1) => [-DISPLACEMENT * factor, 0], | ||
ArrowUp: (factor = 1) => [0, -DISPLACEMENT * factor], | ||
ArrowDown: (factor = 1) => [0, DISPLACEMENT * factor] | ||
}; | ||
class DragEngine extends CoordinatesEngine { | ||
constructor(...args) { | ||
super(...args); | ||
_defineProperty(this, "ingKey", 'dragging'); | ||
} | ||
reset() { | ||
super.reset(); | ||
const state = this.state; | ||
state._pointerId = undefined; | ||
state._pointerActive = false; | ||
state._keyboardActive = false; | ||
state._preventScroll = false; | ||
state._delayed = false; | ||
state.swipe = [0, 0]; | ||
state.tap = false; | ||
state.canceled = false; | ||
state.cancel = this.cancel.bind(this); | ||
} | ||
setup() { | ||
const state = this.state; | ||
if (state._bounds instanceof HTMLElement) { | ||
const boundRect = state._bounds.getBoundingClientRect(); | ||
const targetRect = state.target.getBoundingClientRect(); | ||
const _bounds = { | ||
left: boundRect.left - targetRect.left + state.offset[0], | ||
right: boundRect.right - targetRect.right + state.offset[0], | ||
top: boundRect.top - targetRect.top + state.offset[1], | ||
bottom: boundRect.bottom - targetRect.bottom + state.offset[1] | ||
}; | ||
state._bounds = coordinatesConfigResolver.bounds(_bounds); | ||
} | ||
} | ||
cancel() { | ||
const state = this.state; | ||
if (state.canceled) return; | ||
setTimeout(() => { | ||
state.canceled = true; | ||
state._active = false; | ||
this.compute(); | ||
this.emit(); | ||
}, 0); | ||
} | ||
setActive() { | ||
this.state._active = this.state._pointerActive || this.state._keyboardActive; | ||
} | ||
clean() { | ||
this.pointerClean(); | ||
this.state._pointerActive = false; | ||
this.state._keyboardActive = false; | ||
super.clean(); | ||
} | ||
pointerDown(event) { | ||
if (event.buttons != null && event.buttons % 2 !== 1) return; | ||
this.ctrl.setEventIds(event); | ||
if (this.config.pointerCapture) { | ||
event.target.setPointerCapture(event.pointerId); | ||
} | ||
const state = this.state; | ||
const config = this.config; | ||
if (state._pointerActive) return; | ||
this.start(event); | ||
this.setupPointer(event); | ||
state._pointerId = pointerId(event); | ||
state._pointerActive = true; | ||
state.values = pointerValues(event); | ||
state.initial = state.values; | ||
if (config.preventScroll) { | ||
this.setupScrollPrevention(event); | ||
} else if (config.delay > 0) { | ||
this.setupDelayTrigger(event); | ||
for (let key in _handlers) { | ||
if (RE_NOT_NATIVE.test(key)) { | ||
actions.add(RegExp.lastMatch); | ||
handlers[key] = _handlers[key]; | ||
} else { | ||
this.startPointerDrag(event); | ||
native[key] = _handlers[key]; | ||
} | ||
} | ||
startPointerDrag(event) { | ||
const state = this.state; | ||
state._active = true; | ||
state._preventScroll = true; | ||
state._delayed = false; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
pointerMove(event) { | ||
const state = this.state; | ||
const config = this.config; | ||
if (!state._pointerActive) return; | ||
const id = pointerId(event); | ||
if (state._pointerId && id !== state._pointerId) return; | ||
const values = pointerValues(event); | ||
if (document.pointerLockElement === event.target) { | ||
state._delta = [event.movementX, event.movementY]; | ||
} else { | ||
state._delta = V.sub(values, state.values); | ||
state.values = values; | ||
} | ||
V.addTo(state._movement, state._delta); | ||
this.compute(event); | ||
if (state._delayed) { | ||
this.timeoutStore.remove('dragDelay'); | ||
this.startPointerDrag(event); | ||
return; | ||
} | ||
if (config.preventScroll && !state._preventScroll) { | ||
if (state.axis) { | ||
if (state.axis === config.preventScrollAxis || config.preventScrollAxis === 'xy') { | ||
state._active = false; | ||
this.clean(); | ||
return; | ||
} else { | ||
this.timeoutStore.remove('startPointerDrag'); | ||
this.startPointerDrag(event); | ||
return; | ||
} | ||
} else { | ||
return; | ||
} | ||
} | ||
this.emit(); | ||
} | ||
pointerUp(event) { | ||
this.ctrl.setEventIds(event); | ||
try { | ||
if (this.config.pointerCapture && event.target.hasPointerCapture(event.pointerId)) { | ||
; | ||
event.target.releasePointerCapture(event.pointerId); | ||
} | ||
} catch (_unused) { | ||
if (process.env.NODE_ENV === 'development') { | ||
console.warn(`[@use-gesture]: If you see this message, it's likely that you're using an outdated version of \`@react-three/fiber\`. \n\nPlease upgrade to the latest version.`); | ||
} | ||
} | ||
const state = this.state; | ||
const config = this.config; | ||
if (!state._pointerActive) return; | ||
const id = pointerId(event); | ||
if (state._pointerId && id !== state._pointerId) return; | ||
this.state._pointerActive = false; | ||
this.setActive(); | ||
this.compute(event); | ||
const [dx, dy] = state._distance; | ||
state.tap = dx <= 3 && dy <= 3; | ||
if (state.tap && config.filterTaps) { | ||
state._force = true; | ||
} else { | ||
const [dirx, diry] = state.direction; | ||
const [vx, vy] = state.velocity; | ||
const [mx, my] = state.movement; | ||
const [svx, svy] = config.swipe.velocity; | ||
const [sx, sy] = config.swipe.distance; | ||
const sdt = config.swipe.duration; | ||
if (state.elapsedTime < sdt) { | ||
if (Math.abs(vx) > svx && Math.abs(mx) > sx) state.swipe[0] = dirx; | ||
if (Math.abs(vy) > svy && Math.abs(my) > sy) state.swipe[1] = diry; | ||
} | ||
} | ||
this.emit(); | ||
} | ||
pointerClick(event) { | ||
if (!this.state.tap) { | ||
event.preventDefault(); | ||
event.stopPropagation(); | ||
} | ||
} | ||
setupPointer(event) { | ||
const config = this.config; | ||
let device = config.device; | ||
if (process.env.NODE_ENV === 'development') { | ||
try { | ||
if (device === 'pointer') { | ||
const currentTarget = 'uv' in event ? event.sourceEvent.currentTarget : event.currentTarget; | ||
const style = window.getComputedStyle(currentTarget); | ||
if (style.touchAction === 'auto') { | ||
console.warn(`[@use-gesture]: The drag target has its \`touch-action\` style property set to \`auto\`. It is recommended to add \`touch-action: 'none'\` so that the drag gesture behaves correctly on touch-enabled devices. For more information read this: https://use-gesture.netlify.app/docs/extras/#touch-action.\n\nThis message will only show in development mode. It won't appear in production. If this is intended, you can ignore it.`, currentTarget); | ||
} | ||
} | ||
} catch (_unused2) {} | ||
} | ||
if (config.pointerLock) { | ||
event.currentTarget.requestPointerLock(); | ||
} | ||
if (!config.pointerCapture) { | ||
this.eventStore.add(this.sharedConfig.window, device, 'change', this.pointerMove.bind(this)); | ||
this.eventStore.add(this.sharedConfig.window, device, 'end', this.pointerUp.bind(this)); | ||
} | ||
} | ||
pointerClean() { | ||
if (this.config.pointerLock && document.pointerLockElement === this.state.target) { | ||
document.exitPointerLock(); | ||
} | ||
} | ||
preventScroll(event) { | ||
if (this.state._preventScroll && event.cancelable) { | ||
event.preventDefault(); | ||
} | ||
} | ||
setupScrollPrevention(event) { | ||
persistEvent(event); | ||
this.eventStore.add(this.sharedConfig.window, 'touch', 'change', this.preventScroll.bind(this), { | ||
passive: false | ||
}); | ||
this.eventStore.add(this.sharedConfig.window, 'touch', 'end', this.clean.bind(this), { | ||
passive: false | ||
}); | ||
this.eventStore.add(this.sharedConfig.window, 'touch', 'cancel', this.clean.bind(this), { | ||
passive: false | ||
}); | ||
this.timeoutStore.add('startPointerDrag', this.startPointerDrag.bind(this), this.config.preventScroll, event); | ||
} | ||
setupDelayTrigger(event) { | ||
this.state._delayed = true; | ||
this.timeoutStore.add('dragDelay', this.startPointerDrag.bind(this), this.config.delay, event); | ||
} | ||
keyDown(event) { | ||
const deltaFn = KEYS_DELTA_MAP[event.key]; | ||
const state = this.state; | ||
if (deltaFn) { | ||
const factor = event.shiftKey ? 10 : event.altKey ? 0.1 : 1; | ||
state._delta = deltaFn(factor); | ||
this.start(event); | ||
state._keyboardActive = true; | ||
V.addTo(state._movement, state._delta); | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
} | ||
keyUp(event) { | ||
if (!(event.key in KEYS_DELTA_MAP)) return; | ||
this.state._keyboardActive = false; | ||
this.setActive(); | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
bind(bindFunction) { | ||
const device = this.config.device; | ||
bindFunction(device, 'start', this.pointerDown.bind(this)); | ||
if (this.config.pointerCapture) { | ||
bindFunction(device, 'change', this.pointerMove.bind(this)); | ||
bindFunction(device, 'end', this.pointerUp.bind(this)); | ||
bindFunction(device, 'cancel', this.pointerUp.bind(this)); | ||
} | ||
bindFunction('key', 'down', this.keyDown.bind(this)); | ||
bindFunction('key', 'up', this.keyUp.bind(this)); | ||
if (this.config.filterTaps) { | ||
bindFunction('click', '', this.pointerClick.bind(this), { | ||
capture: true | ||
}); | ||
} | ||
} | ||
return [handlers, native, actions]; | ||
} | ||
function persistEvent(event) { | ||
'persist' in event && typeof event.persist === 'function' && event.persist(); | ||
} | ||
function registerGesture(actions, handlers, handlerKey, key, internalHandlers, config) { | ||
if (!actions.has(handlerKey)) return; | ||
const startKey = handlerKey + 'Start'; | ||
const endKey = handlerKey + 'End'; | ||
const DEFAULT_PREVENT_SCROLL_DELAY = 250; | ||
const DEFAULT_DRAG_DELAY = 180; | ||
const DEFAULT_SWIPE_VELOCITY = 0.5; | ||
const DEFAULT_SWIPE_DISTANCE = 50; | ||
const DEFAULT_SWIPE_DURATION = 250; | ||
const dragConfigResolver = _objectSpread2(_objectSpread2({}, coordinatesConfigResolver), {}, { | ||
pointerLock(_v, _k, { | ||
pointer: { | ||
lock = false, | ||
touch = false | ||
} = {} | ||
}) { | ||
this.useTouch = SUPPORT.touch && touch; | ||
return SUPPORT.pointerLock && lock; | ||
}, | ||
const fn = state => { | ||
let memo = undefined; | ||
if (state.first && startKey in handlers) handlers[startKey](state); | ||
if (handlerKey in handlers) memo = handlers[handlerKey](state); | ||
if (state.last && endKey in handlers) handlers[endKey](state); | ||
return memo; | ||
}; | ||
device(_v, _k) { | ||
if (this.useTouch) return 'touch'; | ||
if (this.pointerLock) return 'mouse'; | ||
if (SUPPORT.pointer) return 'pointer'; | ||
if (SUPPORT.touch) return 'touch'; | ||
return 'mouse'; | ||
}, | ||
preventScroll(value = false, _k, { | ||
preventScrollAxis = 'y' | ||
}) { | ||
if (preventScrollAxis) this.preventScrollAxis = preventScrollAxis; | ||
if (!SUPPORT.touch) return false; | ||
if (typeof value === 'number') return value; | ||
return value ? DEFAULT_PREVENT_SCROLL_DELAY : false; | ||
}, | ||
pointerCapture(_v, _k, { | ||
pointer: { | ||
capture = true | ||
} = {} | ||
}) { | ||
return !this.pointerLock && this.device === 'pointer' && capture; | ||
}, | ||
threshold(value, _k, { | ||
filterTaps = false, | ||
axis = undefined | ||
}) { | ||
const threshold = V.toVector(value, filterTaps ? 3 : axis ? 1 : 0); | ||
this.filterTaps = filterTaps; | ||
return threshold; | ||
}, | ||
swipe({ | ||
velocity = DEFAULT_SWIPE_VELOCITY, | ||
distance = DEFAULT_SWIPE_DISTANCE, | ||
duration = DEFAULT_SWIPE_DURATION | ||
} = {}) { | ||
return { | ||
velocity: this.transform(V.toVector(velocity)), | ||
distance: this.transform(V.toVector(distance)), | ||
duration | ||
}; | ||
}, | ||
delay(value = 0) { | ||
switch (value) { | ||
case true: | ||
return DEFAULT_DRAG_DELAY; | ||
case false: | ||
return 0; | ||
default: | ||
return value; | ||
} | ||
} | ||
}); | ||
if (process.env.NODE_ENV === 'development') { | ||
Object.assign(dragConfigResolver, { | ||
useTouch(value) { | ||
if (value !== undefined) { | ||
throw Error(`[@use-gesture]: \`useTouch\` option has been renamed to \`pointer.touch\`. Use it as in \`{ pointer: { touch: true } }\`.`); | ||
} | ||
}, | ||
experimental_preventWindowScrollY(value) { | ||
if (value !== undefined) { | ||
throw Error(`[@use-gesture]: \`experimental_preventWindowScrollY\` option has been renamed to \`preventScroll\`.`); | ||
} | ||
}, | ||
swipeVelocity(value) { | ||
if (value !== undefined) { | ||
throw Error(`[@use-gesture]: \`swipeVelocity\` option has been renamed to \`swipe.velocity\`. Use it as in \`{ swipe: { velocity: 0.5 } }\`.`); | ||
} | ||
}, | ||
swipeDistance(value) { | ||
if (value !== undefined) { | ||
throw Error(`[@use-gesture]: \`swipeDistance\` option has been renamed to \`swipe.distance\`. Use it as in \`{ swipe: { distance: 50 } }\`.`); | ||
} | ||
}, | ||
swipeDuration(value) { | ||
if (value !== undefined) { | ||
throw Error(`[@use-gesture]: \`swipeDuration\` option has been renamed to \`swipe.duration\`. Use it as in \`{ swipe: { duration: 250 } }\`.`); | ||
} | ||
} | ||
}); | ||
internalHandlers[key] = fn; | ||
config[key] = config[key] || {}; | ||
} | ||
const SCALE_ANGLE_RATIO_INTENT_DEG = 30; | ||
const PINCH_WHEEL_RATIO = 60; | ||
class PinchEngine extends Engine { | ||
constructor(...args) { | ||
super(...args); | ||
_defineProperty(this, "ingKey", 'pinching'); | ||
} | ||
init() { | ||
this.state.offset = [1, 0]; | ||
this.state.lastOffset = [1, 0]; | ||
this.state._pointerEvents = new Map(); | ||
} | ||
reset() { | ||
super.reset(); | ||
const state = this.state; | ||
state._touchIds = []; | ||
state.canceled = false; | ||
state.cancel = this.cancel.bind(this); | ||
state.turns = 0; | ||
} | ||
computeOffset() { | ||
const { | ||
movement, | ||
lastOffset | ||
} = this.state; | ||
this.state.offset = [(1 + movement[0]) * lastOffset[0], movement[1] + lastOffset[1]]; | ||
} | ||
computeMovement() { | ||
const { | ||
offset, | ||
lastOffset | ||
} = this.state; | ||
this.state.movement = [offset[0] / lastOffset[0] - 1, offset[1] - lastOffset[1]]; | ||
this.state.da = this.state.values; | ||
} | ||
intent(v) { | ||
const state = this.state; | ||
if (!state.axis) { | ||
const axisMovementDifference = Math.abs(v[0]) * SCALE_ANGLE_RATIO_INTENT_DEG - Math.abs(v[1]); | ||
if (axisMovementDifference < 0) state.axis = 'angle';else if (axisMovementDifference > 0) state.axis = 'scale'; | ||
} | ||
if (this.config.lockDirection) { | ||
if (state.axis === 'scale') v[1] = 0;else if (state.axis === 'angle') v[0] = 0; | ||
} | ||
} | ||
cancel() { | ||
const state = this.state; | ||
if (state.canceled) return; | ||
setTimeout(() => { | ||
state.canceled = true; | ||
state._active = false; | ||
this.compute(); | ||
this.emit(); | ||
}, 0); | ||
} | ||
touchStart(event) { | ||
this.ctrl.setEventIds(event); | ||
const state = this.state; | ||
const ctrlTouchIds = this.ctrl.touchIds; | ||
if (state._active) { | ||
if (state._touchIds.every(id => ctrlTouchIds.has(id))) return; | ||
} | ||
if (ctrlTouchIds.size < 2) return; | ||
this.start(event); | ||
state._touchIds = Array.from(ctrlTouchIds).slice(0, 2); | ||
const payload = touchDistanceAngle(event, state._touchIds); | ||
this.pinchStart(event, payload); | ||
} | ||
pointerStart(event) { | ||
if (event.buttons != null && event.buttons % 2 !== 1) return; | ||
this.ctrl.setEventIds(event); | ||
event.target.setPointerCapture(event.pointerId); | ||
const state = this.state; | ||
const _pointerEvents = state._pointerEvents; | ||
const ctrlPointerIds = this.ctrl.pointerIds; | ||
if (state._active) { | ||
if (Array.from(_pointerEvents.keys()).every(id => ctrlPointerIds.has(id))) return; | ||
} | ||
if (_pointerEvents.size < 2) { | ||
_pointerEvents.set(event.pointerId, event); | ||
} | ||
if (state._pointerEvents.size < 2) return; | ||
this.start(event); | ||
const payload = distanceAngle(...Array.from(_pointerEvents.values())); | ||
this.pinchStart(event, payload); | ||
} | ||
pinchStart(event, payload) { | ||
const state = this.state; | ||
state.origin = payload.origin; | ||
state.values = [payload.distance, payload.angle]; | ||
state.initial = state.values; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
touchMove(event) { | ||
if (!this.state._active) return; | ||
const payload = touchDistanceAngle(event, this.state._touchIds); | ||
this.pinchMove(event, payload); | ||
} | ||
pointerMove(event) { | ||
const _pointerEvents = this.state._pointerEvents; | ||
if (_pointerEvents.has(event.pointerId)) { | ||
_pointerEvents.set(event.pointerId, event); | ||
} | ||
if (!this.state._active) return; | ||
const payload = distanceAngle(...Array.from(_pointerEvents.values())); | ||
this.pinchMove(event, payload); | ||
} | ||
pinchMove(event, payload) { | ||
const state = this.state; | ||
const prev_a = state.values[1]; | ||
const delta_a = payload.angle - prev_a; | ||
let delta_turns = 0; | ||
if (Math.abs(delta_a) > 270) delta_turns += Math.sign(delta_a); | ||
state.values = [payload.distance, payload.angle - 360 * delta_turns]; | ||
state.origin = payload.origin; | ||
state.turns = delta_turns; | ||
state._movement = [state.values[0] / state.initial[0] - 1, state.values[1] - state.initial[1]]; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
touchEnd(event) { | ||
this.ctrl.setEventIds(event); | ||
if (!this.state._active) return; | ||
if (this.state._touchIds.some(id => !this.ctrl.touchIds.has(id))) { | ||
this.state._active = false; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
} | ||
pointerEnd(event) { | ||
const state = this.state; | ||
this.ctrl.setEventIds(event); | ||
try { | ||
event.target.releasePointerCapture(event.pointerId); | ||
} catch (_unused) {} | ||
if (state._pointerEvents.has(event.pointerId)) { | ||
state._pointerEvents.delete(event.pointerId); | ||
} | ||
if (!state._active) return; | ||
if (state._pointerEvents.size < 2) { | ||
state._active = false; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
} | ||
gestureStart(event) { | ||
if (event.cancelable) event.preventDefault(); | ||
const state = this.state; | ||
if (state._active) return; | ||
this.start(event); | ||
state.values = [event.scale, event.rotation]; | ||
state.origin = [event.clientX, event.clientY]; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
gestureMove(event) { | ||
if (event.cancelable) event.preventDefault(); | ||
if (!this.state._active) return; | ||
const state = this.state; | ||
state.values = [event.scale, event.rotation]; | ||
state.origin = [event.clientX, event.clientY]; | ||
const _previousMovement = state._movement; | ||
state._movement = [event.scale - 1, event.rotation]; | ||
state._delta = V.sub(state._movement, _previousMovement); | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
gestureEnd(event) { | ||
if (!this.state._active) return; | ||
this.state._active = false; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
wheel(event) { | ||
if (!event.ctrlKey) return; | ||
if (!this.state._active) this.wheelStart(event);else this.wheelChange(event); | ||
this.timeoutStore.add('wheelEnd', this.wheelEnd.bind(this)); | ||
} | ||
wheelStart(event) { | ||
this.start(event); | ||
this.wheelChange(event); | ||
} | ||
wheelChange(event) { | ||
const isR3f = ('uv' in event); | ||
if (!isR3f) { | ||
if (event.cancelable) { | ||
event.preventDefault(); | ||
} | ||
if (process.env.NODE_ENV === 'development' && !event.defaultPrevented) { | ||
console.warn(`[@use-gesture]: To properly support zoom on trackpads, try using the \`target\` option.\n\nThis message will only appear in development mode.`); | ||
} | ||
} | ||
const state = this.state; | ||
state._delta = [-wheelValues(event)[1] / PINCH_WHEEL_RATIO, 0]; | ||
V.addTo(state._movement, state._delta); | ||
this.state.origin = [event.clientX, event.clientY]; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
wheelEnd() { | ||
if (!this.state._active) return; | ||
this.state._active = false; | ||
this.compute(); | ||
this.emit(); | ||
} | ||
bind(bindFunction) { | ||
const device = this.config.device; | ||
if (!!device) { | ||
bindFunction(device, 'start', this[device + 'Start'].bind(this)); | ||
bindFunction(device, 'change', this[device + 'Move'].bind(this)); | ||
bindFunction(device, 'end', this[device + 'End'].bind(this)); | ||
} else { | ||
bindFunction('wheel', '', this.wheel.bind(this), { | ||
passive: false | ||
}); | ||
} | ||
} | ||
function parseMergedHandlers(mergedHandlers, mergedConfig) { | ||
const [handlers, nativeHandlers, actions] = sortHandlers(mergedHandlers); | ||
const internalHandlers = {}; | ||
registerGesture(actions, handlers, 'onDrag', 'drag', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onWheel', 'wheel', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onScroll', 'scroll', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onPinch', 'pinch', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onMove', 'move', internalHandlers, mergedConfig); | ||
registerGesture(actions, handlers, 'onHover', 'hover', internalHandlers, mergedConfig); | ||
return { | ||
handlers: internalHandlers, | ||
config: mergedConfig, | ||
nativeHandlers | ||
}; | ||
} | ||
const pinchConfigResolver = _objectSpread2(_objectSpread2({}, commonConfigResolver), {}, { | ||
useTouch(_v, _k, { | ||
pointer: { | ||
touch = false | ||
} = {} | ||
}) { | ||
return SUPPORT.touch && touch; | ||
}, | ||
device(_v, _k, config) { | ||
const sharedConfig = config.shared; | ||
if (sharedConfig.target && !SUPPORT.touch && SUPPORT.gesture) return 'gesture'; | ||
if (this.useTouch) return 'touch'; | ||
if (SUPPORT.touch && SUPPORT.pointer) return 'pointer'; | ||
if (SUPPORT.touch) return 'touch'; | ||
}, | ||
bounds(_v, _k, { | ||
scaleBounds = {}, | ||
angleBounds = {} | ||
}) { | ||
const _scaleBounds = state => { | ||
const D = assignDefault(call(scaleBounds, state), { | ||
min: -Infinity, | ||
max: Infinity | ||
}); | ||
return [D.min, D.max]; | ||
}; | ||
const _angleBounds = state => { | ||
const A = assignDefault(call(angleBounds, state), { | ||
min: -Infinity, | ||
max: Infinity | ||
}); | ||
return [A.min, A.max]; | ||
}; | ||
if (typeof scaleBounds !== 'function' && typeof angleBounds !== 'function') return [_scaleBounds(), _angleBounds()]; | ||
return state => [_scaleBounds(state), _angleBounds(state)]; | ||
}, | ||
threshold(value, _k, config) { | ||
this.lockDirection = config.axis === 'lock'; | ||
const threshold = V.toVector(value, this.lockDirection ? [0.1, 3] : 0); | ||
return threshold; | ||
} | ||
}); | ||
class WheelEngine extends CoordinatesEngine { | ||
constructor(...args) { | ||
super(...args); | ||
_defineProperty(this, "ingKey", 'wheeling'); | ||
} | ||
wheel(event) { | ||
if (!this.state._active) this.start(event); | ||
this.wheelChange(event); | ||
this.timeoutStore.add('wheelEnd', this.wheelEnd.bind(this)); | ||
} | ||
wheelChange(event) { | ||
if (event.cancelable) event.preventDefault(); | ||
const state = this.state; | ||
state._delta = wheelValues(event); | ||
V.addTo(this.state._movement, state._delta); | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
wheelEnd() { | ||
if (!this.state._active) return; | ||
this.state._active = false; | ||
this.compute(); | ||
this.emit(); | ||
} | ||
bind(bindFunction) { | ||
bindFunction('wheel', '', this.wheel.bind(this)); | ||
} | ||
} | ||
const wheelConfigResolver = coordinatesConfigResolver; | ||
class ScrollEngine extends CoordinatesEngine { | ||
constructor(...args) { | ||
super(...args); | ||
_defineProperty(this, "ingKey", 'scrolling'); | ||
} | ||
scroll(event) { | ||
if (!this.state._active) this.start(event); | ||
this.scrollChange(event); | ||
this.timeoutStore.add('scrollEnd', this.scrollEnd.bind(this)); | ||
} | ||
scrollChange(event) { | ||
if (event.cancelable) event.preventDefault(); | ||
const state = this.state; | ||
const values = scrollValues(event); | ||
state._delta = V.sub(values, state.values); | ||
V.addTo(state._movement, state._delta); | ||
state.values = values; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
scrollEnd() { | ||
if (!this.state._active) return; | ||
this.state._active = false; | ||
this.compute(); | ||
this.emit(); | ||
} | ||
bind(bindFunction) { | ||
bindFunction('scroll', '', this.scroll.bind(this)); | ||
} | ||
} | ||
const scrollConfigResolver = coordinatesConfigResolver; | ||
class MoveEngine extends CoordinatesEngine { | ||
constructor(...args) { | ||
super(...args); | ||
_defineProperty(this, "ingKey", 'moving'); | ||
} | ||
move(event) { | ||
if (this.config.mouseOnly && event.pointerType !== 'mouse') return; | ||
if (!this.state._active) this.moveStart(event);else this.moveChange(event); | ||
this.timeoutStore.add('moveEnd', this.moveEnd.bind(this)); | ||
} | ||
moveStart(event) { | ||
this.start(event); | ||
const state = this.state; | ||
state.values = pointerValues(event); | ||
this.compute(event); | ||
state.initial = state.values; | ||
this.emit(); | ||
} | ||
moveChange(event) { | ||
if (!this.state._active) return; | ||
const values = pointerValues(event); | ||
const state = this.state; | ||
state._delta = V.sub(values, state.values); | ||
V.addTo(state._movement, state._delta); | ||
state.values = values; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
moveEnd(event) { | ||
if (!this.state._active) return; | ||
this.state._active = false; | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
bind(bindFunction) { | ||
bindFunction('pointer', 'change', this.move.bind(this)); | ||
bindFunction('pointer', 'leave', this.moveEnd.bind(this)); | ||
} | ||
} | ||
const moveConfigResolver = _objectSpread2(_objectSpread2({}, coordinatesConfigResolver), {}, { | ||
mouseOnly: (value = true) => value | ||
}); | ||
class HoverEngine extends CoordinatesEngine { | ||
constructor(...args) { | ||
super(...args); | ||
_defineProperty(this, "ingKey", 'hovering'); | ||
} | ||
enter(event) { | ||
if (this.config.mouseOnly && event.pointerType !== 'mouse') return; | ||
this.start(event); | ||
this.state.values = pointerValues(event); | ||
this.compute(event); | ||
this.emit(); | ||
} | ||
leave(event) { | ||
if (this.config.mouseOnly && event.pointerType !== 'mouse') return; | ||
const state = this.state; | ||
if (!state._active) return; | ||
state._active = false; | ||
const values = pointerValues(event); | ||
state._movement = state._delta = V.sub(values, state.values); | ||
state.values = values; | ||
this.compute(event); | ||
state.delta = state.movement; | ||
this.emit(); | ||
} | ||
bind(bindFunction) { | ||
bindFunction('pointer', 'enter', this.enter.bind(this)); | ||
bindFunction('pointer', 'leave', this.leave.bind(this)); | ||
} | ||
} | ||
const hoverConfigResolver = _objectSpread2(_objectSpread2({}, coordinatesConfigResolver), {}, { | ||
mouseOnly: (value = true) => value | ||
}); | ||
export { Controller, DragEngine, HoverEngine, MoveEngine, PinchEngine, ScrollEngine, WheelEngine, dragConfigResolver, hoverConfigResolver, moveConfigResolver, parseMergedHandlers, pinchConfigResolver, registerEngine, scrollConfigResolver, wheelConfigResolver }; | ||
export { Controller, parseMergedHandlers }; |
{ | ||
"name": "@use-gesture/core", | ||
"version": "10.0.0-beta.10", | ||
"version": "10.0.0-beta.11", | ||
"description": "Core engine for receiving gestures", | ||
@@ -13,2 +13,3 @@ "license": "MIT", | ||
"./utils.ts", | ||
"./actions.ts", | ||
"./types.ts" | ||
@@ -15,0 +16,0 @@ ] |
import { sharedConfigResolver } from './sharedConfigResolver' | ||
import { ConfigResolverMap } from '../imports' | ||
import { ConfigResolverMap } from '../actions' | ||
import { GestureKey, InternalConfig, UserGestureConfig } from '../types' | ||
@@ -42,2 +42,9 @@ | ||
const resolver = ConfigResolverMap.get(key as GestureKey)! | ||
if (process.env.NODE_ENV === 'development') { | ||
if (!resolver) | ||
// eslint-disable-next-line no-console | ||
console.warn( | ||
`[@use-gesture]: You've created a custom handler that that uses the \`${key}\` gesture but isn't properly configured.\n\nPlease add \`${key}Action\` when creating your handler.` | ||
) | ||
} | ||
_config[key] = resolveWith({ shared: _config.shared, ...rest[key] }, resolver) | ||
@@ -44,0 +51,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import { EngineMap } from './imports' | ||
import { EngineMap } from './actions' | ||
import { parse } from './config/resolver' | ||
@@ -3,0 +3,0 @@ import { isTouch, toReactHandlerProp, touchIds } from './utils/events' |
export { Controller } from './Controller' | ||
export { DragEngine } from './engines/DragEngine' | ||
export { dragConfigResolver } from './config/dragConfigResolver' | ||
export { PinchEngine } from './engines/PinchEngine' | ||
export { pinchConfigResolver } from './config/pinchConfigResolver' | ||
export { WheelEngine } from './engines/WheelEngine' | ||
export { wheelConfigResolver } from './config/wheelConfigResolver' | ||
export { ScrollEngine } from './engines/ScrollEngine' | ||
export { scrollConfigResolver } from './config/scrollConfigResolver' | ||
export { MoveEngine } from './engines/MoveEngine' | ||
export { moveConfigResolver } from './config/moveConfigResolver' | ||
export { HoverEngine } from './engines/HoverEngine' | ||
export { hoverConfigResolver } from './config/hoverConfigResolver' | ||
export { registerEngine, parseMergedHandlers } from './imports' | ||
export { parseMergedHandlers } from './parser' |
@@ -6,1 +6,2 @@ export * from './config' | ||
export * from './handlers' | ||
export * from './action' |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
276899
105
8237
16