fix: prevent asset conflicts between React and Grid.js versions

Add coexistence checks to all enqueue methods to prevent loading
both React and Grid.js assets simultaneously.

Changes:
- ReactAdmin.php: Only enqueue React assets when ?react=1
- Init.php: Skip Grid.js when React active on admin pages
- Form.php, Coupon.php, Access.php: Restore classic assets when ?react=0
- Customer.php, Product.php, License.php: Add coexistence checks

Now the toggle between Classic and React versions works correctly.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
dwindown
2026-04-18 17:02:14 +07:00
parent bd9cdac02e
commit e8fbfb14c1
74973 changed files with 6658406 additions and 71 deletions

184
node_modules/@use-gesture/core/src/Controller.ts generated vendored Normal file
View File

@@ -0,0 +1,184 @@
import { EngineMap } from './actions'
import { parse } from './config/resolver'
import { isTouch, parseProp, toHandlerProp, touchIds } from './utils/events'
import { EventStore } from './EventStore'
import { TimeoutStore } from './TimeoutStore'
import { chain } from './utils/fn'
import { GestureKey, InternalConfig, InternalHandlers, NativeHandlers, State, UserGestureConfig } from './types'
export class Controller {
/**
* The list of gestures handled by the Controller.
*/
public gestures = new Set<GestureKey>()
/**
* The event store that keeps track of the config.target listeners.
*/
private _targetEventStore = new EventStore(this)
/**
* Object that keeps track of all gesture event listeners.
*/
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)
}
/**
* Sets pointer or touch ids based on the event.
* @param event
*/
setEventIds(event: TouchEvent | PointerEvent) {
if (isTouch(event)) {
this.touchIds = new Set(touchIds(event as TouchEvent))
return this.touchIds
} else if ('pointerId' in event) {
if (event.type === 'pointerup' || event.type === 'pointercancel') this.pointerIds.delete(event.pointerId)
else if (event.type === 'pointerdown') this.pointerIds.add(event.pointerId)
return this.pointerIds
}
}
/**
* Attaches handlers to the controller.
* @param handlers
* @param nativeHandlers
*/
applyHandlers(handlers: InternalHandlers, nativeHandlers?: NativeHandlers) {
this.handlers = handlers
this.nativeHandlers = nativeHandlers
}
/**
* Compute and attaches a config to the controller.
* @param config
* @param gestureKey
*/
applyConfig(config: UserGestureConfig, gestureKey?: GestureKey) {
this.config = parse(config, gestureKey, this.config)
}
/**
* Cleans all side effects (listeners, timeouts). When the gesture is
* destroyed (in React, when the component is unmounted.)
*/
clean() {
this._targetEventStore.clean()
for (const key of this.gestures) {
this.gestureEventStores[key]!.clean()
this.gestureTimeoutStores[key]!.clean()
}
}
/**
* Executes side effects (attaching listeners to a `config.target`). Ran on
* each render.
*/
effect() {
if (this.config.shared.target) this.bind()
return () => this._targetEventStore.clean()
}
/**
* The bind function that can be returned by the gesture handler (a hook in
* React for example.)
* @param args
*/
bind(...args: any[]) {
const sharedConfig = this.config.shared
const props: any = {}
let target
if (sharedConfig.target) {
target = sharedConfig.target()
// if target is undefined let's stop
if (!target) return
}
if (sharedConfig.enabled) {
// Adding gesture handlers
for (const gestureKey of this.gestures) {
const gestureConfig = this.config[gestureKey]!
const bindFunction = bindToProps(props, gestureConfig.eventOptions, !!target)
if (gestureConfig.enabled) {
const Engine = EngineMap.get(gestureKey)!
// @ts-ignore
new Engine(this, args, gestureKey).bind(bindFunction)
}
}
// Adding native handlers
const nativeBindFunction = bindToProps(props, sharedConfig.eventOptions, !!target)
for (const eventKey in this.nativeHandlers) {
nativeBindFunction(
eventKey,
'',
// @ts-ignore
(event) => this.nativeHandlers[eventKey]({ ...this.state.shared, event, args }),
undefined,
true
)
}
}
// If target isn't set, we return an object that contains gesture handlers
// mapped to props handler event keys.
for (const handlerProp in props) {
props[handlerProp] = chain(...props[handlerProp])
}
// When target isn't specified then return hanlder props.
if (!target) return props
// When target is specified, then add listeners to the controller target
// store.
for (const handlerProp in props) {
const { device, capture, passive } = parseProp(handlerProp)
this._targetEventStore.add(target, device, '', props[handlerProp], { capture, passive })
}
}
}
function setupGesture(ctrl: Controller, gestureKey: GestureKey) {
ctrl.gestures.add(gestureKey)
ctrl.gestureEventStores[gestureKey] = new EventStore(ctrl, gestureKey)
ctrl.gestureTimeoutStores[gestureKey] = new TimeoutStore()
}
function resolveGestures(ctrl: Controller, internalHandlers: InternalHandlers) {
// make sure hover handlers are added first to prevent bugs such as #322
// where the hover pointerLeave handler is removed before the move
// pointerLeave, which prevents hovering: false to be fired.
if (internalHandlers.drag) setupGesture(ctrl, 'drag')
if (internalHandlers.wheel) setupGesture(ctrl, 'wheel')
if (internalHandlers.scroll) setupGesture(ctrl, 'scroll')
if (internalHandlers.move) setupGesture(ctrl, 'move')
if (internalHandlers.pinch) setupGesture(ctrl, 'pinch')
if (internalHandlers.hover) setupGesture(ctrl, 'hover')
}
const bindToProps =
(props: any, eventOptions: AddEventListenerOptions, withPassiveOption: boolean) =>
(
device: string,
action: string,
handler: (event: any) => void,
options: AddEventListenerOptions = {},
isNative = false
) => {
const capture = options.capture ?? eventOptions.capture
const passive = options.passive ?? eventOptions.passive
// a native handler is already passed as a prop like "onMouseDown"
let handlerProp = isNative ? device : toHandlerProp(device, action, capture)
if (withPassiveOption && passive) handlerProp += 'Passive'
props[handlerProp] = props[handlerProp] || []
props[handlerProp].push(handler)
}

38
node_modules/@use-gesture/core/src/EventStore.ts generated vendored Normal file
View File

@@ -0,0 +1,38 @@
import type { Controller } from './Controller'
import { GestureKey } from './types'
import { toDomEventType } from './utils/events'
export class EventStore {
private _listeners = new Set<() => void>()
private _ctrl: Controller
private _gestureKey?: GestureKey
constructor(ctrl: Controller, gestureKey?: GestureKey) {
this._ctrl = ctrl
this._gestureKey = gestureKey
}
add(
element: EventTarget,
device: string,
action: string,
handler: (event: any) => void,
options?: AddEventListenerOptions
) {
const listeners = this._listeners
const type = toDomEventType(device, action)
const _options = this._gestureKey ? this._ctrl.config[this._gestureKey]!.eventOptions : {}
const eventOptions = { ..._options, ...options }
element.addEventListener(type, handler, eventOptions)
const remove = () => {
element.removeEventListener(type, handler, eventOptions)
listeners.delete(remove)
}
listeners.add(remove)
return remove
}
clean() {
this._listeners.forEach((remove) => remove())
this._listeners.clear() // just for safety
}
}

23
node_modules/@use-gesture/core/src/TimeoutStore.ts generated vendored Normal file
View File

@@ -0,0 +1,23 @@
export class TimeoutStore {
private _timeouts = new Map<string, number>()
add<FunctionType extends (...args: any[]) => any>(
key: string,
callback: FunctionType,
ms = 140,
...args: Parameters<FunctionType>
) {
this.remove(key)
this._timeouts.set(key, window.setTimeout(callback, ms, ...args))
}
remove(key: string) {
const timeout = this._timeouts.get(key)
if (timeout) window.clearTimeout(timeout)
}
clean() {
this._timeouts.forEach((timeout) => void window.clearTimeout(timeout))
this._timeouts.clear()
}
}

64
node_modules/@use-gesture/core/src/actions.ts generated vendored Normal file
View File

@@ -0,0 +1,64 @@
import { GestureKey, EngineClass, Action } from './types'
import { ResolverMap } from './config/resolver'
import { DragEngine } from './engines/DragEngine'
import { dragConfigResolver } from './config/dragConfigResolver'
import { PinchEngine } from './engines/PinchEngine'
import { pinchConfigResolver } from './config/pinchConfigResolver'
import { MoveEngine } from './engines/MoveEngine'
import { moveConfigResolver } from './config/moveConfigResolver'
import { ScrollEngine } from './engines/ScrollEngine'
import { scrollConfigResolver } from './config/scrollConfigResolver'
import { WheelEngine } from './engines/WheelEngine'
import { wheelConfigResolver } from './config/wheelConfigResolver'
import { HoverEngine } from './engines/HoverEngine'
import { hoverConfigResolver } from './config/hoverConfigResolver'
export const EngineMap = new Map<GestureKey, EngineClass<any>>()
export const ConfigResolverMap = new Map<GestureKey, ResolverMap>()
export function registerAction(action: Action) {
EngineMap.set(action.key, action.engine)
ConfigResolverMap.set(action.key, action.resolver)
}
export const dragAction: Action = {
key: 'drag',
engine: DragEngine as any,
resolver: dragConfigResolver
}
export const hoverAction: Action = {
key: 'hover',
engine: HoverEngine as any,
resolver: hoverConfigResolver
}
export const moveAction: Action = {
key: 'move',
engine: MoveEngine as any,
resolver: moveConfigResolver
}
export const pinchAction: Action = {
key: 'pinch',
engine: PinchEngine as any,
resolver: pinchConfigResolver
}
export const scrollAction: Action = {
key: 'scroll',
engine: ScrollEngine as any,
resolver: scrollConfigResolver
}
export const wheelAction: Action = {
key: 'wheel',
engine: WheelEngine as any,
resolver: wheelConfigResolver
}

View File

@@ -0,0 +1,81 @@
import { InternalGestureOptions } from '../types'
import { Vector2, State, GenericOptions } from '../types'
import { V } from '../utils/maths'
export const identity = (v: Vector2) => v
export const DEFAULT_RUBBERBAND = 0.15
export const commonConfigResolver = {
enabled(value = true) {
return value
},
eventOptions(value: AddEventListenerOptions | undefined, _k: string, config: { shared: GenericOptions }) {
return { ...config.shared.eventOptions, ...value }
},
preventDefault(value = false) {
return value
},
triggerAllEvents(value = false) {
return value
},
rubberband(value: number | boolean | Vector2 = 0): Vector2 {
switch (value) {
case true:
return [DEFAULT_RUBBERBAND, DEFAULT_RUBBERBAND]
case false:
return [0, 0]
default:
return V.toVector(value)
}
},
from(value: number | Vector2 | ((s: State) => Vector2)) {
if (typeof value === 'function') return value
// eslint-disable-next-line eqeqeq
if (value != null) return V.toVector(value)
},
transform(this: InternalGestureOptions, value: any, _k: string, config: { shared: GenericOptions }) {
const transform = value || config.shared.transform
this.hasCustomTransform = !!transform
if (process.env.NODE_ENV === 'development') {
const originalTransform = transform || identity
return (v: Vector2) => {
const r = originalTransform(v)
if (!isFinite(r[0]) || !isFinite(r[1])) {
// eslint-disable-next-line no-console
console.warn(`[@use-gesture]: config.transform() must produce a valid result, but it was: [${r[0]},${[1]}]`)
}
return r
}
}
return transform || identity
},
threshold(value: any) {
return V.toVector(value, 0)
}
}
if (process.env.NODE_ENV === 'development') {
Object.assign(commonConfigResolver, {
domTarget(value: any) {
if (value !== undefined) {
throw Error(`[@use-gesture]: \`domTarget\` option has been renamed to \`target\`.`)
}
return NaN
},
lockDirection(value: any) {
if (value !== undefined) {
throw Error(
`[@use-gesture]: \`lockDirection\` option has been merged with \`axis\`. Use it as in \`{ axis: 'lock' }\``
)
}
return NaN
},
initial(value: any) {
if (value !== undefined) {
throw Error(`[@use-gesture]: \`initial\` option has been renamed to \`from\`.`)
}
return NaN
}
})
}

View File

