Socket
Socket
Sign inDemoInstall

@use-gesture/core

Package Overview
Dependencies
Maintainers
1
Versions
67
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@use-gesture/core - npm Package Compare versions

Comparing version 10.0.0-beta.1 to 10.0.0-beta.2

dist/declarations/src/engines/DragEngine.d.ts

59

dist/declarations/src/Controller.d.ts
import { EventStore } from './EventStore';
import { TimeoutStore } from './TimeoutStore';
import { GestureKey, InternalConfig, InternalHandlers, NativeHandlers, State, UserGestureConfig } from './types';
interface ControllerConstructor {
new (handlers: InternalHandlers): Controller;
}
export interface Controller {
export declare class Controller {
/**
* The list of gestures handled by the Controller.
*/
_gestures: Set<GestureKey>;
gestures: Set<GestureKey>;
/**
* The event store that keeps track of the config.target listeners.
*/
_targetEventStore: EventStore;
private _targetEventStore;
/**
* Object that keeps track of all gesture event listeners.
*/
_gestureEventStores: {
gestureEventStores: {
[key in GestureKey]?: EventStore;
};
/**
* Object that keeps track of all gesture timeouts.
*/
_gestureTimeoutStores: {
gestureTimeoutStores: {
[key in GestureKey]?: TimeoutStore;
};
/**
* Gesture handlers.
*/
_handlers: InternalHandlers;
/**
* Native event handlers.
*/
_nativeHandlers?: NativeHandlers;
/**
* Computed configuration.
*/
_config: InternalConfig;
/**
* Pointer ids active on the target.
*/
_pointerIds: Set<number>;
/**
* Touch identifiers active on the target.
*/
_touchIds: Set<number>;
/**
* The Controller state reflecting the state of all gestures.
*/
handlers: InternalHandlers;
private nativeHandlers?;
config: InternalConfig;
pointerIds: Set<number>;
touchIds: Set<number>;
state: State;
constructor(handlers: InternalHandlers);
/**

@@ -56,3 +33,3 @@ * Sets pointer or touch ids based on the event.

*/
setEventIds(this: Controller, event: TouchEvent | PointerEvent): void;
setEventIds(event: TouchEvent | PointerEvent): void;
/**

@@ -63,3 +40,3 @@ * Attaches handlers to the controller.

*/
applyHandlers(this: Controller, handlers: InternalHandlers, nativeHandlers?: NativeHandlers): void;
applyHandlers(handlers: InternalHandlers, nativeHandlers?: NativeHandlers): void;
/**

@@ -70,3 +47,3 @@ * Compute and attaches a config to the controller.

*/
applyConfig(this: Controller, config: UserGestureConfig, gestureKey?: GestureKey): void;
applyConfig(config: UserGestureConfig, gestureKey?: GestureKey): void;
/**

@@ -76,3 +53,3 @@ * Cleans all side effects (listeners, timeouts). When the gesture is

*/
clean(this: Controller): void;
clean(): void;
/**

@@ -82,3 +59,3 @@ * Executes side effects (attaching listeneds to a `config.target`). Ran on

*/
effect(this: Controller): void;
effect(): () => void;
/**

@@ -89,5 +66,3 @@ * The bind function that can be returned by the gesture handler (a hook in

*/
bind(this: Controller, ...args: any[]): NativeHandlers | void;
bind(...args: any[]): any;
}
export declare const Controller: ControllerConstructor;
export {};
import { Engine } from './Engine';
import type { Controller } from '../Controller';
import { CoordinatesKey, GestureKey } from '../types';
export interface CoordinatesEngineConstructor {
new <Key extends CoordinatesKey>(ctrl: Controller, args: any[], key: Key): CoordinatesEngine<Key>;
import { CoordinatesKey, Vector2 } from '../types';
export declare abstract class CoordinatesEngine<Key extends CoordinatesKey> extends Engine<Key> {
reset(): void;
init(): void;
computeOffset(): void;
computeMovement(): void;
intent(v: Vector2): void;
}
export interface CoordinatesEngine<Key extends GestureKey = CoordinatesKey> extends Engine<Key> {
}
export declare const CoordinatesEngine: CoordinatesEngineConstructor;
import { Controller } from '../Controller';
import { EventStore } from '../EventStore';
import { TimeoutStore } from '../TimeoutStore';
import { GestureKey, Handler, IngKey, InternalConfig, State, Vector2 } from '../types';
export interface EngineConstructor {
new <Key extends GestureKey>(ctrl: Controller, args: any[], key: Key): Engine<Key>;
import { GestureKey, IngKey, State, Vector2 } from '../types';
export interface Engine<Key extends GestureKey> {
/**
* Function that some gestures can use to add initilization
* properties to the state when it is created.
*/
init?(): void;
/**
* Setup function that some gestures can use to set additional properties of
* the state when the gesture starts.
*/
setup?(): void;
/**
* Function used by some gestures to determine the intentionality of a
* a movement depending on thresholds. The intent function can change the
* `state._active` or `state._blocked` flags if the gesture isn't intentional.
* @param movement
*/
intent?(movement: Vector2): void;
}
export interface Engine<Key extends GestureKey = GestureKey> {
export declare abstract class Engine<Key extends GestureKey> {
/**

@@ -16,3 +30,3 @@ * The Controller handling state.

*/
key: Key;
readonly key: Key;
/**

@@ -22,3 +36,3 @@ * The key representing the active state of the gesture in the shared state.

*/
ingKey: IngKey;
abstract readonly ingKey: IngKey;
/**

@@ -28,56 +42,68 @@ * The arguments passed to the `bind` function.

args: any[];
constructor(ctrl: Controller, args: any[], key: Key);
/**
* Shortcut to the gesture state read from the Controller.
* Function implemented by gestures that compute the offset from the state
* movement.
*/
state: NonNullable<State[Key]>;
abstract computeOffset(): void;
/**
* Shortcut to the shared state read from the Controller
* Function implemented by the gestures that compute the movement from the
* corrected offset (after bounds and potential rubberbanding).
*/
shared: State['shared'];
abstract computeMovement(): void;
/**
* Shortcut to the gesture config read from the Controller.
* Executes the bind function so that listeners are properly set by the
* Controller.
* @param bindFunction
*/
config: NonNullable<InternalConfig[Key]>;
abstract bind(bindFunction: (device: string, action: string, handler: (event: any) => void, options?: AddEventListenerOptions) => void): void;
/**
* Shortcut to the shared config read from the Controller.
* Shortcut to the gesture state read from the Controller.
*/
sharedConfig: InternalConfig['shared'];
get state(): NonNullable<State[Key]>;
set state(state: NonNullable<State[Key]>);
/**
* Shortcut to the shared state read from the Controller
*/
get shared(): import("../types").SharedGestureState;
/**
* Shortcut to the gesture event store read from the Controller.
*/
eventStore: EventStore;
get eventStore(): NonNullable<{
drag?: import("../EventStore").EventStore | undefined;
wheel?: import("../EventStore").EventStore | undefined;
scroll?: import("../EventStore").EventStore | undefined;
move?: import("../EventStore").EventStore | undefined;
hover?: import("../EventStore").EventStore | undefined;
pinch?: import("../EventStore").EventStore | undefined;
}[Key]>;
/**
* Shortcut to the gesture timeout store read from the Controller.
*/
timeoutStore: TimeoutStore;
get timeoutStore(): NonNullable<{
drag?: import("../TimeoutStore").TimeoutStore | undefined;
wheel?: import("../TimeoutStore").TimeoutStore | undefined;
scroll?: import("../TimeoutStore").TimeoutStore | undefined;
move?: import("../TimeoutStore").TimeoutStore | undefined;
hover?: import("../TimeoutStore").TimeoutStore | undefined;
pinch?: import("../TimeoutStore").TimeoutStore | undefined;
}[Key]>;
/**
* Shortcut to the gesture handler read from the Controller.
* Shortcut to the gesture config read from the Controller.
*/
handler: Handler<Key>;
get config(): NonNullable<import("../types").InternalConfig[Key]>;
/**
* Function that some gestures can use to add initilization
* properties to the state when it is created.
* Shortcut to the shared config read from the Controller.
*/
init?(this: Engine<Key>): void;
get sharedConfig(): import("../types").InternalGenericOptions;
/**
* Setup function that some gestures can use to set additional properties of
* the state when the gesture starts.
* Shortcut to the gesture handler read from the Controller.
*/
setup?(this: Engine<Key>): void;
get handler(): NonNullable<import("../types").InternalHandlers[Key]>;
reset(): void;
/**
* Function used by some gestures to determine the intentionality of a
* a movement depending on thresholds. The intent function can change the
* `state._active` or `state._blocked` flags if the gesture isn't intentional.
* @param movement
*/
intent?(this: Engine<Key>, movement: Vector2): void;
/**
* Function that resets the state.
*/
reset(this: Engine<Key>): void;
/**
* Function ran at the start of the gesture.
* @param event
*/
start(this: Engine<Key>, event: NonNullable<State[Key]>['event']): void;
start(event: NonNullable<State[Key]>['event']): void;
/**

@@ -87,28 +113,11 @@ * Computes all sorts of state attributes, including kinematics.

*/
compute(this: Engine<Key>, event?: NonNullable<State[Key]>['event']): void;
compute(event?: NonNullable<State[Key]>['event']): void;
/**
* Function implemented by gestures that compute the offset from the state
* movement.
*/
computeOffset(this: Engine<Key>): void;
/**
* Function implemented by the gestures that compute the movement from the
* corrected offset (after bounds and potential rubberbanding).
*/
computeMovement(this: Engine<Key>): void;
/**
* Fires the gesture handler.
*/
emit(this: Engine<Key>): void;
emit(): void;
/**
* Cleans the gesture timeouts and event listeners.
*/
clean(this: Engine<Key>): void;
/**
* Executes the bind function so that listeners are properly set by the
* Controller.
* @param bindFunction
*/
bind(this: Engine<Key>, bindFunction: (device: string, action: string, handler: (event: any) => void, options?: AddEventListenerOptions) => void): void;
clean(): void;
}
export declare const Engine: EngineConstructor;

@@ -1,11 +0,8 @@

interface EventStoreConstructor {
new (ctrl: any): EventStore;
import type { Controller } from './Controller';
export declare class EventStore {
private _listeners;
private _ctrl;
constructor(ctrl: Controller);
add(element: EventTarget, device: string, action: string, handler: (event: any) => void, options?: AddEventListenerOptions): void;
clean(): void;
}
export interface EventStore {
_ctrl: any;
_listeners: (() => void)[];
clean(this: EventStore): void;
add(this: EventStore, element: EventTarget, device: string, action: string, handler: (event: any) => void, options?: AddEventListenerOptions): void;
}
export declare const EventStore: EventStoreConstructor;
export {};
import { ResolverMap } from './config/resolver';
import { DragEngineConstructor } from './engines/DragEngine/DragEngineCore';
import { HoverEngineConstructor } from './engines/HoverEngine/HoverEngineCore';
import { MoveEngineConstructor } from './engines/MoveEngine/MoveEngineCore';
import { PinchEngineConstructor } from './engines/PinchEngine/PinchEngineCore';
import { ScrollEngineConstructor } from './engines/ScrollEngine/ScrollEngineCore';
import { WheelEngineConstructor } from './engines/WheelEngine/WheelEngineCore';
import type { Controller } from './Controller';
import type { Engine } from './engines/Engine';
import { GestureHandlers, GestureKey, UserGestureConfig } from './types';
declare type GestureEngineConstuctor = DragEngineConstructor | ScrollEngineConstructor | WheelEngineConstructor | PinchEngineConstructor | HoverEngineConstructor | MoveEngineConstructor;
export declare const EngineMap: Map<GestureKey, GestureEngineConstuctor>;
export declare type EngineClass<Key extends GestureKey> = {
new (controller: Controller, args: any[], key: Key): Engine<Key>;
};
export declare const EngineMap: Map<GestureKey, EngineClass<any>>;
export declare const ConfigResolverMap: Map<GestureKey, ResolverMap>;
export declare function registerEngine(action: GestureKey, Engine: GestureEngineConstuctor): void;
export declare function registerEngine<Key extends GestureKey>(action: Key, Engine: EngineClass<Key>): void;
export declare function parseMergedHandlers(mergedHandlers: GestureHandlers, mergedConfig: UserGestureConfig): {

@@ -18,2 +16,1 @@ handlers: {};

};
export {};

@@ -1,11 +0,6 @@

interface TimeoutStoreConstructor {
new (): TimeoutStore;
export declare class TimeoutStore {
private _timeouts;
add<FunctionType extends (...args: any) => any>(key: string, callback: FunctionType, ms?: number, ...args: Parameters<FunctionType>): void;
remove(key: string): void;
clean(): void;
}
export interface TimeoutStore {
_timeouts: Map<string, number>;
add<FunctionType extends (...args: any) => any>(this: TimeoutStore, key: string, callback: FunctionType, ms?: number, ...args: Parameters<FunctionType>): void;
remove(this: TimeoutStore, key: string): void;
clean(this: TimeoutStore): void;
}
export declare const TimeoutStore: TimeoutStoreConstructor;
export {};

@@ -427,43 +427,50 @@ 'use strict';

const EventStore = function EventStore(ctrl) {
this._ctrl = ctrl;
this._listeners = [];
};
class EventStore {
constructor(ctrl) {
_defineProperty(this, "_listeners", []);
EventStore.prototype.add = function (element, device, action, handler, options) {
const type = toDomEventType(device, action);
const eventOptions = options || this._ctrl._config.shared.eventOptions;
element.addEventListener(type, handler, eventOptions);
this._ctrl = ctrl;
}
this._listeners.push(() => element.removeEventListener(type, handler, eventOptions));
};
add(element, device, action, handler, options) {
const type = toDomEventType(device, action);
const eventOptions = options || this._ctrl.config.shared.eventOptions;
element.addEventListener(type, handler, eventOptions);
EventStore.prototype.clean = function () {
this._listeners.forEach(remove => remove());
this._listeners.push(() => element.removeEventListener(type, handler, eventOptions));
}
this._listeners = [];
};
clean() {
this._listeners.forEach(remove => remove());
const TimeoutStore = function TimeoutStore() {
this._timeouts = new Map();
};
this._listeners = [];
}
TimeoutStore.prototype.add = function (key, callback, ms = 140, ...args) {
this.remove(key);
}
this._timeouts.set(key, window.setTimeout(callback, ms, ...args));
};
class TimeoutStore {
constructor() {
_defineProperty(this, "_timeouts", new Map());
}
TimeoutStore.prototype.remove = function (key) {
const timeout = this._timeouts.get(key);
add(key, callback, ms = 140, ...args) {
this.remove(key);
if (timeout) window.clearTimeout(timeout);
};
this._timeouts.set(key, window.setTimeout(callback, ms, ...args));
}
TimeoutStore.prototype.clean = function () {
this._timeouts.forEach(timeout => void window.clearTimeout(timeout));
remove(key) {
const timeout = this._timeouts.get(key);
this._timeouts.clear();
};
if (timeout) window.clearTimeout(timeout);
}
clean() {
this._timeouts.forEach(timeout => void window.clearTimeout(timeout));
this._timeouts.clear();
}
}
function call(v, ...args) {

@@ -494,91 +501,100 @@ if (typeof v === 'function') {

const Controller = function Controller(handlers) {
this._gestures = new Set();
this._targetEventStore = new EventStore(this);
this._gestureEventStores = {};
this._gestureTimeoutStores = {};
this._handlers = {};
this._nativeHandlers = {};
this._config = {};
this._pointerIds = new Set();
this._touchIds = new Set();
this.state = {
shared: {
shiftKey: false,
metaKey: false,
ctrlKey: false,
altKey: false
}
};
resolveGestures(this, handlers);
};
class Controller {
constructor(handlers) {
_defineProperty(this, "gestures", new Set());
Controller.prototype.setEventIds = function (event) {
if (isTouch(event)) {
this._touchIds = new Set(Touches.ids(event));
} else if ('pointerId' in event) {
if (event.type === 'pointerup') this._pointerIds.delete(event.pointerId);else this._pointerIds.add(event.pointerId);
_defineProperty(this, "_targetEventStore", new EventStore(this));
_defineProperty(this, "gestureEventStores", {});
_defineProperty(this, "gestureTimeoutStores", {});
_defineProperty(this, "handlers", {});
_defineProperty(this, "config", {});
_defineProperty(this, "pointerIds", new Set());
_defineProperty(this, "touchIds", new Set());
_defineProperty(this, "state", {
shared: {
shiftKey: false,
metaKey: false,
ctrlKey: false,
altKey: false
}
});
resolveGestures(this, handlers);
}
};
Controller.prototype.applyHandlers = function (handlers, nativeHandlers) {
this._handlers = handlers;
this._nativeHandlers = nativeHandlers;
};
setEventIds(event) {
if (isTouch(event)) {
this.touchIds = new Set(Touches.ids(event));
} else if ('pointerId' in event) {
if (event.type === 'pointerup') this.pointerIds.delete(event.pointerId);else this.pointerIds.add(event.pointerId);
}
}
Controller.prototype.applyConfig = function (config, gestureKey) {
this._config = parse(config, gestureKey);
};
applyHandlers(handlers, nativeHandlers) {
this.handlers = handlers;
this.nativeHandlers = nativeHandlers;
}
Controller.prototype.clean = function () {
this._targetEventStore.clean();
applyConfig(config, gestureKey) {
this.config = parse(config, gestureKey);
}
for (const key of this._gestures) {
this._gestureEventStores[key].clean();
clean() {
this._targetEventStore.clean();
this._gestureTimeoutStores[key].clean();
for (const key of this.gestures) {
this.gestureEventStores[key].clean();
this.gestureTimeoutStores[key].clean();
}
}
};
Controller.prototype.effect = function () {
if (this._config.shared.target) this.bind();
return () => this._targetEventStore.clean();
};
effect() {
if (this.config.shared.target) this.bind();
return () => this._targetEventStore.clean();
}
Controller.prototype.bind = function (...args) {
const sharedConfig = this._config.shared;
const eventOptions = sharedConfig.eventOptions;
const props = {};
const bindFunction = sharedConfig.target ? bindToEventStore(this._targetEventStore, sharedConfig.target()) : bindToProps(props, eventOptions);
bind(...args) {
const sharedConfig = this.config.shared;
const eventOptions = sharedConfig.eventOptions;
const props = {};
const bindFunction = sharedConfig.target ? bindToEventStore(this._targetEventStore, sharedConfig.target()) : bindToProps(props, eventOptions);
if (sharedConfig.enabled) {
for (const eventKey in this._nativeHandlers) {
bindFunction(eventKey, '', event => this._nativeHandlers[eventKey](_objectSpread2(_objectSpread2({}, this.state.shared), {}, {
event,
args
})), undefined, true);
if (sharedConfig.enabled) {
for (const eventKey in this.nativeHandlers) {
bindFunction(eventKey, '', event => this.nativeHandlers[eventKey](_objectSpread2(_objectSpread2({}, this.state.shared), {}, {
event,
args
})), undefined, true);
}
for (const gestureKey of this.gestures) {
if (this.config[gestureKey].enabled) {
const Engine = EngineMap.get(gestureKey);
new Engine(this, args, gestureKey).bind(bindFunction);
}
}
}
for (const gestureKey of this._gestures) {
if (this._config[gestureKey].enabled) {
const Engine = EngineMap.get(gestureKey);
new Engine(this, args).bind(bindFunction);
if (!sharedConfig.target) {
for (const handlerProp in props) {
props[handlerProp] = chain(...props[handlerProp]);
}
return props;
}
}
if (!sharedConfig.target) {
for (const handlerProp in props) {
props[handlerProp] = chain(...props[handlerProp]);
}
}
return props;
}
};
function setupGesture(ctrl, gestureKey) {
ctrl._gestures.add(gestureKey);
ctrl._gestureEventStores[gestureKey] = new EventStore(ctrl);
ctrl._gestureTimeoutStores[gestureKey] = new TimeoutStore();
ctrl.gestures.add(gestureKey);
ctrl.gestureEventStores[gestureKey] = new EventStore(ctrl);
ctrl.gestureTimeoutStores[gestureKey] = new TimeoutStore();
}

@@ -654,240 +670,239 @@

const Engine = function Engine(ctrl, args, key) {
this.ctrl = ctrl;
this.key = key;
this.args = args;
class Engine {
constructor(ctrl, args, key) {
this.ctrl = ctrl;
this.args = args;
this.key = key;
if (!this.state) {
this.state = {
values: [0, 0],
initial: [0, 0]
};
if (this.init) this.init();
this.reset();
if (!this.state) {
this.state = {
values: [0, 0],
initial: [0, 0]
};
if (this.init) this.init();
this.reset();
}
}
};
Engine.prototype = {
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];
},
return this.ctrl.gestureEventStores[this.key];
}
get timeoutStore() {
return this.ctrl._gestureTimeoutStores[this.key];
},
return this.ctrl.gestureTimeoutStores[this.key];
}
get config() {
return this.ctrl._config[this.key];
},
return this.ctrl.config[this.key];
}
get sharedConfig() {
return this.ctrl._config.shared;
},
return this.ctrl.config.shared;
}
get handler() {
return this.ctrl._handlers[this.key];
return this.ctrl.handlers[this.key];
}
};
reset() {
const {
state,
shared,
config,
ingKey
} = 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.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;
}
Engine.prototype.reset = function () {
const {
state,
shared,
config,
ingKey
} = 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.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;
Engine.prototype.start = function (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;
}
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;
}
state.startTime = state.timeStamp = event.timeStamp;
};
compute(event) {
const {
state,
config,
shared
} = this;
state.args = this.args;
let dt = 0;
Engine.prototype.compute = function (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 > 0 || shared.touches > 0;
dt = event.timeStamp - state.timeStamp;
state.timeStamp = event.timeStamp;
state.elapsedTime = state.timeStamp - state.startTime;
}
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 > 0 || 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);
if (state._active) {
const _absoluteDelta = state._delta.map(Math.abs);
V.addTo(state._distance, _absoluteDelta);
}
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);
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 (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();
}
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();
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.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];
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();
}
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;
}
Engine.prototype.emit = function () {
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();
}
Engine.prototype.clean = function () {
this.eventStore.clean();
this.timeoutStore.clean();
};
}
const CoordinatesEngine = function CoordinatesEngine(ctrl, args, key) {
Engine.call(this, ctrl, args, key);
};
CoordinatesEngine.prototype = Object.create(Engine.prototype);
class CoordinatesEngine extends Engine {
reset() {
super.reset();
this.state.axis = undefined;
}
CoordinatesEngine.prototype.reset = function () {
Engine.prototype.reset.call(this);
this.state.axis = undefined;
};
init() {
this.state.offset = [0, 0];
this.state.lastOffset = [0, 0];
}
CoordinatesEngine.prototype.init = function () {
this.state.offset = [0, 0];
this.state.lastOffset = [0, 0];
};
computeOffset() {
const state = this.state;
state.offset = V.add(state.lastOffset, state.movement);
}
CoordinatesEngine.prototype.computeOffset = function () {
const state = this.state;
state.offset = V.add(state.lastOffset, state.movement);
};
computeMovement() {
const {
offset,
lastOffset
} = this.state;
this.state.movement = V.sub(offset, lastOffset);
this.state.xy = this.state.values;
}
CoordinatesEngine.prototype.computeMovement = function () {
const {
offset,
lastOffset
} = this.state;
this.state.movement = V.sub(offset, lastOffset);
this.state.xy = this.state.values;
};
intent(v) {
const state = this.state;
CoordinatesEngine.prototype.intent = function (v) {
const state = this.state;
if (!state.axis) {
const axisMovementDifference = Math.abs(v[0]) - Math.abs(v[1]);
if (axisMovementDifference < 0) state.axis = 'y';else if (axisMovementDifference > 0) state.axis = 'x';
}
if (!state.axis) {
const axisMovementDifference = Math.abs(v[0]) - Math.abs(v[1]);
if (axisMovementDifference < 0) state.axis = 'y';else if (axisMovementDifference > 0) state.axis = 'x';
}
const axis = state.axis;
const axis = state.axis;
if (this.config.lockDirection) {
if (axis) {
state._blocked = false;
if (axis === 'x') v[1] = 0;else if (axis === 'y') v[0] = 0;
} else {
state._blocked = false;
if (this.config.lockDirection) {
if (axis) {
state._blocked = false;
if (axis === 'x') v[1] = 0;else if (axis === 'y') v[0] = 0;
} else {
state._blocked = false;
}
} else if (this.config.axis) {
if (!!axis && axis === this.config.axis) {
state._blocked = false;
if (axis === 'x') v[1] = 0;else if (axis === 'y') v[0] = 0;
} else {
state._blocked = true;
}
}
} else if (this.config.axis) {
if (!!axis && axis === this.config.axis) {
state._blocked = false;
if (axis === 'x') v[1] = 0;else if (axis === 'y') v[0] = 0;
} else {
state._blocked = true;
}
}
};
}
const DEFAULT_RUBBERBAND = 0.15;

@@ -1090,285 +1105,315 @@ const commonConfigResolver = {

ConfigResolverMap.set('drag', dragConfigResolver);
const DragEngine = function DragEngine(ctrl, args) {
this.ingKey = 'dragging';
CoordinatesEngine.call(this, ctrl, args, 'drag');
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]
};
DragEngine.prototype = Object.create(CoordinatesEngine.prototype);
class DragEngine extends CoordinatesEngine {
constructor(...args) {
super(...args);
DragEngine.prototype.reset = function () {
CoordinatesEngine.prototype.reset.call(this);
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);
};
_defineProperty(this, "ingKey", 'dragging');
}
DragEngine.prototype.setup = function () {
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);
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);
}
};
DragEngine.prototype.cancel = function () {
const state = this.state;
if (state.canceled) return;
setTimeout(() => {
state.canceled = true;
state._active = false;
this.compute();
this.emit();
}, 0);
};
setup() {
const state = this.state;
DragEngine.prototype.setActive = function ({
pointer,
keyboard
} = {}) {
this.state._active = (pointer !== null && pointer !== void 0 ? pointer : this.state._pointerActive) || (keyboard !== null && keyboard !== void 0 ? keyboard : this.state._keyboardActive);
};
if (state._bounds instanceof HTMLElement) {
const boundRect = state._bounds.getBoundingClientRect();
DragEngine.prototype.clean = function () {
this.pointerClean();
this.state._pointerActive = false;
this.state._keyboardActive = false;
CoordinatesEngine.prototype.clean.call(this);
};
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);
}
}
DragEngine.prototype.bind = function (bindFunction) {
const device = this.config.device;
bindFunction(device, 'start', this.pointerDown.bind(this));
bindFunction(device, 'end', this.pointerUp.bind(this));
bindFunction('key', 'down', this.keyDown.bind(this));
bindFunction('key', 'up', this.keyUp.bind(this));
cancel() {
const state = this.state;
if (state.canceled) return;
setTimeout(() => {
state.canceled = true;
state._active = false;
this.compute();
this.emit();
}, 0);
}
if (this.sharedConfig.r3f) {
bindFunction(device, 'change', this.pointerMove.bind(this));
setActive() {
this.state._active = this.state._pointerActive || this.state._keyboardActive;
}
if (this.config.filterTaps) {
bindFunction('click', '', this.pointerClick.bind(this), {
capture: true
});
clean() {
this.pointerClean();
this.state._pointerActive = false;
this.state._keyboardActive = false;
super.clean();
}
};
DragEngine.prototype.pointerDown = function (event) {
this.ctrl.setEventIds(event);
const state = this.state;
const config = this.config;
if (state._pointerActive) return;
this.start(event);
this.setupPointer(event);
state._pointerId = Pointer.id(event);
state._pointerActive = true;
state.values = Pointer.values(event);
state.initial = state.values;
pointerDown(event) {
this.ctrl.setEventIds(event);
if (config.preventScroll) {
this.setupScrollPrevention(event);
} else if (config.delay > 0) {
this.setupDelayTrigger(event);
} else {
this.startPointerDrag(event);
}
};
if (this.config.pointerCapture) {
event.target.setPointerCapture(event.pointerId);
}
DragEngine.prototype.startPointerDrag = function (event) {
const state = this.state;
state._active = true;
state._preventScroll = true;
state._delayed = false;
this.compute(event);
this.emit();
};
const state = this.state;
const config = this.config;
if (state._pointerActive) return;
this.start(event);
this.setupPointer(event);
state._pointerId = Pointer.id(event);
state._pointerActive = true;
state.values = Pointer.values(event);
state.initial = state.values;
DragEngine.prototype.pointerMove = function (event) {
const state = this.state;
const config = this.config;
if (!state._pointerActive) return;
const id = Pointer.id(event);
if (state._pointerId && id !== state._pointerId) return;
const values = Pointer.values(event);
if (config.preventScroll) {
this.setupScrollPrevention(event);
} else if (config.delay > 0) {
this.setupDelayTrigger(event);
} else {
this.startPointerDrag(event);
}
}
if (document.pointerLockElement === event.target) {
state._delta = [event.movementX, event.movementY];
} else {
state._delta = V.sub(values, state.values);
state.values = values;
startPointerDrag(event) {
const state = this.state;
state._active = true;
state._preventScroll = true;
state._delayed = false;
this.compute(event);
this.emit();
}
V.addTo(state._movement, state._delta);
this.compute(event);
pointerMove(event) {
const state = this.state;
const config = this.config;
if (!state._pointerActive) return;
const id = Pointer.id(event);
if (state._pointerId && id !== state._pointerId) return;
const values = Pointer.values(event);
if (state._delayed) {
this.timeoutStore.remove('dragDelay');
this.startPointerDrag(event);
return;
}
if (document.pointerLockElement === event.target) {
state._delta = [event.movementX, event.movementY];
} else {
state._delta = V.sub(values, state.values);
state.values = values;
}
if (config.preventScroll && !state._preventScroll) {
if (state.axis) {
if (state.axis === 'x') {
this.timeoutStore.remove('startPointerDrag');
this.startPointerDrag(event);
return;
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 === 'x') {
this.timeoutStore.remove('startPointerDrag');
this.startPointerDrag(event);
return;
} else {
state._active = false;
this.clean();
return;
}
} else {
state._active = false;
this.clean();
return;
}
} else {
return;
}
this.emit();
}
this.emit();
};
pointerUp(event) {
this.ctrl.setEventIds(event);
DragEngine.prototype.pointerUp = function (event) {
this.ctrl.setEventIds(event);
const state = this.state;
const config = this.config;
if (!state._pointerActive) return;
const id = Pointer.id(event);
if (state._pointerId && id !== state._pointerId) return;
this.setActive({
pointer: false
});
this.compute(event);
const [dx, dy] = state._distance;
state.tap = dx <= 3 && dy <= 3;
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.`);
}
}
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;
const state = this.state;
const config = this.config;
if (!state._pointerActive) return;
const id = Pointer.id(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.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;
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();
}
this.emit();
};
pointerClick(event) {
if (!this.state.tap) event.stopPropagation();
}
DragEngine.prototype.pointerClick = function (event) {
if (!this.state.tap) event.stopPropagation();
};
setupPointer(event) {
const config = this.config;
let device = config.device;
const target = event.target;
const currentTarget = event.currentTarget;
DragEngine.prototype.setupPointer = function (event) {
const config = this.config;
let device = config.device;
const target = event.target;
const currentTarget = event.currentTarget;
if (process.env.NODE_ENV === 'development') {
try {
if (device === 'pointer') {
const _currentTarget = this.sharedConfig.r3f ? event.sourceEvent.currentTarget : event.currentTarget;
if (process.env.NODE_ENV === 'development') {
try {
if (device === 'pointer') {
const _currentTarget = this.sharedConfig.r3f ? event.sourceEvent.currentTarget : event.currentTarget;
const style = window.getComputedStyle(_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 (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);
if (config.pointerLock) {
currentTarget.requestPointerLock();
}
if (device === 'touch' || config.pointerCapture) {
if (!this.sharedConfig.r3f) {
if (process.env.NODE_ENV === 'development') {
if (event.uv) {
console.warn(`[@use-gesture]: You're probably using \`use-gesture\` on with \`@react-three/fiber\` without setting the drag config option \`r3f: true\`. The gesture will now probably fail.`);
}
}
if (document.pointerLockElement === target) device = 'mouse';
this.eventStore.add(target, device, 'change', this.pointerMove.bind(this));
}
} catch (_unused) {}
} else {
if (!this.sharedConfig.r3f) {
this.eventStore.add(this.sharedConfig.window, device, 'change', this.pointerMove.bind(this));
this.eventStore.add(this.sharedConfig.window, device, 'end', this.pointerUp.bind(this));
}
}
}
if (config.pointerLock) {
currentTarget.requestPointerLock();
}
pointerClean() {
const state = this.state;
if (!state._pointerActive) return;
if (config.pointerCapture) {
target.setPointerCapture(event.pointerId);
if (this.config.pointerLock && document.pointerLockElement === state.target) {
document.exitPointerLock();
}
}
if (device === 'touch' || config.pointerCapture) {
if (!this.sharedConfig.r3f) {
if (process.env.NODE_ENV === 'development') {
if (event.uv) {
console.warn(`[@use-gesture]: You're probably using \`use-gesture\` on with \`@react-three/fiber\` without setting the drag config option \`r3f: true\`. The gesture will now probably fail.`);
}
}
if (document.pointerLockElement === target) device = 'mouse';
this.eventStore.add(target, device, 'change', this.pointerMove.bind(this));
preventScroll(event) {
if (this.state._preventScroll && event.cancelable) {
event.preventDefault();
}
} else {
if (!this.sharedConfig.r3f) {
this.eventStore.add(this.sharedConfig.window, device, 'change', this.pointerMove.bind(this));
this.eventStore.add(this.sharedConfig.window, device, 'end', this.pointerUp.bind(this));
}
}
};
DragEngine.prototype.pointerClean = function () {
const state = this.state;
const target = state.target;
if (!state._pointerActive) return;
const event = state.event;
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), 250, event);
}
if (this.config.pointerLock && document.pointerLockElement === state.target) {
document.exitPointerLock();
setupDelayTrigger(event) {
this.state._delayed = true;
this.timeoutStore.add('dragDelay', this.startPointerDrag.bind(this), this.config.delay, event);
}
try {
if (this.config.pointerCapture && target.hasPointerCapture(event.pointerId)) {
target.releasePointerCapture(event.pointerId);
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();
}
} catch (_unused2) {
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.`);
}
}
};
DragEngine.prototype.preventScroll = function (event) {
if (this.state._preventScroll && event.cancelable) {
event.preventDefault();
keyUp(event) {
if (!(event.key in KEYS_DELTA_MAP)) return;
this.state._keyboardActive = false;
this.setActive();
this.compute(event);
this.emit();
}
};
DragEngine.prototype.setupScrollPrevention = function (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), 250, event);
};
bind(bindFunction) {
const device = this.config.device;
bindFunction(device, 'start', this.pointerDown.bind(this));
bindFunction(device, 'end', this.pointerUp.bind(this));
bindFunction('key', 'down', this.keyDown.bind(this));
bindFunction('key', 'up', this.keyUp.bind(this));
DragEngine.prototype.setupDelayTrigger = function (event) {
this.state._delayed = true;
this.timeoutStore.add('dragDelay', this.startPointerDrag.bind(this), this.config.delay, event);
};
if (this.sharedConfig.r3f) {
bindFunction(device, 'change', this.pointerMove.bind(this));
}
if (this.config.filterTaps) {
bindFunction('click', '', this.pointerClick.bind(this), {
capture: true
});
}
}
}
function persistEvent(event) {

@@ -1378,34 +1423,2 @@ 'persist' in event && typeof event.persist === 'function' && event.persist();

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]
};
DragEngine.prototype.keyDown = function (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();
}
};
DragEngine.prototype.keyUp = function (event) {
if (!(event.key in KEYS_DELTA_MAP)) return;
this.setActive({
keyboard: false
});
this.compute(event);
this.emit();
};
const pinchConfigResolver = _objectSpread2(_objectSpread2({}, commonConfigResolver), {}, {

@@ -1469,254 +1482,254 @@ useTouch(_v, _k, {

const SCALE_ANGLE_RATIO_INTENT_RAD = SCALE_ANGLE_RATIO_INTENT_DEG / 180 * Math.PI;
const PinchEngine = function PinchEngine(ctrl, args) {
this.ingKey = 'pinching';
Engine.call(this, ctrl, args, 'pinch');
};
PinchEngine.prototype = Object.create(Engine.prototype);
const PINCH_WHEEL_RATIO = 60;
class PinchEngine extends Engine {
constructor(...args) {
super(...args);
PinchEngine.prototype.init = function () {
this.state.offset = [1, 0];
this.state.lastOffset = [1, 0];
this.state._pointerEvents = new Map();
};
_defineProperty(this, "ingKey", 'pinching');
}
PinchEngine.prototype.reset = function () {
Engine.prototype.reset.call(this);
const state = this.state;
state._touchIds = [];
state.canceled = false;
state.cancel = this.cancel.bind(this);
state.turns = 0;
};
init() {
this.state.offset = [1, 0];
this.state.lastOffset = [1, 0];
this.state._pointerEvents = new Map();
}
PinchEngine.prototype.computeOffset = function () {
const {
movement,
lastOffset
} = this.state;
this.state.offset = [(1 + movement[0]) * lastOffset[0], movement[1] + lastOffset[1]];
};
reset() {
super.reset();
const state = this.state;
state._touchIds = [];
state.canceled = false;
state.cancel = this.cancel.bind(this);
state.turns = 0;
}
PinchEngine.prototype.computeMovement = function () {
const {
offset,
lastOffset
} = this.state;
this.state.movement = [offset[0] / lastOffset[0] - 1, offset[1] - lastOffset[1]];
this.state.da = this.state.values;
};
PinchEngine.prototype.intent = function (v) {
const state = this.state;
if (!state.axis) {
const angleScaleRatio = this.config.useRad ? SCALE_ANGLE_RATIO_INTENT_RAD : SCALE_ANGLE_RATIO_INTENT_DEG;
const axisMovementDifference = Math.abs(v[0]) * angleScaleRatio - Math.abs(v[1]);
if (axisMovementDifference < 0) state.axis = 'angle';else if (axisMovementDifference > 0) state.axis = 'scale';
computeOffset() {
const {
movement,
lastOffset
} = this.state;
this.state.offset = [(1 + movement[0]) * lastOffset[0], movement[1] + lastOffset[1]];
}
if (this.config.lockDirection) {
if (state.axis === 'scale') v[1] = 0;else if (state.axis === 'angle') v[0] = 0;
computeMovement() {
const {
offset,
lastOffset
} = this.state;
this.state.movement = [offset[0] / lastOffset[0] - 1, offset[1] - lastOffset[1]];
this.state.da = this.state.values;
}
};
PinchEngine.prototype.cancel = function () {
const state = this.state;
if (state.canceled) return;
setTimeout(() => {
state.canceled = true;
state._active = false;
this.compute();
this.emit();
}, 0);
};
intent(v) {
const state = this.state;
PinchEngine.prototype.bind = function (bindFunction) {
const device = this.config.device;
if (!state.axis) {
const angleScaleRatio = this.config.useRad ? SCALE_ANGLE_RATIO_INTENT_RAD : SCALE_ANGLE_RATIO_INTENT_DEG;
const axisMovementDifference = Math.abs(v[0]) * angleScaleRatio - Math.abs(v[1]);
if (axisMovementDifference < 0) state.axis = 'angle';else if (axisMovementDifference > 0) state.axis = 'scale';
}
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));
};
if (this.config.lockDirection) {
if (state.axis === 'scale') v[1] = 0;else if (state.axis === 'angle') v[0] = 0;
}
}
function convertAngle(engine, value) {
if (engine.config.useRad) return value / 180 * Math.PI;
return value;
}
PinchEngine.prototype.touchStart = function (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;
cancel() {
const state = this.state;
if (state.canceled) return;
setTimeout(() => {
state.canceled = true;
state._active = false;
this.compute();
this.emit();
}, 0);
}
if (ctrlTouchIds.size < 2) return;
this.start(event);
state._touchIds = Array.from(ctrlTouchIds).slice(0, 2);
const payload = Touches.distanceAngle(event, state._touchIds);
this.pinchStart(event, payload);
};
touchStart(event) {
this.ctrl.setEventIds(event);
const state = this.state;
const ctrlTouchIds = this.ctrl.touchIds;
PinchEngine.prototype.pointerStart = function (event) {
this.ctrl.setEventIds(event);
const state = this.state;
const _pointerEvents = state._pointerEvents;
const ctrlPointerIds = this.ctrl._pointerIds;
if (state._active) {
if (state._touchIds.every(id => ctrlTouchIds.has(id))) return;
}
if (state._active) {
if (Array.from(_pointerEvents.keys()).every(id => ctrlPointerIds.has(id))) return;
if (ctrlTouchIds.size < 2) return;
this.start(event);
state._touchIds = Array.from(ctrlTouchIds).slice(0, 2);
const payload = Touches.distanceAngle(event, state._touchIds);
this.pinchStart(event, payload);
}
if (_pointerEvents.size < 2) {
_pointerEvents.set(event.pointerId, event);
pointerStart(event) {
this.ctrl.setEventIds(event);
event.target.setPointerCapture(event.pointerId);
}
const state = this.state;
const _pointerEvents = state._pointerEvents;
const ctrlPointerIds = this.ctrl.pointerIds;
if (state._pointerEvents.size < 2) return;
this.start(event);
const payload = distanceAngle(...Array.from(_pointerEvents.values()));
this.pinchStart(event, payload);
};
if (state._active) {
if (Array.from(_pointerEvents.keys()).every(id => ctrlPointerIds.has(id))) return;
}
PinchEngine.prototype.pinchStart = function (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();
};
if (_pointerEvents.size < 2) {
_pointerEvents.set(event.pointerId, event);
}
PinchEngine.prototype.touchMove = function (event) {
if (!this.state._active) return;
const payload = Touches.distanceAngle(event, this.state._touchIds);
this.pinchMove(event, payload);
};
if (state._pointerEvents.size < 2) return;
this.start(event);
const payload = distanceAngle(...Array.from(_pointerEvents.values()));
this.pinchStart(event, payload);
}
PinchEngine.prototype.pointerMove = function (event) {
const _pointerEvents = this.state._pointerEvents;
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();
}
if (_pointerEvents.has(event.pointerId)) {
_pointerEvents.set(event.pointerId, event);
touchMove(event) {
if (!this.state._active) return;
const payload = Touches.distanceAngle(event, this.state._touchIds);
this.pinchMove(event, payload);
}
if (!this.state._active) return;
const payload = distanceAngle(...Array.from(_pointerEvents.values()));
this.pinchMove(event, payload);
};
pointerMove(event) {
const _pointerEvents = this.state._pointerEvents;
PinchEngine.prototype.pinchMove = function (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, convertAngle(this, state.values[1] - state.initial[1])];
this.compute(event);
this.emit();
};
if (_pointerEvents.has(event.pointerId)) {
_pointerEvents.set(event.pointerId, event);
}
PinchEngine.prototype.touchEnd = function (event) {
this.ctrl.setEventIds(event);
if (!this.state._active) return;
if (!this.state._active) return;
const payload = distanceAngle(...Array.from(_pointerEvents.values()));
this.pinchMove(event, payload);
}
if (this.state._touchIds.some(id => !this.ctrl._touchIds.has(id))) {
this.state._active = false;
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, convertAngle(this, state.values[1] - state.initial[1])];
this.compute(event);
this.emit();
}
};
PinchEngine.prototype.pointerEnd = function (event) {
const state = this.state;
this.ctrl.setEventIds(event);
touchEnd(event) {
this.ctrl.setEventIds(event);
if (!this.state._active) return;
if (state._pointerEvents.has(event.pointerId)) {
state._pointerEvents.delete(event.pointerId);
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();
}
}
if (!state._active) return;
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();
}
if (state._pointerEvents.size < 2) {
state._active = false;
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, convertAngle(this, event.rotation)];
state._delta = V.sub(state._movement, _previousMovement);
this.compute(event);
this.emit();
}
};
const PINCH_WHEEL_RATIO = 60;
gestureEnd(event) {
if (!this.state._active) return;
this.state._active = false;
this.compute(event);
this.emit();
}
PinchEngine.prototype.wheel = function (event) {
if (!event.ctrlKey) return;
if (!this.state._active) this.wheelStart(event);else this.wheelChange(event);
this.timeoutStore.add('wheelEnd', this.wheelEnd.bind(this));
};
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));
}
PinchEngine.prototype.wheelStart = function (event) {
if (event.cancelable) event.preventDefault();else if (process.env.NODE_ENV === 'development') {
console.warn(`[@use-gesture]: To properly support zoom on trackpads, try using the \`target\` option and \`config.eventOptions.passive\` set to \`false\`. This message will only appear in development mode.`, event.currentTarget);
wheelStart(event) {
if (event.cancelable) event.preventDefault();else if (process.env.NODE_ENV === 'development') {
console.warn(`[@use-gesture]: To properly support zoom on trackpads, try using the \`target\` option and \`config.eventOptions.passive\` set to \`false\`. This message will only appear in development mode.`, event.currentTarget);
}
this.start(event);
this.wheelChange(event);
}
this.start(event);
this.wheelChange(event);
};
PinchEngine.prototype.wheelChange = function (event) {
if (event.cancelable) event.preventDefault();
const state = this.state;
state._delta = [-Wheel.values(event)[1] / PINCH_WHEEL_RATIO, 0];
V.addTo(state._movement, state._delta);
this.state.origin = [event.clientX, event.clientY];
this.compute(event);
this.emit();
};
wheelChange(event) {
if (event.cancelable) event.preventDefault();
const state = this.state;
state._delta = [-Wheel.values(event)[1] / PINCH_WHEEL_RATIO, 0];
V.addTo(state._movement, state._delta);
this.state.origin = [event.clientX, event.clientY];
this.compute(event);
this.emit();
}
PinchEngine.prototype.wheelEnd = function () {
if (!this.state._active) return;
this.state._active = false;
this.compute();
this.emit();
};
wheelEnd() {
if (!this.state._active) return;
this.state._active = false;
this.compute();
this.emit();
}
PinchEngine.prototype.gestureStart = function (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();
};
bind(bindFunction) {
const device = this.config.device;
PinchEngine.prototype.gestureMove = function (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, convertAngle(this, event.rotation)];
state._delta = V.sub(state._movement, _previousMovement);
this.compute(event);
this.emit();
};
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));
}
PinchEngine.prototype.gestureEnd = function (event) {
if (!this.state._active) return;
this.state._active = false;
this.compute(event);
this.emit();
};
}
function convertAngle(engine, value) {
if (engine.config.useRad) return value / 180 * Math.PI;
return value;
}

