source: imaps-frontend/node_modules/@use-gesture/core/src/Controller.ts

main
Last change on this file was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 6.1 KB
Line 
1import { EngineMap } from './actions'
2import { parse } from './config/resolver'
3import { isTouch, parseProp, toHandlerProp, touchIds } from './utils/events'
4import { EventStore } from './EventStore'
5import { TimeoutStore } from './TimeoutStore'
6import { chain } from './utils/fn'
7import { GestureKey, InternalConfig, InternalHandlers, NativeHandlers, State, UserGestureConfig } from './types'
8
9export class Controller {
10 /**
11 * The list of gestures handled by the Controller.
12 */
13 public gestures = new Set<GestureKey>()
14 /**
15 * The event store that keeps track of the config.target listeners.
16 */
17 private _targetEventStore = new EventStore(this)
18 /**
19 * Object that keeps track of all gesture event listeners.
20 */
21 public gestureEventStores: { [key in GestureKey]?: EventStore } = {}
22 public gestureTimeoutStores: { [key in GestureKey]?: TimeoutStore } = {}
23 public handlers: InternalHandlers = {}
24 private nativeHandlers?: NativeHandlers
25 public config = {} as InternalConfig
26 public pointerIds = new Set<number>()
27 public touchIds = new Set<number>()
28 public state = {
29 shared: {
30 shiftKey: false,
31 metaKey: false,
32 ctrlKey: false,
33 altKey: false
34 }
35 } as State
36
37 constructor(handlers: InternalHandlers) {
38 resolveGestures(this, handlers)
39 }
40 /**
41 * Sets pointer or touch ids based on the event.
42 * @param event
43 */
44 setEventIds(event: TouchEvent | PointerEvent) {
45 if (isTouch(event)) {
46 this.touchIds = new Set(touchIds(event as TouchEvent))
47 return this.touchIds
48 } else if ('pointerId' in event) {
49 if (event.type === 'pointerup' || event.type === 'pointercancel') this.pointerIds.delete(event.pointerId)
50 else if (event.type === 'pointerdown') this.pointerIds.add(event.pointerId)
51 return this.pointerIds
52 }
53 }
54 /**
55 * Attaches handlers to the controller.
56 * @param handlers
57 * @param nativeHandlers
58 */
59 applyHandlers(handlers: InternalHandlers, nativeHandlers?: NativeHandlers) {
60 this.handlers = handlers
61 this.nativeHandlers = nativeHandlers
62 }
63 /**
64 * Compute and attaches a config to the controller.
65 * @param config
66 * @param gestureKey
67 */
68 applyConfig(config: UserGestureConfig, gestureKey?: GestureKey) {
69 this.config = parse(config, gestureKey, this.config)
70 }
71 /**
72 * Cleans all side effects (listeners, timeouts). When the gesture is
73 * destroyed (in React, when the component is unmounted.)
74 */
75 clean() {
76 this._targetEventStore.clean()
77 for (const key of this.gestures) {
78 this.gestureEventStores[key]!.clean()
79 this.gestureTimeoutStores[key]!.clean()
80 }
81 }
82 /**
83 * Executes side effects (attaching listeners to a `config.target`). Ran on
84 * each render.
85 */
86 effect() {
87 if (this.config.shared.target) this.bind()
88 return () => this._targetEventStore.clean()
89 }
90 /**
91 * The bind function that can be returned by the gesture handler (a hook in
92 * React for example.)
93 * @param args
94 */
95 bind(...args: any[]) {
96 const sharedConfig = this.config.shared
97 const props: any = {}
98
99 let target
100 if (sharedConfig.target) {
101 target = sharedConfig.target()
102 // if target is undefined let's stop
103 if (!target) return
104 }
105
106 if (sharedConfig.enabled) {
107 // Adding gesture handlers
108 for (const gestureKey of this.gestures) {
109 const gestureConfig = this.config[gestureKey]!
110 const bindFunction = bindToProps(props, gestureConfig.eventOptions, !!target)
111 if (gestureConfig.enabled) {
112 const Engine = EngineMap.get(gestureKey)!
113 // @ts-ignore
114 new Engine(this, args, gestureKey).bind(bindFunction)
115 }
116 }
117
118 // Adding native handlers
119 const nativeBindFunction = bindToProps(props, sharedConfig.eventOptions, !!target)
120 for (const eventKey in this.nativeHandlers) {
121 nativeBindFunction(
122 eventKey,
123 '',
124 // @ts-ignore
125 (event) => this.nativeHandlers[eventKey]({ ...this.state.shared, event, args }),
126 undefined,
127 true
128 )
129 }
130 }
131
132 // If target isn't set, we return an object that contains gesture handlers
133 // mapped to props handler event keys.
134 for (const handlerProp in props) {
135 props[handlerProp] = chain(...props[handlerProp])
136 }
137
138 // When target isn't specified then return hanlder props.
139 if (!target) return props
140
141 // When target is specified, then add listeners to the controller target
142 // store.
143 for (const handlerProp in props) {
144 const { device, capture, passive } = parseProp(handlerProp)
145 this._targetEventStore.add(target, device, '', props[handlerProp], { capture, passive })
146 }
147 }
148}
149
150function setupGesture(ctrl: Controller, gestureKey: GestureKey) {
151 ctrl.gestures.add(gestureKey)
152 ctrl.gestureEventStores[gestureKey] = new EventStore(ctrl, gestureKey)
153 ctrl.gestureTimeoutStores[gestureKey] = new TimeoutStore()
154}
155
156function resolveGestures(ctrl: Controller, internalHandlers: InternalHandlers) {
157 // make sure hover handlers are added first to prevent bugs such as #322
158 // where the hover pointerLeave handler is removed before the move
159 // pointerLeave, which prevents hovering: false to be fired.
160 if (internalHandlers.drag) setupGesture(ctrl, 'drag')
161 if (internalHandlers.wheel) setupGesture(ctrl, 'wheel')
162 if (internalHandlers.scroll) setupGesture(ctrl, 'scroll')
163 if (internalHandlers.move) setupGesture(ctrl, 'move')
164 if (internalHandlers.pinch) setupGesture(ctrl, 'pinch')
165 if (internalHandlers.hover) setupGesture(ctrl, 'hover')
166}
167
168const bindToProps =
169 (props: any, eventOptions: AddEventListenerOptions, withPassiveOption: boolean) =>
170 (
171 device: string,
172 action: string,
173 handler: (event: any) => void,
174 options: AddEventListenerOptions = {},
175 isNative = false
176 ) => {
177 const capture = options.capture ?? eventOptions.capture
178 const passive = options.passive ?? eventOptions.passive
179 // a native handler is already passed as a prop like "onMouseDown"
180 let handlerProp = isNative ? device : toHandlerProp(device, action, capture)
181 if (withPassiveOption && passive) handlerProp += 'Passive'
182 props[handlerProp] = props[handlerProp] || []
183 props[handlerProp].push(handler)
184 }
Note: See TracBrowser for help on using the repository browser.