@@ -0,0 +1,43 @@
import { commonConfigResolver } from './commonConfigResolver'
import { InternalCoordinatesOptions, CoordinatesConfig, Bounds, DragBounds, State, Vector2 } from '../types'
const DEFAULT_AXIS_THRESHOLD = 0
export const coordinatesConfigResolver = {
...commonConfigResolver,
axis(
this: InternalCoordinatesOptions,
_v: any,
_k: string,
{ axis }: CoordinatesConfig
): InternalCoordinatesOptions['axis'] {
this.lockDirection = axis === 'lock'
if (!this.lockDirection) return axis as any
},
axisThreshold(value = DEFAULT_AXIS_THRESHOLD) {
return value
},
bounds(
value: DragBounds | ((state: State) => DragBounds) = {}
): (() => EventTarget | null) | HTMLElement | [Vector2, Vector2] {
if (typeof value === 'function') {
// @ts-ignore
return (state: State) => coordinatesConfigResolver.bounds(value(state))
}
if ('current' in value) {
return () => value.current
}
if (typeof HTMLElement === 'function' && value instanceof HTMLElement) {
return value
}
const { left = -Infinity, right = Infinity, top = -Infinity, bottom = Infinity } = value as Bounds
return [
[left, right],
[top, bottom]
]
}
}

View File

@@ -0,0 +1,135 @@
import { PointerType } from '../types'
import { DragConfig, InternalDragOptions, Vector2 } from '../types'
import { V } from '../utils/maths'
import { coordinatesConfigResolver } from './coordinatesConfigResolver'
import { SUPPORT } from './support'
export const DEFAULT_PREVENT_SCROLL_DELAY = 250
export const DEFAULT_DRAG_DELAY = 180
export const DEFAULT_SWIPE_VELOCITY = 0.5
export const DEFAULT_SWIPE_DISTANCE = 50
export const DEFAULT_SWIPE_DURATION = 250
export const DEFAULT_KEYBOARD_DISPLACEMENT = 10
const DEFAULT_DRAG_AXIS_THRESHOLD: Record<PointerType, number> = { mouse: 0, touch: 0, pen: 8 }
export const dragConfigResolver = {
...coordinatesConfigResolver,
device(
this: InternalDragOptions,
_v: any,
_k: string,
{ pointer: { touch = false, lock = false, mouse = false } = {} }: DragConfig
) {
this.pointerLock = lock && SUPPORT.pointerLock
if (SUPPORT.touch && touch) return 'touch'
if (this.pointerLock) return 'mouse'
if (SUPPORT.pointer && !mouse) return 'pointer'
if (SUPPORT.touch) return 'touch'
return 'mouse'
},
preventScrollAxis(this: InternalDragOptions, value: 'x' | 'y' | 'xy', _k: string, { preventScroll }: DragConfig) {
this.preventScrollDelay =
typeof preventScroll === 'number'
? preventScroll
: preventScroll || (preventScroll === undefined && value)
? DEFAULT_PREVENT_SCROLL_DELAY
: undefined
if (!SUPPORT.touchscreen || preventScroll === false) return undefined
return value ? value : preventScroll !== undefined ? 'y' : undefined
},
pointerCapture(
this: InternalDragOptions,
_v: any,
_k: string,
{ pointer: { capture = true, buttons = 1, keys = true } = {} }
) {
this.pointerButtons = buttons
this.keys = keys
return !this.pointerLock && this.device === 'pointer' && capture
},
threshold(
this: InternalDragOptions,
value: number | Vector2,
_k: string,
{ filterTaps = false, tapsThreshold = 3, axis = undefined }
) {
// TODO add warning when value is 0 and filterTaps or axis is set
const threshold = V.toVector(value, filterTaps ? tapsThreshold : axis ? 1 : 0)
this.filterTaps = filterTaps
this.tapsThreshold = tapsThreshold
return threshold
},
swipe(
this: InternalDragOptions,
{ velocity = DEFAULT_SWIPE_VELOCITY, distance = DEFAULT_SWIPE_DISTANCE, duration = DEFAULT_SWIPE_DURATION } = {}
) {
return {
velocity: this.transform(V.toVector(velocity)),
distance: this.transform(V.toVector(distance)),
duration
}
},
delay(value: number | boolean = 0) {
switch (value) {
case true:
return DEFAULT_DRAG_DELAY
case false:
return 0
default:
return value
}
},
axisThreshold(value: Record<PointerType, number>) {
if (!value) return DEFAULT_DRAG_AXIS_THRESHOLD
return { ...DEFAULT_DRAG_AXIS_THRESHOLD, ...value }
},
keyboardDisplacement(value: number = DEFAULT_KEYBOARD_DISPLACEMENT) {
return value
}
}
if (process.env.NODE_ENV === 'development') {
Object.assign(dragConfigResolver, {
useTouch(value: any) {
if (value !== undefined) {
throw Error(
`[@use-gesture]: \`useTouch\` option has been renamed to \`pointer.touch\`. Use it as in \`{ pointer: { touch: true } }\`.`
)
}
return NaN
},
experimental_preventWindowScrollY(value: any) {
if (value !== undefined) {
throw Error(
`[@use-gesture]: \`experimental_preventWindowScrollY\` option has been renamed to \`preventScroll\`.`
)
}
return NaN
},
swipeVelocity(value: any) {
if (value !== undefined) {
throw Error(
`[@use-gesture]: \`swipeVelocity\` option has been renamed to \`swipe.velocity\`. Use it as in \`{ swipe: { velocity: 0.5 } }\`.`
)
}
return NaN
},
swipeDistance(value: any) {
if (value !== undefined) {
throw Error(
`[@use-gesture]: \`swipeDistance\` option has been renamed to \`swipe.distance\`. Use it as in \`{ swipe: { distance: 50 } }\`.`
)
}
return NaN
},
swipeDuration(value: any) {
if (value !== undefined) {
throw Error(
`[@use-gesture]: \`swipeDuration\` option has been renamed to \`swipe.duration\`. Use it as in \`{ swipe: { duration: 250 } }\`.`
)
}
return NaN
}
})
}

View File

@@ -0,0 +1,6 @@
import { coordinatesConfigResolver } from './coordinatesConfigResolver'
export const hoverConfigResolver = {
...coordinatesConfigResolver,
mouseOnly: (value = true) => value
}

View File

@@ -0,0 +1,6 @@
import { coordinatesConfigResolver } from './coordinatesConfigResolver'
export const moveConfigResolver = {
...coordinatesConfigResolver,
mouseOnly: (value = true) => value
}

View File

@@ -0,0 +1,54 @@
import { ModifierKey } from '../types'
import { PinchConfig, GenericOptions, InternalPinchOptions, State, Vector2 } from '../types'
import { call, assignDefault } from '../utils/fn'
import { V } from '../utils/maths'
import { commonConfigResolver } from './commonConfigResolver'
import { SUPPORT } from './support'
export const pinchConfigResolver = {
...commonConfigResolver,
device(
this: InternalPinchOptions,
_v: any,
_k: string,
{ shared, pointer: { touch = false } = {} }: { shared: GenericOptions } & PinchConfig
) {
// Only try to use gesture events when they are supported and domTarget is set
// as React doesn't support gesture handlers.
const sharedConfig = shared
if (sharedConfig.target && !SUPPORT.touch && SUPPORT.gesture) return 'gesture'
if (SUPPORT.touch && touch) return 'touch'
if (SUPPORT.touchscreen) {
if (SUPPORT.pointer) return 'pointer'
if (SUPPORT.touch) return 'touch'
}
// device is undefined and that's ok, we're going to use wheel to zoom.
},
bounds(_v: any, _k: string, { scaleBounds = {}, angleBounds = {} }: PinchConfig) {
const _scaleBounds = (state?: State) => {
const D = assignDefault(call(scaleBounds, state), { min: -Infinity, max: Infinity })
return [D.min, D.max]
}
const _angleBounds = (state?: State) => {
const A = assignDefault(call(angleBounds, state), { min: -Infinity, max: Infinity })
return [A.min, A.max]
}
if (typeof scaleBounds !== 'function' && typeof angleBounds !== 'function') return [_scaleBounds(), _angleBounds()]
return (state: State) => [_scaleBounds(state), _angleBounds(state)]
},
threshold(this: InternalPinchOptions, value: number | Vector2, _k: string, config: PinchConfig) {
this.lockDirection = config.axis === 'lock'
const threshold = V.toVector(value, this.lockDirection ? [0.1, 3] : 0)
return threshold
},
modifierKey(value: ModifierKey | ModifierKey[]) {
if (value === undefined) return 'ctrlKey'
return value
},
pinchOnWheel(value = true) {
return value
}
}

65
node_modules/@use-gesture/core/src/config/resolver.ts generated vendored Normal file
View File

@@ -0,0 +1,65 @@
import { sharedConfigResolver } from './sharedConfigResolver'
import { ConfigResolverMap } from '../actions'
import { GestureKey, InternalConfig, UserGestureConfig } from '../types'
export type Resolver = (x: any, key: string, obj: any) => any
export type ResolverMap = { [k: string]: Resolver | ResolverMap | boolean }
export function resolveWith<T extends { [k: string]: any }, V extends { [k: string]: any }>(
config: Partial<T> = {},
resolvers: ResolverMap
): V {
const result: any = {}
for (const [key, resolver] of Object.entries(resolvers)) {
switch (typeof resolver) {
case 'function':
if (process.env.NODE_ENV === 'development') {
const r = resolver.call(result, config[key], key, config)
// prevents deprecated resolvers from applying in dev mode
if (!Number.isNaN(r)) result[key] = r
} else {
result[key] = resolver.call(result, config[key], key, config)
}
break
case 'object':
result[key] = resolveWith(config[key], resolver)
break
case 'boolean':
if (resolver) result[key] = config[key]
break
}
}
return result
}
export function parse(newConfig: UserGestureConfig, gestureKey?: GestureKey, _config: any = {}): InternalConfig {
const { target, eventOptions, window, enabled, transform, ...rest } = newConfig as any
_config.shared = resolveWith({ target, eventOptions, window, enabled, transform }, sharedConfigResolver)
if (gestureKey) {
const resolver = ConfigResolverMap.get(gestureKey)!
_config[gestureKey] = resolveWith({ shared: _config.shared, ...rest }, resolver)
} else {
for (const key in rest) {
const resolver = ConfigResolverMap.get(key as GestureKey)!
if (resolver) {
_config[key] = resolveWith({ shared: _config.shared, ...rest[key] }, resolver)
} else if (process.env.NODE_ENV === 'development') {
if (!['drag', 'pinch', 'scroll', 'wheel', 'move', 'hover'].includes(key)) {
if (key === 'domTarget') {
throw Error(`[@use-gesture]: \`domTarget\` option has been renamed to \`target\`.`)
}
// eslint-disable-next-line no-console
console.warn(
`[@use-gesture]: Unknown config key \`${key}\` was used. Please read the documentation for further information.`
)
}
}
}
}
return _config
}

View File

@@ -0,0 +1,3 @@
import { coordinatesConfigResolver } from './coordinatesConfigResolver'
export const scrollConfigResolver = coordinatesConfigResolver

View File

@@ -0,0 +1,23 @@
import { Target } from '../types'
import { SUPPORT } from './support'
export const sharedConfigResolver = {
target(value: Target) {
if (value) {
return () => ('current' in value ? value.current : value)
}
return undefined
},
enabled(value = true) {
return value
},
window(value = SUPPORT.isBrowser ? window : undefined) {
return value
},
eventOptions({ passive = true, capture = false } = {}) {
return { passive, capture }
},
transform(value: any) {
return value
}
}

47
node_modules/@use-gesture/core/src/config/support.ts generated vendored Normal file
View File

@@ -0,0 +1,47 @@
const isBrowser = typeof window !== 'undefined' && window.document && window.document.createElement
function supportsTouchEvents(): boolean {
return isBrowser && 'ontouchstart' in window
}
function isTouchScreen(): boolean {
return supportsTouchEvents() || (isBrowser && window.navigator.maxTouchPoints > 1)
}
function supportsPointerEvents(): boolean {
return isBrowser && 'onpointerdown' in window
}
function supportsPointerLock(): boolean {
return isBrowser && 'exitPointerLock' in window.document
}
function supportsGestureEvents(): boolean {
try {
// TODO [TS] possibly find GestureEvent definitions?
// @ts-ignore: no type definitions for webkit GestureEvents
return 'constructor' in GestureEvent
} catch (e) {
return false
}
}
export const SUPPORT = {
isBrowser,
gesture: supportsGestureEvents(),
/**
* It looks from https://github.com/pmndrs/use-gesture/discussions/421 that
* some touchscreens using webkits don't have 'ontouchstart' in window. So
* we're considering that browsers support TouchEvent if they have
* `maxTouchPoints > 1`
*
* Update 16/09/2023: This generates failure on other Windows systems, so reverting
* back to detecting TouchEvent support only.
* https://github.com/pmndrs/use-gesture/issues/626
*/
touch: supportsTouchEvents(),
// touch: isTouchScreen(),
touchscreen: isTouchScreen(),
pointer: supportsPointerEvents(),
pointerLock: supportsPointerLock()
}