@@ -1726,150 +1739,162 @@ const wheelConfigResolver = coordinatesConfigResolver;

ConfigResolverMap.set('wheel', wheelConfigResolver);
const WheelEngine = function WheelEngine(ctrl, args) {
this.ingKey = 'wheeling';
CoordinatesEngine.call(this, ctrl, args, 'wheel');
};
WheelEngine.prototype = Object.create(CoordinatesEngine.prototype);
class WheelEngine extends CoordinatesEngine {
constructor(...args) {
super(...args);
WheelEngine.prototype.wheel = function (event) {
if (!this.state._active) this.start(event);
this.wheelChange(event);
this.timeoutStore.add('wheelEnd', this.wheelEnd.bind(this));
};
_defineProperty(this, "ingKey", 'wheeling');
}
WheelEngine.prototype.wheelChange = function (event) {
if (event.cancelable) event.preventDefault();
const state = this.state;
state._delta = Wheel.values(event);
V.addTo(this.state._movement, state._delta);
this.compute(event);
this.emit();
};
wheel(event) {
if (!this.state._active) this.start(event);
this.wheelChange(event);
this.timeoutStore.add('wheelEnd', this.wheelEnd.bind(this));
}
WheelEngine.prototype.wheelEnd = function () {
if (!this.state._active) return;
this.state._active = false;
this.compute();
this.emit();
};
wheelChange(event) {
if (event.cancelable) event.preventDefault();
const state = this.state;
state._delta = Wheel.values(event);
V.addTo(this.state._movement, state._delta);
this.compute(event);
this.emit();
}
WheelEngine.prototype.bind = function (bindFunction) {
bindFunction('wheel', '', this.wheel.bind(this));
};
wheelEnd() {
if (!this.state._active) return;
this.state._active = false;
this.compute();
this.emit();
}
bind(bindFunction) {
bindFunction('wheel', '', this.wheel.bind(this));
}
}
const scrollConfigResolver = coordinatesConfigResolver;
ConfigResolverMap.set('scroll', scrollConfigResolver);
const ScrollEngine = function ScrollEngine(ctrl, args) {
this.ingKey = 'scrolling';
CoordinatesEngine.call(this, ctrl, args, 'scroll');
};
ScrollEngine.prototype = Object.create(CoordinatesEngine.prototype);
class ScrollEngine extends CoordinatesEngine {
constructor(...args) {
super(...args);
ScrollEngine.prototype.scroll = function (event) {
if (!this.state._active) this.start(event);
this.scrollChange(event);
this.timeoutStore.add('scrollEnd', this.scrollEnd.bind(this));
};
_defineProperty(this, "ingKey", 'scrolling');
}
ScrollEngine.prototype.scrollChange = function (event) {
if (event.cancelable) event.preventDefault();
const state = this.state;
const values = Scroll.values(event);
state._delta = V.sub(values, state.values);
V.addTo(state._movement, state._delta);
state.values = values;
this.compute(event);
this.emit();
};
scroll(event) {
if (!this.state._active) this.start(event);
this.scrollChange(event);
this.timeoutStore.add('scrollEnd', this.scrollEnd.bind(this));
}
ScrollEngine.prototype.scrollEnd = function () {
if (!this.state._active) return;
this.state._active = false;
this.compute();
this.emit();
};
scrollChange(event) {
if (event.cancelable) event.preventDefault();
const state = this.state;
const values = Scroll.values(event);
state._delta = V.sub(values, state.values);
V.addTo(state._movement, state._delta);
state.values = values;
this.compute(event);
this.emit();
}
ScrollEngine.prototype.bind = function (bindFunction) {
bindFunction('scroll', '', this.scroll.bind(this));
};
scrollEnd() {
if (!this.state._active) return;
this.state._active = false;
this.compute();
this.emit();
}
bind(bindFunction) {
bindFunction('scroll', '', this.scroll.bind(this));
}
}
const moveConfigResolver = coordinatesConfigResolver;
ConfigResolverMap.set('move', moveConfigResolver);
const MoveEngine = function MoveEngine(ctrl, args) {
this.ingKey = 'moving';
CoordinatesEngine.call(this, ctrl, args, 'move');
};
MoveEngine.prototype = Object.create(CoordinatesEngine.prototype);
class MoveEngine extends CoordinatesEngine {
constructor(...args) {
super(...args);
MoveEngine.prototype.move = function (event) {
if (!this.state._active) this.moveStart(event);else this.moveChange(event);
this.timeoutStore.add('moveEnd', this.moveEnd.bind(this));
};
_defineProperty(this, "ingKey", 'moving');
}
MoveEngine.prototype.moveStart = function (event) {
this.start(event);
const state = this.state;
state.values = Pointer.values(event);
this.compute(event);
state.initial = state.values;
this.emit();
};
move(event) {
if (!this.state._active) this.moveStart(event);else this.moveChange(event);
this.timeoutStore.add('moveEnd', this.moveEnd.bind(this));
}
MoveEngine.prototype.moveChange = function (event) {
if (!this.state._active) return;
const values = Pointer.values(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();
};
moveStart(event) {
this.start(event);
const state = this.state;
state.values = Pointer.values(event);
this.compute(event);
state.initial = state.values;
this.emit();
}
MoveEngine.prototype.moveEnd = function (event) {
if (!this.state._active) return;
this.state._active = false;
this.compute(event);
this.emit();
};
moveChange(event) {
if (!this.state._active) return;
const values = Pointer.values(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();
}
MoveEngine.prototype.bind = function (bindFunction) {
bindFunction('mouse', 'change', this.move.bind(this));
bindFunction('mouse', 'leave', this.moveEnd.bind(this));
};
moveEnd(event) {
if (!this.state._active) return;
this.state._active = false;
this.compute(event);
this.emit();
}
bind(bindFunction) {
bindFunction('mouse', 'change', this.move.bind(this));
bindFunction('mouse', 'leave', this.moveEnd.bind(this));
}
}
const hoverConfigResolver = coordinatesConfigResolver;
ConfigResolverMap.set('hover', hoverConfigResolver);
const HoverEngine = function HoverEngine(ctrl, args) {
this.ingKey = 'hovering';
CoordinatesEngine.call(this, ctrl, args, 'hover');
};
HoverEngine.prototype = Object.create(CoordinatesEngine.prototype);
class HoverEngine extends CoordinatesEngine {
constructor(...args) {
super(...args);
HoverEngine.prototype.enter = function (event) {
this.start(event);
this.state.values = Pointer.values(event);
this.compute(event);
this.emit();
};
_defineProperty(this, "ingKey", 'hovering');
}
HoverEngine.prototype.leave = function (event) {
const state = this.state;
if (!state._active) return;
state._active = false;
const values = Pointer.values(event);
state._movement = state._delta = V.sub(values, state.values);
state.values = values;
this.compute(event);
state.delta = state.movement;
this.emit();
};
enter(event) {
this.start(event);
this.state.values = Pointer.values(event);
this.compute(event);
this.emit();
}
HoverEngine.prototype.bind = function (bindFunction) {
bindFunction('mouse', 'enter', this.enter.bind(this));
bindFunction('mouse', 'leave', this.leave.bind(this));
};
leave(event) {
const state = this.state;
if (!state._active) return;
state._active = false;
const values = Pointer.values(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('mouse', 'enter', this.enter.bind(this));
bindFunction('mouse', 'leave', this.leave.bind(this));
}
}
exports.Controller = Controller;

@@ -1876,0 +1901,0 @@ exports.DragEngine = DragEngine;

@@ -427,43 +427,50 @@ 'use strict';

const EventStore = function EventStore(ctrl) {
this._ctrl = ctrl;
this._listeners = [];
};
class EventStore {
constructor(ctrl) {
_defineProperty(this, "_listeners", []);
EventStore.prototype.add = function (element, device, action, handler, options) {
const type = toDomEventType(device, action);
const eventOptions = options || this._ctrl._config.shared.eventOptions;
element.addEventListener(type, handler, eventOptions);
this._ctrl = ctrl;
}
this._listeners.push(() => element.removeEventListener(type, handler, eventOptions));
};
add(element, device, action, handler, options) {
const type = toDomEventType(device, action);
const eventOptions = options || this._ctrl.config.shared.eventOptions;
element.addEventListener(type, handler, eventOptions);
EventStore.prototype.clean = function () {
this._listeners.forEach(remove => remove());
this._listeners.push(() => element.removeEventListener(type, handler, eventOptions));
}
this._listeners = [];
};
clean() {
this._listeners.forEach(remove => remove());
const TimeoutStore = function TimeoutStore() {
this._timeouts = new Map();
};
this._listeners = [];
}
TimeoutStore.prototype.add = function (key, callback, ms = 140, ...args) {
this.remove(key);
}
this._timeouts.set(key, window.setTimeout(callback, ms, ...args));
};
class TimeoutStore {
constructor() {
_defineProperty(this, "_timeouts", new Map());
}
TimeoutStore.prototype.remove = function (key) {
const timeout = this._timeouts.get(key);
add(key, callback, ms = 140, ...args) {
this.remove(key);
if (timeout) window.clearTimeout(timeout);
};
this._timeouts.set(key, window.setTimeout(callback, ms, ...args));
}
TimeoutStore.prototype.clean = function () {
this._timeouts.forEach(timeout => void window.clearTimeout(timeout));
remove(key) {
const timeout = this._timeouts.get(key);
this._timeouts.clear();
};
if (timeout) window.clearTimeout(timeout);
}
clean() {
this._timeouts.forEach(timeout => void window.clearTimeout(timeout));
this._timeouts.clear();
}
}
function call(v, ...args) {

@@ -494,91 +501,100 @@ if (typeof v === 'function') {

const Controller = function Controller(handlers) {
this._gestures = new Set();
this._targetEventStore = new EventStore(this);
this._gestureEventStores = {};
this._gestureTimeoutStores = {};
this._handlers = {};
this._nativeHandlers = {};
this._config = {};
this._pointerIds = new Set();
this._touchIds = new Set();
this.state = {
shared: {
shiftKey: false,
metaKey: false,
ctrlKey: false,
altKey: false
}
};
resolveGestures(this, handlers);
};
class Controller {
constructor(handlers) {
_defineProperty(this, "gestures", new Set());
Controller.prototype.setEventIds = function (event) {
if (isTouch(event)) {
this._touchIds = new Set(Touches.ids(event));
} else if ('pointerId' in event) {
if (event.type === 'pointerup') this._pointerIds.delete(event.pointerId);else this._pointerIds.add(event.pointerId);
_defineProperty(this, "_targetEventStore", new EventStore(this));
_defineProperty(this, "gestureEventStores", {});
_defineProperty(this, "gestureTimeoutStores", {});
_defineProperty(this, "handlers", {});
_defineProperty(this, "config", {});
_defineProperty(this, "pointerIds", new Set());
_defineProperty(this, "touchIds", new Set());
_defineProperty(this, "state", {
shared: {
shiftKey: false,
metaKey: false,
ctrlKey: false,
altKey: false
}
});
resolveGestures(this, handlers);
}
};
Controller.prototype.applyHandlers = function (handlers, nativeHandlers) {
this._handlers = handlers;
this._nativeHandlers = nativeHandlers;
};
setEventIds(event) {
if (isTouch(event)) {
this.touchIds = new Set(Touches.ids(event));
} else if ('pointerId' in event) {
if (event.type === 'pointerup') this.pointerIds.delete(event.pointerId);else this.pointerIds.add(event.pointerId);
}
}
Controller.prototype.applyConfig = function (config, gestureKey) {
this._config = parse(config, gestureKey);
};
applyHandlers(handlers, nativeHandlers) {
this.handlers = handlers;
this.nativeHandlers = nativeHandlers;
}
Controller.prototype.clean = function () {
this._targetEventStore.clean();
applyConfig(config, gestureKey) {
this.config = parse(config, gestureKey);
}
for (const key of this._gestures) {
this._gestureEventStores[key].clean();
clean() {
this._targetEventStore.clean();
this._gestureTimeoutStores[key].clean();
for (const key of this.gestures) {
this.gestureEventStores[key].clean();
this.gestureTimeoutStores[key].clean();
}
}
};
Controller.prototype.effect = function () {
if (this._config.shared.target) this.bind();
return () => this._targetEventStore.clean();
};
effect() {
if (this.config.shared.target) this.bind();
return () => this._targetEventStore.clean();
}
Controller.prototype.bind = function (...args) {
const sharedConfig = this._config.shared;
const eventOptions = sharedConfig.eventOptions;
const props = {};
const bindFunction = sharedConfig.target ? bindToEventStore(this._targetEventStore, sharedConfig.target()) : bindToProps(props, eventOptions);
bind(...args) {
const sharedConfig = this.config.shared;
const eventOptions = sharedConfig.eventOptions;
const props = {};
const bindFunction = sharedConfig.target ? bindToEventStore(this._targetEventStore, sharedConfig.target()) : bindToProps(props, eventOptions);
if (sharedConfig.enabled) {
for (const eventKey in this._nativeHandlers) {
bindFunction(eventKey, '', event => this._nativeHandlers[eventKey](_objectSpread2(_objectSpread2({}, this.state.shared), {}, {
event,
args
})), undefined, true);
if (sharedConfig.enabled) {
for (const eventKey in this.nativeHandlers) {
bindFunction(eventKey, '', event => this.nativeHandlers[eventKey](_objectSpread2(_objectSpread2({}, this.state.shared), {}, {
event,
args
})), undefined, true);
}
for (const gestureKey of this.gestures) {
if (this.config[gestureKey].enabled) {
const Engine = EngineMap.get(gestureKey);
new Engine(this, args, gestureKey).bind(bindFunction);
}
}
}
for (const gestureKey of this._gestures) {
if (this._config[gestureKey].enabled) {
const Engine = EngineMap.get(gestureKey);
new Engine(this, args).bind(bindFunction);
if (!sharedConfig.target) {
for (const handlerProp in props) {
props[handlerProp] = chain(...props[handlerProp]);
}
return props;
}
}
if (!sharedConfig.target) {
for (const handlerProp in props) {
props[handlerProp] = chain(...props[handlerProp]);
}
}
return props;
}
};
function setupGesture(ctrl, gestureKey) {
ctrl._gestures.add(gestureKey);
ctrl._gestureEventStores[gestureKey] = new EventStore(ctrl);
ctrl._gestureTimeoutStores[gestureKey] = new TimeoutStore();
ctrl.gestures.add(gestureKey);
ctrl.gestureEventStores[gestureKey] = new EventStore(ctrl);
ctrl.gestureTimeoutStores[gestureKey] = new TimeoutStore();
}

@@ -654,240 +670,239 @@

const Engine = function Engine(ctrl, args, key) {
this.ctrl = ctrl;
this.key = key;
this.args = args;
class Engine {
constructor(ctrl, args, key) {
this.ctrl = ctrl;
this.args = args;
this.key = key;
if (!this.state) {
this.state = {
values: [0, 0],
initial: [0, 0]
};
if (this.init) this.init();
this.reset();
if (!this.state) {
this.state = {
values: [0, 0],
initial: [0, 0]
};
if (this.init) this.init();
this.reset();
}
}
};
Engine.prototype = {
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];
},
return this.ctrl.gestureEventStores[this.key];
}
get timeoutStore() {
return this.ctrl._gestureTimeoutStores[this.key];
},
return this.ctrl.gestureTimeoutStores[this.key];
}
get config() {
return this.ctrl._config[this.key];
},
return this.ctrl.config[this.key];
}
get sharedConfig() {
return this.ctrl._config.shared;
},
return this.ctrl.config.shared;
}
get handler() {
return this.ctrl._handlers[this.key];
return this.ctrl.handlers[this.key];
}
};
reset() {
const {
state,
shared,
config,
ingKey
} = 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.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;
}
Engine.prototype.reset = function () {
const {
state,
shared,
config,
ingKey
} = 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.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;
Engine.prototype.start = function (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;
}
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;
}
state.startTime = state.timeStamp = event.timeStamp;
};
compute(event) {
const {
state,
config,
shared
} = this;
state.args = this.args;
let dt = 0;
Engine.prototype.compute = function (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 > 0 || shared.touches > 0;
dt = event.timeStamp - state.timeStamp;
state.timeStamp = event.timeStamp;
state.elapsedTime = state.timeStamp - state.startTime;
}
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 > 0 || 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);
if (state._active) {
const _absoluteDelta = state._delta.map(Math.abs);
V.addTo(state._distance, _absoluteDelta);
}
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);
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 (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();
}
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();
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.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];
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();
}
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;
}
Engine.prototype.emit = function () {
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();
}
Engine.prototype.clean = function () {
this.eventStore.clean();
this.timeoutStore.clean();
};
}
const CoordinatesEngine = function CoordinatesEngine(ctrl, args, key) {
Engine.call(this, ctrl, args, key);
};
CoordinatesEngine.prototype = Object.create(Engine.prototype);
class CoordinatesEngine extends Engine {
reset() {
super.reset();
this.state.axis = undefined;
}
CoordinatesEngine.prototype.reset = function () {
Engine.prototype.reset.call(this);
this.state.axis = undefined;
};
init() {
this.state.offset = [0, 0];
this.state.lastOffset = [0, 0];
}
CoordinatesEngine.prototype.init = function () {
this.state.offset = [0, 0];
this.state.lastOffset = [0, 0];
};
computeOffset() {
const state = this.state;
state.offset = V.add(state.lastOffset, state.movement);
}
CoordinatesEngine.prototype.computeOffset = function () {
const state = this.state;
state.offset = V.add(state.lastOffset, state.movement);
};
computeMovement() {
const {
offset,
lastOffset
} = this.state;
this.state.movement = V.sub(offset, lastOffset);
this.state.xy = this.state.values;
}
CoordinatesEngine.prototype.computeMovement = function () {
const {
offset,
lastOffset
} = this.state;
this.state.movement = V.sub(offset, lastOffset);
this.state.xy = this.state.values;
};
intent(v) {
const state = this.state;
CoordinatesEngine.prototype.intent = function (v) {
const state = this.state;
if (!state.axis) {
const axisMovementDifference = Math.abs(v[0]) - Math.abs(v[1]);
if (axisMovementDifference < 0) state.axis = 'y';else if (axisMovementDifference > 0) state.axis = 'x';
}
if (!state.axis) {
const axisMovementDifference = Math.abs(v[0]) - Math.abs(v[1]);
if (axisMovementDifference < 0) state.axis = 'y';else if (axisMovementDifference > 0) state.axis = 'x';
}
const axis = state.axis;
const axis = state.axis;
if (this.config.lockDirection) {
if (axis) {
state._blocked = false;
if (axis === 'x') v[1] = 0;else if (axis === 'y') v[0] = 0;
} else {
state._blocked = false;
if (this.config.lockDirection) {
if (axis) {
state._blocked = false;
if (axis === 'x') v[1] = 0;else if (axis === 'y') v[0] = 0;
} else {
state._blocked = false;
}
} else if (this.config.axis) {
if (!!axis && axis === this.config.axis) {
state._blocked = false;
if (axis === 'x') v[1] = 0;else if (axis === 'y') v[0] = 0;
} else {
state._blocked = true;
}
}
} else if (this.config.axis) {
if (!!axis && axis === this.config.axis) {
state._blocked = false;
if (axis === 'x') v[1] = 0;else if (axis === 'y') v[0] = 0;
} else {
state._blocked = true;
}
}
};
}
const DEFAULT_RUBBERBAND = 0.15;

@@ -1032,263 +1047,293 @@ const commonConfigResolver = {

ConfigResolverMap.set('drag', dragConfigResolver);
const DragEngine = function DragEngine(ctrl, args) {
this.ingKey = 'dragging';
CoordinatesEngine.call(this, ctrl, args, 'drag');
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]
};
DragEngine.prototype = Object.create(CoordinatesEngine.prototype);
class DragEngine extends CoordinatesEngine {
constructor(...args) {
super(...args);
DragEngine.prototype.reset = function () {
CoordinatesEngine.prototype.reset.call(this);
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);
};
_defineProperty(this, "ingKey", 'dragging');
}
DragEngine.prototype.setup = function () {
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);
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);
}
};
DragEngine.prototype.cancel = function () {
const state = this.state;
if (state.canceled) return;
setTimeout(() => {
state.canceled = true;
state._active = false;
this.compute();
this.emit();
}, 0);
};
setup() {
const state = this.state;
DragEngine.prototype.setActive = function ({
pointer,
keyboard
} = {}) {
this.state._active = (pointer !== null && pointer !== void 0 ? pointer : this.state._pointerActive) || (keyboard !== null && keyboard !== void 0 ? keyboard : this.state._keyboardActive);
};
if (state._bounds instanceof HTMLElement) {
const boundRect = state._bounds.getBoundingClientRect();
DragEngine.prototype.clean = function () {
this.pointerClean();
this.state._pointerActive = false;
this.state._keyboardActive = false;
CoordinatesEngine.prototype.clean.call(this);
};
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);
}
}
DragEngine.prototype.bind = function (bindFunction) {
const device = this.config.device;
bindFunction(device, 'start', this.pointerDown.bind(this));
bindFunction(device, 'end', this.pointerUp.bind(this));
bindFunction('key', 'down', this.keyDown.bind(this));
bindFunction('key', 'up', this.keyUp.bind(this));
cancel() {
const state = this.state;
if (state.canceled) return;
setTimeout(() => {
state.canceled = true;
state._active = false;
this.compute();
this.emit();
}, 0);
}
if (this.sharedConfig.r3f) {
bindFunction(device, 'change', this.pointerMove.bind(this));
setActive() {
this.state._active = this.state._pointerActive || this.state._keyboardActive;
}
if (this.config.filterTaps) {
bindFunction('click', '', this.pointerClick.bind(this), {
capture: true
});
clean() {
this.pointerClean();
this.state._pointerActive = false;
this.state._keyboardActive = false;
super.clean();
}
};
DragEngine.prototype.pointerDown = function (event) {
this.ctrl.setEventIds(event);
const state = this.state;
const config = this.config;
if (state._pointerActive) return;
this.start(event);
this.setupPointer(event);
state._pointerId = Pointer.id(event);
state._pointerActive = true;
state.values = Pointer.values(event);
state.initial = state.values;
pointerDown(event) {
this.ctrl.setEventIds(event);
if (config.preventScroll) {
this.setupScrollPrevention(event);
} else if (config.delay > 0) {
this.setupDelayTrigger(event);
} else {
this.startPointerDrag(event);
}
};
if (this.config.pointerCapture) {
event.target.setPointerCapture(event.pointerId);
}
DragEngine.prototype.startPointerDrag = function (event) {
const state = this.state;
state._active = true;
state._preventScroll = true;
state._delayed = false;
this.compute(event);
this.emit();
};
const state = this.state;
const config = this.config;
if (state._pointerActive) return;
this.start(event);
this.setupPointer(event);
state._pointerId = Pointer.id(event);
state._pointerActive = true;
state.values = Pointer.values(event);
state.initial = state.values;
DragEngine.prototype.pointerMove = function (event) {
const state = this.state;
const config = this.config;
if (!state._pointerActive) return;
const id = Pointer.id(event);
if (state._pointerId && id !== state._pointerId) return;
const values = Pointer.values(event);
if (config.preventScroll) {
this.setupScrollPrevention(event);
} else if (config.delay > 0) {
this.setupDelayTrigger(event);
} else {
this.startPointerDrag(event);
}
}
if (document.pointerLockElement === event.target) {
state._delta = [event.movementX, event.movementY];
} else {
state._delta = V.sub(values, state.values);
state.values = values;
startPointerDrag(event) {
const state = this.state;
state._active = true;
state._preventScroll = true;
state._delayed = false;
this.compute(event);
this.emit();
}
V.addTo(state._movement, state._delta);
this.compute(event);
pointerMove(event) {
const state = this.state;
const config = this.config;
if (!state._pointerActive) return;
const id = Pointer.id(event);
if (state._pointerId && id !== state._pointerId) return;
const values = Pointer.values(event);
if (state._delayed) {
this.timeoutStore.remove('dragDelay');
this.startPointerDrag(event);
return;
}
if (document.pointerLockElement === event.target) {
state._delta = [event.movementX, event.movementY];
} else {
state._delta = V.sub(values, state.values);
state.values = values;
}
if (config.preventScroll && !state._preventScroll) {
if (state.axis) {
if (state.axis === 'x') {
this.timeoutStore.remove('startPointerDrag');
this.startPointerDrag(event);
return;
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 === 'x') {
this.timeoutStore.remove('startPointerDrag');
this.startPointerDrag(event);
return;
} else {
state._active = false;
this.clean();
return;
}
} else {
state._active = false;
this.clean();
return;
}
} else {
return;
}
this.emit();
}
this.emit();
};
pointerUp(event) {
this.ctrl.setEventIds(event);
DragEngine.prototype.pointerUp = function (event) {
this.ctrl.setEventIds(event);
const state = this.state;
const config = this.config;
if (!state._pointerActive) return;
const id = Pointer.id(event);
if (state._pointerId && id !== state._pointerId) return;
this.setActive({
pointer: false
});
this.compute(event);
const [dx, dy] = state._distance;
state.tap = dx <= 3 && dy <= 3;
try {
if (this.config.pointerCapture && event.target.hasPointerCapture(event.pointerId)) {
;
event.target.releasePointerCapture(event.pointerId);
}
} catch (_unused) {
}
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;
const state = this.state;
const config = this.config;
if (!state._pointerActive) return;
const id = Pointer.id(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.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;
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();
}
this.emit();
};
pointerClick(event) {
if (!this.state.tap) event.stopPropagation();
}
DragEngine.prototype.pointerClick = function (event) {
if (!this.state.tap) event.stopPropagation();
};
setupPointer(event) {
const config = this.config;
let device = config.device;
const target = event.target;
const currentTarget = event.currentTarget;
DragEngine.prototype.setupPointer = function (event) {
const config = this.config;
let device = config.device;
const target = event.target;
const currentTarget = event.currentTarget;
if (config.pointerLock) {
currentTarget.requestPointerLock();
}
if (config.pointerLock) {
currentTarget.requestPointerLock();
}
if (device === 'touch' || config.pointerCapture) {
if (!this.sharedConfig.r3f) {
if (config.pointerCapture) {
target.setPointerCapture(event.pointerId);
if (document.pointerLockElement === target) device = 'mouse';
this.eventStore.add(target, device, 'change', this.pointerMove.bind(this));
}
} else {
if (!this.sharedConfig.r3f) {
this.eventStore.add(this.sharedConfig.window, device, 'change', this.pointerMove.bind(this));
this.eventStore.add(this.sharedConfig.window, device, 'end', this.pointerUp.bind(this));
}
}
}
if (device === 'touch' || config.pointerCapture) {
if (!this.sharedConfig.r3f) {
pointerClean() {
const state = this.state;
if (!state._pointerActive) return;
if (document.pointerLockElement === target) device = 'mouse';
this.eventStore.add(target, device, 'change', this.pointerMove.bind(this));
if (this.config.pointerLock && document.pointerLockElement === state.target) {
document.exitPointerLock();
}
} else {
if (!this.sharedConfig.r3f) {
this.eventStore.add(this.sharedConfig.window, device, 'change', this.pointerMove.bind(this));
this.eventStore.add(this.sharedConfig.window, device, 'end', this.pointerUp.bind(this));
}
preventScroll(event) {
if (this.state._preventScroll && event.cancelable) {
event.preventDefault();
}
}
};
DragEngine.prototype.pointerClean = function () {
const state = this.state;
const target = state.target;
if (!state._pointerActive) return;
const event = state.event;
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), 250, event);
}
if (this.config.pointerLock && document.pointerLockElement === state.target) {
document.exitPointerLock();
setupDelayTrigger(event) {
this.state._delayed = true;
this.timeoutStore.add('dragDelay', this.startPointerDrag.bind(this), this.config.delay, event);
}
try {
if (this.config.pointerCapture && target.hasPointerCapture(event.pointerId)) {
target.releasePointerCapture(event.pointerId);
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();
}
} catch (_unused2) {
}
};
DragEngine.prototype.preventScroll = function (event) {
if (this.state._preventScroll && event.cancelable) {
event.preventDefault();
keyUp(event) {
if (!(event.key in KEYS_DELTA_MAP)) return;
this.state._keyboardActive = false;
this.setActive();
this.compute(event);
this.emit();
}
};
DragEngine.prototype.setupScrollPrevention = function (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), 250, event);
};
bind(bindFunction) {
const device = this.config.device;
bindFunction(device, 'start', this.pointerDown.bind(this));
bindFunction(device, 'end', this.pointerUp.bind(this));
bindFunction('key', 'down', this.keyDown.bind(this));
bindFunction('key', 'up', this.keyUp.bind(this));
DragEngine.prototype.setupDelayTrigger = function (event) {
this.state._delayed = true;
this.timeoutStore.add('dragDelay', this.startPointerDrag.bind(this), this.config.delay, event);
};
if (this.sharedConfig.r3f) {
bindFunction(device, 'change', this.pointerMove.bind(this));
}
if (this.config.filterTaps) {
bindFunction('click', '', this.pointerClick.bind(this), {
capture: true
});
}
}
}
function persistEvent(event) {

@@ -1298,34 +1343,2 @@ 'persist' in event && typeof event.persist === 'function' && event.persist();

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]
};
DragEngine.prototype.keyDown = function (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();
}
};
DragEngine.prototype.keyUp = function (event) {
if (!(event.key in KEYS_DELTA_MAP)) return;
this.setActive({
keyboard: false
});
this.compute(event);
this.emit();
};
const pinchConfigResolver = _objectSpread2(_objectSpread2({}, commonConfigResolver), {}, {

@@ -1389,252 +1402,252 @@ useTouch(_v, _k, {

const SCALE_ANGLE_RATIO_INTENT_RAD = SCALE_ANGLE_RATIO_INTENT_DEG / 180 * Math.PI;
const PinchEngine = function PinchEngine(ctrl, args) {
this.ingKey = 'pinching';
Engine.call(this, ctrl, args, 'pinch');
};
PinchEngine.prototype = Object.create(Engine.prototype);
const PINCH_WHEEL_RATIO = 60;
class PinchEngine extends Engine {
constructor(...args) {
super(...args);
PinchEngine.prototype.init = function () {
this.state.offset = [1, 0];
this.state.lastOffset = [1, 0];
this.state._pointerEvents = new Map();
};
_defineProperty(this, "ingKey", 'pinching');
}
PinchEngine.prototype.reset = function () {
Engine.prototype.reset.call(this);
const state = this.state;
state._touchIds = [];
state.canceled = false;
state.cancel = this.cancel.bind(this);
state.turns = 0;
};
init() {
this.state.offset = [1, 0];
this.state.lastOffset = [1, 0];
this.state._pointerEvents = new Map();
}
PinchEngine.prototype.computeOffset = function () {
const {
movement,
lastOffset
} = this.state;
this.state.offset = [(1 + movement[0]) * lastOffset[0], movement[1] + lastOffset[1]];
};
reset() {
super.reset();
const state = this.state;
state._touchIds = [];
state.canceled = false;
state.cancel = this.cancel.bind(this);
state.turns = 0;
}
PinchEngine.prototype.computeMovement = function () {
const {
offset,
lastOffset
} = this.state;
this.state.movement = [offset[0] / lastOffset[0] - 1, offset[1] - lastOffset[1]];
this.state.da = this.state.values;
};
PinchEngine.prototype.intent = function (v) {
const state = this.state;
if (!state.axis) {
const angleScaleRatio = this.config.useRad ? SCALE_ANGLE_RATIO_INTENT_RAD : SCALE_ANGLE_RATIO_INTENT_DEG;
const axisMovementDifference = Math.abs(v[0]) * angleScaleRatio - Math.abs(v[1]);
if (axisMovementDifference < 0) state.axis = 'angle';else if (axisMovementDifference > 0) state.axis = 'scale';
computeOffset() {
const {
movement,
lastOffset
} = this.state;
this.state.offset = [(1 + movement[0]) * lastOffset[0], movement[1] + lastOffset[1]];
}
if (this.config.lockDirection) {
if (state.axis === 'scale') v[1] = 0;else if (state.axis === 'angle') v[0] = 0;
computeMovement() {
const {
offset,
lastOffset
} = this.state;
this.state.movement = [offset[0] / lastOffset[0] - 1, offset[1] - lastOffset[1]];
this.state.da = this.state.values;
}
};
PinchEngine.prototype.cancel = function () {
const state = this.state;
if (state.canceled) return;
setTimeout(() => {
state.canceled = true;
state._active = false;
this.compute();
this.emit();
}, 0);
};
intent(v) {
const state = this.state;
PinchEngine.prototype.bind = function (bindFunction) {
const device = this.config.device;
if (!state.axis) {
const angleScaleRatio = this.config.useRad ? SCALE_ANGLE_RATIO_INTENT_RAD : SCALE_ANGLE_RATIO_INTENT_DEG;
const axisMovementDifference = Math.abs(v[0]) * angleScaleRatio - Math.abs(v[1]);
if (axisMovementDifference < 0) state.axis = 'angle';else if (axisMovementDifference > 0) state.axis = 'scale';
}
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));
};
if (this.config.lockDirection) {
if (state.axis === 'scale') v[1] = 0;else if (state.axis === 'angle') v[0] = 0;
}
}
function convertAngle(engine, value) {
if (engine.config.useRad) return value / 180 * Math.PI;
return value;
}
PinchEngine.prototype.touchStart = function (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;
cancel() {
const state = this.state;
if (state.canceled) return;
setTimeout(() => {
state.canceled = true;
state._active = false;
this.compute();
this.emit();
}, 0);
}
if (ctrlTouchIds.size < 2) return;
this.start(event);
state._touchIds = Array.from(ctrlTouchIds).slice(0, 2);
const payload = Touches.distanceAngle(event, state._touchIds);
this.pinchStart(event, payload);
};
touchStart(event) {
this.ctrl.setEventIds(event);
const state = this.state;
const ctrlTouchIds = this.ctrl.touchIds;
PinchEngine.prototype.pointerStart = function (event) {
this.ctrl.setEventIds(event);
const state = this.state;
const _pointerEvents = state._pointerEvents;
const ctrlPointerIds = this.ctrl._pointerIds;
if (state._active) {
if (state._touchIds.every(id => ctrlTouchIds.has(id))) return;
}
if (state._active) {
if (Array.from(_pointerEvents.keys()).every(id => ctrlPointerIds.has(id))) return;
if (ctrlTouchIds.size < 2) return;
this.start(event);
state._touchIds = Array.from(ctrlTouchIds).slice(0, 2);
const payload = Touches.distanceAngle(event, state._touchIds);
this.pinchStart(event, payload);
}
if (_pointerEvents.size < 2) {
_pointerEvents.set(event.pointerId, event);
pointerStart(event) {
this.ctrl.setEventIds(event);
event.target.setPointerCapture(event.pointerId);
}
const state = this.state;
const _pointerEvents = state._pointerEvents;
const ctrlPointerIds = this.ctrl.pointerIds;
if (state._pointerEvents.size < 2) return;
this.start(event);
const payload = distanceAngle(...Array.from(_pointerEvents.values()));
this.pinchStart(event, payload);
};
if (state._active) {
if (Array.from(_pointerEvents.keys()).every(id => ctrlPointerIds.has(id))) return;
}
PinchEngine.prototype.pinchStart = function (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();
};
if (_pointerEvents.size < 2) {
_pointerEvents.set(event.pointerId, event);
}
PinchEngine.prototype.touchMove = function (event) {
if (!this.state._active) return;
const payload = Touches.distanceAngle(event, this.state._touchIds);
this.pinchMove(event, payload);
};
if (state._pointerEvents.size < 2) return;
this.start(event);
const payload = distanceAngle(...Array.from(_pointerEvents.values()));
this.pinchStart(event, payload);
}
PinchEngine.prototype.pointerMove = function (event) {
const _pointerEvents = this.state._pointerEvents;
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();
}
if (_pointerEvents.has(event.pointerId)) {
_pointerEvents.set(event.pointerId, event);
touchMove(event) {
if (!this.state._active) return;
const payload = Touches.distanceAngle(event, this.state._touchIds);
this.pinchMove(event, payload);
}
if (!this.state._active) return;
const payload = distanceAngle(...Array.from(_pointerEvents.values()));
this.pinchMove(event, payload);
};
pointerMove(event) {
const _pointerEvents = this.state._pointerEvents;
PinchEngine.prototype.pinchMove = function (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, convertAngle(this, state.values[1] - state.initial[1])];
this.compute(event);
this.emit();
};
if (_pointerEvents.has(event.pointerId)) {
_pointerEvents.set(event.pointerId, event);
}
PinchEngine.prototype.touchEnd = function (event) {
this.ctrl.setEventIds(event);
if (!this.state._active) return;
if (!this.state._active) return;
const payload = distanceAngle(...Array.from(_pointerEvents.values()));
this.pinchMove(event, payload);
}
if (this.state._touchIds.some(id => !this.ctrl._touchIds.has(id))) {
this.state._active = false;
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, convertAngle(this, state.values[1] - state.initial[1])];
this.compute(event);
this.emit();
}
};
PinchEngine.prototype.pointerEnd = function (event) {
const state = this.state;
this.ctrl.setEventIds(event);
touchEnd(event) {
this.ctrl.setEventIds(event);
if (!this.state._active) return;
if (state._pointerEvents.has(event.pointerId)) {
state._pointerEvents.delete(event.pointerId);
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();
}
}
if (!state._active) return;
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();
}
if (state._pointerEvents.size < 2) {
state._active = false;
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, convertAngle(this, event.rotation)];
state._delta = V.sub(state._movement, _previousMovement);
this.compute(event);
this.emit();
}
};
const PINCH_WHEEL_RATIO = 60;
gestureEnd(event) {
if (!this.state._active) return;
this.state._active = false;
this.compute(event);
this.emit();
}
PinchEngine.prototype.wheel = function (event) {
if (!event.ctrlKey) return;
if (!this.state._active) this.wheelStart(event);else this.wheelChange(event);
this.timeoutStore.add('wheelEnd', this.wheelEnd.bind(this));
};
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));
}
PinchEngine.prototype.wheelStart = function (event) {
if (event.cancelable) event.preventDefault();
this.start(event);
this.wheelChange(event);
};
wheelStart(event) {
if (event.cancelable) event.preventDefault();
this.start(event);
this.wheelChange(event);
}
PinchEngine.prototype.wheelChange = function (event) {
if (event.cancelable) event.preventDefault();
const state = this.state;
state._delta = [-Wheel.values(event)[1] / PINCH_WHEEL_RATIO, 0];
V.addTo(state._movement, state._delta);
this.state.origin = [event.clientX, event.clientY];
this.compute(event);
this.emit();
};
wheelChange(event) {
if (event.cancelable) event.preventDefault();
const state = this.state;
state._delta = [-Wheel.values(event)[1] / PINCH_WHEEL_RATIO, 0];
V.addTo(state._movement, state._delta);
this.state.origin = [event.clientX, event.clientY];
this.compute(event);
this.emit();
}
PinchEngine.prototype.wheelEnd = function () {
if (!this.state._active) return;
this.state._active = false;
this.compute();
this.emit();
};
wheelEnd() {
if (!this.state._active) return;
this.state._active = false;
this.compute();
this.emit();
}
PinchEngine.prototype.gestureStart = function (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();
};
bind(bindFunction) {
const device = this.config.device;
PinchEngine.prototype.gestureMove = function (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, convertAngle(this, event.rotation)];
state._delta = V.sub(state._movement, _previousMovement);
this.compute(event);
this.emit();
};
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));
}
PinchEngine.prototype.gestureEnd = function (event) {
if (!this.state._active) return;
this.state._active = false;
this.compute(event);
this.emit();
};
}
function convertAngle(engine, value) {
if (engine.config.useRad) return value / 180 * Math.PI;
return value;
}

@@ -1644,150 +1657,162 @@ const wheelConfigResolver = coordinatesConfigResolver;

ConfigResolverMap.set('wheel', wheelConfigResolver);
const WheelEngine = function WheelEngine(ctrl, args) {
this.ingKey = 'wheeling';
CoordinatesEngine.call(this, ctrl, args, 'wheel');
};
WheelEngine.prototype = Object.create(CoordinatesEngine.prototype);
class WheelEngine extends CoordinatesEngine {
constructor(...args) {
super(...args);
WheelEngine.prototype.wheel = function (event) {
if (!this.state._active) this.start(event);
this.wheelChange(event);
this.timeoutStore.add('wheelEnd', this.wheelEnd.bind(this));
};
_defineProperty(this, "ingKey", 'wheeling');
}
WheelEngine.prototype.wheelChange = function (event) {
if (event.cancelable) event.preventDefault();
const state = this.state;
state._delta = Wheel.values(event);
V.addTo(this.state._movement, state._delta);
this.compute(event);
this.emit();
};
wheel(event) {
if (!this.state._active) this.start(event);
this.wheelChange(event);
this.timeoutStore.add('wheelEnd', this.wheelEnd.bind(this));
}
WheelEngine.prototype.wheelEnd = function () {
if (!this.state._active) return;
this.state._active = false;
this.compute();
this.emit();
};
wheelChange(event) {
if (event.cancelable) event.preventDefault();
const state = this.state;
state._delta = Wheel.values(event);
V.addTo(this.state._movement, state._delta);
this.compute(event);
this.emit();
}
WheelEngine.prototype.bind = function (bindFunction) {
bindFunction('wheel', '', this.wheel.bind(this));
};
wheelEnd() {
if (!this.state._active) return;
this.state._active = false;
this.compute();
this.emit();
}
bind(bindFunction) {
bindFunction('wheel', '', this.wheel.bind(this));
}
}
const scrollConfigResolver = coordinatesConfigResolver;
ConfigResolverMap.set('scroll', scrollConfigResolver);
const ScrollEngine = function ScrollEngine(ctrl, args) {
this.ingKey = 'scrolling';
CoordinatesEngine.call(this, ctrl, args, 'scroll');
};
ScrollEngine.prototype = Object.create(CoordinatesEngine.prototype);
class ScrollEngine extends CoordinatesEngine {
constructor(...args) {
super(...args);
ScrollEngine.prototype.scroll = function (event) {
if (!this.state._active) this.start(event);
this.scrollChange(event);
this.timeoutStore.add('scrollEnd', this.scrollEnd.bind(this));
};
_defineProperty(this, "ingKey", 'scrolling');
}
ScrollEngine.prototype.scrollChange = function (event) {
if (event.cancelable) event.preventDefault();
const state = this.state;
const values = Scroll.values(event);
state._delta = V.sub(values, state.values);
V.addTo(state._movement, state._delta);
state.values = values;
this.compute(event);
this.emit();
};
scroll(event) {
if (!this.state._active) this.start(event);
this.scrollChange(event);
this.timeoutStore.add('scrollEnd', this.scrollEnd.bind(this));
}
ScrollEngine.prototype.scrollEnd = function () {
if (!this.state._active) return;
this.state._active = false;
this.compute();
this.emit();
};
scrollChange(event) {
if (event.cancelable) event.preventDefault();
const state = this.state;
const values = Scroll.values(event);
state._delta = V.sub(values, state.values);
V.addTo(state._movement, state._delta);
state.values = values;
this.compute(event);
this.emit();
}
ScrollEngine.prototype.bind = function (bindFunction) {
bindFunction('scroll', '', this.scroll.bind(this));
};
scrollEnd() {
if (!this.state._active) return;
this.state._active = false;
this.compute();
this.emit();
}
bind(bindFunction) {
bindFunction('scroll', '', this.scroll.bind(this));
}
}
const moveConfigResolver = coordinatesConfigResolver;
ConfigResolverMap.set('move', moveConfigResolver);
const MoveEngine = function MoveEngine(ctrl, args) {
this.ingKey = 'moving';
CoordinatesEngine.call(this, ctrl, args, 'move');
};
MoveEngine.prototype = Object.create(CoordinatesEngine.prototype);
class MoveEngine extends CoordinatesEngine {
constructor(...args) {
super(...args);
MoveEngine.prototype.move = function (event) {
if (!this.state._active) this.moveStart(event);else this.moveChange(event);
this.timeoutStore.add('moveEnd', this.moveEnd.bind(this));
};
_defineProperty(this, "ingKey", 'moving');
}
MoveEngine.prototype.moveStart = function (event) {
this.start(event);
const state = this.state;
state.values = Pointer.values(event);
this.compute(event);
state.initial = state.values;
this.emit();
};
move(event) {
if (!this.state._active) this.moveStart(event);else this.moveChange(event);
this.timeoutStore.add('moveEnd', this.moveEnd.bind(this));
}
MoveEngine.prototype.moveChange = function (event) {
if (!this.state._active) return;
const values = Pointer.values(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();
};
moveStart(event) {
this.start(event);
const state = this.state;
state.values = Pointer.values(event);
this.compute(event);
state.initial = state.values;
this.emit();
}
MoveEngine.prototype.moveEnd = function (event) {
if (!this.state._active) return;
this.state._active = false;
this.compute(event);
this.emit();
};
moveChange(event) {
if (!this.state._active) return;
const values = Pointer.values(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();
}
MoveEngine.prototype.bind = function (bindFunction) {
bindFunction('mouse', 'change', this.move.bind(this));
bindFunction('mouse', 'leave', this.moveEnd.bind(this));
};
moveEnd(event) {
if (!this.state._active) return;
this.state._active = false;
this.compute(event);
this.emit();
}
bind(bindFunction) {
bindFunction('mouse', 'change', this.move.bind(this));
bindFunction('mouse', 'leave', this.moveEnd.bind(this));
}
}
const hoverConfigResolver = coordinatesConfigResolver;
ConfigResolverMap.set('hover', hoverConfigResolver);
const HoverEngine = function HoverEngine(ctrl, args) {
this.ingKey = 'hovering';
CoordinatesEngine.call(this, ctrl, args, 'hover');
};
HoverEngine.prototype = Object.create(CoordinatesEngine.prototype);
class HoverEngine extends CoordinatesEngine {
constructor(...args) {
super(...args);
HoverEngine.prototype.enter = function (event) {
this.start(event);
this.state.values = Pointer.values(event);
this.compute(event);
this.emit();
};
_defineProperty(this, "ingKey", 'hovering');
}
HoverEngine.prototype.leave = function (event) {
const state = this.state;
if (!state._active) return;
state._active = false;
const values = Pointer.values(event);
state._movement = state._delta = V.sub(values, state.values);
state.values = values;
this.compute(event);
state.delta = state.movement;
this.emit();
};
enter(event) {
this.start(event);
this.state.values = Pointer.values(event);
this.compute(event);
this.emit();
}
HoverEngine.prototype.bind = function (bindFunction) {
bindFunction('mouse', 'enter', this.enter.bind(this));
bindFunction('mouse', 'leave', this.leave.bind(this));
};
leave(event) {
const state = this.state;
if (!state._active) return;
state._active = false;
const values = Pointer.values(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('mouse', 'enter', this.enter.bind(this));
bindFunction('mouse', 'leave', this.leave.bind(this));
}
}
exports.Controller = Controller;

@@ -1794,0 +1819,0 @@ exports.DragEngine = DragEngine;

@@ -423,43 +423,50 @@ function _defineProperty(obj, key, value) {

const EventStore = function EventStore(ctrl) {
this._ctrl = ctrl;
this._listeners = [];
};
class EventStore {
constructor(ctrl) {
_defineProperty(this, "_listeners", []);
EventStore.prototype.add = function (element, device, action, handler, options) {
const type = toDomEventType(device, action);
const eventOptions = options || this._ctrl._config.shared.eventOptions;
element.addEventListener(type, handler, eventOptions);
this._ctrl = ctrl;
}
this._listeners.push(() => element.removeEventListener(type, handler, eventOptions));
};
add(element, device, action, handler, options) {
const type = toDomEventType(device, action);
const eventOptions = options || this._ctrl.config.shared.eventOptions;
element.addEventListener(type, handler, eventOptions);
EventStore.prototype.clean = function () {
this._listeners.forEach(remove => remove());
this._listeners.push(() => element.removeEventListener(type, handler, eventOptions));
}
this._listeners = [];
};
clean() {
this._listeners.forEach(remove => remove());
const TimeoutStore = function TimeoutStore() {
this._timeouts = new Map();
};
this._listeners = [];
}
TimeoutStore.prototype.add = function (key, callback, ms = 140, ...args) {
this.remove(key);
}
this._timeouts.set(key, window.setTimeout(callback, ms, ...args));
};
class TimeoutStore {
constructor() {
_defineProperty(this, "_timeouts", new Map());
}
TimeoutStore.prototype.remove = function (key) {
const timeout = this._timeouts.get(key);
add(key, callback, ms = 140, ...args) {
this.remove(key);
if (timeout) window.clearTimeout(timeout);
};
this._timeouts.set(key, window.setTimeout(callback, ms, ...args));
}
TimeoutStore.prototype.clean = function () {
this._timeouts.forEach(timeout => void window.clearTimeout(timeout));
remove(key) {
const timeout = this._timeouts.get(key);
this._timeouts.clear();
};
if (timeout) window.clearTimeout(timeout);
}
clean() {
this._timeouts.forEach(timeout => void window.clearTimeout(timeout));
this._timeouts.clear();
}
}
function call(v, ...args) {

@@ -490,91 +497,100 @@ if (typeof v === 'function') {

const Controller = function Controller(handlers) {
this._gestures = new Set();
this._targetEventStore = new EventStore(this);
this._gestureEventStores = {};
this._gestureTimeoutStores = {};
this._handlers = {};
this._nativeHandlers = {};
this._config = {};
this._pointerIds = new Set();
this._touchIds = new Set();
this.state = {
shared: {
shiftKey: false,
metaKey: false,
ctrlKey: false,
altKey: false
}
};
resolveGestures(this, handlers);
};
class Controller {
constructor(handlers) {
_defineProperty(this, "gestures", new Set());
Controller.prototype.setEventIds = function (event) {
if (isTouch(event)) {
this._touchIds = new Set(Touches.ids(event));
} else if ('pointerId' in event) {
if (event.type === 'pointerup') this._pointerIds.delete(event.pointerId);else this._pointerIds.add(event.pointerId);
_defineProperty(this, "_targetEventStore", new EventStore(this));
_defineProperty(this, "gestureEventStores", {});
_defineProperty(this, "gestureTimeoutStores", {});
_defineProperty(this, "handlers", {});
_defineProperty(this, "config", {});
_defineProperty(this, "pointerIds", new Set());
_defineProperty(this, "touchIds", new Set());
_defineProperty(this, "state", {
shared: {
shiftKey: false,
metaKey: false,
ctrlKey: false,
altKey: false
}
});
resolveGestures(this, handlers);
}
};
Controller.prototype.applyHandlers = function (handlers, nativeHandlers) {
this._handlers = handlers;
this._nativeHandlers = nativeHandlers;
};
setEventIds(event) {
if (isTouch(event)) {
this.touchIds = new Set(Touches.ids(event));
} else if ('pointerId' in event) {
if (event.type === 'pointerup') this.pointerIds.delete(event.pointerId);else this.pointerIds.add(event.pointerId);
}
}
Controller.prototype.applyConfig = function (config, gestureKey) {
this._config = parse(config, gestureKey);
};
applyHandlers(handlers, nativeHandlers) {
this.handlers = handlers;
this.nativeHandlers = nativeHandlers;
}
Controller.prototype.clean = function () {
this._targetEventStore.clean();
applyConfig(config, gestureKey) {
this.config = parse(config, gestureKey);
}
for (const key of this._gestures) {
this._gestureEventStores[key].clean();
clean() {
this._targetEventStore.clean();
this._gestureTimeoutStores[key].clean();
for (const key of this.gestures) {
this.gestureEventStores[key].clean();
this.gestureTimeoutStores[key].clean();
}
}
};
Controller.prototype.effect = function () {
if (this._config.shared.target) this.bind();
return () => this._targetEventStore.clean();
};
effect() {
if (this.config.shared.target) this.bind();
return () => this._targetEventStore.clean();
}
Controller.prototype.bind = function (...args) {
const sharedConfig = this._config.shared;
const eventOptions = sharedConfig.eventOptions;
const props = {};
const bindFunction = sharedConfig.target ? bindToEventStore(this._targetEventStore, sharedConfig.target()) : bindToProps(props, eventOptions);
bind(...args) {
const sharedConfig = this.config.shared;
const eventOptions = sharedConfig.eventOptions;
const props = {};
const bindFunction = sharedConfig.target ? bindToEventStore(this._targetEventStore, sharedConfig.target()) : bindToProps(props, eventOptions);
if (sharedConfig.enabled) {
for (const eventKey in this._nativeHandlers) {
bindFunction(eventKey, '', event => this._nativeHandlers[eventKey](_objectSpread2(_objectSpread2({}, this.state.shared), {}, {
event,
args
})), undefined, true);
if (sharedConfig.enabled) {
for (const eventKey in this.nativeHandlers) {
bindFunction(eventKey, '', event => this.nativeHandlers[eventKey](_objectSpread2(_objectSpread2({}, this.state.shared), {}, {
event,
args
})), undefined, true);
}
for (const gestureKey of this.gestures) {
if (this.config[gestureKey].enabled) {
const Engine = EngineMap.get(gestureKey);
new Engine(this, args, gestureKey).bind(bindFunction);
}
}
}
for (const gestureKey of this._gestures) {
if (this._config[gestureKey].enabled) {
const Engine = EngineMap.get(gestureKey);
new Engine(this, args).bind(bindFunction);
if (!sharedConfig.target) {
for (const handlerProp in props) {
props[handlerProp] = chain(...props[handlerProp]);
}
return props;
}
}
if (!sharedConfig.target) {
for (const handlerProp in props) {
props[handlerProp] = chain(...props[handlerProp]);
}
}
return props;
}
};
function setupGesture(ctrl, gestureKey) {
ctrl._gestures.add(gestureKey);
ctrl._gestureEventStores[gestureKey] = new EventStore(ctrl);
ctrl._gestureTimeoutStores[gestureKey] = new TimeoutStore();
ctrl.gestures.add(gestureKey);
ctrl.gestureEventStores[gestureKey] = new EventStore(ctrl);
ctrl.gestureTimeoutStores[gestureKey] = new TimeoutStore();
}

@@ -650,240 +666,239 @@

const Engine = function Engine(ctrl, args, key) {
this.ctrl = ctrl;
this.key = key;
this.args = args;
class Engine {
constructor(ctrl, args, key) {
this.ctrl = ctrl;
this.args = args;
this.key = key;
if (!this.state) {
this.state = {
values: [0, 0],
initial: [0, 0]
};
if (this.init) this.init();
this.reset();
if (!this.state) {
this.state = {
values: [0, 0],
initial: [0, 0]
};
if (this.init) this.init();
this.reset();
}
}
};
Engine.prototype = {
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];
},
return this.ctrl.gestureEventStores[this.key];
}
get timeoutStore() {
return this.ctrl._gestureTimeoutStores[this.key];
},
return this.ctrl.gestureTimeoutStores[this.key];
}
get config() {
return this.ctrl._config[this.key];
},
return this.ctrl.config[this.key];
}
get sharedConfig() {
return this.ctrl._config.shared;
},
return this.ctrl.config.shared;
}
get handler() {
return this.ctrl._handlers[this.key];
return this.ctrl.handlers[this.key];
}
};
reset() {
const {
state,
shared,
config,
ingKey
} = 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.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;
}
Engine.prototype.reset = function () {
const {
state,
shared,
config,
ingKey
} = 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.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;
Engine.prototype.start = function (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;
}
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;
}
state.startTime = state.timeStamp = event.timeStamp;
};
compute(event) {
const {
state,
config,
shared
} = this;
state.args = this.args;
let dt = 0;
Engine.prototype.compute = function (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 > 0 || shared.touches > 0;
dt = event.timeStamp - state.timeStamp;
state.timeStamp = event.timeStamp;
state.elapsedTime = state.timeStamp - state.startTime;
}
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 > 0 || 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);
if (state._active) {
const _absoluteDelta = state._delta.map(Math.abs);
V.addTo(state._distance, _absoluteDelta);
}
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);
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 (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();
}
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();
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.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];
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();
}
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;
}
Engine.prototype.emit = function () {
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();
}
Engine.prototype.clean = function () {
this.eventStore.clean();
this.timeoutStore.clean();
};
}
const CoordinatesEngine = function CoordinatesEngine(ctrl, args, key) {
Engine.call(this, ctrl, args, key);
};
CoordinatesEngine.prototype = Object.create(Engine.prototype);
class CoordinatesEngine extends Engine {
reset() {
super.reset();
this.state.axis = undefined;
}
CoordinatesEngine.prototype.reset = function () {
Engine.prototype.reset.call(this);
this.state.axis = undefined;
};
init() {
this.state.offset = [0, 0];
this.state.lastOffset = [0, 0];
}
CoordinatesEngine.prototype.init = function () {
this.state.offset = [0, 0];
this.state.lastOffset = [0, 0];
};
computeOffset() {
const state = this.state;
state.offset = V.add(state.lastOffset, state.movement);
}
CoordinatesEngine.prototype.computeOffset = function () {
const state = this.state;
state.offset = V.add(state.lastOffset, state.movement);
};
computeMovement() {
const {
offset,
lastOffset
} = this.state;
this.state.movement = V.sub(offset, lastOffset);
this.state.xy = this.state.values;
}
CoordinatesEngine.prototype.computeMovement = function () {
const {
offset,
lastOffset
} = this.state;
this.state.movement = V.sub(offset, lastOffset);
this.state.xy = this.state.values;
};
intent(v) {
const state = this.state;
CoordinatesEngine.prototype.intent = function (v) {
const state = this.state;
if (!state.axis) {
const axisMovementDifference = Math.abs(v[0]) - Math.abs(v[1]);
if (axisMovementDifference < 0) state.axis = 'y';else if (axisMovementDifference > 0) state.axis = 'x';
}
if (!state.axis) {
const axisMovementDifference = Math.abs(v[0]) - Math.abs(v[1]);
if (axisMovementDifference < 0) state.axis = 'y';else if (axisMovementDifference > 0) state.axis = 'x';
}
const axis = state.axis;
const axis = state.axis;
if (this.config.lockDirection) {
if (axis) {
state._blocked = false;
if (axis === 'x') v[1] = 0;else if (axis === 'y') v[0] = 0;
} else {
state._blocked = false;
if (this.config.lockDirection) {
if (axis) {
state._blocked = false;
if (axis === 'x') v[1] = 0;else if (axis === 'y') v[0] = 0;
} else {
state._blocked = false;
}
} else if (this.config.axis) {
if (!!axis && axis === this.config.axis) {
state._blocked = false;
if (axis === 'x') v[1] = 0;else if (axis === 'y') v[0] = 0;
} else {
state._blocked = true;
}
}
} else if (this.config.axis) {
if (!!axis && axis === this.config.axis) {
state._blocked = false;
if (axis === 'x') v[1] = 0;else if (axis === 'y') v[0] = 0;
} else {
state._blocked = true;
}
}
};
}
const DEFAULT_RUBBERBAND = 0.15;

@@ -1086,285 +1101,315 @@ const commonConfigResolver = {

ConfigResolverMap.set('drag', dragConfigResolver);
const DragEngine = function DragEngine(ctrl, args) {
this.ingKey = 'dragging';
CoordinatesEngine.call(this, ctrl, args, 'drag');
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]
};
DragEngine.prototype = Object.create(CoordinatesEngine.prototype);
class DragEngine extends CoordinatesEngine {
constructor(...args) {
super(...args);
DragEngine.prototype.reset = function () {
CoordinatesEngine.prototype.reset.call(this);
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);
};
_defineProperty(this, "ingKey", 'dragging');
}
DragEngine.prototype.setup = function () {
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);
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);
}
};
DragEngine.prototype.cancel = function () {
const state = this.state;
if (state.canceled) return;
setTimeout(() => {
state.canceled = true;
state._active = false;
this.compute();
this.emit();
}, 0);
};
setup() {
const state = this.state;
DragEngine.prototype.setActive = function ({
pointer,
keyboard
} = {}) {
this.state._active = (pointer !== null && pointer !== void 0 ? pointer : this.state._pointerActive) || (keyboard !== null && keyboard !== void 0 ? keyboard : this.state._keyboardActive);
};
if (state._bounds instanceof HTMLElement) {
const boundRect = state._bounds.getBoundingClientRect();
DragEngine.prototype.clean = function () {
this.pointerClean();
this.state._pointerActive = false;
this.state._keyboardActive = false;
CoordinatesEngine.prototype.clean.call(this);
};
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);
}
}
DragEngine.prototype.bind = function (bindFunction) {
const device = this.config.device;
bindFunction(device, 'start', this.pointerDown.bind(this));
bindFunction(device, 'end', this.pointerUp.bind(this));
bindFunction('key', 'down', this.keyDown.bind(this));
bindFunction('key', 'up', this.keyUp.bind(this));
cancel() {
const state = this.state;
if (state.canceled) return;
setTimeout(() => {
state.canceled = true;
state._active = false;
this.compute();
this.emit();
}, 0);
}
if (this.sharedConfig.r3f) {
bindFunction(device, 'change', this.pointerMove.bind(this));
setActive() {
this.state._active = this.state._pointerActive || this.state._keyboardActive;
}
if (this.config.filterTaps) {
bindFunction('click', '', this.pointerClick.bind(this), {
capture: true
});
clean() {
this.pointerClean();
this.state._pointerActive = false;
this.state._keyboardActive = false;
super.clean();
}
};
DragEngine.prototype.pointerDown = function (event) {
this.ctrl.setEventIds(event);
const state = this.state;
const config = this.config;
if (state._pointerActive) return;
this.start(event);
this.setupPointer(event);
state._pointerId = Pointer.id(event);
state._pointerActive = true;
state.values = Pointer.values(event);
state.initial = state.values;
pointerDown(event) {
this.ctrl.setEventIds(event);
if (config.preventScroll) {
this.setupScrollPrevention(event);
} else if (config.delay > 0) {
this.setupDelayTrigger(event);
} else {
this.startPointerDrag(event);
}
};
if (this.config.pointerCapture) {
event.target.setPointerCapture(event.pointerId);
}
DragEngine.prototype.startPointerDrag = function (event) {
const state = this.state;
state._active = true;
state._preventScroll = true;
state._delayed = false;
this.compute(event);
this.emit();
};
const state = this.state;
const config = this.config;
if (state._pointerActive) return;
this.start(event);
this.setupPointer(event);
state._pointerId = Pointer.id(event);
state._pointerActive = true;
state.values = Pointer.values(event);
state.initial = state.values;
DragEngine.prototype.pointerMove = function (event) {
const state = this.state;
const config = this.config;
if (!state._pointerActive) return;
const id = Pointer.id(event);
if (state._pointerId && id !== state._pointerId) return;
const values = Pointer.values(event);
if (config.preventScroll) {
this.setupScrollPrevention(event);
} else if (config.delay > 0) {
this.setupDelayTrigger(event);
} else {
this.startPointerDrag(event);
}
}
if (document.pointerLockElement === event.target) {
state._delta = [event.movementX, event.movementY];
} else {
state._delta = V.sub(values, state.values);
state.values = values;
startPointerDrag(event) {
const state = this.state;
state._active = true;
state._preventScroll = true;
state._delayed = false;
this.compute(event);
this.emit();
}
V.addTo(state._movement, state._delta);
this.compute(event);
pointerMove(event) {
const state = this.state;
const config = this.config;
if (!state._pointerActive) return;
const id = Pointer.id(event);
if (state._pointerId && id !== state._pointerId) return;
const values = Pointer.values(event);
if (state._delayed) {
this.timeoutStore.remove('dragDelay');
this.startPointerDrag(event);
return;
}
if (document.pointerLockElement === event.target) {
state._delta = [event.movementX, event.movementY];
} else {
state._delta = V.sub(values, state.values);
state.values = values;
}
if (config.preventScroll && !state._preventScroll) {
if (state.axis) {
if (state.axis === 'x') {
this.timeoutStore.remove('startPointerDrag');
this.startPointerDrag(event);
return;
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 === 'x') {
this.timeoutStore.remove('startPointerDrag');
this.startPointerDrag(event);
return;
} else {
state._active = false;
this.clean();
return;
}
} else {
state._active = false;
this.clean();
return;
}
} else {
return;
}
this.emit();
}
this.emit();
};
pointerUp(event) {
this.ctrl.setEventIds(event);
DragEngine.prototype.pointerUp = function (event) {
this.ctrl.setEventIds(event);
const state = this.state;
const config = this.config;
if (!state._pointerActive) return;
const id = Pointer.id(event);
if (state._pointerId && id !== state._pointerId) return;
this.setActive({
pointer: false
});
this.compute(event);
const [dx, dy] = state._distance;
state.tap = dx <= 3 && dy <= 3;
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.`);
}
}
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;
const state = this.state;
const config = this.config;
if (!state._pointerActive) return;
const id = Pointer.id(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.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;
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();
}
this.emit();
};
pointerClick(event) {
if (!this.state.tap) event.stopPropagation();
}
DragEngine.prototype.pointerClick = function (event) {
if (!this.state.tap) event.stopPropagation();
};
setupPointer(event) {
const config = this.config;
let device = config.device;
const target = event.target;
const currentTarget = event.currentTarget;
DragEngine.prototype.setupPointer = function (event) {
const config = this.config;
let device = config.device;
const target = event.target;
const currentTarget = event.currentTarget;
if (process.env.NODE_ENV === 'development') {
try {
if (device === 'pointer') {
const _currentTarget = this.sharedConfig.r3f ? event.sourceEvent.currentTarget : event.currentTarget;
if (process.env.NODE_ENV === 'development') {
try {
if (device === 'pointer') {
const _currentTarget = this.sharedConfig.r3f ? event.sourceEvent.currentTarget : event.currentTarget;
const style = window.getComputedStyle(_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 (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);
if (config.pointerLock) {
currentTarget.requestPointerLock();
}
if (device === 'touch' || config.pointerCapture) {
if (!this.sharedConfig.r3f) {
if (process.env.NODE_ENV === 'development') {
if (event.uv) {
console.warn(`[@use-gesture]: You're probably using \`use-gesture\` on with \`@react-three/fiber\` without setting the drag config option \`r3f: true\`. The gesture will now probably fail.`);
}
}
if (document.pointerLockElement === target) device = 'mouse';
this.eventStore.add(target, device, 'change', this.pointerMove.bind(this));
}
} catch (_unused) {}
} else {
if (!this.sharedConfig.r3f) {
this.eventStore.add(this.sharedConfig.window, device, 'change', this.pointerMove.bind(this));
this.eventStore.add(this.sharedConfig.window, device, 'end', this.pointerUp.bind(this));
}
}
}
if (config.pointerLock) {
currentTarget.requestPointerLock();
}
pointerClean() {
const state = this.state;
if (!state._pointerActive) return;
if (config.pointerCapture) {
target.setPointerCapture(event.pointerId);
if (this.config.pointerLock && document.pointerLockElement === state.target) {
document.exitPointerLock();
}
}
if (device === 'touch' || config.pointerCapture) {
if (!this.sharedConfig.r3f) {
if (process.env.NODE_ENV === 'development') {
if (event.uv) {
console.warn(`[@use-gesture]: You're probably using \`use-gesture\` on with \`@react-three/fiber\` without setting the drag config option \`r3f: true\`. The gesture will now probably fail.`);
}
}
if (document.pointerLockElement === target) device = 'mouse';
this.eventStore.add(target, device, 'change', this.pointerMove.bind(this));
preventScroll(event) {
if (this.state._preventScroll && event.cancelable) {
event.preventDefault();
}
} else {
if (!this.sharedConfig.r3f) {
this.eventStore.add(this.sharedConfig.window, device, 'change', this.pointerMove.bind(this));
this.eventStore.add(this.sharedConfig.window, device, 'end', this.pointerUp.bind(this));
}
}
};
DragEngine.prototype.pointerClean = function () {
const state = this.state;
const target = state.target;
if (!state._pointerActive) return;
const event = state.event;
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), 250, event);
}
if (this.config.pointerLock && document.pointerLockElement === state.target) {
document.exitPointerLock();
setupDelayTrigger(event) {
this.state._delayed = true;
this.timeoutStore.add('dragDelay', this.startPointerDrag.bind(this), this.config.delay, event);
}
try {
if (this.config.pointerCapture && target.hasPointerCapture(event.pointerId)) {
target.releasePointerCapture(event.pointerId);
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();
}
} catch (_unused2) {
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.`);
}
}
};
DragEngine.prototype.preventScroll = function (event) {
if (this.state._preventScroll && event.cancelable) {
event.preventDefault();
keyUp(event) {
if (!(event.key in KEYS_DELTA_MAP)) return;
this.state._keyboardActive = false;
this.setActive();
this.compute(event);
this.emit();
}
};
DragEngine.prototype.setupScrollPrevention = function (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), 250, event);
};
bind(bindFunction) {
const device = this.config.device;
bindFunction(device, 'start', this.pointerDown.bind(this));
bindFunction(device, 'end', this.pointerUp.bind(this));
bindFunction('key', 'down', this.keyDown.bind(this));
bindFunction('key', 'up', this.keyUp.bind(this));
DragEngine.prototype.setupDelayTrigger = function (event) {
this.state._delayed = true;
this.timeoutStore.add('dragDelay', this.startPointerDrag.bind(this), this.config.delay, event);
};
if (this.sharedConfig.r3f) {
bindFunction(device, 'change', this.pointerMove.bind(this));
}
if (this.config.filterTaps) {
bindFunction('click', '', this.pointerClick.bind(this), {
capture: true
});
}
}
}
function persistEvent(event) {

@@ -1374,34 +1419,2 @@ 'persist' in event && typeof event.persist === 'function' && event.persist();

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]
};
DragEngine.prototype.keyDown = function (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();
}
};
DragEngine.prototype.keyUp = function (event) {
if (!(event.key in KEYS_DELTA_MAP)) return;
this.setActive({
keyboard: false
});
this.compute(event);
this.emit();
};
const pinchConfigResolver = _objectSpread2(_objectSpread2({}, commonConfigResolver), {}, {

@@ -1465,254 +1478,254 @@ useTouch(_v, _k, {

const SCALE_ANGLE_RATIO_INTENT_RAD = SCALE_ANGLE_RATIO_INTENT_DEG / 180 * Math.PI;
const PinchEngine = function PinchEngine(ctrl, args) {
this.ingKey = 'pinching';
Engine.call(this, ctrl, args, 'pinch');
};
PinchEngine.prototype = Object.create(Engine.prototype);
const PINCH_WHEEL_RATIO = 60;
class PinchEngine extends Engine {
constructor(...args) {
super(...args);
PinchEngine.prototype.init = function () {
this.state.offset = [1, 0];
this.state.lastOffset = [1, 0];
this.state._pointerEvents = new Map();
};
_defineProperty(this, "ingKey", 'pinching');
}
PinchEngine.prototype.reset = function () {
Engine.prototype.reset.call(this);
const state = this.state;
state._touchIds = [];
state.canceled = false;
state.cancel = this.cancel.bind(this);
state.turns = 0;
};
init() {
this.state.offset = [1, 0];
this.state.lastOffset = [1, 0];
this.state._pointerEvents = new Map();
}
PinchEngine.prototype.computeOffset = function () {
const {
movement,
lastOffset
} = this.state;
this.state.offset = [(1 + movement[0]) * lastOffset[0], movement[1] + lastOffset[1]];
};
reset() {
super.reset();
const state = this.state;
state._touchIds = [];
state.canceled = false;
state.cancel = this.cancel.bind(this);
state.turns = 0;
}
PinchEngine.prototype.computeMovement = function () {
const {
offset,
lastOffset
} = this.state;
this.state.movement = [offset[0] / lastOffset[0] - 1, offset[1] - lastOffset[1]];
this.state.da = this.state.values;
};
PinchEngine.prototype.intent = function (v) {
const state = this.state;
if (!state.axis) {
const angleScaleRatio = this.config.useRad ? SCALE_ANGLE_RATIO_INTENT_RAD : SCALE_ANGLE_RATIO_INTENT_DEG;
const axisMovementDifference = Math.abs(v[0]) * angleScaleRatio - Math.abs(v[1]);
if (axisMovementDifference < 0) state.axis = 'angle';else if (axisMovementDifference > 0) state.axis = 'scale';
computeOffset() {
const {
movement,
lastOffset
} = this.state;
this.state.offset = [(1 + movement[0]) * lastOffset[0], movement[1] + lastOffset[1]];
}
if (this.config.lockDirection) {
if (state.axis === 'scale') v[1] = 0;else if (state.axis === 'angle') v[0] = 0;
computeMovement() {
const {
offset,
lastOffset
} = this.state;
this.state.movement = [offset[0] / lastOffset[0] - 1, offset[1] - lastOffset[1]];
this.state.da = this.state.values;
}
};
PinchEngine.prototype.cancel = function () {
const state = this.state;
if (state.canceled) return;
setTimeout(() => {
state.canceled = true;
state._active = false;
this.compute();
this.emit();
}, 0);
};
intent(v) {
const state = this.state;
PinchEngine.prototype.bind = function (bindFunction) {
const device = this.config.device;
if (!state.axis) {
const angleScaleRatio = this.config.useRad ? SCALE_ANGLE_RATIO_INTENT_RAD : SCALE_ANGLE_RATIO_INTENT_DEG;
const axisMovementDifference = Math.abs(v[0]) * angleScaleRatio - Math.abs(v[1]);
if (axisMovementDifference < 0) state.axis = 'angle';else if (axisMovementDifference > 0) state.axis = 'scale';
}
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));
};
if (this.config.lockDirection) {
if (state.axis === 'scale') v[1] = 0;else if (state.axis === 'angle') v[0] = 0;
}
}
function convertAngle(engine, value) {
if (engine.config.useRad) return value / 180 * Math.PI;
return value;
}
PinchEngine.prototype.touchStart = function (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;
cancel() {
const state = this.state;
if (state.canceled) return;
setTimeout(() => {
state.canceled = true;
state._active = false;
this.compute();
this.emit();
}, 0);
}
if (ctrlTouchIds.size < 2) return;
this.start(event);
state._touchIds = Array.from(ctrlTouchIds).slice(0, 2);
const payload = Touches.distanceAngle(event, state._touchIds);
this.pinchStart(event, payload);
};
touchStart(event) {
this.ctrl.setEventIds(event);
const state = this.state;
const ctrlTouchIds = this.ctrl.touchIds;
PinchEngine.prototype.pointerStart = function (event) {
this.ctrl.setEventIds(event);
const state = this.state;
const _pointerEvents = state._pointerEvents;
const ctrlPointerIds = this.ctrl._pointerIds;
if (state._active) {
if (state._touchIds.every(id => ctrlTouchIds.has(id))) return;
}
if (state._active) {
if (Array.from(_pointerEvents.keys()).every(id => ctrlPointerIds.has(id))) return;
if (ctrlTouchIds.size < 2) return;
this.start(event);
state._touchIds = Array.from(ctrlTouchIds).slice(0, 2);
const payload = Touches.distanceAngle(event, state._touchIds);
this.pinchStart(event, payload);
}
if (_pointerEvents.size < 2) {
_pointerEvents.set(event.pointerId, event);
pointerStart(event) {
this.ctrl.setEventIds(event);
event.target.setPointerCapture(event.pointerId);
}
const state = this.state;
const _pointerEvents = state._pointerEvents;
const ctrlPointerIds = this.ctrl.pointerIds;
if (state._pointerEvents.size < 2) return;
this.start(event);
const payload = distanceAngle(...Array.from(_pointerEvents.values()));
this.pinchStart(event, payload);
};
if (state._active) {
if (Array.from(_pointerEvents.keys()).every(id => ctrlPointerIds.has(id))) return;
}
PinchEngine.prototype.pinchStart = function (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();
};
if (_pointerEvents.size < 2) {
_pointerEvents.set(event.pointerId, event);
}
PinchEngine.prototype.touchMove = function (event) {
if (!this.state._active) return;
const payload = Touches.distanceAngle(event, this.state._touchIds);
this.pinchMove(event, payload);
};
if (state._pointerEvents.size < 2) return;
this.start(event);
const payload = distanceAngle(...Array.from(_pointerEvents.values()));
this.pinchStart(event, payload);
}
PinchEngine.prototype.pointerMove = function (event) {
const _pointerEvents = this.state._pointerEvents;
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();
}
if (_pointerEvents.has(event.pointerId)) {
_pointerEvents.set(event.pointerId, event);
touchMove(event) {
if (!this.state._active) return;
const payload = Touches.distanceAngle(event, this.state._touchIds);
this.pinchMove(event, payload);
}
if (!this.state._active) return;
const payload = distanceAngle(...Array.from(_pointerEvents.values()));
this.pinchMove(event, payload);
};
pointerMove(event) {
const _pointerEvents = this.state._pointerEvents;
PinchEngine.prototype.pinchMove = function (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, convertAngle(this, state.values[1] - state.initial[1])];
this.compute(event);
this.emit();
};
if (_pointerEvents.has(event.pointerId)) {
_pointerEvents.set(event.pointerId, event);
}
PinchEngine.prototype.touchEnd = function (event) {
this.ctrl.setEventIds(event);
if (!this.state._active) return;
if (!this.state._active) return;
const payload = distanceAngle(...Array.from(_pointerEvents.values()));
this.pinchMove(event, payload);
}
if (this.state._touchIds.some(id => !this.ctrl._touchIds.has(id))) {
this.state._active = false;
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, convertAngle(this, state.values[1] - state.initial[1])];
this.compute(event);
this.emit();
}
};
PinchEngine.prototype.pointerEnd = function (event) {
const state = this.state;
this.ctrl.setEventIds(event);
touchEnd(event) {
this.ctrl.setEventIds(event);
if (!this.state._active) return;
if (state._pointerEvents.has(event.pointerId)) {
state._pointerEvents.delete(event.pointerId);
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();
}
}
if (!state._active) return;
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();
}
if (state._pointerEvents.size < 2) {
state._active = false;
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, convertAngle(this, event.rotation)];
state._delta = V.sub(state._movement, _previousMovement);
this.compute(event);
this.emit();
}
};
const PINCH_WHEEL_RATIO = 60;
gestureEnd(event) {
if (!this.state._active) return;
this.state._active = false;
this.compute(event);
this.emit();
}
PinchEngine.prototype.wheel = function (event) {
if (!event.ctrlKey) return;
if (!this.state._active) this.wheelStart(event);else this.wheelChange(event);
this.timeoutStore.add('wheelEnd', this.wheelEnd.bind(this));
};
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));
}
PinchEngine.prototype.wheelStart = function (event) {
if (event.cancelable) event.preventDefault();else if (process.env.NODE_ENV === 'development') {
console.warn(`[@use-gesture]: To properly support zoom on trackpads, try using the \`target\` option and \`config.eventOptions.passive\` set to \`false\`. This message will only appear in development mode.`, event.currentTarget);
wheelStart(event) {
if (event.cancelable) event.preventDefault();else if (process.env.NODE_ENV === 'development') {
console.warn(`[@use-gesture]: To properly support zoom on trackpads, try using the \`target\` option and \`config.eventOptions.passive\` set to \`false\`. This message will only appear in development mode.`, event.currentTarget);
}
this.start(event);
this.wheelChange(event);
}
this.start(event);
this.wheelChange(event);
};
PinchEngine.prototype.wheelChange = function (event) {
if (event.cancelable) event.preventDefault();
const state = this.state;
state._delta = [-Wheel.values(event)[1] / PINCH_WHEEL_RATIO, 0];
V.addTo(state._movement, state._delta);
this.state.origin = [event.clientX, event.clientY];
this.compute(event);
this.emit();
};
wheelChange(event) {
if (event.cancelable) event.preventDefault();
const state = this.state;
state._delta = [-Wheel.values(event)[1] / PINCH_WHEEL_RATIO, 0];
V.addTo(state._movement, state._delta);
this.state.origin = [event.clientX, event.clientY];
this.compute(event);
this.emit();
}
PinchEngine.prototype.wheelEnd = function () {
if (!this.state._active) return;
this.state._active = false;
this.compute();
this.emit();
};
wheelEnd() {
if (!this.state._active) return;
this.state._active = false;
this.compute();
this.emit();
}
PinchEngine.prototype.gestureStart = function (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();
};
bind(bindFunction) {
const device = this.config.device;
PinchEngine.prototype.gestureMove = function (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, convertAngle(this, event.rotation)];
state._delta = V.sub(state._movement, _previousMovement);
this.compute(event);
this.emit();
};
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));
}
PinchEngine.prototype.gestureEnd = function (event) {
if (!this.state._active) return;
this.state._active = false;
this.compute(event);
this.emit();
};
}
function convertAngle(engine, value) {
if (engine.config.useRad) return value / 180 * Math.PI;
return value;
}