View File

@@ -0,0 +1,3 @@
import { coordinatesConfigResolver } from './coordinatesConfigResolver'
export const wheelConfigResolver = coordinatesConfigResolver

View File

@@ -0,0 +1,70 @@
import { Engine } from './Engine'
import { V } from '../utils/maths'
import { CoordinatesKey, Vector2 } from '../types'
import { getPointerType } from '../utils/events'
function selectAxis([dx, dy]: Vector2, threshold: number) {
const absDx = Math.abs(dx)
const absDy = Math.abs(dy)
if (absDx > absDy && absDx > threshold) {
return 'x'
}
if (absDy > absDx && absDy > threshold) {
return 'y'
}
return undefined
}
export abstract class CoordinatesEngine<Key extends CoordinatesKey> extends Engine<Key> {
aliasKey = 'xy'
reset() {
super.reset()
this.state.axis = undefined
}
init() {
this.state.offset = [0, 0]
this.state.lastOffset = [0, 0]
}
computeOffset() {
this.state.offset = V.add(this.state.lastOffset, this.state.movement)
}
computeMovement() {
this.state.movement = V.sub(this.state.offset, this.state.lastOffset)
}
axisIntent(event?: UIEvent) {
const state = this.state
const config = this.config
if (!state.axis && event) {
const threshold =
typeof config.axisThreshold === 'object' ? config.axisThreshold[getPointerType(event)] : config.axisThreshold
state.axis = selectAxis(state._movement, threshold)
}
// We block the movement if either:
// - config.lockDirection or config.axis was set but axis isn't detected yet
// - config.axis was set but is different than detected axis
state._blocked =
((config.lockDirection || !!config.axis) && !state.axis) || (!!config.axis && config.axis !== state.axis)
}
restrictToAxis(v: Vector2) {
if (this.config.axis || this.config.lockDirection) {
switch (this.state.axis) {
case 'x':
v[1] = 0
break // [ x, 0 ]
case 'y':
v[0] = 0
break // [ 0, y ]
}
}
}
}

View File

@@ -0,0 +1,383 @@
import { CoordinatesEngine } from './CoordinatesEngine'
import { coordinatesConfigResolver } from '../config/coordinatesConfigResolver'
import { pointerId, getPointerType, pointerValues } from '../utils/events'
import { V } from '../utils/maths'
import { Vector2 } from '../types'
const KEYS_DELTA_MAP = {
ArrowRight: (displacement: number, factor: number = 1) => [displacement * factor, 0],
ArrowLeft: (displacement: number, factor: number = 1) => [-1 * displacement * factor, 0],
ArrowUp: (displacement: number, factor: number = 1) => [0, -1 * displacement * factor],
ArrowDown: (displacement: number, factor: number = 1) => [0, displacement * factor]
}
export class DragEngine extends CoordinatesEngine<'drag'> {
ingKey = 'dragging' as const
// superseeds generic Engine reset call
reset(this: DragEngine) {
super.reset()
const state = this.state
state._pointerId = undefined
state._pointerActive = false
state._keyboardActive = false
state._preventScroll = false
state._delayed = false
state.swipe = [0, 0]
state.tap = false
state.canceled = false
state.cancel = this.cancel.bind(this)
}
setup() {
const state = this.state
if (state._bounds instanceof HTMLElement) {
const boundRect = state._bounds.getBoundingClientRect()
const targetRect = (state.currentTarget as HTMLElement).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) as [Vector2, Vector2]
}
}
cancel() {
const state = this.state
if (state.canceled) return
state.canceled = true
state._active = false
setTimeout(() => {
// we run compute with no event so that kinematics won't be computed
this.compute()
this.emit()
}, 0)
}
setActive() {
this.state._active = this.state._pointerActive || this.state._keyboardActive
}
// superseeds Engine clean function
clean() {
this.pointerClean()
this.state._pointerActive = false
this.state._keyboardActive = false
super.clean()
}
pointerDown(event: PointerEvent) {
const config = this.config
const state = this.state
if (
event.buttons != null &&
// If the user submits an array as pointer.buttons, don't start the drag
// if event.buttons isn't included inside that array.
(Array.isArray(config.pointerButtons)
? !config.pointerButtons.includes(event.buttons)
: // If the user submits a number as pointer.buttons, refuse the drag if
// config.pointerButtons is different than `-1` and if event.buttons
// doesn't match the combination.
config.pointerButtons !== -1 && config.pointerButtons !== event.buttons)
)
return
const ctrlIds = this.ctrl.setEventIds(event)
// We need to capture all pointer ids so that we can keep track of them when
// they're released off the target
if (config.pointerCapture) {
;(event.target as HTMLElement).setPointerCapture(event.pointerId)
}
if (
// in some situations (https://github.com/pmndrs/use-gesture/issues/494#issuecomment-1127584116)
// like when a new browser tab is opened during a drag gesture, the drag
// can be interrupted mid-way, and can stall. This happens because the
// pointerId that initiated the gesture is lost, and since the drag
// persists until that pointerId is lifted with pointerup, it never ends.
//
// Therefore, when we detect that only one pointer is pressing the screen,
// we consider that the gesture can proceed.
ctrlIds &&
ctrlIds.size > 1 &&
state._pointerActive
)
return
this.start(event)
this.setupPointer(event)
state._pointerId = pointerId(event)
state._pointerActive = true
this.computeValues(pointerValues(event))
this.computeInitial()
if (config.preventScrollAxis && getPointerType(event) !== 'mouse') {
// when preventScrollAxis is set we don't consider the gesture active
// until it's deliberate
state._active = false
this.setupScrollPrevention(event)
} else if (config.delay > 0) {
this.setupDelayTrigger(event)
// makes sure we emit all events when `triggerAllEvents` flag is `true`
if (config.triggerAllEvents) {
this.compute(event)
this.emit()
}
} else {
this.startPointerDrag(event)
}
}
startPointerDrag(event: PointerEvent) {
const state = this.state
state._active = true
state._preventScroll = true
state._delayed = false
this.compute(event)
this.emit()
}
pointerMove(event: PointerEvent) {
const state = this.state
const config = this.config
if (!state._pointerActive) return
const id = pointerId(event)
if (state._pointerId !== undefined && id !== state._pointerId) return
const _values = pointerValues(event)
if (document.pointerLockElement === event.target) {
state._delta = [event.movementX, event.movementY]
} else {
state._delta = V.sub(_values, state._values)
this.computeValues(_values)
}
V.addTo(state._movement, state._delta)
this.compute(event)
// if the gesture is delayed but deliberate, then we can start it
// immediately.
if (state._delayed && state.intentional) {
this.timeoutStore.remove('dragDelay')
// makes sure `first` is still true when moving for the first time after a
// delay.
state.active = false
this.startPointerDrag(event)
return
}
if (config.preventScrollAxis && !state._preventScroll) {
if (state.axis) {
if (state.axis === config.preventScrollAxis || config.preventScrollAxis === 'xy') {
state._active = false
this.clean()
return
} else {
this.timeoutStore.remove('startPointerDrag')
this.startPointerDrag(event)
return
}
} else {
return
}
}
this.emit()
}
pointerUp(event: PointerEvent) {
this.ctrl.setEventIds(event)
// We release the pointer id if it has pointer capture
try {
if (this.config.pointerCapture && (event.target as HTMLElement).hasPointerCapture(event.pointerId)) {
// this shouldn't be necessary as it should be automatic when releasing the pointer
;(event.target as HTMLElement).releasePointerCapture(event.pointerId)
}
} catch {
if (process.env.NODE_ENV === 'development') {
// eslint-disable-next-line no-console
console.warn(
`[@use-gesture]: If you see this message, it's likely that you're using an outdated version of \`@react-three/fiber\`. \n\nPlease upgrade to the latest version.`
)
}
}
const state = this.state
const config = this.config
if (!state._active || !state._pointerActive) return
const id = pointerId(event)
if (state._pointerId !== undefined && id !== state._pointerId) return
this.state._pointerActive = false
this.setActive()
this.compute(event)
const [dx, dy] = state._distance
state.tap = dx <= config.tapsThreshold && dy <= config.tapsThreshold
if (state.tap && config.filterTaps) {
state._force = true
} else {
const [_dx, _dy] = state._delta
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) {
const _vx = Math.abs(_dx / state.timeDelta)
const _vy = Math.abs(_dy / state.timeDelta)
if (_vx > svx && Math.abs(_mx) > sx) state.swipe[0] = Math.sign(_dx)
if (_vy > svy && Math.abs(_my) > sy) state.swipe[1] = Math.sign(_dy)
}
}
this.emit()
}
pointerClick(event: MouseEvent) {
// event.detail indicates the number of buttons being pressed. When it's
// null, it's likely to be a keyboard event from the Enter Key that could
// be used for accessibility, and therefore shouldn't be prevented.
// See https://github.com/pmndrs/use-gesture/issues/530
if (!this.state.tap && event.detail > 0) {
event.preventDefault()
event.stopPropagation()
}
}
setupPointer(event: PointerEvent) {
const config = this.config
const device = config.device
if (process.env.NODE_ENV === 'development') {
try {
if (device === 'pointer' && config.preventScrollDelay === undefined) {
// @ts-ignore (warning for r3f)
const currentTarget = 'uv' in event ? event.sourceEvent.currentTarget : event.currentTarget
const style = window.getComputedStyle(currentTarget)
if (style.touchAction === 'auto') {
// eslint-disable-next-line no-console
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 {}
}
if (config.pointerLock) {
;(event.currentTarget as HTMLElement).requestPointerLock()
}
if (!config.pointerCapture) {
this.eventStore.add(this.sharedConfig.window, device, 'change', this.pointerMove.bind(this))
this.eventStore.add(this.sharedConfig.window, device, 'end', this.pointerUp.bind(this))
this.eventStore.add(this.sharedConfig.window, device, 'cancel', this.pointerUp.bind(this))
}
}
pointerClean() {
if (this.config.pointerLock && document.pointerLockElement === this.state.currentTarget) {
document.exitPointerLock()
}
}
preventScroll(event: PointerEvent) {
if (this.state._preventScroll && event.cancelable) {
event.preventDefault()
}
}
setupScrollPrevention(event: PointerEvent) {
// fixes https://github.com/pmndrs/use-gesture/issues/497
this.state._preventScroll = false
persistEvent(event)
// we add window listeners that will prevent the scroll when the user has started dragging
const remove = this.eventStore.add(this.sharedConfig.window, 'touch', 'change', this.preventScroll.bind(this), {
passive: false
})
this.eventStore.add(this.sharedConfig.window, 'touch', 'end', remove)
this.eventStore.add(this.sharedConfig.window, 'touch', 'cancel', remove)
this.timeoutStore.add('startPointerDrag', this.startPointerDrag.bind(this), this.config.preventScrollDelay!, event)
}
setupDelayTrigger(event: PointerEvent) {
this.state._delayed = true
this.timeoutStore.add(
'dragDelay',
() => {
// forces drag to start no matter the threshold when delay is reached
this.state._step = [0, 0]
this.startPointerDrag(event)
},
this.config.delay
)
}
keyDown(event: KeyboardEvent) {
// @ts-ignore
const deltaFn = KEYS_DELTA_MAP[event.key]
if (deltaFn) {
const state = this.state
const factor = event.shiftKey ? 10 : event.altKey ? 0.1 : 1
this.start(event)
state._delta = deltaFn(this.config.keyboardDisplacement, factor)
state._keyboardActive = true
V.addTo(state._movement, state._delta)
this.compute(event)
this.emit()
}
}
keyUp(event: KeyboardEvent) {
if (!(event.key in KEYS_DELTA_MAP)) return
this.state._keyboardActive = false
this.setActive()
this.compute(event)
this.emit()
}
bind(bindFunction: any) {
const device = this.config.device
bindFunction(device, 'start', this.pointerDown.bind(this))
if (this.config.pointerCapture) {
bindFunction(device, 'change', this.pointerMove.bind(this))
bindFunction(device, 'end', this.pointerUp.bind(this))
bindFunction(device, 'cancel', this.pointerUp.bind(this))
bindFunction('lostPointerCapture', '', this.pointerUp.bind(this))
}
if (this.config.keys) {
bindFunction('key', 'down', this.keyDown.bind(this))
bindFunction('key', 'up', this.keyUp.bind(this))
}
if (this.config.filterTaps) {
bindFunction('click', '', this.pointerClick.bind(this), { capture: true, passive: false })
}
}
}
function persistEvent(event: PointerEvent) {
// @ts-ignore
'persist' in event && typeof event.persist === 'function' && event.persist()
}

386
node_modules/@use-gesture/core/src/engines/Engine.ts generated vendored Normal file
View File

@@ -0,0 +1,386 @@
import { Controller } from '../Controller'
import { getEventDetails } from '../utils/events'
import { call } from '../utils/fn'
import { V, computeRubberband } from '../utils/maths'
import { GestureKey, IngKey, State, Vector2 } from '../types'
import { NonUndefined } from '../types'
/**
* The lib doesn't compute the kinematics on the last event of the gesture
* (i.e. for a drag gesture, the `pointerup` coordinates will generally match the
* last `pointermove` coordinates which would result in all drags ending with a
* `[0,0]` velocity). However, when the timestamp difference between the last
* event (ie pointerup) and the before last event (ie pointermove) is greater
* than BEFORE_LAST_KINEMATICS_DELAY, the kinematics are computed (which would
* mean that if you release your drag after stopping for more than
* BEFORE_LAST_KINEMATICS_DELAY, the velocity will be indeed 0).
*
* See https://github.com/pmndrs/use-gesture/issues/332 for more details.
*/
const BEFORE_LAST_KINEMATICS_DELAY = 32
// eslint-disable-next-line @typescript-eslint/no-unused-vars
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 event
*/
axisIntent?(event?: UIEvent): void
restrictToAxis?(movement: Vector2): void
}
export abstract class Engine<Key extends GestureKey> {
/**
* The Controller handling state.
*/
ctrl: Controller
/**
* The gesture key ('drag' | 'pinch' | 'wheel' | 'scroll' | 'move' | 'hover')
*/
readonly key: Key
/**
* The key representing the active state of the gesture in the shared state.
* ('dragging' | 'pinching' | 'wheeling' | 'scrolling' | 'moving' | 'hovering')
*/
abstract readonly ingKey: IngKey
/**
* The arguments passed to the `bind` function.
*/
/**
* State prop that aliases state values (`xy` or `da`).
*/
abstract readonly aliasKey: string
args: any[]
constructor(ctrl: Controller, args: any[], key: Key) {
this.ctrl = ctrl
this.args = args
this.key = key
if (!this.state) {
this.state = {} as any
this.computeValues([0, 0])
this.computeInitial()
if (this.init) this.init()
this.reset()
}
}
/**
* Function implemented by gestures that compute the offset from the state
* movement.
*/
abstract computeOffset(): void
/**
* Function implemented by the gestures that compute the movement from the
* corrected offset (after bounds and potential rubberbanding).
*/
abstract computeMovement(): void
/**
* Executes the bind function so that listeners are properly set by the
* Controller.
* @param bindFunction
*/
abstract bind(
bindFunction: (
device: string,
action: string,
handler: (event: any) => void,
options?: AddEventListenerOptions
) => void
): void
/**
* Shortcut to the gesture state read from the Controller.
*/
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]!
}
/**
* Shortcut to the gesture timeout store read from the Controller.
*/
get timeoutStore() {
return this.ctrl.gestureTimeoutStores[this.key]!
}
/**
* Shortcut to the gesture config read from the Controller.
*/
get config() {
return this.ctrl.config[this.key]!
}
/**
* Shortcut to the shared config read from the Controller.
*/
get sharedConfig() {
return this.ctrl.config.shared
}
/**
* Shortcut to the gesture handler read from the Controller.
*/
get handler() {
return this.ctrl.handlers[this.key]!
}
reset() {
const { state, shared, ingKey, args } = this
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._direction = [0, 0]
state._delta = [0, 0]
// prettier-ignore
state._bounds = [[-Infinity, Infinity], [-Infinity, Infinity]]
state.args = args
state.axis = undefined
state.memo = undefined
state.elapsedTime = state.timeDelta = 0
state.direction = [0, 0]
state.distance = [0, 0]
state.overflow = [0, 0]
state._movementBound = [false, false]
state.velocity = [0, 0]
state.movement = [0, 0]
state.delta = [0, 0]
state.timeStamp = 0
}
/**
* Function ran at the start of the gesture.
* @param event
*/
start(event: NonUndefined<State[Key]>['event']) {
const state = this.state
const config = this.config
if (!state._active) {
this.reset()
this.computeInitial()
state._active = true
state.target = event.target!
state.currentTarget = event.currentTarget!
state.lastOffset = config.from ? call(config.from, state) : state.offset
state.offset = state.lastOffset
state.startTime = state.timeStamp = event.timeStamp
}
}
/**
* Assign raw values to `state._values` and transformed values to
* `state.values`.
* @param values
*/
computeValues(values: Vector2) {
const state = this.state
state._values = values
// transforming values into user-defined coordinates (#402)
state.values = this.config.transform(values)
}
/**
* Assign `state._values` to `state._initial` and transformed `state.values` to
* `state.initial`.
* @param values
*/
computeInitial() {
const state = this.state
state._initial = state._values
state.initial = state.values
}
/**
* Computes all sorts of state attributes, including kinematics.
* @param event
*/
compute(event?: NonUndefined<State[Key]>['event']) {
const { state, config, shared } = this
state.args = this.args
let dt = 0
if (event) {
// sets the shared state with event properties
state.event = event
// if config.preventDefault is true, then preventDefault
if (config.preventDefault && event.cancelable) state.event.preventDefault()
state.type = event.type
shared.touches = this.ctrl.pointerIds.size || this.ctrl.touchIds.size
shared.locked = !!document.pointerLockElement
Object.assign(shared, getEventDetails(event))
shared.down = shared.pressed = shared.buttons % 2 === 1 || shared.touches > 0
// 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)
}
// let's run intentionality check.
if (this.axisIntent) this.axisIntent(event)
// _movement is calculated by each gesture engine
const [_m0, _m1] = state._movement
const [t0, t1] = config.threshold
const { _step, values } = state
if (config.hasCustomTransform) {
// When the user is using a custom transform, we're using `_step` to store
// the first value passing the threshold.
if (_step[0] === false) _step[0] = Math.abs(_m0) >= t0 && values[0]
if (_step[1] === false) _step[1] = Math.abs(_m1) >= t1 && values[1]
} else {
// `_step` will hold the threshold at which point the gesture was triggered.
// The threshold is signed depending on which direction triggered it.
if (_step[0] === false) _step[0] = Math.abs(_m0) >= t0 && Math.sign(_m0) * t0
if (_step[1] === false) _step[1] = Math.abs(_m1) >= t1 && Math.sign(_m1) * t1
}
state.intentional = _step[0] !== false || _step[1] !== false
if (!state.intentional) return
const movement: Vector2 = [0, 0]
if (config.hasCustomTransform) {
const [v0, v1] = values
movement[0] = _step[0] !== false ? v0 - _step[0] : 0
movement[1] = _step[1] !== false ? v1 - _step[1] : 0
} else {
movement[0] = _step[0] !== false ? _m0 - _step[0] : 0
movement[1] = _step[1] !== false ? _m1 - _step[1] : 0
}
if (this.restrictToAxis && !state._blocked) this.restrictToAxis(movement)
const previousOffset = state.offset
const gestureIsActive = (state._active && !state._blocked) || state.active
if (gestureIsActive) {
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()
}
state.movement = movement
this.computeOffset()
}
}
const [ox, oy] = state.offset
const [[x0, x1], [y0, y1]] = state._bounds
state.overflow = [ox < x0 ? -1 : ox > x1 ? 1 : 0, oy < y0 ? -1 : oy > y1 ? 1 : 0]
// _movementBound will store the latest _movement value
// before it went off bounds.
state._movementBound[0] = state.overflow[0]
? state._movementBound[0] === false
? state._movement[0]
: state._movementBound[0]
: false
state._movementBound[1] = state.overflow[1]
? state._movementBound[1] === false
? state._movement[1]
: state._movementBound[1]
: false
// @ts-ignore
const rubberband: Vector2 = state._active ? config.rubberband || [0, 0] : [0, 0]
state.offset = computeRubberband(state._bounds, state.offset, rubberband)
state.delta = V.sub(state.offset, previousOffset)
this.computeMovement()
if (gestureIsActive && (!state.last || dt > BEFORE_LAST_KINEMATICS_DELAY)) {
state.delta = V.sub(state.offset, previousOffset)
const absoluteDelta = state.delta.map(Math.abs) as Vector2
V.addTo(state.distance, absoluteDelta)
state.direction = state.delta.map(Math.sign) as Vector2
state._direction = state._delta.map(Math.sign) as Vector2
// calculates kinematics unless the gesture starts or ends or if the
// dt === 0 (which can happen on high frame rate monitors, see issue #581)
// because of privacy protection:
// https://developer.mozilla.org/en-US/docs/Web/API/Event/timeStamp#reduced_time_precision
if (!state.first && dt > 0) {
state.velocity = [absoluteDelta[0] / dt, absoluteDelta[1] / dt]
state.timeDelta = dt
}
}
}
/**
* Fires the gesture handler.
*/
emit() {
const state = this.state
const shared = this.shared
const config = this.config
if (!state._active) this.clean()
// we don't trigger the handler if the gesture is blocked or 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
// @ts-ignore
const memo = this.handler({ ...shared, ...state, [this.aliasKey]: state.values })
// 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()
}
}

View File

@@ -0,0 +1,38 @@
import { CoordinatesEngine } from './CoordinatesEngine'
import { pointerValues } from '../utils/events'
import { V } from '../utils/maths'
export class HoverEngine extends CoordinatesEngine<'hover'> {
ingKey = 'hovering' as const
enter(event: PointerEvent) {
if (this.config.mouseOnly && event.pointerType !== 'mouse') return
this.start(event)
this.computeValues(pointerValues(event))
this.compute(event)
this.emit()
}
leave(event: PointerEvent) {
if (this.config.mouseOnly && event.pointerType !== 'mouse') return
const state = this.state
if (!state._active) return
state._active = false
const values = pointerValues(event)
state._movement = state._delta = V.sub(values, state._values)
this.computeValues(values)
this.compute(event)
state.delta = state.movement
this.emit()
}
bind(bindFunction: any) {
bindFunction('pointer', 'enter', this.enter.bind(this))
bindFunction('pointer', 'leave', this.leave.bind(this))
}
}

View File

@@ -0,0 +1,47 @@
import { CoordinatesEngine } from './CoordinatesEngine'
import { pointerValues } from '../utils/events'
import { V } from '../utils/maths'
export class MoveEngine extends CoordinatesEngine<'move'> {
ingKey = 'moving' as const
move(event: PointerEvent) {
if (this.config.mouseOnly && event.pointerType !== 'mouse') return
if (!this.state._active) this.moveStart(event)
else this.moveChange(event)
this.timeoutStore.add('moveEnd', this.moveEnd.bind(this))
}
moveStart(event: PointerEvent) {
this.start(event)
this.computeValues(pointerValues(event))
this.compute(event)
this.computeInitial()
this.emit()
}
moveChange(event: PointerEvent) {
if (!this.state._active) return
const values = pointerValues(event)
const state = this.state
state._delta = V.sub(values, state._values)
V.addTo(state._movement, state._delta)
this.computeValues(values)
this.compute(event)
this.emit()
}
moveEnd(event?: PointerEvent) {
if (!this.state._active) return
this.state._active = false
this.compute(event)
this.emit()
}
bind(bindFunction: any) {
bindFunction('pointer', 'change', this.move.bind(this))
bindFunction('pointer', 'leave', this.moveEnd.bind(this))
}
}

View File

@@ -0,0 +1,313 @@
import { Engine } from './Engine'
import { touchDistanceAngle, distanceAngle, wheelValues } from '../utils/events'
import { V } from '../utils/maths'
import { Vector2, WebKitGestureEvent } from '../types'
import { clampStateInternalMovementToBounds } from '../utils/state'
const SCALE_ANGLE_RATIO_INTENT_DEG = 30
const PINCH_WHEEL_RATIO = 100
export class PinchEngine extends Engine<'pinch'> {
ingKey = 'pinching' as const
aliasKey = 'da'
init() {
this.state.offset = [1, 0]
this.state.lastOffset = [1, 0]
this.state._pointerEvents = new Map()
}
// superseeds generic Engine reset call
reset() {
super.reset()
const state = this.state
state._touchIds = []
state.canceled = false
state.cancel = this.cancel.bind(this)
state.turns = 0
}
computeOffset() {
const { type, movement, lastOffset } = this.state
if (type === 'wheel') {
this.state.offset = V.add(movement, lastOffset)
} else {
this.state.offset = [(1 + movement[0]) * lastOffset[0], movement[1] + lastOffset[1]]
}
}
computeMovement() {
const { offset, lastOffset } = this.state
this.state.movement = [offset[0] / lastOffset[0], offset[1] - lastOffset[1]]
}
axisIntent() {
const state = this.state
const [_m0, _m1] = state._movement
if (!state.axis) {
const axisMovementDifference = Math.abs(_m0) * SCALE_ANGLE_RATIO_INTENT_DEG - Math.abs(_m1)
if (axisMovementDifference < 0) state.axis = 'angle'
else if (axisMovementDifference > 0) state.axis = 'scale'
}
}
restrictToAxis(v: Vector2) {
if (this.config.lockDirection) {
if (this.state.axis === 'scale') v[1] = 0
else if (this.state.axis === 'angle') v[0] = 0
}
}
cancel() {
const state = this.state
if (state.canceled) return
setTimeout(() => {
state.canceled = true
state._active = false
// we run compute with no event so that kinematics won't be computed
this.compute()
this.emit()
}, 0)
}
touchStart(event: TouchEvent) {
this.ctrl.setEventIds(event)
const state = this.state
const ctrlTouchIds = this.ctrl.touchIds
if (state._active) {
// check that the touchIds that initiated the gesture are still enabled
// This is useful for when the page loses track of the pointers (minifying
// gesture on iPad).
if (state._touchIds.every((id) => ctrlTouchIds.has(id))) return
// The gesture is still active, but probably didn't have the opportunity to
// end properly, so we restart the pinch.
}
if (ctrlTouchIds.size < 2) return
this.start(event)
state._touchIds = Array.from(ctrlTouchIds).slice(0, 2) as [number, number]
const payload = touchDistanceAngle(event, state._touchIds)
if (!payload) return
this.pinchStart(event, payload)
}
pointerStart(event: PointerEvent) {
if (event.buttons != null && event.buttons % 2 !== 1) return
this.ctrl.setEventIds(event)
;(event.target as HTMLElement).setPointerCapture(event.pointerId)
const state = this.state
const _pointerEvents = state._pointerEvents
const ctrlPointerIds = this.ctrl.pointerIds
if (state._active) {
// see touchStart comment
if (Array.from(_pointerEvents.keys()).every((id) => ctrlPointerIds.has(id))) return
}
if (_pointerEvents.size < 2) {
_pointerEvents.set(event.pointerId, event)
}
if (state._pointerEvents.size < 2) return
this.start(event)
// @ts-ignore
const payload = distanceAngle(...Array.from(_pointerEvents.values()))
if (!payload) return
this.pinchStart(event, payload)
}
pinchStart(event: PointerEvent | TouchEvent, payload: { distance: number; angle: number; origin: Vector2 }) {
const state = this.state
state.origin = payload.origin
this.computeValues([payload.distance, payload.angle])
this.computeInitial()
this.compute(event)
this.emit()
}
touchMove(event: TouchEvent) {
if (!this.state._active) return
const payload = touchDistanceAngle(event, this.state._touchIds)
if (!payload) return
this.pinchMove(event, payload)
}
pointerMove(event: PointerEvent) {
const _pointerEvents = this.state._pointerEvents
if (_pointerEvents.has(event.pointerId)) {
_pointerEvents.set(event.pointerId, event)
}
if (!this.state._active) return
// @ts-ignore
const payload = distanceAngle(...Array.from(_pointerEvents.values()))
if (!payload) return
this.pinchMove(event, payload)
}
pinchMove(event: PointerEvent | TouchEvent, payload: { distance: number; angle: number; origin: Vector2 }) {
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)
this.computeValues([payload.distance, payload.angle - 360 * delta_turns])
state.origin = payload.origin
state.turns = delta_turns
state._movement = [state._values[0] / state._initial[0] - 1, state._values[1] - state._initial[1]]
this.compute(event)
this.emit()
}
touchEnd(event: TouchEvent) {
this.ctrl.setEventIds(event)
if (!this.state._active) return
if (this.state._touchIds.some((id) => !this.ctrl.touchIds.has(id))) {
this.state._active = false
this.compute(event)
this.emit()
}
}
pointerEnd(event: PointerEvent) {
const state = this.state
this.ctrl.setEventIds(event)
try {
// @ts-ignore r3f
event.target.releasePointerCapture(event.pointerId)
} catch {}
if (state._pointerEvents.has(event.pointerId)) {
state._pointerEvents.delete(event.pointerId)
}
if (!state._active) return
if (state._pointerEvents.size < 2) {
state._active = false
this.compute(event)
this.emit()
}
}
gestureStart(event: WebKitGestureEvent) {
if (event.cancelable) event.preventDefault()
const state = this.state
if (state._active) return
this.start(event)
this.computeValues([event.scale, event.rotation])
state.origin = [event.clientX, event.clientY]
this.compute(event)
this.emit()
}
gestureMove(event: WebKitGestureEvent) {
if (event.cancelable) event.preventDefault()
if (!this.state._active) return
const state = this.state
this.computeValues([event.scale, event.rotation])
state.origin = [event.clientX, event.clientY]
const _previousMovement = state._movement
state._movement = [event.scale - 1, event.rotation]
state._delta = V.sub(state._movement, _previousMovement)
this.compute(event)
this.emit()
}
gestureEnd(event: WebKitGestureEvent) {
if (!this.state._active) return
this.state._active = false
this.compute(event)
this.emit()
}
wheel(event: WheelEvent) {
const modifierKey = this.config.modifierKey
if (modifierKey && (Array.isArray(modifierKey) ? !modifierKey.find((k) => event[k]) : !event[modifierKey])) return
if (!this.state._active) this.wheelStart(event)
else this.wheelChange(event)
this.timeoutStore.add('wheelEnd', this.wheelEnd.bind(this))
}
wheelStart(event: WheelEvent) {
this.start(event)
this.wheelChange(event)
}
wheelChange(event: WheelEvent) {
const isR3f = 'uv' in event
if (!isR3f) {
if (event.cancelable) {
event.preventDefault()
}
if (process.env.NODE_ENV === 'development' && !event.defaultPrevented) {
// eslint-disable-next-line no-console
console.warn(
`[@use-gesture]: To properly support zoom on trackpads, try using the \`target\` option.\n\nThis message will only appear in development mode.`
)
}
}
const state = this.state
state._delta = [(-wheelValues(event)[1] / PINCH_WHEEL_RATIO) * state.offset[0], 0]
V.addTo(state._movement, state._delta)
// _movement rolls back to when it passed the bounds.
clampStateInternalMovementToBounds(state)
this.state.origin = [event.clientX, event.clientY]
this.compute(event)
this.emit()
}
wheelEnd() {
if (!this.state._active) return
this.state._active = false
this.compute()
this.emit()
}
bind(bindFunction: any) {
const device = this.config.device
if (!!device) {
// @ts-ignore
bindFunction(device, 'start', this[device + 'Start'].bind(this))
// @ts-ignore
bindFunction(device, 'change', this[device + 'Move'].bind(this))
// @ts-ignore
bindFunction(device, 'end', this[device + 'End'].bind(this))
// @ts-ignore
bindFunction(device, 'cancel', this[device + 'End'].bind(this))
// @ts-ignore
bindFunction('lostPointerCapture', '', this[device + 'End'].bind(this))
}
// we try to set a passive listener, knowing that in any case React will
// ignore it.
if (this.config.pinchOnWheel) {
bindFunction('wheel', '', this.wheel.bind(this), { passive: false })
}
}
}

View File

@@ -0,0 +1,37 @@
import { CoordinatesEngine } from './CoordinatesEngine'
import { scrollValues } from '../utils/events'
import { V } from '../utils/maths'
export class ScrollEngine extends CoordinatesEngine<'scroll'> {
ingKey = 'scrolling' as const
scroll(event: UIEvent) {
if (!this.state._active) this.start(event)
this.scrollChange(event)
this.timeoutStore.add('scrollEnd', this.scrollEnd.bind(this))
}
scrollChange(event: UIEvent) {
if (event.cancelable) event.preventDefault()
const state = this.state
const values = scrollValues(event)
state._delta = V.sub(values, state._values)
V.addTo(state._movement, state._delta)
this.computeValues(values)
this.compute(event)
this.emit()
}
scrollEnd() {
if (!this.state._active) return
this.state._active = false
this.compute()
this.emit()
}
bind(bindFunction: any) {
bindFunction('scroll', '', this.scroll.bind(this))
}
}

View File

@@ -0,0 +1,43 @@
import { CoordinatesEngine } from './CoordinatesEngine'
import { wheelValues } from '../utils/events'
import { V } from '../utils/maths'
import { clampStateInternalMovementToBounds } from '../utils/state'
export interface WheelEngine extends CoordinatesEngine<'wheel'> {
wheel(this: WheelEngine, event: WheelEvent): void
wheelChange(this: WheelEngine, event: WheelEvent): void
wheelEnd(this: WheelEngine): void
}
export class WheelEngine extends CoordinatesEngine<'wheel'> {
ingKey = 'wheeling' as const
wheel(event: WheelEvent) {
if (!this.state._active) this.start(event)
this.wheelChange(event)
this.timeoutStore.add('wheelEnd', this.wheelEnd.bind(this))
}
wheelChange(event: WheelEvent) {
const state = this.state
state._delta = wheelValues(event)
V.addTo(state._movement, state._delta)
// _movement rolls back to when it passed the bounds.
clampStateInternalMovementToBounds(state)
this.compute(event)
this.emit()
}
wheelEnd() {
if (!this.state._active) return
this.state._active = false
this.compute()
this.emit()
}
bind(bindFunction: any) {
bindFunction('wheel', '', this.wheel.bind(this))
}
}

2
node_modules/@use-gesture/core/src/index.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
export { Controller } from './Controller'
export { parseMergedHandlers } from './parser'

78
node_modules/@use-gesture/core/src/parser.ts generated vendored Normal file
View File

@@ -0,0 +1,78 @@
import { FullGestureState, GestureHandlers, GestureKey, InternalHandlers, UserGestureConfig } from './types'
import { EngineMap } from './actions'
const RE_NOT_NATIVE = /^on(Drag|Wheel|Scroll|Move|Pinch|Hover)/
function sortHandlers(_handlers: GestureHandlers) {
const native: any = {}
const handlers: InternalHandlers = {}
const actions = new Set()
for (let key in _handlers) {
if (RE_NOT_NATIVE.test(key)) {
actions.add(RegExp.lastMatch)
// @ts-ignore
handlers[key] = _handlers[key]
} else {
// @ts-ignore
native[key] = _handlers[key]
}
}
return [handlers, native, actions]
}
type HandlerKey = 'onDrag' | 'onPinch' | 'onWheel' | 'onMove' | 'onScroll' | 'onHover'
function registerGesture(
actions: Set<unknown>,
handlers: GestureHandlers,
handlerKey: HandlerKey,
key: GestureKey,
internalHandlers: any,
config: any
) {
if (!actions.has(handlerKey)) return
if (!EngineMap.has(key)) {
if (process.env.NODE_ENV === 'development') {
// eslint-disable-next-line no-console
console.warn(
`[@use-gesture]: You've created a custom handler that that uses the \`${key}\` gesture but isn't properly configured.\n\nPlease add \`${key}Action\` when creating your handler.`
)
}
return
}
const startKey = handlerKey + 'Start'
const endKey = handlerKey + 'End'
const fn = (state: FullGestureState<GestureKey>) => {
let memo = undefined
// @ts-ignore
if (state.first && startKey in handlers) handlers[startKey](state)
// @ts-ignore
if (handlerKey in handlers) memo = handlers[handlerKey](state)
// @ts-ignore
if (state.last && endKey in handlers) handlers[endKey](state)
return memo
}
internalHandlers[key] = fn
config[key] = config[key] || {}
}
export function parseMergedHandlers(mergedHandlers: GestureHandlers, mergedConfig: UserGestureConfig) {
const [handlers, nativeHandlers, actions] = sortHandlers(mergedHandlers)
const internalHandlers = {}
registerGesture(actions, handlers, 'onDrag', 'drag', internalHandlers, mergedConfig)
registerGesture(actions, handlers, 'onWheel', 'wheel', internalHandlers, mergedConfig)
registerGesture(actions, handlers, 'onScroll', 'scroll', internalHandlers, mergedConfig)
registerGesture(actions, handlers, 'onPinch', 'pinch', internalHandlers, mergedConfig)
registerGesture(actions, handlers, 'onMove', 'move', internalHandlers, mergedConfig)
registerGesture(actions, handlers, 'onHover', 'hover', internalHandlers, mergedConfig)
return { handlers: internalHandlers, config: mergedConfig, nativeHandlers }
}

3
node_modules/@use-gesture/core/src/types.ts generated vendored Normal file
View File

@@ -0,0 +1,3 @@
// type exports for core
export * from './types/index'

14
node_modules/@use-gesture/core/src/types/action.ts generated vendored Normal file
View File

@@ -0,0 +1,14 @@
import type { ResolverMap } from '../config/resolver'
import type { Controller } from '../Controller'
import type { Engine } from '../engines/Engine'
import { GestureKey } from './config'
export type EngineClass<Key extends GestureKey> = {
new (controller: Controller, args: any[], key: Key): Engine<Key>
}
export type Action = {
key: GestureKey
engine: EngineClass<GestureKey>
resolver: ResolverMap
}

250
node_modules/@use-gesture/core/src/types/config.ts generated vendored Normal file
View File

@@ -0,0 +1,250 @@
import { State } from './state'
import { Vector2, Target, PointerType, NonUndefined } from './utils'
export type GestureKey = Exclude<keyof State, 'shared'>
export type CoordinatesKey = Exclude<GestureKey, 'pinch'>
export type GenericOptions = {
/**
* Lets you specify a dom node or ref you want to attach the gesture to.
*/
target?: Target
/**
* Lets you specify which window element the gesture should bind events to
* (only relevant for the drag gesture).
*/
window?: EventTarget
/**
* Lets you customize if you want events to be passive or captured.
*/
eventOptions?: AddEventListenerOptions
/**
* When set to false none of the handlers will be fired.
*/
enabled?: boolean
/**
* A function that you can use to transform movement and offset values. Useful
* to map your screen coordinates to custom space coordinates such as a
* canvas.
*/
transform?: (v: Vector2) => Vector2
}
export type GestureOptions<T extends GestureKey> = GenericOptions & {
/**
* Whether the gesture is enabled.
*/
enabled?: boolean
/**
* Lets you customize if you want events to be passive or captured.
*/
eventOptions?: AddEventListenerOptions
/**
* The position `offset` will start from.
*/
from?: Vector2 | ((state: NonUndefined<State[T]>) => Vector2)
/**
* The handler will fire only when the gesture displacement is greater than
* the threshold.
*/
threshold?: number | Vector2
/**
* The handler will preventDefault all events when `true`.
*/
preventDefault?: boolean
/**
* Forces the handler to fire even for non intentional displacement (ignores
* the threshold). In that case, the intentional attribute from state will
* remain false until the threshold is reached.
*/
triggerAllEvents?: boolean
/**
* The elasticity coefficient of the gesture when going out of bounds. When
* set to true, the elasticiy coefficient will be defaulted to 0.15
*/
rubberband?: boolean | number | Vector2
/**
* A function that you can use to transform movement and offset values. Useful
* to map your screen coordinates to custom space coordinates such as a
* canvas.
*/
transform?: (v: Vector2) => Vector2
}
export type Bounds = {
top?: number
bottom?: number
left?: number
right?: number
}
export type CoordinatesConfig<Key extends CoordinatesKey = CoordinatesKey> = GestureOptions<Key> & {
/**
* The handler will only trigger if a movement is detected on the specified
* axis.
*/
axis?: 'x' | 'y' | 'lock'
/**
* Limits the gesture `offset` to the specified bounds.
*/
bounds?: Bounds | ((state: State[Key]) => Bounds)
/**
* Determines the number of pixels in one direction needed for axises to be
* calculated.
*/
axisThreshold?: number
}
export type PinchBounds = { min?: number; max?: number }
export type ModifierKey = 'ctrlKey' | 'altKey' | 'metaKey' | null
export type PinchConfig = GestureOptions<'pinch'> & {
pointer?: {
/**
* If true, pinch will use touch events on touch-enabled devices.
*/
touch?: boolean
}
/**
* Limits the scale `offset` to the specified bounds.
*/
scaleBounds?: PinchBounds | ((state: State['pinch']) => PinchBounds)
/**
* Limits the angle `offset` to the specified bounds.
*/
angleBounds?: PinchBounds | ((state: State['pinch']) => PinchBounds)
/**
* Scales OR rotates when set to 'lock'.
*/
axis?: 'lock' | undefined
/**
* Key that triggers scale when using the wheel. Defaults to `'ctrlKey'`.
*/
modifierKey?: ModifierKey | NonNullable<ModifierKey>[]
/**
* Whether wheel should trigger a pinch at all.
*/
pinchOnWheel?: boolean
}
export type DragBounds = Bounds | HTMLElement | { current: HTMLElement | null }
type MoveAndHoverMouseOnly = {
/**
* If false, onMove or onHover handlers will also fire on touch devices.
*/
mouseOnly?: boolean
}
export type MoveConfig = CoordinatesConfig<'move'> & MoveAndHoverMouseOnly
export type HoverConfig = MoveAndHoverMouseOnly
export type DragConfig = Omit<CoordinatesConfig<'drag'>, 'axisThreshold' | 'bounds'> & {
/**
* If true, the component won't trigger your drag logic if the user just clicked on the component.
*/
filterTaps?: boolean
/**
* The maximum total displacement a tap can have
*/
tapsThreshold?: number
/**
* Set this option to true when using with @react-three/fiber objects.
*/
/**
* Limits the gesture `offset` to the specified bounds. Can be a ref or a dom
* node.
*/
bounds?: DragBounds | ((state: State['drag']) => DragBounds)
pointer?: {
/**
* The buttons combination that would trigger the drag. Use `-1` to allow
* for any button combination to start the drag.
*/
buttons?: number | number[]
/**
* If true, drag will use touch events on touch-enabled devices.
*/
touch?: boolean
/**
* If true, drag will use touch events on touch-enabled devices, and use
* mouse events on non touch devices.
*/
mouse?: boolean
/**
* If false, will disable KeyboardEvents that would otherwise trigger the
* drag gesture when the element is focused. Defaults to true.
*/
keys?: boolean
/**
* Doesn't use setPointerCapture when false and delegate drag handling to
* window
*/
capture?: boolean
/**
* Will perform a pointer lock when drag starts, and exit pointer lock when
* drag ends,
*/
lock?: boolean
}
swipe?: {
/**
* The minimum velocity per axis (in pixels / ms) the drag gesture needs to
* reach before the pointer is released.
*/
velocity?: number | Vector2
/**
* The minimum distance per axis (in pixels) the drag gesture needs to
* travel to trigger a swipe. Defaults to 50.
*/
distance?: number | Vector2
/**
* The maximum duration in milliseconds that a swipe is detected. Defaults
* to 250.
*/
duration?: number
}
/**
* If set, the drag will be triggered after the duration of the delay (in ms).
* When set to true, delay is defaulted to 250ms.
*/
preventScroll?: boolean | number
/**
* If set, the drag will allow scrolling in the direction of this axis until
* the preventScroll duration has elapsed. Defaults to only 'y'.
*/
preventScrollAxis?: 'x' | 'y' | 'xy'
/**
* If set, the handler will be delayed for the duration of the delay (in ms)
* — or if the user starts moving. When set to true, delay is defaulted
* to 180ms.
*/
delay?: boolean | number
/**
* Key-number record that determines for each device (`'mouse'`, `'touch'`,
* `'pen'`) the number of pixels of drag in one direction needed for axises to
* be calculated.
*/
axisThreshold?: Partial<Record<PointerType, number>>
/**
* The distance (in pixels) emulated by arrow keys.
*/
keyboardDisplacement?: number
}
export type UserDragConfig = GenericOptions & DragConfig
export type UserPinchConfig = GenericOptions & PinchConfig
export type UserWheelConfig = GenericOptions & CoordinatesConfig<'wheel'>
export type UserScrollConfig = GenericOptions & CoordinatesConfig<'scroll'>
export type UserMoveConfig = GenericOptions & MoveConfig
export type UserHoverConfig = GenericOptions & HoverConfig
export type UserGestureConfig = GenericOptions & {
drag?: DragConfig
wheel?: CoordinatesConfig<'wheel'>
scroll?: CoordinatesConfig<'scroll'>
move?: MoveConfig
pinch?: PinchConfig
hover?: { enabled?: boolean } & HoverConfig
}

61
node_modules/@use-gesture/core/src/types/handlers.ts generated vendored Normal file
View File

@@ -0,0 +1,61 @@
import { FullGestureState, State, EventTypes } from './state'
import { GestureKey } from './config'
import { DOMHandlers, EventHandler } from './utils'
export type Handler<Key extends GestureKey, EventType = EventTypes[Key]> = (
state: Omit<FullGestureState<Key>, 'event'> & { event: EventType }
) => any | void
// if no type is provided in the user generic for a given key
// then return the default EventTypes that key
type check<T extends AnyHandlerEventTypes, Key extends GestureKey> = undefined extends T[Key] ? EventTypes[Key] : T[Key]
export type UserHandlers<T extends AnyHandlerEventTypes = EventTypes> = {
onDrag: Handler<'drag', check<T, 'drag'>>
onDragStart: Handler<'drag', check<T, 'drag'>>
onDragEnd: Handler<'drag', check<T, 'drag'>>
onPinch: Handler<'pinch', check<T, 'pinch'>>
onPinchStart: Handler<'pinch', check<T, 'pinch'>>
onPinchEnd: Handler<'pinch', check<T, 'pinch'>>
onWheel: Handler<'wheel', check<T, 'wheel'>>
onWheelStart: Handler<'wheel', check<T, 'wheel'>>
onWheelEnd: Handler<'wheel', check<T, 'wheel'>>
onMove: Handler<'move', check<T, 'move'>>
onMoveStart: Handler<'move', check<T, 'move'>>
onMoveEnd: Handler<'move', check<T, 'move'>>
onScroll: Handler<'scroll', check<T, 'scroll'>>
onScrollStart: Handler<'scroll', check<T, 'scroll'>>
onScrollEnd: Handler<'scroll', check<T, 'scroll'>>
onHover: Handler<'hover', check<T, 'hover'>>
}
type NativeHandlersKeys = keyof Omit<DOMHandlers, keyof UserHandlers>
type GetEventType<Key extends NativeHandlersKeys> = DOMHandlers[Key] extends EventHandler<infer EventType> | undefined
? EventType
: UIEvent
export type NativeHandlers<T extends AnyHandlerEventTypes = {}> = {
[key in NativeHandlersKeys]?: (
state: State['shared'] & { event: undefined extends T[key] ? GetEventType<key> : T[key]; args: any },
...args: any
) => void
}
// allows overriding the event type from the returned state in handlers
export type AnyHandlerEventTypes = Partial<
{
drag: any
wheel: any
scroll: any
move: any
pinch: any
hover: any
} & { [key in NativeHandlersKeys]: any }
>
export type GestureHandlers<HandlerType extends AnyHandlerEventTypes = EventTypes> = Partial<
NativeHandlers<HandlerType> & UserHandlers<HandlerType>
>
export type InternalHandlers = { [Key in GestureKey]?: Handler<Key, any> }

6
node_modules/@use-gesture/core/src/types/index.ts generated vendored Normal file
View File

@@ -0,0 +1,6 @@
export * from './config'
export * from './internalConfig'
export * from './state'
export * from './utils'
export * from './handlers'
export * from './action'

View File

@@ -0,0 +1,74 @@
import { GestureKey, CoordinatesKey, ModifierKey } from './config'
import { State } from './state'
import { PointerType, Vector2 } from './utils'
export type InternalGenericOptions = {
target?: () => EventTarget
eventOptions: AddEventListenerOptions
window: EventTarget
enabled: boolean
transform?: (v: Vector2) => Vector2
}
export type InternalGestureOptions<Key extends GestureKey = GestureKey> = {
enabled: boolean
eventOptions: AddEventListenerOptions
from: Vector2 | ((state: State[Key]) => Vector2)
threshold: Vector2
preventDefault: boolean
triggerAllEvents: boolean
rubberband: Vector2
bounds: [Vector2, Vector2] | ((state: State[Key]) => [Vector2, Vector2])
hasCustomTransform: boolean
transform: (v: Vector2) => Vector2
}
export type InternalCoordinatesOptions<Key extends CoordinatesKey = CoordinatesKey> = InternalGestureOptions<Key> & {
axis?: 'x' | 'y'
lockDirection: boolean
axisThreshold: number
}
export type InternalDragOptions = Omit<InternalCoordinatesOptions<'drag'>, 'axisThreshold'> & {
filterTaps: boolean
tapsThreshold: number
pointerButtons: number | number[]
pointerCapture: boolean
preventScrollDelay?: number
preventScrollAxis?: 'x' | 'y' | 'xy'
pointerLock: boolean
keys: boolean
device: 'pointer' | 'touch' | 'mouse'
swipe: {
velocity: Vector2
distance: Vector2
duration: number
}
delay: number
axisThreshold: Record<PointerType, number>
keyboardDisplacement: number
}
export type InternalPinchOptions = InternalGestureOptions<'pinch'> & {
/**
* When device is undefined, we'll be using wheel to zoom.
*/
device: 'gesture' | 'pointer' | 'touch' | undefined
lockDirection: boolean
modifierKey: ModifierKey | NonNullable<ModifierKey>[]
pinchOnWheel: boolean
}
type MoveAndHoverMouseOnly = {
mouseOnly: boolean
}
export type InternalConfig = {
shared: InternalGenericOptions
drag?: InternalDragOptions
wheel?: InternalCoordinatesOptions<'wheel'>
scroll?: InternalCoordinatesOptions<'scroll'>
move?: InternalCoordinatesOptions<'move'> & MoveAndHoverMouseOnly
hover?: InternalCoordinatesOptions<'hover'> & MoveAndHoverMouseOnly
pinch?: InternalPinchOptions
}

269
node_modules/@use-gesture/core/src/types/state.ts generated vendored Normal file
View File

@@ -0,0 +1,269 @@
import { GestureKey } from './config'
import { NonUndefined, Vector2, WebKitGestureEvent } from './utils'
export type IngKey = 'dragging' | 'wheeling' | 'moving' | 'hovering' | 'scrolling' | 'pinching'
export type SharedGestureState = {
/**
* True if the element is being dragged.
*/
dragging?: boolean
/**
* True if the element is being wheeled.
*/
wheeling?: boolean
/**
* True if the element is being moved.
*/
moving?: boolean
/**
* True if the element is being hovered.
*/
hovering?: boolean
/**
* True if the element is being scrolled.
*/
scrolling?: boolean
/**
* True if the element is being pinched.
*/
pinching?: boolean
/**
* Number of fingers touching the screen.
*/
touches: number
/**
* True when the main mouse button or touch is pressed.
*/
pressed: boolean
/**
* Alias for pressed.
*/
down: boolean
/**
* True if the document is in lock mode.
*/
locked: boolean
/**
* Indicates which buttons are pressed (https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons).
*/
buttons: number
/**
* True when the Shift key is pressed.
*/
shiftKey: boolean
/**
* True when the Alt key is pressed.
*/
altKey: boolean
/**
* True when the Meta key is pressed.
*/
metaKey: boolean
/**
* True when the Control key is pressed.
*/
ctrlKey: boolean
}
export type CommonGestureState = {
_active: boolean
_blocked: boolean
_force: boolean
_step: [false | number, false | number]
_movementBound: [false | number, false | number]
_values: Vector2
_initial: Vector2
_movement: Vector2
_distance: Vector2
_direction: Vector2
_delta: Vector2
_bounds: [Vector2, Vector2]
/**
* The event triggering the gesture.
*/
event: UIEvent
/**
* The event target.
*/
target: EventTarget
/**
* The event current target.
*/
currentTarget: EventTarget
/**
* True when the gesture is intentional (passed the threshold).
*/
intentional: boolean
/**
* Cumulative distance of the gesture. Deltas are summed with their absolute
* values.
*/
distance: Vector2
/**
* Displacement of the current gesture.
*/
movement: Vector2
/**
* Difference between the current movement and the previous movement.
*/
delta: Vector2
/**
* Cumulative displacements of all gestures (sum of all movements triggered
* by the handler)
*/
offset: Vector2
/**
* Offset when the gesture started.
*/
lastOffset: Vector2
/**
* Velocity vector.
*/
velocity: Vector2
/**
* Current raw values of the gesture. Can be coordinates or distance / angle
* depending on the gesture.
*/
values: Vector2
/**
* Raw values when the gesture started.
*/
initial: Vector2
/**
* Direction per axis. `-1` when going down, `1` when going up, `0` when still.
*/
direction: Vector2
/**
* Bound overflow per axis. `-1` when overflowing bounds to the left/top, `1` when overflowing bounds to the right/bottom.
*/
overflow: Vector2
/**
* True when it's the first event of the active gesture.
*/
first: boolean
/**
* True when it's the last event of the active gesture.
*/
last: boolean
/**
* True when the gesture is active.
*/
active: boolean
/**
* The timestamp (ms) of when the gesture started.
*/
startTime: number
/**
* The timestamp (ms) of the current event.
*/
timeStamp: number
/**
* Elapsed time (ms) of the current gesture.
*/
elapsedTime: number
/**
* Time delta (ms) with the previous event.
*/
timeDelta: number
/**
* Event type.
*/
type: string
/**
* Value returned by your handler on its previous run.
*/
memo?: any
/**
* The arguments passed to the bind function (only relevant in React when
* using `<div {...bind(someArgument)} />`)
*/
args?: any
}
export type CoordinatesState = CommonGestureState & {
/**
* The initial axis (x or y) of the gesture.
*/
axis: 'x' | 'y' | undefined
/**
* Pointer coordinates (alias to values)
*/
xy: Vector2
}
export type DragState = CoordinatesState & {
_pointerId?: number
_pointerActive: boolean
_keyboardActive: boolean
_preventScroll: boolean
_delayed: boolean
/**
* True when the drag gesture has been canceled by the `cancel` function.
*/
canceled: boolean
/**
* Function that can be called to cancel the drag.
*/
cancel(): void
/**
* True if the drag gesture is recognized as a tap (ie when the displacement
* is lower than 3px per axis).
*/
tap: boolean
/**
* [swipeX, swipeY] is [0, 0] if no swipe detected, -1 or 1 otherwise.
*/
swipe: Vector2
}
export interface PinchState extends CommonGestureState {
_pointerEvents: Map<number, PointerEvent>
_touchIds: [] | [number, number]
/**
* Distance and angle raw values (alias to values).
*/
da: Vector2
/**
* The initial axis (scale or angle) of the gesture.
*/
axis: 'scale' | 'angle' | undefined
/**
* Coordinates of the center of touch events, or the cursor when using wheel
* to pinch.
*/
origin: Vector2
/**
* The number of full rotation the current gesture has performed.
*/
turns: number
/**
* True when the pinch gesture has been canceled by the `cancel` function.
*/
canceled: boolean
/**
* Function that can be called to cancel the pinch.
*/
cancel(): void
}
export type EventTypes = {
drag: PointerEvent | TouchEvent | MouseEvent | KeyboardEvent
wheel: WheelEvent
scroll: UIEvent
move: PointerEvent
hover: PointerEvent
pinch: PointerEvent | TouchEvent | WheelEvent | WebKitGestureEvent
}
export interface State {
shared: SharedGestureState
drag?: DragState & { event: EventTypes['drag'] }
wheel?: CoordinatesState & { event: EventTypes['wheel'] }
scroll?: CoordinatesState & { event: EventTypes['scroll'] }
move?: CoordinatesState & { event: EventTypes['move'] }
hover?: CoordinatesState & { event: EventTypes['hover'] }
pinch?: PinchState & { event: EventTypes['pinch'] }
}
export type FullGestureState<Key extends GestureKey> = SharedGestureState & NonUndefined<State[Key]>

197
node_modules/@use-gesture/core/src/types/utils.ts generated vendored Normal file
View File

@@ -0,0 +1,197 @@
export type Vector2 = [number, number]
export type WebKitGestureEvent = PointerEvent & { scale: number; rotation: number }
export type Target = EventTarget | { current: EventTarget | null }
export type PointerType = 'mouse' | 'touch' | 'pen'
// replaces NonUndefined from 4.7 and inferior versions
export type NonUndefined<T> = T extends undefined ? never : T
export type EventHandler<E extends Event = Event> = (event: E) => void
// rip off from React types
export interface DOMHandlers {
// Clipboard Events
onCopy?: EventHandler<ClipboardEvent>
onCopyCapture?: EventHandler<ClipboardEvent>
onCut?: EventHandler<ClipboardEvent>
onCutCapture?: EventHandler<ClipboardEvent>
onPaste?: EventHandler<ClipboardEvent>
onPasteCapture?: EventHandler<ClipboardEvent>
// Composition Events
onCompositionEnd?: EventHandler<CompositionEvent>
onCompositionEndCapture?: EventHandler<CompositionEvent>
onCompositionStart?: EventHandler<CompositionEvent>
onCompositionStartCapture?: EventHandler<CompositionEvent>
onCompositionUpdate?: EventHandler<CompositionEvent>
onCompositionUpdateCapture?: EventHandler<CompositionEvent>
// Focus Events
onFocus?: EventHandler<FocusEvent>
onFocusCapture?: EventHandler<FocusEvent>
onBlur?: EventHandler<FocusEvent>
onBlurCapture?: EventHandler<FocusEvent>
// Form Events
onChange?: EventHandler<FormDataEvent>
onChangeCapture?: EventHandler<FormDataEvent>
onBeforeInput?: EventHandler<FormDataEvent>
onBeforeInputCapture?: EventHandler<FormDataEvent>
onInput?: EventHandler<FormDataEvent>
onInputCapture?: EventHandler<FormDataEvent>
onReset?: EventHandler<FormDataEvent>
onResetCapture?: EventHandler<FormDataEvent>
onSubmit?: EventHandler<FormDataEvent>
onSubmitCapture?: EventHandler<FormDataEvent>
onInvalid?: EventHandler<FormDataEvent>
onInvalidCapture?: EventHandler<FormDataEvent>
// Image Events
onLoad?: EventHandler
onLoadCapture?: EventHandler
onError?: EventHandler // also a Media Event
onErrorCapture?: EventHandler // also a Media Event
// Keyboard Events
onKeyDown?: EventHandler<KeyboardEvent>
onKeyDownCapture?: EventHandler<KeyboardEvent>
onKeyUp?: EventHandler<KeyboardEvent>
onKeyUpCapture?: EventHandler<KeyboardEvent>
// Media Events
onAbort?: EventHandler
onAbortCapture?: EventHandler
onCanPlay?: EventHandler
onCanPlayCapture?: EventHandler
onCanPlayThrough?: EventHandler
onCanPlayThroughCapture?: EventHandler
onDurationChange?: EventHandler
onDurationChangeCapture?: EventHandler
onEmptied?: EventHandler
onEmptiedCapture?: EventHandler
onEncrypted?: EventHandler
onEncryptedCapture?: EventHandler
onEnded?: EventHandler
onEndedCapture?: EventHandler
onLoadedData?: EventHandler
onLoadedDataCapture?: EventHandler
onLoadedMetadata?: EventHandler
onLoadedMetadataCapture?: EventHandler
onLoadStart?: EventHandler
onLoadStartCapture?: EventHandler
onPause?: EventHandler
onPauseCapture?: EventHandler
onPlay?: EventHandler
onPlayCapture?: EventHandler
onPlaying?: EventHandler
onPlayingCapture?: EventHandler
onProgress?: EventHandler
onProgressCapture?: EventHandler
onRateChange?: EventHandler
onRateChangeCapture?: EventHandler
onSeeked?: EventHandler
onSeekedCapture?: EventHandler
onSeeking?: EventHandler
onSeekingCapture?: EventHandler
onStalled?: EventHandler
onStalledCapture?: EventHandler
onSuspend?: EventHandler
onSuspendCapture?: EventHandler
onTimeUpdate?: EventHandler
onTimeUpdateCapture?: EventHandler
onVolumeChange?: EventHandler
onVolumeChangeCapture?: EventHandler
onWaiting?: EventHandler
onWaitingCapture?: EventHandler
// MouseEvents
onAuxClick?: EventHandler<MouseEvent>
onAuxClickCapture?: EventHandler<MouseEvent>
onClick?: EventHandler<MouseEvent>
onClickCapture?: EventHandler<MouseEvent>
onContextMenu?: EventHandler<MouseEvent>
onContextMenuCapture?: EventHandler<MouseEvent>
onDoubleClick?: EventHandler<MouseEvent>
onDoubleClickCapture?: EventHandler<MouseEvent>
onDrag?: EventHandler<DragEvent>
onDragCapture?: EventHandler<DragEvent>
onDragEnd?: EventHandler<DragEvent>
onDragEndCapture?: EventHandler<DragEvent>
onDragEnter?: EventHandler<DragEvent>
onDragEnterCapture?: EventHandler<DragEvent>
onDragExit?: EventHandler<DragEvent>
onDragExitCapture?: EventHandler<DragEvent>
onDragLeave?: EventHandler<DragEvent>
onDragLeaveCapture?: EventHandler<DragEvent>
onDragOver?: EventHandler<DragEvent>
onDragOverCapture?: EventHandler<DragEvent>
onDragStart?: EventHandler<DragEvent>
onDragStartCapture?: EventHandler<DragEvent>
onDrop?: EventHandler<DragEvent>
onDropCapture?: EventHandler<DragEvent>
onMouseDown?: EventHandler<MouseEvent>
onMouseDownCapture?: EventHandler<MouseEvent>
onMouseEnter?: EventHandler<MouseEvent>
onMouseLeave?: EventHandler<MouseEvent>
onMouseMove?: EventHandler<MouseEvent>
onMouseMoveCapture?: EventHandler<MouseEvent>
onMouseOut?: EventHandler<MouseEvent>
onMouseOutCapture?: EventHandler<MouseEvent>
onMouseOver?: EventHandler<MouseEvent>
onMouseOverCapture?: EventHandler<MouseEvent>
onMouseUp?: EventHandler<MouseEvent>
onMouseUpCapture?: EventHandler<MouseEvent>
// Selection Events
onSelect?: EventHandler
onSelectCapture?: EventHandler
// Touch Events
onTouchCancel?: EventHandler<TouchEvent>
onTouchCancelCapture?: EventHandler<TouchEvent>
onTouchEnd?: EventHandler<TouchEvent>
onTouchEndCapture?: EventHandler<TouchEvent>
onTouchMove?: EventHandler<TouchEvent>
onTouchMoveCapture?: EventHandler<TouchEvent>
onTouchStart?: EventHandler<TouchEvent>
onTouchStartCapture?: EventHandler<TouchEvent>
// Pointer Events
onPointerDown?: EventHandler<PointerEvent>
onPointerDownCapture?: EventHandler<PointerEvent>
onPointerMove?: EventHandler<PointerEvent>
onPointerMoveCapture?: EventHandler<PointerEvent>
onPointerUp?: EventHandler<PointerEvent>
onPointerUpCapture?: EventHandler<PointerEvent>
onPointerCancel?: EventHandler<PointerEvent>
onPointerCancelCapture?: EventHandler<PointerEvent>
onPointerEnter?: EventHandler<PointerEvent>
onPointerLeave?: EventHandler<PointerEvent>
onPointerOver?: EventHandler<PointerEvent>
onPointerOverCapture?: EventHandler<PointerEvent>
onPointerOut?: EventHandler<PointerEvent>
onPointerOutCapture?: EventHandler<PointerEvent>
onGotPointerCapture?: EventHandler<PointerEvent>
onGotPointerCaptureCapture?: EventHandler<PointerEvent>
onLostPointerCapture?: EventHandler<PointerEvent>
onLostPointerCaptureCapture?: EventHandler<PointerEvent>
// UI Events
onScroll?: EventHandler<UIEvent>
onScrollCapture?: EventHandler<UIEvent>
// Wheel Events
onWheel?: EventHandler<WheelEvent>
onWheelCapture?: EventHandler<WheelEvent>
// Animation Events
onAnimationStart?: EventHandler<AnimationEvent>
onAnimationStartCapture?: EventHandler<AnimationEvent>
onAnimationEnd?: EventHandler<AnimationEvent>
onAnimationEndCapture?: EventHandler<AnimationEvent>
onAnimationIteration?: EventHandler<AnimationEvent>
onAnimationIterationCapture?: EventHandler<AnimationEvent>
// Transition Events
onTransitionEnd?: EventHandler<TransitionEvent>
onTransitionEndCapture?: EventHandler<TransitionEvent>
}

3
node_modules/@use-gesture/core/src/utils.ts generated vendored Normal file
View File

@@ -0,0 +1,3 @@
// additional core exports
export { rubberbandIfOutOfBounds } from './utils/maths'

144
node_modules/@use-gesture/core/src/utils/events.ts generated vendored Normal file
View File

@@ -0,0 +1,144 @@
import { PointerType } from '../types'
import { Vector2 } from '../types'
const EVENT_TYPE_MAP: any = {
pointer: { start: 'down', change: 'move', end: 'up' },
mouse: { start: 'down', change: 'move', end: 'up' },
touch: { start: 'start', change: 'move', end: 'end' },
gesture: { start: 'start', change: 'change', end: 'end' }
}
function capitalize(string: string) {
if (!string) return ''
return string[0].toUpperCase() + string.slice(1)
}
const actionsWithoutCaptureSupported = ['enter', 'leave']
function hasCapture(capture = false, actionKey: string) {
return capture && !actionsWithoutCaptureSupported.includes(actionKey)
}
export function toHandlerProp(device: string, action = '', capture: boolean = false) {
const deviceProps = EVENT_TYPE_MAP[device]
const actionKey = deviceProps ? deviceProps[action] || action : action
return 'on' + capitalize(device) + capitalize(actionKey) + (hasCapture(capture, actionKey) ? 'Capture' : '')
}
const pointerCaptureEvents = ['gotpointercapture', 'lostpointercapture']
export function parseProp(prop: string) {
let eventKey = prop.substring(2).toLowerCase()
const passive = !!~eventKey.indexOf('passive')
if (passive) eventKey = eventKey.replace('passive', '')
const captureKey = pointerCaptureEvents.includes(eventKey) ? 'capturecapture' : 'capture'
// capture = true
const capture = !!~eventKey.indexOf(captureKey)
// pointermovecapture => pointermove
if (capture) eventKey = eventKey.replace('capture', '')
return { device: eventKey, capture, passive }
}
export function toDomEventType(device: string, action = '') {
const deviceProps = EVENT_TYPE_MAP[device]
const actionKey = deviceProps ? deviceProps[action] || action : action
return device + actionKey
}
export function isTouch(event: UIEvent) {
return 'touches' in event
}
export function getPointerType(event: UIEvent): PointerType {
if (isTouch(event)) return 'touch'
if ('pointerType' in event) return (event as PointerEvent).pointerType as PointerType
return 'mouse'
}
function getCurrentTargetTouchList(event: TouchEvent) {
return Array.from(event.touches).filter(
(e) => e.target === event.currentTarget || (event.currentTarget as Node)?.contains?.(e.target as Node)
)
}
function getTouchList(event: TouchEvent) {
return event.type === 'touchend' || event.type === 'touchcancel' ? event.changedTouches : event.targetTouches
}
function getValueEvent<EventType extends TouchEvent | PointerEvent>(
event: EventType
): EventType extends TouchEvent ? Touch : PointerEvent {
return (isTouch(event) ? getTouchList(event as TouchEvent)[0] : event) as any
}
export function distanceAngle(P1: Touch | PointerEvent, P2: Touch | PointerEvent) {
// add a try catch
// attempt to fix https://github.com/pmndrs/use-gesture/issues/551
try {
const dx = P2.clientX - P1.clientX
const dy = P2.clientY - P1.clientY
const cx = (P2.clientX + P1.clientX) / 2
const cy = (P2.clientY + P1.clientY) / 2
const distance = Math.hypot(dx, dy)
const angle = -(Math.atan2(dx, dy) * 180) / Math.PI
const origin = [cx, cy] as Vector2
return { angle, distance, origin }
} catch {}
return null
}
export function touchIds(event: TouchEvent) {
return getCurrentTargetTouchList(event).map((touch) => touch.identifier)
}
export function touchDistanceAngle(event: TouchEvent, ids: number[]) {
const [P1, P2] = Array.from(event.touches).filter((touch) => ids.includes(touch.identifier))
return distanceAngle(P1, P2)
}
export function pointerId(event: PointerEvent | TouchEvent) {
const valueEvent = getValueEvent(event)
return isTouch(event) ? (valueEvent as Touch).identifier : (valueEvent as PointerEvent).pointerId
}
export function pointerValues(event: PointerEvent | TouchEvent): Vector2 {
// if ('spaceX' in event) return [event.spaceX, event.spaceY]
const valueEvent = getValueEvent(event)
return [valueEvent.clientX, valueEvent.clientY]
}
// wheel delta defaults from https://github.com/facebookarchive/fixed-data-table/blob/master/src/vendor_upstream/dom/normalizeWheel.js
const LINE_HEIGHT = 40
const PAGE_HEIGHT = 800
export function wheelValues(event: WheelEvent): Vector2 {
let { deltaX, deltaY, deltaMode } = event
// normalize wheel values, especially for Firefox
if (deltaMode === 1) {
deltaX *= LINE_HEIGHT
deltaY *= LINE_HEIGHT
} else if (deltaMode === 2) {
deltaX *= PAGE_HEIGHT
deltaY *= PAGE_HEIGHT
}
return [deltaX, deltaY]
}
export function scrollValues(event: UIEvent): Vector2 {
// If the currentTarget is the window then we return the scrollX/Y position.
// If not (ie the currentTarget is a DOM element), then we return scrollLeft/Top
const { scrollX, scrollY, scrollLeft, scrollTop } = event.currentTarget as Element & Window
return [scrollX ?? scrollLeft ?? 0, scrollY ?? scrollTop ?? 0]
}
export function getEventDetails(event: any) {
const payload: any = {}
if ('buttons' in event) payload.buttons = event.buttons
if ('shiftKey' in event) {
const { shiftKey, altKey, metaKey, ctrlKey } = event
Object.assign(payload, { shiftKey, altKey, metaKey, ctrlKey })
}
return payload
}

27
node_modules/@use-gesture/core/src/utils/fn.ts generated vendored Normal file
View File

@@ -0,0 +1,27 @@
export function call<T>(v: T | ((...args: any[]) => T), ...args: any[]): T {
if (typeof v === 'function') {
// @ts-ignore
return v(...args)
} else {
return v
}
}
export function noop() {}
export function chain(...fns: Function[]): Function {
if (fns.length === 0) return noop
if (fns.length === 1) return fns[0]
return function (this: any) {
let result
for (const fn of fns) {
result = fn.apply(this, arguments) || result
}
return result
}
}
export function assignDefault<T extends Object>(value: Partial<T> | undefined, fallback: T): T {
return Object.assign({}, fallback, value || {})
}

49
node_modules/@use-gesture/core/src/utils/maths.ts generated vendored Normal file
View File

@@ -0,0 +1,49 @@
import { Vector2 } from '../types'
export function clamp(v: number, min: number, max: number) {
return Math.max(min, Math.min(v, max))
}
export const V = {
toVector<T>(v: T | [T, T] | undefined, fallback?: T | [T, T]): [T, T] {
if (v === undefined) v = fallback as T | [T, T]
return Array.isArray(v) ? v : [v, v]
},
add(v1: Vector2, v2: Vector2): Vector2 {
return [v1[0] + v2[0], v1[1] + v2[1]]
},
sub(v1: Vector2, v2: Vector2): Vector2 {
return [v1[0] - v2[0], v1[1] - v2[1]]
},
addTo(v1: Vector2, v2: Vector2) {
v1[0] += v2[0]
v1[1] += v2[1]
},
subTo(v1: Vector2, v2: Vector2) {
v1[0] -= v2[0]
v1[1] -= v2[1]
}
}
// Based on @aholachek ;)
// https://twitter.com/chpwn/status/285540192096497664
// iOS constant = 0.55
// https://medium.com/@nathangitter/building-fluid-interfaces-ios-swift-9732bb934bf5
function rubberband(distance: number, dimension: number, constant: number) {
if (dimension === 0 || Math.abs(dimension) === Infinity) return Math.pow(distance, constant * 5)
return (distance * dimension * constant) / (dimension + constant * distance)
}
export function rubberbandIfOutOfBounds(position: number, min: number, max: number, constant = 0.15) {
if (constant === 0) return clamp(position, min, max)
if (position < min) return -rubberband(min - position, max - min, constant) + min
if (position > max) return +rubberband(position - max, max - min, constant) + max
return position
}
export function computeRubberband(bounds: [Vector2, Vector2], [Vx, Vy]: Vector2, [Rx, Ry]: Vector2): Vector2 {
const [[X0, X1], [Y0, Y1]] = bounds
return [rubberbandIfOutOfBounds(Vx, X0, X1, Rx), rubberbandIfOutOfBounds(Vy, Y0, Y1, Ry)]
}

19
node_modules/@use-gesture/core/src/utils/state.ts generated vendored Normal file
View File

@@ -0,0 +1,19 @@
import { CommonGestureState } from '../types'
// _movement rolls back to when it passed the bounds.
/**
* @note code is currently used in WheelEngine and PinchEngine.
*/
export function clampStateInternalMovementToBounds(state: CommonGestureState) {
const [ox, oy] = state.overflow
const [dx, dy] = state._delta
const [dirx, diry] = state._direction
if ((ox < 0 && dx > 0 && dirx < 0) || (ox > 0 && dx < 0 && dirx > 0)) {
state._movement[0] = state._movementBound[0] as number
}
if ((oy < 0 && dy > 0 && diry < 0) || (oy > 0 && dy < 0 && diry > 0)) {
state._movement[1] = state._movementBound[1] as number
}
}