@@ -1722,150 +1735,162 @@ const wheelConfigResolver = coordinatesConfigResolver;

ConfigResolverMap.set('wheel', wheelConfigResolver);
const WheelEngine = function WheelEngine(ctrl, args) {
this.ingKey = 'wheeling';
CoordinatesEngine.call(this, ctrl, args, 'wheel');
};
WheelEngine.prototype = Object.create(CoordinatesEngine.prototype);
class WheelEngine extends CoordinatesEngine {
constructor(...args) {
super(...args);
WheelEngine.prototype.wheel = function (event) {
if (!this.state._active) this.start(event);
this.wheelChange(event);
this.timeoutStore.add('wheelEnd', this.wheelEnd.bind(this));
};
_defineProperty(this, "ingKey", 'wheeling');
}
WheelEngine.prototype.wheelChange = function (event) {
if (event.cancelable) event.preventDefault();
const state = this.state;
state._delta = Wheel.values(event);
V.addTo(this.state._movement, state._delta);
this.compute(event);
this.emit();
};
wheel(event) {
if (!this.state._active) this.start(event);
this.wheelChange(event);
this.timeoutStore.add('wheelEnd', this.wheelEnd.bind(this));
}
WheelEngine.prototype.wheelEnd = function () {
if (!this.state._active) return;
this.state._active = false;
this.compute();
this.emit();
};
wheelChange(event) {
if (event.cancelable) event.preventDefault();
const state = this.state;
state._delta = Wheel.values(event);
V.addTo(this.state._movement, state._delta);
this.compute(event);
this.emit();
}
WheelEngine.prototype.bind = function (bindFunction) {
bindFunction('wheel', '', this.wheel.bind(this));
};
wheelEnd() {
if (!this.state._active) return;
this.state._active = false;
this.compute();
this.emit();
}
bind(bindFunction) {
bindFunction('wheel', '', this.wheel.bind(this));
}
}
const scrollConfigResolver = coordinatesConfigResolver;
ConfigResolverMap.set('scroll', scrollConfigResolver);
const ScrollEngine = function ScrollEngine(ctrl, args) {
this.ingKey = 'scrolling';
CoordinatesEngine.call(this, ctrl, args, 'scroll');
};
ScrollEngine.prototype = Object.create(CoordinatesEngine.prototype);
class ScrollEngine extends CoordinatesEngine {
constructor(...args) {
super(...args);
ScrollEngine.prototype.scroll = function (event) {
if (!this.state._active) this.start(event);
this.scrollChange(event);
this.timeoutStore.add('scrollEnd', this.scrollEnd.bind(this));
};
_defineProperty(this, "ingKey", 'scrolling');
}
ScrollEngine.prototype.scrollChange = function (event) {
if (event.cancelable) event.preventDefault();
const state = this.state;
const values = Scroll.values(event);
state._delta = V.sub(values, state.values);
V.addTo(state._movement, state._delta);
state.values = values;
this.compute(event);
this.emit();
};
scroll(event) {
if (!this.state._active) this.start(event);
this.scrollChange(event);
this.timeoutStore.add('scrollEnd', this.scrollEnd.bind(this));
}
ScrollEngine.prototype.scrollEnd = function () {
if (!this.state._active) return;
this.state._active = false;
this.compute();
this.emit();
};
scrollChange(event) {
if (event.cancelable) event.preventDefault();
const state = this.state;
const values = Scroll.values(event);
state._delta = V.sub(values, state.values);
V.addTo(state._movement, state._delta);
state.values = values;
this.compute(event);
this.emit();
}
ScrollEngine.prototype.bind = function (bindFunction) {
bindFunction('scroll', '', this.scroll.bind(this));
};
scrollEnd() {
if (!this.state._active) return;
this.state._active = false;
this.compute();
this.emit();
}
bind(bindFunction) {
bindFunction('scroll', '', this.scroll.bind(this));
}
}
const moveConfigResolver = coordinatesConfigResolver;
ConfigResolverMap.set('move', moveConfigResolver);
const MoveEngine = function MoveEngine(ctrl, args) {
this.ingKey = 'moving';
CoordinatesEngine.call(this, ctrl, args, 'move');
};
MoveEngine.prototype = Object.create(CoordinatesEngine.prototype);
class MoveEngine extends CoordinatesEngine {
constructor(...args) {
super(...args);
MoveEngine.prototype.move = function (event) {
if (!this.state._active) this.moveStart(event);else this.moveChange(event);
this.timeoutStore.add('moveEnd', this.moveEnd.bind(this));
};
_defineProperty(this, "ingKey", 'moving');
}
MoveEngine.prototype.moveStart = function (event) {
this.start(event);
const state = this.state;
state.values = Pointer.values(event);
this.compute(event);
state.initial = state.values;
this.emit();
};
move(event) {
if (!this.state._active) this.moveStart(event);else this.moveChange(event);
this.timeoutStore.add('moveEnd', this.moveEnd.bind(this));
}
MoveEngine.prototype.moveChange = function (event) {
if (!this.state._active) return;
const values = Pointer.values(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();
};
moveStart(event) {
this.start(event);
const state = this.state;
state.values = Pointer.values(event);
this.compute(event);
state.initial = state.values;
this.emit();
}
MoveEngine.prototype.moveEnd = function (event) {
if (!this.state._active) return;
this.state._active = false;
this.compute(event);
this.emit();
};
moveChange(event) {
if (!this.state._active) return;
const values = Pointer.values(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();
}
MoveEngine.prototype.bind = function (bindFunction) {
bindFunction('mouse', 'change', this.move.bind(this));
bindFunction('mouse', 'leave', this.moveEnd.bind(this));
};
moveEnd(event) {
if (!this.state._active) return;
this.state._active = false;
this.compute(event);
this.emit();
}
bind(bindFunction) {
bindFunction('mouse', 'change', this.move.bind(this));
bindFunction('mouse', 'leave', this.moveEnd.bind(this));
}
}
const hoverConfigResolver = coordinatesConfigResolver;
ConfigResolverMap.set('hover', hoverConfigResolver);
const HoverEngine = function HoverEngine(ctrl, args) {
this.ingKey = 'hovering';
CoordinatesEngine.call(this, ctrl, args, 'hover');
};
HoverEngine.prototype = Object.create(CoordinatesEngine.prototype);
class HoverEngine extends CoordinatesEngine {
constructor(...args) {
super(...args);
HoverEngine.prototype.enter = function (event) {
this.start(event);
this.state.values = Pointer.values(event);
this.compute(event);
this.emit();
};
_defineProperty(this, "ingKey", 'hovering');
}
HoverEngine.prototype.leave = function (event) {
const state = this.state;
if (!state._active) return;
state._active = false;
const values = Pointer.values(event);
state._movement = state._delta = V.sub(values, state.values);
state.values = values;
this.compute(event);
state.delta = state.movement;
this.emit();
};
enter(event) {
this.start(event);
this.state.values = Pointer.values(event);
this.compute(event);
this.emit();
}
HoverEngine.prototype.bind = function (bindFunction) {
bindFunction('mouse', 'enter', this.enter.bind(this));
bindFunction('mouse', 'leave', this.leave.bind(this));
};
leave(event) {
const state = this.state;
if (!state._active) return;
state._active = false;
const values = Pointer.values(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('mouse', 'enter', this.enter.bind(this));
bindFunction('mouse', 'leave', this.leave.bind(this));
}
}
export { Controller, DragEngine, HoverEngine, MoveEngine, PinchEngine, ScrollEngine, WheelEngine, parseMergedHandlers, registerEngine };
{
"name": "@use-gesture/core",
"version": "10.0.0-beta.1",
"version": "10.0.0-beta.2",
"description": "Core engine for receiving gestures",

@@ -8,2 +8,3 @@ "license": "MIT",

"module": "dist/use-gesture-core.esm.js",
"sideEffects": false,
"repository": {

@@ -10,0 +11,0 @@ "type": "git",

@@ -9,52 +9,45 @@ import { EngineMap } from './imports'

interface ControllerConstructor {
new (handlers: InternalHandlers): Controller
}
export interface Controller {
export class Controller {
/**
* The list of gestures handled by the Controller.
*/
_gestures: Set<GestureKey>
public gestures = new Set<GestureKey>()
/**
* The event store that keeps track of the config.target listeners.
*/
_targetEventStore: EventStore
private _targetEventStore = new EventStore(this)
/**
* Object that keeps track of all gesture event listeners.
*/
_gestureEventStores: { [key in GestureKey]?: EventStore }
public gestureEventStores: { [key in GestureKey]?: EventStore } = {}
public gestureTimeoutStores: { [key in GestureKey]?: TimeoutStore } = {}
public handlers: InternalHandlers = {}
private nativeHandlers?: NativeHandlers
public config = {} as InternalConfig
public pointerIds = new Set<number>()
public touchIds = new Set<number>()
public state = {
shared: {
shiftKey: false,
metaKey: false,
ctrlKey: false,
altKey: false
}
} as State
constructor(handlers: InternalHandlers) {
resolveGestures(this, handlers)
}
/**
* Object that keeps track of all gesture timeouts.
*/
_gestureTimeoutStores: { [key in GestureKey]?: TimeoutStore }
/**
* Gesture handlers.
*/
_handlers: InternalHandlers
/**
* Native event handlers.
*/
_nativeHandlers?: NativeHandlers
/**
* Computed configuration.
*/
_config: InternalConfig
/**
* Pointer ids active on the target.
*/
_pointerIds: Set<number>
/**
* Touch identifiers active on the target.
*/
_touchIds: Set<number>
/**
* The Controller state reflecting the state of all gestures.
*/
state: State
/**
* Sets pointer or touch ids based on the event.
* @param event
*/
setEventIds(this: Controller, event: TouchEvent | PointerEvent): void
setEventIds(event: TouchEvent | PointerEvent) {
if (isTouch(event)) {
this.touchIds = new Set(Touches.ids(event as TouchEvent))
} else if ('pointerId' in event) {
if (event.type === 'pointerup') this.pointerIds.delete(event.pointerId)
else this.pointerIds.add(event.pointerId)
}
}
/**

@@ -65,3 +58,6 @@ * Attaches handlers to the controller.

*/
applyHandlers(this: Controller, handlers: InternalHandlers, nativeHandlers?: NativeHandlers): void
applyHandlers(handlers: InternalHandlers, nativeHandlers?: NativeHandlers) {
this.handlers = handlers
this.nativeHandlers = nativeHandlers
}
/**

@@ -72,3 +68,5 @@ * Compute and attaches a config to the controller.

*/
applyConfig(this: Controller, config: UserGestureConfig, gestureKey?: GestureKey): void
applyConfig(config: UserGestureConfig, gestureKey?: GestureKey) {
this.config = parse(config, gestureKey)
}
/**

@@ -78,3 +76,9 @@ * Cleans all side effects (listeners, timeouts). When the gesture is

*/
clean(this: Controller): void
clean() {
this._targetEventStore.clean()
for (const key of this.gestures) {
this.gestureEventStores[key]!.clean()
this.gestureTimeoutStores[key]!.clean()
}
}
/**

@@ -84,3 +88,6 @@ * Executes side effects (attaching listeneds to a `config.target`). Ran on

*/
effect(this: Controller): void
effect() {
if (this.config.shared.target) this.bind()
return () => this._targetEventStore.clean()
}
/**

@@ -91,104 +98,49 @@ * The bind function that can be returned by the gesture handler (a hook in

*/
bind(this: Controller, ...args: any[]): NativeHandlers | void
}
bind(...args: any[]) {
const sharedConfig = this.config.shared
const eventOptions = sharedConfig.eventOptions
const props: any = {}
export const Controller: ControllerConstructor = function (this: Controller, handlers: InternalHandlers) {
this._gestures = new Set()
this._targetEventStore = new EventStore(this)
this._gestureEventStores = {}
this._gestureTimeoutStores = {}
this._handlers = {}
this._nativeHandlers = {}
this._config = {} as InternalConfig
this._pointerIds = new Set()
this._touchIds = new Set()
this.state = {
shared: {
shiftKey: false,
metaKey: false,
ctrlKey: false,
altKey: false
}
} as State
const bindFunction = sharedConfig.target
? bindToEventStore(this._targetEventStore, sharedConfig.target())
: bindToProps(props, eventOptions)
resolveGestures(this, handlers)
} as any
if (sharedConfig.enabled) {
// Adding native handlers
for (const eventKey in this.nativeHandlers) {
bindFunction(
eventKey,
'',
// @ts-ignore
(event) => this.nativeHandlers[eventKey]({ ...this.state.shared, event, args }),
undefined,
true
)
}
Controller.prototype.setEventIds = function (event) {
if (isTouch(event)) {
this._touchIds = new Set(Touches.ids(event as TouchEvent))
} else if ('pointerId' in event) {
if (event.type === 'pointerup') this._pointerIds.delete(event.pointerId)
else this._pointerIds.add(event.pointerId)
}
} as Controller['setEventIds']
Controller.prototype.applyHandlers = function (handlers, nativeHandlers) {
this._handlers = handlers
this._nativeHandlers = nativeHandlers
} as Controller['applyHandlers']
Controller.prototype.applyConfig = function (config, gestureKey) {
this._config = parse(config, gestureKey)
} as Controller['applyConfig']
Controller.prototype.clean = function () {
this._targetEventStore.clean()
for (const key of this._gestures) {
this._gestureEventStores[key]!.clean()
this._gestureTimeoutStores[key]!.clean()
}
} as Controller['clean']
Controller.prototype.effect = function () {
if (this._config.shared.target) this.bind()
return () => this._targetEventStore.clean()
} as Controller['effect']
Controller.prototype.bind = function (...args) {
const sharedConfig = this._config.shared
const eventOptions = sharedConfig.eventOptions
const props: any = {}
const bindFunction = sharedConfig.target
? bindToEventStore(this._targetEventStore, sharedConfig.target())
: bindToProps(props, eventOptions)
if (sharedConfig.enabled) {
// Adding native handlers
for (const eventKey in this._nativeHandlers) {
bindFunction(
eventKey,
'',
// @ts-ignore
(event) => this._nativeHandlers[eventKey]({ ...this.state.shared, event, args }),
undefined,
true
)
// Adding gesture handlers
for (const gestureKey of this.gestures) {
if (this.config[gestureKey]!.enabled) {
const Engine = EngineMap.get(gestureKey)!
// @ts-ignore
new Engine(this, args, gestureKey).bind(bindFunction)
}
}
}
// Adding gesture handlers
for (const gestureKey of this._gestures) {
if (this._config[gestureKey]!.enabled) {
const Engine = EngineMap.get(gestureKey)!
// @ts-ignore
new Engine(this, args).bind(bindFunction)
// If target isn't set, we return an object that contains gesture handlers
// mapped to props handler event keys.
if (!sharedConfig.target) {
for (const handlerProp in props) {
props[handlerProp] = chain(...props[handlerProp])
}
return props
}
}
}
// If target isn't set, we return an object that contains gesture handlers
// mapped to props handler event keys.
if (!sharedConfig.target) {
for (const handlerProp in props) {
props[handlerProp] = chain(...props[handlerProp])
}
return props
}
} as Controller['bind']
function setupGesture(ctrl: Controller, gestureKey: GestureKey) {
ctrl._gestures.add(gestureKey)
ctrl._gestureEventStores[gestureKey] = new EventStore(ctrl)
ctrl._gestureTimeoutStores[gestureKey] = new TimeoutStore()
ctrl.gestures.add(gestureKey)
ctrl.gestureEventStores[gestureKey] = new EventStore(ctrl)
ctrl.gestureTimeoutStores[gestureKey] = new TimeoutStore()
}

@@ -195,0 +147,0 @@

import { Engine } from './Engine'
import { V } from '../utils/maths'
import type { Controller } from '../Controller'
import { CoordinatesKey, GestureKey } from '../types'
import { CoordinatesKey, Vector2 } from '../types'
export interface CoordinatesEngineConstructor {
new <Key extends CoordinatesKey>(ctrl: Controller, args: any[], key: Key): CoordinatesEngine<Key>
}
export abstract class CoordinatesEngine<Key extends CoordinatesKey> extends Engine<Key> {
reset() {
super.reset()
this.state.axis = undefined
}
export interface CoordinatesEngine<Key extends GestureKey = CoordinatesKey> extends Engine<Key> {}
init() {
this.state.offset = [0, 0]
this.state.lastOffset = [0, 0]
}
export const CoordinatesEngine: CoordinatesEngineConstructor = function <Key extends CoordinatesKey>(
this: CoordinatesEngine<Key>,
ctrl: Controller,
args: any[],
key: Key
) {
// @ts-ignore
Engine.call(this, ctrl, args, key)
} as any
computeOffset() {
const state = this.state
state.offset = V.add(state.lastOffset, state.movement)
}
CoordinatesEngine.prototype = Object.create(Engine.prototype)
computeMovement() {
const { offset, lastOffset } = this.state
this.state.movement = V.sub(offset, lastOffset)
// let's take profit from this function to set `values` alias to `xy`
this.state.xy = this.state.values
}
CoordinatesEngine.prototype.reset = function () {
Engine.prototype.reset.call(this)
this.state.axis = undefined
} as CoordinatesEngine['reset']
intent(v: Vector2) {
const state = this.state
CoordinatesEngine.prototype.init = function () {
this.state.offset = [0, 0]
this.state.lastOffset = [0, 0]
} as CoordinatesEngine['init']
if (!state.axis) {
const axisMovementDifference = Math.abs(v[0]) - Math.abs(v[1])
if (axisMovementDifference < 0) state.axis = 'y'
else if (axisMovementDifference > 0) state.axis = 'x'
}
CoordinatesEngine.prototype.computeOffset = function () {
const state = this.state
state.offset = V.add(state.lastOffset, state.movement)
} as CoordinatesEngine['computeOffset']
const axis = state.axis
CoordinatesEngine.prototype.computeMovement = function () {
const { offset, lastOffset } = this.state
this.state.movement = V.sub(offset, lastOffset)
// let's take profit from this function to set `values` alias to `xy`
this.state.xy = this.state.values
} as CoordinatesEngine['computeMovement']
CoordinatesEngine.prototype.intent = function (v) {
const state = this.state
if (!state.axis) {
const axisMovementDifference = Math.abs(v[0]) - Math.abs(v[1])
if (axisMovementDifference < 0) state.axis = 'y'
else if (axisMovementDifference > 0) state.axis = 'x'
}
const axis = state.axis
if (this.config.lockDirection) {
if (axis) {
state._blocked = false
if (axis === 'x') v[1] = 0
else if (axis === 'y') v[0] = 0
} else {
state._blocked = false
if (this.config.lockDirection) {
if (axis) {
state._blocked = false
if (axis === 'x') v[1] = 0
else if (axis === 'y') v[0] = 0
} else {
state._blocked = false
}
} else if (this.config.axis) {
if (!!axis && axis === this.config.axis) {
state._blocked = false
if (axis === 'x') v[1] = 0
else if (axis === 'y') v[0] = 0
} else {
state._blocked = true
}
}
} else if (this.config.axis) {
if (!!axis && axis === this.config.axis) {
state._blocked = false
if (axis === 'x') v[1] = 0
else if (axis === 'y') v[0] = 0
} else {
state._blocked = true
}
}
} as CoordinatesEngine['intent']
}
import { Controller } from '../Controller'
import { EventStore } from '../EventStore'
import { TimeoutStore } from '../TimeoutStore'
import { getEventDetails } from '../utils/events'
import { call } from '../utils/fn'
import { V, computeRubberband } from '../utils/maths'
import { GestureKey, Handler, IngKey, InternalConfig, State, Vector2 } from '../types'
import { GestureKey, IngKey, State, Vector2 } from '../types'
export interface EngineConstructor {
new <Key extends GestureKey>(ctrl: Controller, args: any[], key: Key): Engine<Key>
}
export interface Engine<Key extends GestureKey = GestureKey> {
export interface Engine<Key extends GestureKey> {
/**
* The Controller handling state.
*/
ctrl: Controller
/**
* The gesture key ('drag' | 'pinch' | 'wheel' | 'scroll' | 'move' | 'hover')
*/
key: Key
/**
* The key representing the active state of the gesture in the shared state.
* ('dragging' | 'pinching' | 'wheeling' | 'scrolling' | 'moving' | 'hovering')
*/
ingKey: IngKey
/**
* The arguments passed to the `bind` function.
*/
args: any[]
/**
* Shortcut to the gesture state read from the Controller.
*/
state: NonNullable<State[Key]>
/**
* Shortcut to the shared state read from the Controller
*/
shared: State['shared']
/**
* Shortcut to the gesture config read from the Controller.
*/
config: NonNullable<InternalConfig[Key]>
/**
* Shortcut to the shared config read from the Controller.
*/
sharedConfig: InternalConfig['shared']
/**
* Shortcut to the gesture event store read from the Controller.
*/
eventStore: EventStore
/**
* Shortcut to the gesture timeout store read from the Controller.
*/
timeoutStore: TimeoutStore
/**
* Shortcut to the gesture handler read from the Controller.
*/
handler: Handler<Key>
/**
* Function that some gestures can use to add initilization
* properties to the state when it is created.
*/
init?(this: Engine<Key>): void
init?(): void
/**

@@ -68,3 +17,3 @@ * Setup function that some gestures can use to set additional properties of

*/
setup?(this: Engine<Key>): void
setup?(): void
/**

@@ -76,22 +25,43 @@ * Function used by some gestures to determine the intentionality of a

*/
intent?(this: Engine<Key>, movement: Vector2): void
intent?(movement: Vector2): void
}
export abstract class Engine<Key extends GestureKey> {
/**
* Function that resets the state.
* The Controller handling state.
*/
reset(this: Engine<Key>): void
ctrl: Controller
/**
* Function ran at the start of the gesture.
* @param event
* The gesture key ('drag' | 'pinch' | 'wheel' | 'scroll' | 'move' | 'hover')
*/
start(this: Engine<Key>, event: NonNullable<State[Key]>['event']): void
readonly key: Key
/**
* Computes all sorts of state attributes, including kinematics.
* @param event
* The key representing the active state of the gesture in the shared state.
* ('dragging' | 'pinching' | 'wheeling' | 'scrolling' | 'moving' | 'hovering')
*/
compute(this: Engine<Key>, event?: NonNullable<State[Key]>['event']): void
abstract readonly ingKey: IngKey
/**
* The arguments passed to the `bind` function.
*/
args: any[]
constructor(ctrl: Controller, args: any[], key: Key) {
this.ctrl = ctrl
this.args = args
this.key = key
if (!this.state) {
this.state = {
values: [0, 0],
initial: [0, 0]
} as any
if (this.init) this.init()
this.reset()
}
}
/**
* Function implemented by gestures that compute the offset from the state
* movement.
*/
computeOffset(this: Engine<Key>): void
abstract computeOffset(): void
/**

@@ -101,12 +71,4 @@ * Function implemented by the gestures that compute the movement from the

*/
computeMovement(this: Engine<Key>): void
abstract computeMovement(): void
/**
* Fires the gesture handler.
*/
emit(this: Engine<Key>): void
/**
* Cleans the gesture timeouts and event listeners.
*/
clean(this: Engine<Key>): void
/**
* Executes the bind function so that listeners are properly set by the

@@ -116,4 +78,3 @@ * Controller.

*/
bind(
this: Engine<Key>,
abstract bind(
bindFunction: (

@@ -126,202 +87,209 @@ device: string,

): void
}
export const Engine: EngineConstructor = function <Key extends GestureKey>(
this: Engine<Key>,
ctrl: Controller,
args: any[],
key: Key
) {
this.ctrl = ctrl
this.key = key
this.args = args
if (!this.state) {
this.state = {
values: [0, 0],
initial: [0, 0]
} as any
if (this.init) this.init()
this.reset()
/**
* Shortcut to the gesture state read from the Controller.
*/
get state() {
return this.ctrl.state[this.key]!
}
} as any
Engine.prototype = {
get state() {
return this.ctrl.state[this.key]
},
set state(state) {
this.ctrl.state[this.key] = state
},
}
/**
* Shortcut to the shared state read from the Controller
*/
get shared() {
return this.ctrl.state.shared
},
}
/**
* Shortcut to the gesture event store read from the Controller.
*/
get eventStore() {
return this.ctrl._gestureEventStores[this.key]
},
return this.ctrl.gestureEventStores[this.key]!
}
/**
* Shortcut to the gesture timeout store read from the Controller.
*/
get timeoutStore() {
return this.ctrl._gestureTimeoutStores[this.key]
},
return this.ctrl.gestureTimeoutStores[this.key]!
}
/**
* Shortcut to the gesture config read from the Controller.
*/
get config() {
return this.ctrl._config[this.key]
},
return this.ctrl.config[this.key]!
}
/**
* Shortcut to the shared config read from the Controller.
*/
get sharedConfig() {
return this.ctrl._config.shared
},
return this.ctrl.config.shared
}
/**
* Shortcut to the gesture handler read from the Controller.
*/
get handler() {
return this.ctrl._handlers[this.key]
return this.ctrl.handlers[this.key]!
}
}
Engine.prototype.reset = function () {
const { state, shared, config, ingKey } = 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]
// the _threshold is the difference between a [0,0] origin offset converted to
// its new space coordinates
state._threshold = V.sub(transform(threshold), transform([0, 0])).map(Math.abs) as Vector2
// prettier-ignore
state._bounds = [[-Infinity, Infinity], [-Infinity, Infinity]]
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
} as Engine['reset']
Engine.prototype.start = function (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
reset() {
const { state, shared, config, ingKey } = 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]
// the _threshold is the difference between a [0,0] origin offset converted to
// its new space coordinates
state._threshold = V.sub(transform(threshold), transform([0, 0])).map(Math.abs) as Vector2
// prettier-ignore
state._bounds = [[-Infinity, Infinity], [-Infinity, Infinity]]
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
}
state.startTime = state.timeStamp = event.timeStamp
} as Engine['start']
/**
* Function ran at the start of the gesture.
* @param event
*/
start(event: NonNullable<State[Key]>['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
}
/**
* Computes all sorts of state attributes, including kinematics.
* @param event
*/
compute(event?: NonNullable<State[Key]>['event']) {
const { state, config, shared } = this
state.args = this.args
Engine.prototype.compute = function (event) {
const { state, config, shared } = this
state.args = this.args
let dt = 0
let dt = 0
if (event) {
// sets the shared state with event properties
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 > 0 || shared.touches > 0
if (event) {
// sets the shared state with event properties
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 > 0 || shared.touches > 0
// sets time stamps
dt = event.timeStamp - state.timeStamp
state.timeStamp = event.timeStamp
state.elapsedTime = state.timeStamp - state.startTime
}
// sets time stamps
dt = event.timeStamp - state.timeStamp
state.timeStamp = event.timeStamp
state.elapsedTime = state.timeStamp - state.startTime
}
// only compute _distance if the state is active otherwise we might compute it
// twice when the gesture ends because state._delta wouldn't have changed on
// the last frame.
if (state._active) {
const _absoluteDelta = state._delta.map(Math.abs) as Vector2
V.addTo(state._distance, _absoluteDelta)
}
// only compute _distance if the state is active otherwise we might compute it
// twice when the gesture ends because state._delta wouldn't have changed on
// the last frame.
if (state._active) {
const _absoluteDelta = state._delta.map(Math.abs) as Vector2
V.addTo(state._distance, _absoluteDelta)
}
const [_m0, _m1] = config.transform(state._movement)
const [_t0, _t1] = state._threshold
// Step will hold the threshold at which point the gesture was triggered. The
// threshold is signed depending on which direction triggered it.
let [_s0, _s1] = state._step
const [_m0, _m1] = config.transform(state._movement)
const [_t0, _t1] = state._threshold
// Step will hold the threshold at which point the gesture was triggered. The
// threshold is signed depending on which direction triggered it.
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
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
state.intentional = _s0 !== false || _s1 !== false
if (!state.intentional) return
if (!state.intentional) return
state._step = [_s0, _s1]
state._step = [_s0, _s1]
const movement: Vector2 = [0, 0]
const movement: Vector2 = [0, 0]
movement[0] = _s0 !== false ? _m0 - _s0 : 0
movement[1] = _s1 !== false ? _m1 - _s1 : 0
movement[0] = _s0 !== false ? _m0 - _s0 : 0
movement[1] = _s1 !== false ? _m1 - _s1 : 0
// let's run intentionality check.
if (this.intent) this.intent(movement)
// let's run intentionality check.
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 ((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()
}
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
const previousMovement = state.movement
state.movement = movement
this.computeOffset()
this.computeOffset()
if (!state.last) {
state.delta = V.sub(movement, previousMovement)
const absoluteDelta = state.delta.map(Math.abs) as Vector2
if (!state.last) {
state.delta = V.sub(movement, previousMovement)
const absoluteDelta = state.delta.map(Math.abs) as Vector2
V.addTo(state.distance, absoluteDelta)
state.direction = state.delta.map(Math.sign) as Vector2
V.addTo(state.distance, absoluteDelta)
state.direction = state.delta.map(Math.sign) as Vector2
if (!state.first && dt > 0) {
// calculates kinematics unless the gesture starts or ends
state.velocity = [absoluteDelta[0] / dt, absoluteDelta[1] / dt]
if (!state.first && dt > 0) {
// calculates kinematics unless the gesture starts or ends
state.velocity = [absoluteDelta[0] / dt, absoluteDelta[1] / dt]
}
}
}
}
// @ts-ignore
const rubberband: Vector2 = state._active ? config.rubberband || [0, 0] : [0, 0]
state.offset = computeRubberband(state._bounds, state.offset, rubberband)
this.computeMovement()
}
/**
* Fires the gesture handler.
*/
emit() {
const state = this.state
const shared = this.shared
const config = this.config
// @ts-ignore
const rubberband: Vector2 = state._active ? config.rubberband || [0, 0] : [0, 0]
state.offset = computeRubberband(state._bounds, state.offset, rubberband)
this.computeMovement()
} as Engine['compute']
if (!state._active) this.clean()
Engine.prototype.emit = function () {
const state = this.state
const shared = this.shared
const config = this.config
// we don't trigger the handler if the gesture is blockedor non intentional,
// unless the `_force` flag was set or the `triggerAllEvents` option was set
// to true in the config.
if ((state._blocked || !state.intentional) && !state._force && !config.triggerAllEvents) return
if (!state._active) this.clean()
// @ts-ignore
const memo = this.handler({ ...shared, ...state })
// we don't trigger the handler if the gesture is blockedor non intentional,
// unless the `_force` flag was set or the `triggerAllEvents` option was set
// to true in the config.
if ((state._blocked || !state.intentional) && !state._force && !config.triggerAllEvents) return
const memo = this.handler({
...shared,
...state
})
// Sets memo to the returned value of the handler (unless it's undefined)
if (memo !== undefined) state.memo = memo
} as Engine['emit']
Engine.prototype.clean = function () {
this.eventStore.clean()
this.timeoutStore.clean()
} as Engine['clean']
// Sets memo to the returned value of the handler (unless it's undefined)
if (memo !== undefined) state.memo = memo
}
/**
* Cleans the gesture timeouts and event listeners.
*/
clean() {
this.eventStore.clean()
this.timeoutStore.clean()
}
}

@@ -0,13 +1,12 @@

import type { Controller } from './Controller'
import { toDomEventType } from './utils/events'
interface EventStoreConstructor {
new (ctrl: any): EventStore
}
export class EventStore {
private _listeners: (() => void)[] = []
private _ctrl: Controller
constructor(ctrl: Controller) {
this._ctrl = ctrl
}
export interface EventStore {
_ctrl: any
_listeners: (() => void)[]
clean(this: EventStore): void
add(
this: EventStore,
element: EventTarget,

@@ -18,20 +17,13 @@ device: string,

options?: AddEventListenerOptions
): void
) {
const type = toDomEventType(device, action)
const eventOptions = options || this._ctrl.config.shared.eventOptions
element.addEventListener(type, handler, eventOptions)
this._listeners.push(() => element.removeEventListener(type, handler, eventOptions))
}
clean() {
this._listeners.forEach((remove) => remove())
this._listeners = []
}
}
export const EventStore: EventStoreConstructor = function (this: EventStore, ctrl: any) {
this._ctrl = ctrl
this._listeners = []
} as any
EventStore.prototype.add = function (element, device, action, handler, options) {
const type = toDomEventType(device, action)
const eventOptions = options || this._ctrl._config.shared.eventOptions
element.addEventListener(type, handler, eventOptions)
this._listeners.push(() => element.removeEventListener(type, handler, eventOptions))
} as EventStore['add']
EventStore.prototype.clean = function () {
this._listeners.forEach((remove) => remove())
this._listeners = []
} as EventStore['clean']
import { ResolverMap } from './config/resolver'
import { DragEngineConstructor } from './engines/DragEngine/DragEngineCore'
import { HoverEngineConstructor } from './engines/HoverEngine/HoverEngineCore'
import { MoveEngineConstructor } from './engines/MoveEngine/MoveEngineCore'
import { PinchEngineConstructor } from './engines/PinchEngine/PinchEngineCore'
import { ScrollEngineConstructor } from './engines/ScrollEngine/ScrollEngineCore'
import { WheelEngineConstructor } from './engines/WheelEngine/WheelEngineCore'
import type { Controller } from './Controller'
import type { Engine } from './engines/Engine'
import { FullGestureState, GestureHandlers, GestureKey, InternalHandlers, UserGestureConfig } from './types'
type GestureEngineConstuctor =
| DragEngineConstructor
| ScrollEngineConstructor
| WheelEngineConstructor
| PinchEngineConstructor
| HoverEngineConstructor
| MoveEngineConstructor
export type EngineClass<Key extends GestureKey> = {
new (controller: Controller, args: any[], key: Key): Engine<Key>
}
export const EngineMap = new Map<GestureKey, GestureEngineConstuctor>()
export const EngineMap = new Map<GestureKey, EngineClass<any>>()
export const ConfigResolverMap = new Map<GestureKey, ResolverMap>()
export function registerEngine(action: GestureKey, Engine: GestureEngineConstuctor) {
export function registerEngine<Key extends GestureKey>(action: Key, Engine: EngineClass<Key>) {
EngineMap.set(action, Engine)

@@ -23,0 +15,0 @@ }

@@ -1,35 +0,23 @@

interface TimeoutStoreConstructor {
new (): TimeoutStore
}
export class TimeoutStore {
private _timeouts = new Map<string, number>()
export interface TimeoutStore {
_timeouts: Map<string, number>
add<FunctionType extends (...args: any) => any>(
this: TimeoutStore,
key: string,
callback: FunctionType,
ms?: number,
ms = 140,
...args: Parameters<FunctionType>
): void
remove(this: TimeoutStore, key: string): void
clean(this: TimeoutStore): void
}
) {
this.remove(key)
this._timeouts.set(key, window.setTimeout(callback, ms, ...args))
}
export const TimeoutStore: TimeoutStoreConstructor = function (this: TimeoutStore) {
this._timeouts = new Map()
} as any
remove(key: string) {
const timeout = this._timeouts.get(key)
if (timeout) window.clearTimeout(timeout)
}
TimeoutStore.prototype.add = function (key, callback, ms = 140, ...args) {
this.remove(key)
this._timeouts.set(key, window.setTimeout(callback, ms, ...args))
} as TimeoutStore['add']
TimeoutStore.prototype.remove = function (key) {
const timeout = this._timeouts.get(key)
if (timeout) window.clearTimeout(timeout)
} as TimeoutStore['remove']
TimeoutStore.prototype.clean = function () {
this._timeouts.forEach((timeout) => void window.clearTimeout(timeout))
this._timeouts.clear()
} as TimeoutStore['clean']
clean() {
this._timeouts.forEach((timeout) => void window.clearTimeout(timeout))
this._timeouts.clear()
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc