gesturx 2.1.0 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,19 +1,434 @@
1
1
  # gesturx
2
2
 
3
- Modern multi touch gesture recognizer using rxjs.
3
+ [![npm](https://img.shields.io/npm/v/gesturx)](https://www.npmjs.com/package/gesturx)
4
+ [![license](https://img.shields.io/npm/l/gesturx)](https://github.com/mbret/gesturx/blob/main/LICENSE)
4
5
 
5
- # Documentation
6
+ Gesture recognition for the browser, built on [rxjs](https://rxjs.dev). gesturx turns the pointer events of touch, mouse and pen into taps, pans, pinches, rotations, swipes and holds.
6
7
 
7
- Head over the [documentation](https://bret-maxime.gitbook.io/gesturx).
8
+ Try the gestures in the [demo](https://gesturx.vercel.app/).
8
9
 
9
- # Demo
10
+ - [Installation](#installation)
11
+ - [Quick start](#quick-start)
12
+ - [Recognizable](#recognizable)
13
+ - [Recognizers](#recognizers): [Tap](#tap), [Pan](#pan), [Pinch](#pinch), [Rotate](#rotate), [Swipe](#swipe), [Hold](#hold)
14
+ - [Events](#events)
15
+ - [failWith](#failwith)
16
+ - [Updating a recognizer](#updating-a-recognizer)
17
+ - [Custom gestures](#custom-gestures)
18
+ - [Notes](#notes)
19
+ - [Known limitations](#known-limitations)
10
20
 
11
- [https://gesturx.vercel.app/](https://gesturx.vercel.app/)
21
+ ## Installation
12
22
 
13
- # License
23
+ ```bash
24
+ npm install gesturx rxjs
25
+ ```
14
26
 
15
- MIT
27
+ - rxjs 7 is a peer dependency. If your app doesn't use rxjs yet, it adds rxjs to your bundle.
28
+ - gesturx is published as ES modules only.
29
+ - It needs a browser with Pointer Events. The build targets Chrome 87, Edge 88, Firefox 78 and Safari 14.
16
30
 
17
- # author
31
+ ## Quick start
18
32
 
19
- [mbret](https://github.com/mbret)
33
+ ```ts
34
+ import { PanRecognizer, Recognizable, TapRecognizer } from "gesturx";
35
+
36
+ const pan = new PanRecognizer();
37
+ // no tap is recognized while a pan runs
38
+ const tap = new TapRecognizer({
39
+ options: { maxTaps: 3, multiTapThreshold: 300 },
40
+ failWith: [pan],
41
+ });
42
+
43
+ const recognizable = new Recognizable({ recognizers: [pan, tap] });
44
+
45
+ recognizable.events$.subscribe(({ event }) => {
46
+ if (event.type === "tap") {
47
+ console.log(`${event.taps} taps`);
48
+ }
49
+
50
+ if (event.type === "panMove") {
51
+ console.log(`moved ${event.deltaX}px, ${event.deltaY}px`);
52
+ }
53
+ });
54
+
55
+ recognizable.update({ container: document.getElementById("app")! });
56
+ ```
57
+
58
+ Recognition starts when `events$` has a subscriber and a container is set. It stops when you unsubscribe.
59
+
60
+ ## Recognizable
61
+
62
+ A `Recognizable` puts several recognizers on one element.
63
+
64
+ ```ts
65
+ import { HoldRecognizer, Recognizable, SwipeRecognizer } from "gesturx";
66
+
67
+ const recognizable = new Recognizable({
68
+ container: document.getElementById("app")!,
69
+ disableTextSelection: true,
70
+ recognizers: [new SwipeRecognizer(), new HoldRecognizer()],
71
+ });
72
+
73
+ const subscription = recognizable.events$.subscribe(({ event, recognizer }) => {
74
+ console.log(event.type, recognizer);
75
+ });
76
+
77
+ recognizable.state$.subscribe(({ fingers }) => {
78
+ console.log(`${fingers} fingers`);
79
+ });
80
+
81
+ // to stop recognizing
82
+ subscription.unsubscribe();
83
+ ```
84
+
85
+ - `events$` emits `{ event, recognizer }` for the events of all its recognizers.
86
+ - `state$` emits `{ fingers }`: the most fingers that one of its recognizers recognizes at that moment.
87
+ - `update({ container })` sets the element on all its recognizers. Set the options of each recognizer on the recognizer itself.
88
+ - When it gets a container, it sets `touch-action: none` on it. Without that, the browser scrolls or zooms on touch screens, and cancels the pointer events.
89
+ - `disableTextSelection: true` also sets `user-select: none` on the container.
90
+ - Give each recognizer to one `Recognizable` only, because each `Recognizable` writes its config to its recognizers.
91
+ - Overlapping elements with their own recognizers can recognize the same gesture.
92
+
93
+ ## Recognizers
94
+
95
+ A recognizer also works alone, on any element. Alone, it doesn't set `touch-action`: set `touch-action: none` on its container yourself.
96
+
97
+ ```ts
98
+ import { PanRecognizer } from "gesturx";
99
+
100
+ const card = document.getElementById("card")!;
101
+ card.style.touchAction = "none";
102
+
103
+ const pan = new PanRecognizer({ container: card });
104
+
105
+ const subscription = pan.events$.subscribe((event) => {
106
+ if (event.type === "panMove") {
107
+ card.style.transform = `translate(${event.deltaX}px, ${event.deltaY}px)`;
108
+ }
109
+ });
110
+
111
+ // to stop recognizing
112
+ subscription.unsubscribe();
113
+ ```
114
+
115
+ The other examples in this README use a recognizer alone, and expect `touch-action: none` on the container from your CSS.
116
+
117
+ Every recognizer takes the same config in its constructor and in `update()`:
118
+
119
+ | Key | Meaning |
120
+ | --- | --- |
121
+ | `container` | The element to listen on. |
122
+ | `options` | The options of the recognizer, listed in its section below. |
123
+ | `failWith` | Recognizers that block this one while they run. See [failWith](#failwith). |
124
+ | `afterEventReceived` | A function that changes each pointer event before the recognizer reads it. |
125
+
126
+ Every recognizer has:
127
+
128
+ - `events$`: its events. A subscription starts the recognition.
129
+ - `state$`: `{ fingers }`, the fingers of the gesture it recognizes, from its start event to its end event. It is 0 at other times, and it stays 0 for a tap or a swipe.
130
+ - `update(config)`: see [Updating a recognizer](#updating-a-recognizer).
131
+
132
+ Only the primary button starts a gesture: a finger, a pen tip or a left click. A right click, a middle click or a pen eraser starts nothing.
133
+
134
+ The distance thresholds below are measured on each axis: a finger passes a 15 px threshold when it moves 15 px on the x axis or on the y axis.
135
+
136
+ ### Tap
137
+
138
+ `TapRecognizer` emits `tap` when fingers press and release quickly. `taps` counts the presses.
139
+
140
+ | Option | Default | Meaning |
141
+ | --- | --- | --- |
142
+ | `maxTaps` | `1` | The most taps in one gesture. A gesture with more taps is ignored. |
143
+ | `multiTapThreshold` | `100 * (maxTaps - 1)` ms | The time to wait after a release for one more press. |
144
+ | `maximumPressTime` | `150` ms | A press held longer cancels the gesture. |
145
+ | `tolerance` | `10` px | A press that moves farther than this from the first press cancels the gesture. |
146
+
147
+ Two fingers down at the same time cancel the gesture too. With `maxTaps` of 2 or more, every `tap` comes `multiTapThreshold` after the last release, a double tap too.
148
+
149
+ ```ts
150
+ import { TapRecognizer } from "gesturx";
151
+
152
+ const tap = new TapRecognizer({
153
+ container: document.getElementById("app")!,
154
+ options: { maxTaps: 2, multiTapThreshold: 300 },
155
+ });
156
+
157
+ tap.events$.subscribe(({ taps }) => {
158
+ console.log(taps === 2 ? "double tap" : "single tap");
159
+ });
160
+ ```
161
+
162
+ ### Pan
163
+
164
+ `PanRecognizer` follows fingers that press and move. It emits `panStart`, then `panMove` at each move, then `panEnd`.
165
+
166
+ | Option | Default | Meaning |
167
+ | --- | --- | --- |
168
+ | `posThreshold` | `15` px | The distance that a finger moves before the pan starts. |
169
+ | `delay` | `0` ms | The time to wait after the threshold before the pan starts. A release in that time cancels the pan. |
170
+ | `numInputs` | `1` | The fingers it needs. The pan ends when fewer fingers stay pressed. |
171
+
172
+ ```ts
173
+ import { PanRecognizer } from "gesturx";
174
+
175
+ const pan = new PanRecognizer({
176
+ container: document.getElementById("app")!,
177
+ options: { numInputs: 2 },
178
+ });
179
+
180
+ pan.events$.subscribe(({ type, deltaX, deltaY }) => {
181
+ console.log(type, deltaX, deltaY);
182
+ });
183
+ ```
184
+
185
+ ### Pinch
186
+
187
+ `PinchRecognizer` follows two or more fingers that move closer or apart. It emits `pinchStart`, `pinchMove` and `pinchEnd`.
188
+
189
+ | Option | Default | Meaning |
190
+ | --- | --- | --- |
191
+ | `posThreshold` | `0` px | The distance that a finger moves before the pinch starts. At 0, the pinch starts when the second finger touches. |
192
+
193
+ Its events add these fields:
194
+
195
+ | Field | Meaning |
196
+ | --- | --- |
197
+ | `scale` | The average distance between the fingers, divided by the one at the start. |
198
+ | `distance` | The change in that average distance since the start, in px. |
199
+ | `deltaDistance` | The change in distance since the previous event, in px. |
200
+ | `deltaDistanceScale` | The change in scale since the previous event. Their product over the pinch is `scale`. |
201
+
202
+ A finger that touches or lifts during a pinch doesn't change `scale` or `distance`.
203
+
204
+ ```ts
205
+ import { PinchRecognizer } from "gesturx";
206
+
207
+ const photo = document.getElementById("photo")!;
208
+ const pinch = new PinchRecognizer({ container: photo });
209
+
210
+ pinch.events$.subscribe(({ scale }) => {
211
+ photo.style.transform = `scale(${scale})`;
212
+ });
213
+ ```
214
+
215
+ ### Rotate
216
+
217
+ `RotateRecognizer` follows two or more fingers that turn around their center. It emits `rotateStart`, `rotateMove` and `rotateEnd`.
218
+
219
+ | Option | Default | Meaning |
220
+ | --- | --- | --- |
221
+ | `posThreshold` | `15` px | The distance that a finger moves before the rotation starts. |
222
+ | `numInputs` | `2` | The fingers it needs. A value lower than 2 doesn't work. |
223
+
224
+ The rotation starts when a finger has moved `posThreshold`, even if the fingers don't turn. A pinch therefore starts a rotation too, with an `angle` near 0.
225
+
226
+ Its events add `angle`, the angle turned since the start, and `deltaAngle`, the angle turned since the previous event. Both are in degrees, and a positive angle is clockwise on the screen.
227
+
228
+ ```ts
229
+ import { RotateRecognizer } from "gesturx";
230
+
231
+ const dial = document.getElementById("dial")!;
232
+ const rotate = new RotateRecognizer({ container: dial });
233
+
234
+ rotate.events$.subscribe(({ angle }) => {
235
+ dial.style.transform = `rotate(${angle}deg)`;
236
+ });
237
+ ```
238
+
239
+ ### Swipe
240
+
241
+ `SwipeRecognizer` emits `swipe` when a finger lifts after a fast move.
242
+
243
+ | Option | Default | Meaning |
244
+ | --- | --- | --- |
245
+ | `escapeVelocity` | `0.9` px/ms | The speed on the x axis or the y axis that the move must reach. |
246
+
247
+ The speed is the average speed from the press to the release. The event adds `angle`, the direction from the press to the release in degrees: 0 is right, 90 is down, -90 is up, and 180 or -180 is left. `velocityX` and `velocityY` give the speed.
248
+
249
+ ```ts
250
+ import { SwipeRecognizer } from "gesturx";
251
+
252
+ const swipe = new SwipeRecognizer({
253
+ container: document.getElementById("app")!,
254
+ });
255
+
256
+ swipe.events$.subscribe(({ angle }) => {
257
+ if (Math.abs(angle) <= 45) {
258
+ console.log("right");
259
+ } else if (Math.abs(angle) >= 135) {
260
+ console.log("left");
261
+ } else {
262
+ console.log(angle > 0 ? "down" : "up");
263
+ }
264
+ });
265
+ ```
266
+
267
+ ### Hold
268
+
269
+ `HoldRecognizer` emits `holdStart` when fingers press, and `holdEnd` when they lift.
270
+
271
+ | Option | Default | Meaning |
272
+ | --- | --- | --- |
273
+ | `delay` | `0` ms | The time that the fingers stay pressed before the hold starts. It counts from the press, or from the threshold when `posThreshold` is set. A release in that time cancels the hold. Moving doesn't cancel it. |
274
+ | `numInputs` | `1` | The fingers it needs. The hold ends when fewer fingers stay pressed. |
275
+ | `posThreshold` | `0` px | The distance that a finger moves before the hold starts. |
276
+
277
+ ```ts
278
+ import { HoldRecognizer } from "gesturx";
279
+
280
+ const hold = new HoldRecognizer({
281
+ container: document.getElementById("app")!,
282
+ options: { delay: 500 },
283
+ });
284
+
285
+ hold.events$.subscribe(({ type }) => {
286
+ console.log(type === "holdStart" ? "long press" : "released");
287
+ });
288
+ ```
289
+
290
+ ## Events
291
+
292
+ The events of every recognizer have these fields:
293
+
294
+ | Field | Meaning |
295
+ | --- | --- |
296
+ | `type` | The name of the event, for example `panMove`. |
297
+ | `event` | The `PointerEvent` that caused it. For a tap, the last press. |
298
+ | `pointers` | The latest `PointerEvent` of each finger that is still pressed. An end event leaves out the finger that lifted, so a one-finger `panEnd` has none. A tap has its last press. |
299
+ | `center` | The center of the fingers, `{ x, y }`, in client coordinates. |
300
+ | `deltaX`, `deltaY` | The distance that the center moved since the start event, in px. They are 0 at the start event, which comes after the threshold. A finger that touches or lifts doesn't change them. |
301
+ | `velocityX`, `velocityY` | `deltaX` and `deltaY` divided by `delay`, in px/ms. They can be negative. |
302
+ | `delay` | The time since the start event, in ms. |
303
+ | `startTime` | The time of the start event, from `Date.now()`. |
304
+ | `deltaPointersAngle` | The angle that the fingers turned since the previous event, in degrees. It is 0 when the number of fingers changed. |
305
+ | `pointersAverageDistance` | The average distance between two fingers, over all pairs, in px. |
306
+
307
+ A tap is one event, so its `startTime` is the time it is reported, and its `delay`, deltas and velocities are 0.
308
+
309
+ The package exports the types of the events (`TapEvent`, `PanEvent`, `PinchEvent`, `RotateEvent`, `SwipeEvent`, `HoldEvent` and their base `RecognizerEvent`), of the options (`TapRecognizerOptions` and the others), and `RecognizableState`.
310
+
311
+ ## failWith
312
+
313
+ `failWith` blocks a recognizer while other recognizers run:
314
+
315
+ - It doesn't start a gesture while one of them runs. That gesture is dropped, not delayed.
316
+ - If one of them starts during its gesture, the gesture stops. A pan, a pinch, a rotation or a hold emits its end event. A tap or a swipe emits nothing.
317
+
318
+ `failWith` accepts a `PanRecognizer`, a `PinchRecognizer`, a `RotateRecognizer`, a `HoldRecognizer`, or any object with `start$` and `end$` observables. A source runs from a value of `start$` to a value of `end$`:
319
+
320
+ ```ts
321
+ import { Subject } from "rxjs";
322
+ import { PanRecognizer } from "gesturx";
323
+
324
+ const dialogOpened$ = new Subject<void>();
325
+ const dialogClosed$ = new Subject<void>();
326
+
327
+ const pan = new PanRecognizer({
328
+ container: document.getElementById("app")!,
329
+ failWith: [{ start$: dialogOpened$, end$: dialogClosed$ }],
330
+ });
331
+
332
+ pan.events$.subscribe(({ type }) => {
333
+ console.log(type);
334
+ });
335
+
336
+ // no pan from here
337
+ dialogOpened$.next();
338
+ // pans again from here
339
+ dialogClosed$.next();
340
+ ```
341
+
342
+ A recognizer subscribes to its `failWith` sources by the time it has a subscriber and a container. A recognizer in a `failWith` list therefore recognizes gestures, even without a subscriber of its own. A `TapRecognizer` is the exception: it subscribes to its sources at its first press.
343
+
344
+ ## Updating a recognizer
345
+
346
+ `update()` changes the config of a recognizer at any time:
347
+
348
+ ```ts
349
+ import { PanRecognizer } from "gesturx";
350
+
351
+ const pan = new PanRecognizer({ container: document.getElementById("app")! });
352
+
353
+ pan.events$.subscribe(({ type }) => {
354
+ console.log(type);
355
+ });
356
+
357
+ // the other options stay as they are
358
+ pan.update({ options: { posThreshold: 30 } });
359
+ ```
360
+
361
+ - The options that you don't pass keep their values. `options: undefined` keeps all of them.
362
+ - An option passed as `undefined` or `NaN` keeps its value too.
363
+ - `failWith` or `afterEventReceived` passed as `undefined` keep their values. Pass `failWith: []` to remove `failWith`.
364
+ - A new `container` moves the listeners to the new element.
365
+
366
+ ## Custom gestures
367
+
368
+ To make a gesture of your own, extend `Recognizer`. The second argument of `super()` sets `numInputs`, `posThreshold` and `delay` for the gesture that the base class follows. The base class gives you protected members:
369
+
370
+ - `panStart$`, `panMove$` and `panEnd$`: that gesture, as `RecognizerEvent`s. `pan$` has all of them, with a `type` of `start`, `move` or `end`.
371
+ - `pointerEvent$`, `pointerDown$`, `pointerMove$`, `pointerUp$` and `pointerCancel$`: the pointer events of the container. `pointerDown$` has the presses of the primary button only.
372
+ - `failWithActive$`: `true` while one of the `failWith` sources runs. The streams above ignore `failWith`, so drop your events while it is `true`.
373
+ - `reportFingers(isEnd)`: an operator for your `events$` that reports the fingers of its events in `state$`, until an event for which `isEnd` returns `true`. Without it, `state$` stays 0.
374
+
375
+ ```ts
376
+ import { filter, map, type Observable, withLatestFrom } from "rxjs";
377
+ import {
378
+ Recognizer,
379
+ type RecognizerConfig,
380
+ type RecognizerEvent,
381
+ } from "gesturx";
382
+
383
+ interface TwoFingerDragEvent extends RecognizerEvent {
384
+ type: "twoFingerDrag";
385
+ }
386
+
387
+ class TwoFingerDragRecognizer extends Recognizer<object, TwoFingerDragEvent> {
388
+ public events$: Observable<TwoFingerDragEvent>;
389
+
390
+ constructor(config?: RecognizerConfig<object>) {
391
+ super(config, { numInputs: 2, posThreshold: 10 });
392
+
393
+ this.events$ = this.panMove$.pipe(
394
+ withLatestFrom(this.failWithActive$),
395
+ filter(([, failWithActive]) => !failWithActive),
396
+ map(([event]) => ({ ...event, type: "twoFingerDrag" as const })),
397
+ );
398
+ }
399
+ }
400
+
401
+ const drag = new TwoFingerDragRecognizer({
402
+ container: document.getElementById("app")!,
403
+ });
404
+
405
+ drag.events$.subscribe(({ deltaX, deltaY }) => {
406
+ console.log(deltaX, deltaY);
407
+ });
408
+ ```
409
+
410
+ A `Recognizable` accepts a custom recognizer like the others. For a complete example, read [`SwipeRecognizer`](https://github.com/mbret/gesturx/blob/main/src/core/swipe/SwipeRecognizer.ts).
411
+
412
+ ## Notes
413
+
414
+ ### pointercancel
415
+
416
+ The browser sends `pointercancel` when it takes over a pointer, for example to start the native drag of an image. The coordinates of that event can be hundreds of pixels away from the fingers. When a gesture ends with a `pointercancel`, its end event references it, but `deltaX` and `deltaY` stay as they were in the previous event. `center`, and the `angle` of a swipe, do use its coordinates.
417
+
418
+ ### contextmenu
419
+
420
+ A `contextmenu` event ends the gesture of its pointer, as a release does. A right click opens the context menu, and so can a long press on a touch screen.
421
+
422
+ ## Known limitations
423
+
424
+ - `update()` during a gesture drops the gesture without an end event, and `state$` keeps its fingers ([#140](https://github.com/mbret/gesturx/issues/140)). A recognizer with that one in its `failWith` then stays blocked until that one ends a later gesture ([#152](https://github.com/mbret/gesturx/issues/152)).
425
+ - A recognizer keeps its `failWith` sources subscribed after you unsubscribe from it ([#151](https://github.com/mbret/gesturx/issues/151)).
426
+ - A `TapRecognizer` follows its `failWith` sources from its first press. A source that started before that press doesn't block it.
427
+ - With `maxTaps: 2`, the default `multiTapThreshold` of 100 ms is short for a double tap at normal speed. Set it to about 300 ([#150](https://github.com/mbret/gesturx/issues/150)).
428
+ - A swipe checks the average speed of the move, not the speed at the release ([#141](https://github.com/mbret/gesturx/issues/141)).
429
+ - A `container` set to `undefined` or `null` doesn't detach a recognizer, and the recognizer ignores the next calls to `update()` until it gets a container again. Unsubscribe instead ([#154](https://github.com/mbret/gesturx/issues/154)).
430
+ - A mouse drag ends when the cursor leaves the container ([#156](https://github.com/mbret/gesturx/issues/156)).
431
+
432
+ ## License
433
+
434
+ MIT, by [mbret](https://github.com/mbret).
package/dist/index.d.ts CHANGED
@@ -13,12 +13,18 @@ export declare interface HoldEvent extends RecognizerEvent {
13
13
 
14
14
  export declare class HoldRecognizer extends Recognizer<HoldRecognizerOptions, HoldEvent> implements HoldRecognizerInterface {
15
15
  events$: Observable<HoldEvent>;
16
+ start$: Observable<HoldEvent>;
17
+ end$: Observable<HoldEvent>;
16
18
  constructor(options?: RecognizerConfig<HoldRecognizerOptions>);
17
19
  update(options: RecognizerConfig<HoldRecognizerOptions>): void;
18
20
  }
19
21
 
20
22
  declare interface HoldRecognizerInterface extends Recognizer<HoldRecognizerOptions, HoldEvent> {
21
23
  events$: Observable<HoldEvent>;
24
+ /** The holdStart events. Another recognizer's `failWith` reads them. */
25
+ start$: Observable<HoldEvent>;
26
+ /** The holdEnd events. Another recognizer's `failWith` reads them. */
27
+ end$: Observable<HoldEvent>;
22
28
  update(options: RecognizerConfig<HoldRecognizerOptions>): void;
23
29
  }
24
30
 
@@ -224,7 +230,7 @@ export declare interface RecognizerEvent {
224
230
  */
225
231
  pointers: PointerEvent[];
226
232
  /**
227
- * Delay between the user action and the event recognition
233
+ * Time since the start event, in ms
228
234
  */
229
235
  delay: number;
230
236
  deltaX: number;
@@ -273,12 +279,18 @@ export declare interface RotateEvent extends RecognizerEvent {
273
279
 
274
280
  export declare class RotateRecognizer extends Recognizer<RotateRecognizerOptions, RotateEvent> implements RotateRecognizerInterface {
275
281
  events$: Observable<RotateEvent>;
282
+ start$: Observable<RotateEvent>;
283
+ end$: Observable<RotateEvent>;
276
284
  constructor(config?: RecognizerConfig<RotateRecognizerOptions>);
277
285
  update(options: RecognizerConfig<RotateRecognizerOptions>): void;
278
286
  }
279
287
 
280
288
  declare interface RotateRecognizerInterface extends Recognizer<RotateRecognizerOptions, RotateEvent> {
281
289
  events$: Observable<RotateEvent>;
290
+ /** The rotateStart events. Another recognizer's `failWith` reads them. */
291
+ start$: Observable<RotateEvent>;
292
+ /** The rotateEnd events. Another recognizer's `failWith` reads them. */
293
+ end$: Observable<RotateEvent>;
282
294
  update(options: RecognizerConfig<RotateRecognizerOptions>): void;
283
295
  }
284
296
 
@@ -363,7 +375,7 @@ export declare interface TapRecognizerOptions {
363
375
  * A longer time will delay the click event but make it easier to multi taps.
364
376
  * Try to find a good balance between latency and accessibility.
365
377
  *
366
- * @default 0
378
+ * @default 100 * (maxTaps - 1)
367
379
  */
368
380
  multiTapThreshold?: number;
369
381
  /**
package/dist/index.js CHANGED
@@ -231,10 +231,10 @@ var Z = class {
231
231
  ...e,
232
232
  failWith: e.failWith ?? n.failWith,
233
233
  afterEventReceived: e.afterEventReceived ?? n.afterEventReceived,
234
- ...e.options && { options: {
234
+ options: e.options ? {
235
235
  ...n.options,
236
236
  ...N(e.options)
237
- } },
237
+ } : n.options,
238
238
  panConfig: {
239
239
  ...n.panConfig,
240
240
  ...N(t)
@@ -251,7 +251,7 @@ var Z = class {
251
251
  delay: 0,
252
252
  posThreshold: 0,
253
253
  ...N(e.options)
254
- }), X(this, "events$", void 0);
254
+ }), X(this, "events$", void 0), X(this, "start$", void 0), X(this, "end$", void 0);
255
255
  let t = this.panStart$.pipe(E(this.failWithActive$), c(([, e]) => !e), p(([e]) => ({
256
256
  type: "holdStart",
257
257
  ...e
@@ -265,7 +265,7 @@ var Z = class {
265
265
  type: "holdEnd"
266
266
  })), S(this.panEnd$));
267
267
  return m(g(e), n, r);
268
- }), this.reportFingers((e) => e.type === "holdEnd"), v());
268
+ }), this.reportFingers((e) => e.type === "holdEnd"), v()), this.start$ = this.events$.pipe(c((e) => e.type === "holdStart")), this.end$ = this.events$.pipe(c((e) => e.type === "holdEnd"));
269
269
  }
270
270
  update(e) {
271
271
  super.update(e, e.options);
@@ -363,7 +363,7 @@ var Z = class {
363
363
  numInputs: 2,
364
364
  posThreshold: 15,
365
365
  ...N(e.options)
366
- }), X(this, "events$", void 0), this.events$ = this.config$.pipe(x(() => {
366
+ }), X(this, "events$", void 0), X(this, "start$", void 0), X(this, "end$", void 0), this.events$ = this.config$.pipe(x(() => {
367
367
  let e = this.panStart$.pipe(E(this.failWithActive$), c(([, e]) => !e), p(([e]) => ({
368
368
  ...e,
369
369
  type: "rotateStart",
@@ -397,7 +397,7 @@ var Z = class {
397
397
  type: "rotateEnd"
398
398
  })));
399
399
  return m(e, n, r);
400
- }), this.reportFingers((e) => e.type === "rotateEnd"), v());
400
+ }), this.reportFingers((e) => e.type === "rotateEnd"), v()), this.start$ = this.events$.pipe(c((e) => e.type === "rotateStart")), this.end$ = this.events$.pipe(c((e) => e.type === "rotateEnd"));
401
401
  }
402
402
  update(e) {
403
403
  super.update(e, e.options);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["calculateDistance","pointB","pointA","calculateAverageDistance","n","pointerEvents","sum","i","innerSum","event1","event2","calculateRadianAngleBetweenPoints","deltaX","pointerB","pointerA","deltaY","calculateDegreeAngleBetweenPoints","calculateCentroid","points","point","acc","numPoints","calculateAngleDelta","initialPoints","newPoints","initialCentroid","newCentroid","totalAngleDelta","initialAngle","initialPoint","angleDelta","index","radianDelta","isDefined","arg","omitUnset","values","value","hasAtLeastOneItem","events","filterNotEmpty","stream","filter","isWithinPosThreshold","start","startEvent","end","endEvent","posThreshold","calculateVelocity","delay","matchPointer","newPointer","pointer","isPointerOffEvent","pointerEvent","isPrimaryButtonPress","event","fromPointerDown","fromEvent","container","map","afterEventReceived","trackPointers","pointerUp$","pointerEvent$","pointerLeave$","pointerCancel$","pointerMove$","contextMenu$","isPointerRemoved","mergeMap","pointerDown$","defer","of","pointerDown","merge","takeWhile","scan","_deleted","rest","pointers","shareLatest","shareReplay","isValidConfig","config","filterPointerOff","calculateNewDelta","newCenter","prevCenter","prevDeltaX","prevDeltaY","scanToRecognizerEvent","getCenterFromData","data","_acc$latestActivePoin","_curr$latestActivePoi","curr","prevActivePointersNumber","currActivePointersNumber","deltaPointersAngle","latestActivePointers","startTime","getPointerEvents","_typeof","o","toPrimitive","t","e","r","toPropertyKey","_defineProperty","Recognizer","BehaviorSubject","events$","tap","isEnd","finalize","switchMap","share","failWith$","failWith","distinctUntilChanged","areRunnings$","start$","recognizer","end$","startWith","combineLatest","runnings","running","_config$panConfig","_config$panConfig2","_config$panConfig3","numInputs","trackPointers$","hasEnoughFingers","hasNotEnoughFingers","exhaustMap","initialPointerEvents","panReleased$","first","delay$","timer","panStart$","withLatestFrom","takeUntil","panUpdate$","skip","panEnd$","rawEvent$","recognizerEvent","previous","current","panConfig","existingConfig","HoldRecognizer","options","failWithActive","failingActive$","isActive","trailingEndEventIfFailed$","holdStartEvent","PanRecognizer","panMove$","latestEvent","panStartEvent","panStarted$","scanPanEventToPinchEvent","hasChangedFingers","previousPointersAverageDistance","reference","scale","distance","deltaDistance","deltaDistanceScale","initialEvent","PinchRecognizer","latestPinchEvent","pinchStarted$","pinchMove$","pinchEnd$","defaultIfEmpty","pinchStartEvent","Recognizable","states","state","disableTextSelection","RotateRecognizer","rotateStart$","rotate$","rotateStartEvent","angle","rotateMove$","rotateEnd$","isRecognizedAsSwipe","escapeVelocity","SwipeRecognizer","initializedWith","takeWhenPressedTooLong","timeout","takeWhenOutsideThreshold","initialPointerEvent","tolerance","TapRecognizer","_config$options","_config$options2","maxTaps","multiTapThreshold","activePointers$","hasMoreThanOneActivePointer$","bufferPointerDowns","buffer","debounceTime","ignoreElements","pointerDowns$","pointerDownsBuffered$","clickedTooFarFromOriginalTap$","hasFingersPressedForTooLong$","maximumPressTime","takeUntil$","active","lastPress"],"sources":["../src/core/utils/geometry.ts","../src/core/utils/utils.ts","../src/core/utils/events.ts","../src/core/utils/operators.ts","../src/core/recognizer/operators.ts","../src/core/recognizer/scanToRecognizerEvent.ts","../src/core/recognizer/utils.ts","../src/core/recognizer/Recognizer.ts","../src/core/hold/HoldRecognizer.ts","../src/core/pan/PanRecognizer.ts","../src/core/pinch/scanPanEventToPinchEvent.ts","../src/core/pinch/PinchRecognizer.ts","../src/core/recognizable/Recognizable.ts","../src/core/rotate/RotateRecognizer.ts","../src/core/swipe/operators.ts","../src/core/swipe/SwipeRecognizer.ts","../src/core/tap/operators.ts","../src/core/tap/TapRecognizer.ts"],"sourcesContent":["export type Point = { x: number; y: number };\n\nexport function calculateDistance(pointA: Point, pointB: Point): number {\n\treturn Math.sqrt((pointB.x - pointA.x) ** 2 + (pointB.y - pointA.y) ** 2);\n}\n\nexport function calculateAverageDistance(pointerEvents: Point[]): number {\n\tconst n = pointerEvents.length;\n\tif (n < 2) return 0; // No distance if fewer than 2 pointers\n\n\tconst totalDistance = pointerEvents.reduce((sum, event1, i) => {\n\t\treturn (\n\t\t\tsum +\n\t\t\tpointerEvents.slice(i + 1).reduce((innerSum, event2) => {\n\t\t\t\treturn innerSum + calculateDistance(event1, event2);\n\t\t\t}, 0)\n\t\t);\n\t}, 0);\n\n\t// Number of pairs is n choose 2: n * (n - 1) / 2\n\tconst numberOfPairs = (n * (n - 1)) / 2;\n\treturn totalDistance / numberOfPairs;\n}\n\nexport function calculateRadianAngleBetweenPoints(\n\tpointerA: Point,\n\tpointerB: Point,\n): number {\n\t// Calculate the differences in coordinates\n\tconst deltaX = pointerB.x - pointerA.x;\n\tconst deltaY = pointerB.y - pointerA.y;\n\n\t// Calculate the angle in radians\n\tconst angleInRadians = Math.atan2(deltaY, deltaX);\n\n\t// Return the angle in degrees\n\treturn angleInRadians;\n}\n\nexport function calculateDegreeAngleBetweenPoints(\n\tpointerA: Point,\n\tpointerB: Point,\n): number {\n\t// Calculate the angle in radians\n\tconst angleInRadians = calculateRadianAngleBetweenPoints(pointerA, pointerB);\n\n\t// Convert the angle to degrees (optional)\n\tconst angleInDegrees = angleInRadians * (180 / Math.PI);\n\n\t// Return the angle in degrees\n\treturn angleInDegrees;\n}\n\nexport function calculateCentroid(points: Point[]) {\n\tconst sum = points.reduce(\n\t\t(acc, point) => {\n\t\t\tacc.x += point.x;\n\t\t\tacc.y += point.y;\n\n\t\t\treturn acc;\n\t\t},\n\t\t{ x: 0, y: 0 },\n\t);\n\n\tconst numPoints = points.length || 1;\n\n\treturn {\n\t\tx: sum.x / numPoints,\n\t\ty: sum.y / numPoints,\n\t};\n}\n\nexport function calculateAngleDelta(\n\tinitialPoints: Point[],\n\tnewPoints: Point[],\n) {\n\tif (initialPoints.length !== newPoints.length) {\n\t\tthrow new Error(\"Initial and new points arrays must have the same length.\");\n\t}\n\n\tconst initialCentroid = calculateCentroid(initialPoints);\n\tconst newCentroid = calculateCentroid(newPoints);\n\n\tlet totalAngleDelta = 0;\n\n\tinitialPoints.forEach((initialPoint, index) => {\n\t\tconst initialAngle = calculateRadianAngleBetweenPoints(\n\t\t\tinitialCentroid,\n\t\t\tinitialPoint,\n\t\t);\n\t\tconst newAngle = calculateRadianAngleBetweenPoints(\n\t\t\tnewCentroid,\n\t\t\tnewPoints[index] ?? initialPoint,\n\t\t);\n\n\t\tlet angleDelta = newAngle - initialAngle;\n\n\t\t// Normalize the angle delta to be within [-PI, PI]\n\t\tif (angleDelta > Math.PI) {\n\t\t\tangleDelta -= 2 * Math.PI;\n\t\t} else if (angleDelta < -Math.PI) {\n\t\t\tangleDelta += 2 * Math.PI;\n\t\t}\n\n\t\ttotalAngleDelta += angleDelta;\n\t});\n\n\t// Return the average angle delta\n\tconst radianDelta = totalAngleDelta / initialPoints.length;\n\tconst degreesDelta = radianDelta * (180 / Math.PI);\n\n\treturn { radianDelta, degreesDelta };\n}\n","import { filter, type Observable } from \"rxjs\";\nimport { calculateCentroid } from \"./geometry\";\n\nexport function isDefined<T>(\n\targ: T | null | undefined,\n): arg is T extends null | undefined ? never : T {\n\treturn arg !== null && arg !== undefined;\n}\n\n/**\n * `values` without the ones that aren't set: `undefined`, as forwarding an\n * optional value passes, or `NaN`, as `parseInt` gives for an empty field.\n * Spread over defaults or current values, they then leave them alone.\n */\nexport const omitUnset = <T extends object>(values: T | undefined) =>\n\tObject.fromEntries(\n\t\tObject.entries(values ?? {}).filter(\n\t\t\t([, value]) => value !== undefined && !Number.isNaN(value),\n\t\t),\n\t) as Partial<T>;\n\nexport const hasAtLeastOneItem = <T>(events: T[]): events is [T, ...T[]] =>\n\tevents.length > 0;\n\nexport const filterNotEmpty = <T>(\n\tstream: Observable<T[]>,\n): Observable<[T, ...T[]]> => stream.pipe(filter(hasAtLeastOneItem));\n\nexport function isWithinPosThreshold(\n\tstartEvent: PointerEvent,\n\tendEvent: PointerEvent,\n\tposThreshold: number,\n) {\n\tconst start = calculateCentroid([startEvent]);\n\tconst end = calculateCentroid([endEvent]);\n\n\t// Determines if the movement qualifies as a drag\n\treturn (\n\t\tMath.abs(end.x - start.x) >= posThreshold ||\n\t\tMath.abs(end.y - start.y) >= posThreshold\n\t);\n}\n\n/**\n * Avoid division by zero\n * Calculate velocity in pixels per second\n */\nexport const calculateVelocity = (\n\tdelay: number,\n\tdeltaX: number,\n\tdeltaY: number,\n) => {\n\tconst velocityX = delay > 0 ? deltaX / delay : 0;\n\tconst velocityY = delay > 0 ? deltaY / delay : 0;\n\n\treturn {\n\t\tvelocityX,\n\t\tvelocityY,\n\t};\n};\n","import {\n\tdefer,\n\tfilter,\n\tfromEvent,\n\tmap,\n\tmerge,\n\tmergeMap,\n\ttype Observable,\n\tof,\n\tscan,\n\ttakeWhile,\n} from \"rxjs\";\nimport { isDefined } from \"./utils\";\n\nexport function matchPointer(pointer: PointerEvent) {\n\treturn (stream: Observable<PointerEvent>) =>\n\t\tstream.pipe(\n\t\t\tfilter((newPointer) => newPointer.pointerId === pointer.pointerId),\n\t\t);\n}\n\nexport const isPointerOffEvent = (pointerEvent: PointerEvent) =>\n\tpointerEvent.type === \"pointerleave\" ||\n\tpointerEvent.type === \"pointercancel\" ||\n\tpointerEvent.type === \"pointerup\";\n\n/**\n * A press of the primary button: a left click, a finger or a pen's tip. A\n * right click is for the context menu, a middle click for the browser, and a\n * pen's barrel button or eraser for the app.\n *\n * @see https://w3c.github.io/pointerevents/#the-button-property\n */\nconst isPrimaryButtonPress = (event: PointerEvent) => event.button === 0;\n\n/**\n * The presses that start a gesture. Every recognizer tracks a pointer from its\n * press, so a pointer pressed with another button starts none: no tap, pan or\n * pinch, and no share of a multi tap.\n */\nexport const fromPointerDown = ({\n\tcontainer,\n\tafterEventReceived = (event) => event,\n}: {\n\tcontainer: HTMLElement;\n\tafterEventReceived?: (event: PointerEvent) => PointerEvent;\n}) =>\n\tfromEvent<PointerEvent>(container, \"pointerdown\").pipe(\n\t\tmap(afterEventReceived),\n\t\tfilter(isPrimaryButtonPress),\n\t);\n\n/**\n * Track all pointerEvent for active fingers\n */\nexport const trackPointers =\n\t({\n\t\tpointerEvent$,\n\t}: {\n\t\tpointerEvent$: Observable<PointerEvent>;\n\t\t/**\n\t\t * Setting this value to false will not update the list\n\t\t * on pointer move. Use it if you only need to track number of active\n\t\t * fingers.\n\t\t */\n\t\ttrackMove: boolean;\n\t}) =>\n\t(stream: Observable<PointerEvent>) => {\n\t\ttype PointersState = {\n\t\t\tevent: PointerEvent;\n\t\t\tpointers: Record<number, PointerEvent | undefined>;\n\t\t};\n\n\t\tconst pointerUp$ = pointerEvent$.pipe(\n\t\t\tfilter((event) => event.type === \"pointerup\"),\n\t\t);\n\t\tconst pointerLeave$ = pointerEvent$.pipe(\n\t\t\tfilter((event) => event.type === \"pointerleave\"),\n\t\t);\n\t\tconst pointerCancel$ = pointerEvent$.pipe(\n\t\t\tfilter((event) => event.type === \"pointercancel\"),\n\t\t);\n\t\tconst pointerMove$ = pointerEvent$.pipe(\n\t\t\tfilter((event) => event.type === \"pointermove\"),\n\t\t);\n\t\tconst contextMenu$ = fromEvent<PointerEvent>(window, \"contextmenu\");\n\n\t\tconst isPointerRemoved = (event: PointerEvent) =>\n\t\t\t[\"pointercancel\", \"pointerleave\", \"pointerup\", \"contextmenu\"].includes(\n\t\t\t\tevent.type,\n\t\t\t);\n\n\t\treturn stream.pipe(\n\t\t\tmergeMap((pointerDown) => {\n\t\t\t\tconst pointerDown$ = defer(() => of(pointerDown));\n\n\t\t\t\tconst tracking$ = merge(\n\t\t\t\t\tpointerDown$,\n\t\t\t\t\tmerge(\n\t\t\t\t\t\tpointerMove$,\n\t\t\t\t\t\tpointerCancel$,\n\t\t\t\t\t\tpointerLeave$,\n\t\t\t\t\t\tpointerUp$,\n\t\t\t\t\t\tcontextMenu$,\n\t\t\t\t\t),\n\t\t\t\t).pipe(\n\t\t\t\t\tmatchPointer(pointerDown),\n\t\t\t\t\ttakeWhile((event) => !isPointerRemoved(event), true),\n\t\t\t\t);\n\n\t\t\t\treturn tracking$;\n\t\t\t}),\n\t\t\tscan<PointerEvent, PointersState, undefined>((acc, event) => {\n\t\t\t\tif (isPointerRemoved(event)) {\n\t\t\t\t\tconst { [event.pointerId]: _deleted, ...rest } = acc?.pointers ?? {};\n\n\t\t\t\t\tvoid _deleted;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tevent,\n\t\t\t\t\t\tpointers: rest,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tevent,\n\t\t\t\t\tpointers: {\n\t\t\t\t\t\t...(acc?.pointers ?? {}),\n\t\t\t\t\t\t[event.pointerId]: event,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}, undefined),\n\t\t\tmap(({ event, pointers }) => ({\n\t\t\t\tevent,\n\t\t\t\tpointers: Object.values(pointers).filter(isDefined),\n\t\t\t})),\n\t\t);\n\t};\n","import {\n\tdistinctUntilChanged,\n\tfilter,\n\ttype Observable,\n\tshareReplay,\n} from \"rxjs\";\n\nexport const emitOnceWhen =\n\t<T>(condition: (value: T) => boolean) =>\n\t(stream: Observable<T>) =>\n\t\tstream.pipe(\n\t\t\t// only emit once when we have a condition switch\n\t\t\tdistinctUntilChanged((previous, current) => {\n\t\t\t\tconst previousHasLessThan = condition(previous);\n\t\t\t\tconst currentHasLessThan = condition(current);\n\n\t\t\t\treturn previousHasLessThan === currentHasLessThan;\n\t\t\t}),\n\t\t\t// make sure to only pass true\n\t\t\tfilter(condition),\n\t\t);\n\n/**\n * Shares the latest value with late subscribers, and unsubscribes from the\n * source along with the last subscriber, which shareReplay(1) doesn't do.\n */\nexport const shareLatest = <T>() =>\n\tshareReplay<T>({ bufferSize: 1, refCount: true });\n","import { filter, type Observable } from \"rxjs\";\nimport { isPointerOffEvent } from \"../utils/events\";\n\nexport const isValidConfig = <T extends { container?: HTMLElement }>(\n\tstream: Observable<T>,\n) =>\n\tstream.pipe(\n\t\tfilter(\n\t\t\t(config): config is T & { container: HTMLElement } => !!config.container,\n\t\t),\n\t);\n\nexport const filterPointerOff = (stream: Observable<PointerEvent>) =>\n\tstream.pipe(filter(isPointerOffEvent));\n","import { map, type Observable, scan } from \"rxjs\";\nimport {\n\tcalculateAngleDelta,\n\tcalculateAverageDistance,\n\tcalculateCentroid,\n} from \"../utils/geometry\";\nimport { calculateVelocity } from \"../utils/utils\";\nimport type { RecognizerEvent } from \"./RecognizerEvent\";\n\nexport interface RecognizerEventInput {\n\tevent: PointerEvent;\n\tlatestActivePointers: PointerEvent[];\n}\n\ninterface RecognizerEventState extends RecognizerEventInput {\n\tstartTime: number;\n\tcenter: { x: number; y: number };\n\tdeltaX: number;\n\tdeltaY: number;\n\tdeltaPointersAngle: number;\n}\n\nconst calculateNewDelta = (\n\tnewCenter: { x: number; y: number },\n\tprevCenter: { x: number; y: number },\n\tprevDeltaX: number,\n\tprevDeltaY: number,\n) => {\n\tconst deltaX = newCenter.x - prevCenter.x + prevDeltaX;\n\tconst deltaY = newCenter.y - prevCenter.y + prevDeltaY;\n\n\treturn {\n\t\tdeltaX,\n\t\tdeltaY,\n\t};\n};\n\nexport const scanToRecognizerEvent = <T extends RecognizerEventInput>(\n\tstream: Observable<T>,\n): Observable<RecognizerEvent> => {\n\tconst getCenterFromData = (data: T) =>\n\t\tcalculateCentroid(\n\t\t\t!data.latestActivePointers.length\n\t\t\t\t? [data.event]\n\t\t\t\t: data.latestActivePointers,\n\t\t);\n\n\treturn stream.pipe(\n\t\tscan<T, RecognizerEventState, undefined>((acc, curr) => {\n\t\t\tconst newCenter = getCenterFromData(curr);\n\t\t\tconst prevCenter = acc?.center ?? newCenter;\n\t\t\tconst prevDeltaX = acc?.deltaX ?? 0;\n\t\t\tconst prevDeltaY = acc?.deltaY ?? 0;\n\t\t\tconst prevActivePointersNumber = acc?.latestActivePointers?.length ?? 1;\n\t\t\tconst currActivePointersNumber = curr.latestActivePointers?.length ?? 1;\n\n\t\t\tconst hasAddedOrRemovedAFinger =\n\t\t\t\t[\"pointerdown\", \"pointercancel\", \"pointerleave\", \"pointerup\"].includes(\n\t\t\t\t\tcurr.event.type,\n\t\t\t\t) && prevActivePointersNumber !== currActivePointersNumber;\n\n\t\t\tconst hasAtLeastOneFinger = currActivePointersNumber > 0;\n\n\t\t\tconst { deltaX, deltaY } =\n\t\t\t\t(hasAddedOrRemovedAFinger && hasAtLeastOneFinger) ||\n\t\t\t\t/**\n\t\t\t\t * A pointercancel cean come after a drag event and heven being completely\n\t\t\t\t * desync, leading to erroned values. We should just ignore it.\n\t\t\t\t */\n\t\t\t\tcurr.event.type === \"pointercancel\"\n\t\t\t\t\t? calculateNewDelta(newCenter, newCenter, prevDeltaX, prevDeltaY)\n\t\t\t\t\t: calculateNewDelta(newCenter, prevCenter, prevDeltaX, prevDeltaY);\n\n\t\t\tconst { degreesDelta: deltaPointersAngle } =\n\t\t\t\tprevActivePointersNumber === currActivePointersNumber &&\n\t\t\t\tprevActivePointersNumber >= 2 &&\n\t\t\t\tcurrActivePointersNumber >= 2 &&\n\t\t\t\t/**\n\t\t\t\t * A pointercancel cean come after a drag event and heven being completely\n\t\t\t\t * desync, leading to erroned values. We should just ignore it.\n\t\t\t\t */\n\t\t\t\tcurr.event.type !== \"pointercancel\"\n\t\t\t\t\t? calculateAngleDelta(\n\t\t\t\t\t\t\tacc?.latestActivePointers ?? [],\n\t\t\t\t\t\t\tcurr.latestActivePointers ?? [],\n\t\t\t\t\t\t)\n\t\t\t\t\t: { degreesDelta: 0 };\n\n\t\t\treturn {\n\t\t\t\tstartTime: Date.now(),\n\t\t\t\t...acc,\n\t\t\t\t...curr,\n\t\t\t\tcenter: newCenter,\n\t\t\t\tdeltaX,\n\t\t\t\tdeltaY,\n\t\t\t\tdeltaPointersAngle,\n\t\t\t};\n\t\t}, undefined),\n\t\tmap((data) => {\n\t\t\tconst {\n\t\t\t\tdeltaX,\n\t\t\t\tdeltaY,\n\t\t\t\tlatestActivePointers,\n\t\t\t\tstartTime,\n\t\t\t\tcenter,\n\t\t\t\tevent,\n\t\t\t\tdeltaPointersAngle,\n\t\t\t} = data;\n\t\t\tconst events = latestActivePointers ?? [];\n\n\t\t\t// Calculate the change in time\n\t\t\tconst now = Date.now();\n\t\t\tconst delay = now - startTime;\n\n\t\t\tconst { velocityX, velocityY } = calculateVelocity(delay, deltaX, deltaY);\n\t\t\tconst pointersAverageDistance =\n\t\t\t\tcalculateAverageDistance(latestActivePointers);\n\n\t\t\treturn {\n\t\t\t\tdeltaX,\n\t\t\t\tdeltaY,\n\t\t\t\tvelocityX,\n\t\t\t\tvelocityY,\n\t\t\t\tdelay,\n\t\t\t\tcenter,\n\t\t\t\tpointers: events,\n\t\t\t\tstartTime,\n\t\t\t\tevent,\n\t\t\t\tdeltaPointersAngle,\n\t\t\t\tpointersAverageDistance,\n\t\t\t} satisfies RecognizerEvent;\n\t\t}),\n\t);\n};\n","import { fromEvent, map, merge } from \"rxjs\";\nimport { fromPointerDown } from \"../utils/events\";\n\nexport const getPointerEvents = ({\n\tcontainer,\n\tafterEventReceived = (event) => event,\n}: {\n\tcontainer: HTMLElement;\n\tafterEventReceived?: (event: PointerEvent) => PointerEvent;\n}) => {\n\tconst pointerDown$ = fromPointerDown({ afterEventReceived, container });\n\tconst pointerUp$ = fromEvent<PointerEvent>(container, \"pointerup\").pipe(\n\t\tmap(afterEventReceived),\n\t);\n\tconst pointerMove$ = fromEvent<PointerEvent>(container, \"pointermove\").pipe(\n\t\tmap(afterEventReceived),\n\t);\n\t/**\n\t * Mostly used to handle cursor leaving window on mouse pointers.\n\t */\n\tconst pointerLeave$ = fromEvent<PointerEvent>(container, \"pointerleave\").pipe(\n\t\tmap(afterEventReceived),\n\t);\n\t/**\n\t * Handle things such as contextual menu popup or\n\t * native swipe navigation conflict.\n\t */\n\tconst pointerCancel$ = fromEvent<PointerEvent>(\n\t\tcontainer,\n\t\t\"pointercancel\",\n\t).pipe(map(afterEventReceived));\n\n\tconst pointerEvents$ = merge(\n\t\tpointerDown$,\n\t\tpointerCancel$,\n\t\tpointerLeave$,\n\t\tpointerUp$,\n\t\tpointerMove$,\n\t);\n\n\treturn {\n\t\tpointerEvents$,\n\t\tpointerDown$,\n\t\tpointerCancel$,\n\t\tpointerLeave$,\n\t\tpointerUp$,\n\t\tpointerMove$,\n\t};\n};\n","import {\n\tBehaviorSubject,\n\tcombineLatest,\n\tdistinctUntilChanged,\n\texhaustMap,\n\tfilter,\n\tfinalize,\n\tfirst,\n\tmap,\n\tmerge,\n\tmergeMap,\n\ttype Observable,\n\tof,\n\tshare,\n\tshareReplay,\n\tskip,\n\tstartWith,\n\tswitchMap,\n\ttakeUntil,\n\ttap,\n\ttimer,\n\twithLatestFrom,\n} from \"rxjs\";\nimport { matchPointer, trackPointers } from \"../utils/events\";\nimport { shareLatest } from \"../utils/operators\";\nimport { isWithinPosThreshold, omitUnset } from \"../utils/utils\";\nimport { filterPointerOff, isValidConfig } from \"./operators\";\nimport type { RecognizerEvent } from \"./RecognizerEvent\";\nimport { scanToRecognizerEvent } from \"./scanToRecognizerEvent\";\nimport { getPointerEvents } from \"./utils\";\n\nexport type { RecognizerEvent };\n\ntype PanConfig = {\n\tposThreshold?: number;\n\tdelay?: number;\n\t/**\n\t * Number of inputs to trigger the event.\n\t * Default to 1\n\t */\n\tnumInputs?: number;\n};\n\nexport interface FailWith {\n\tstart$: Observable<unknown>;\n\tend$: Observable<unknown>;\n}\n\nexport type RecognizerConfig<Options> = {\n\tcontainer?: HTMLElement;\n\tafterEventReceived?: (event: PointerEvent) => PointerEvent;\n\toptions?: Options;\n\tfailWith?: FailWith[];\n};\n\nexport interface RecognizerPanEvent extends RecognizerEvent {\n\ttype: \"start\" | \"move\" | \"end\";\n}\n\nexport type State = {\n\t/**\n\t * Fingers of the gesture the recognizer recognizes, as of its latest\n\t * event, from its start event until its end event. None the rest of the\n\t * time, and none for a gesture recognized once the fingers are lifted,\n\t * as a tap or a swipe.\n\t */\n\tfingers: number;\n};\n\nexport abstract class Recognizer<\n\tOptions extends object = never,\n\tEvent extends RecognizerEvent = RecognizerEvent,\n> {\n\tprotected configSubject = new BehaviorSubject<\n\t\tRecognizerConfig<Options> & {\n\t\t\tpanConfig?: PanConfig;\n\t\t}\n\t>({});\n\tprivate stateSubject = new BehaviorSubject<State>({\n\t\tfingers: 0,\n\t});\n\tprotected pan$: Observable<RecognizerPanEvent>;\n\tprotected panStart$: Observable<RecognizerEvent>;\n\tprotected panMove$: Observable<RecognizerEvent>;\n\tprotected panEnd$: Observable<RecognizerEvent>;\n\n\tprotected pointerEvent$: Observable<PointerEvent>;\n\tprotected pointerDown$: Observable<PointerEvent>;\n\tprotected pointerUp$: Observable<PointerEvent>;\n\tprotected pointerCancel$: Observable<PointerEvent>;\n\tprotected pointerMove$: Observable<PointerEvent>;\n\tprotected pointerOff$: Observable<PointerEvent>;\n\n\tpublic state$: Observable<State>;\n\tpublic config$ = this.configSubject.pipe(isValidConfig);\n\n\tabstract events$: Observable<Event>;\n\n\t/**\n\t * Track active running failWith recognizers\n\t */\n\tprotected failWithActive$: Observable<boolean>;\n\n\t/**\n\t * Reports in state$ the fingers of the gesture the recognizer's events\n\t * recognize, until `isEnd` tells its end event, or until nothing listens\n\t * to them anymore.\n\t */\n\tprotected reportFingers =\n\t\t(isEnd: (event: Event) => boolean) => (events$: Observable<Event>) =>\n\t\t\tevents$.pipe(\n\t\t\t\ttap((event) => {\n\t\t\t\t\tthis.stateSubject.next({\n\t\t\t\t\t\tfingers: isEnd(event) ? 0 : event.pointers.length,\n\t\t\t\t\t});\n\t\t\t\t}),\n\t\t\t\tfinalize(() => {\n\t\t\t\t\tthis.stateSubject.next({ fingers: 0 });\n\t\t\t\t}),\n\t\t\t);\n\n\tconstructor(config?: RecognizerConfig<Options>, panConfig?: PanConfig) {\n\t\tthis.pointerEvent$ = this.config$.pipe(\n\t\t\tswitchMap(\n\t\t\t\t({ container, afterEventReceived }) =>\n\t\t\t\t\tgetPointerEvents({\n\t\t\t\t\t\tcontainer,\n\t\t\t\t\t\tafterEventReceived,\n\t\t\t\t\t}).pointerEvents$,\n\t\t\t),\n\t\t\tshare(),\n\t\t);\n\n\t\tthis.pointerDown$ = this.pointerEvent$.pipe(\n\t\t\tfilter((event) => event.type === \"pointerdown\"),\n\t\t);\n\n\t\tthis.pointerUp$ = this.pointerEvent$.pipe(\n\t\t\tfilter((event) => event.type === \"pointerup\"),\n\t\t);\n\n\t\tthis.pointerMove$ = this.pointerEvent$.pipe(\n\t\t\tfilter((event) => event.type === \"pointermove\"),\n\t\t);\n\n\t\tthis.pointerCancel$ = this.pointerEvent$.pipe(\n\t\t\tfilter((event) => event.type === \"pointercancel\"),\n\t\t);\n\n\t\tthis.pointerOff$ = this.pointerEvent$.pipe(filterPointerOff);\n\n\t\tconst failWith$ = this.config$.pipe(\n\t\t\tmap(({ failWith }) => failWith),\n\t\t\tdistinctUntilChanged(),\n\t\t);\n\n\t\tthis.failWithActive$ = failWith$.pipe(\n\t\t\tswitchMap((failWith) => {\n\t\t\t\tconst areRunnings$ = failWith?.map((recognizer) => {\n\t\t\t\t\tconst start$ = recognizer.start$.pipe(map(() => true));\n\n\t\t\t\t\tconst end$ = recognizer.end$.pipe(map(() => false));\n\n\t\t\t\t\tconst isRunning$ = merge(start$, end$).pipe(startWith(false));\n\n\t\t\t\t\treturn isRunning$;\n\t\t\t\t});\n\n\t\t\t\tif (!areRunnings$?.length) {\n\t\t\t\t\treturn combineLatest([of(false)]);\n\t\t\t\t}\n\n\t\t\t\treturn combineLatest(areRunnings$);\n\t\t\t}),\n\t\t\tmap((runnings) => runnings.some((running) => running)),\n\t\t\t/**\n\t\t\t * Keeps following the failWith recognizers once subscribed: they can't\n\t\t\t * be asked whether they run, so a recognizer subscribing again later\n\t\t\t * would miss the gesture of one that started in between.\n\t\t\t */\n\t\t\tshareReplay(1),\n\t\t);\n\n\t\tthis.pan$ = this.configSubject.pipe(\n\t\t\tisValidConfig,\n\t\t\tswitchMap((config) => {\n\t\t\t\tconst numInputs = Math.max(1, config.panConfig?.numInputs ?? 1);\n\t\t\t\tconst posThreshold = Math.max(0, config.panConfig?.posThreshold ?? 0);\n\t\t\t\tconst delay = Math.max(0, config.panConfig?.delay ?? 0);\n\n\t\t\t\tconst trackPointers$ = this.pointerDown$.pipe(\n\t\t\t\t\ttrackPointers({\n\t\t\t\t\t\tpointerEvent$: this.pointerEvent$,\n\t\t\t\t\t\ttrackMove: true,\n\t\t\t\t\t}),\n\t\t\t\t\tshareLatest(),\n\t\t\t\t);\n\n\t\t\t\tconst hasEnoughFingers = (\n\t\t\t\t\tstream: Observable<{ event: PointerEvent; pointers: PointerEvent[] }>,\n\t\t\t\t) =>\n\t\t\t\t\tstream.pipe(\n\t\t\t\t\t\tfilter(\n\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\tevents,\n\t\t\t\t\t\t\t): events is { event: PointerEvent; pointers: [PointerEvent] } =>\n\t\t\t\t\t\t\t\tevents.pointers.length >= numInputs,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\n\t\t\t\tconst hasNotEnoughFingers = (\n\t\t\t\t\tstream: Observable<{\n\t\t\t\t\t\tevent: PointerEvent;\n\t\t\t\t\t\tpointers: PointerEvent[];\n\t\t\t\t\t}>,\n\t\t\t\t) =>\n\t\t\t\t\tstream.pipe(filter((events) => events.pointers.length < numInputs));\n\n\t\t\t\treturn trackPointers$.pipe(\n\t\t\t\t\thasEnoughFingers,\n\t\t\t\t\texhaustMap(({ pointers: initialPointerEvents }) => {\n\t\t\t\t\t\tconst panReleased$ = trackPointers$.pipe(\n\t\t\t\t\t\t\thasNotEnoughFingers,\n\t\t\t\t\t\t\tfirst(),\n\t\t\t\t\t\t\tshare(),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst delay$ = timer(delay);\n\n\t\t\t\t\t\tconst pointerDownPassingThreshold$ = merge(\n\t\t\t\t\t\t\t...initialPointerEvents.map((pointerEvent) => of(pointerEvent)),\n\t\t\t\t\t\t\tthis.pointerDown$,\n\t\t\t\t\t\t).pipe(\n\t\t\t\t\t\t\tmergeMap((pointerDown) =>\n\t\t\t\t\t\t\t\tmerge(this.pointerMove$, of(pointerDown)).pipe(\n\t\t\t\t\t\t\t\t\tmatchPointer(pointerDown),\n\t\t\t\t\t\t\t\t\tfilter((pointerEvent) =>\n\t\t\t\t\t\t\t\t\t\tisWithinPosThreshold(\n\t\t\t\t\t\t\t\t\t\t\tpointerDown,\n\t\t\t\t\t\t\t\t\t\t\tpointerEvent,\n\t\t\t\t\t\t\t\t\t\t\tposThreshold,\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tfirst(),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst panStart$ = pointerDownPassingThreshold$.pipe(\n\t\t\t\t\t\t\tswitchMap(() => delay$),\n\t\t\t\t\t\t\twithLatestFrom(trackPointers$),\n\t\t\t\t\t\t\tmap(([, { event, pointers }]) => ({\n\t\t\t\t\t\t\t\ttype: \"start\" as const,\n\t\t\t\t\t\t\t\tevent,\n\t\t\t\t\t\t\t\tlatestActivePointers: pointers,\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\tshareLatest(),\n\t\t\t\t\t\t\ttakeUntil(panReleased$),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst panUpdate$ = panStart$.pipe(\n\t\t\t\t\t\t\tmergeMap(() =>\n\t\t\t\t\t\t\t\ttrackPointers$.pipe(\n\t\t\t\t\t\t\t\t\tskip(1),\n\t\t\t\t\t\t\t\t\tmap(({ event, pointers }) => ({\n\t\t\t\t\t\t\t\t\t\ttype: \"move\" as const,\n\t\t\t\t\t\t\t\t\t\tevent,\n\t\t\t\t\t\t\t\t\t\tlatestActivePointers: pointers,\n\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\ttakeUntil(panReleased$),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst panEnd$ = panStart$.pipe(\n\t\t\t\t\t\t\tmergeMap(() =>\n\t\t\t\t\t\t\t\tpanReleased$.pipe(\n\t\t\t\t\t\t\t\t\tmap(({ event, pointers }) => ({\n\t\t\t\t\t\t\t\t\t\ttype: \"end\" as const,\n\t\t\t\t\t\t\t\t\t\tevent,\n\t\t\t\t\t\t\t\t\t\tlatestActivePointers: pointers,\n\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst rawEvent$ = merge(panStart$, panUpdate$, panEnd$).pipe(\n\t\t\t\t\t\t\tshareLatest(),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn rawEvent$.pipe(\n\t\t\t\t\t\t\tscanToRecognizerEvent,\n\t\t\t\t\t\t\twithLatestFrom(rawEvent$),\n\t\t\t\t\t\t\tmap(([recognizerEvent, { type }]) => ({\n\t\t\t\t\t\t\t\t...recognizerEvent,\n\t\t\t\t\t\t\t\ttype,\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}),\n\t\t\tshare(),\n\t\t);\n\n\t\tthis.panStart$ = this.pan$.pipe(\n\t\t\tfilter((event) => event.type === \"start\"),\n\t\t\tmap(({ type, ...rest }) => rest),\n\t\t);\n\n\t\tthis.panMove$ = this.pan$.pipe(\n\t\t\tfilter((event) => event.type === \"move\"),\n\t\t\tmap(({ type, ...rest }) => rest),\n\t\t);\n\n\t\tthis.panEnd$ = this.pan$.pipe(\n\t\t\tfilter((event) => event.type === \"end\"),\n\t\t\tmap(({ type, ...rest }) => rest),\n\t\t);\n\n\t\tthis.state$ = this.stateSubject.pipe(\n\t\t\tdistinctUntilChanged(\n\t\t\t\t(previous, current) => previous.fingers === current.fingers,\n\t\t\t),\n\t\t);\n\n\t\tthis.updateInternal(config ?? {}, panConfig);\n\t}\n\n\tprivate updateInternal(\n\t\tconfig: Partial<RecognizerConfig<Options>>,\n\t\tpanConfig?: PanConfig,\n\t) {\n\t\tconst existingConfig = this.configSubject.getValue();\n\n\t\tthis.configSubject.next({\n\t\t\t...existingConfig,\n\t\t\t...config,\n\t\t\t// unset, as when forwarding an optional value, they stay as they are\n\t\t\tfailWith: config.failWith ?? existingConfig.failWith,\n\t\t\tafterEventReceived:\n\t\t\t\tconfig.afterEventReceived ?? existingConfig.afterEventReceived,\n\t\t\t...(config.options && {\n\t\t\t\t// every option is optional, so leaving out the unset ones keeps them valid\n\t\t\t\toptions: {\n\t\t\t\t\t...existingConfig.options,\n\t\t\t\t\t...omitUnset(config.options),\n\t\t\t\t} as Options,\n\t\t\t}),\n\t\t\tpanConfig: {\n\t\t\t\t...existingConfig.panConfig,\n\t\t\t\t...omitUnset(panConfig),\n\t\t\t},\n\t\t});\n\t}\n\n\tpublic update(\n\t\tconfig: Partial<RecognizerConfig<Options>>,\n\t\tpanConfig?: PanConfig,\n\t) {\n\t\tthis.updateInternal(config, panConfig);\n\t}\n}\n","import {\n\tfilter,\n\tfirst,\n\tmap,\n\tmerge,\n\ttype Observable,\n\tof,\n\tshare,\n\tswitchMap,\n\ttakeUntil,\n\twithLatestFrom,\n} from \"rxjs\";\nimport { Recognizer, type RecognizerConfig } from \"../recognizer/Recognizer\";\nimport { omitUnset } from \"../utils/utils\";\nimport type {\n\tHoldEvent,\n\tHoldRecognizerInterface,\n\tHoldRecognizerOptions,\n} from \"./HoldRecognizerInterface\";\n\nexport type { HoldEvent, HoldRecognizerOptions };\n\nexport class HoldRecognizer\n\textends Recognizer<HoldRecognizerOptions, HoldEvent>\n\timplements HoldRecognizerInterface\n{\n\tpublic events$: Observable<HoldEvent>;\n\n\tconstructor(options: RecognizerConfig<HoldRecognizerOptions> = {}) {\n\t\tsuper(options, {\n\t\t\tnumInputs: 1,\n\t\t\tdelay: 0,\n\t\t\tposThreshold: 0,\n\t\t\t...omitUnset(options.options),\n\t\t});\n\n\t\tconst start$ = this.panStart$.pipe(\n\t\t\twithLatestFrom(this.failWithActive$),\n\t\t\tfilter(([, failWithActive]) => !failWithActive),\n\t\t\tmap(([event]) => {\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"holdStart\" as const,\n\t\t\t\t\t...event,\n\t\t\t\t};\n\t\t\t}),\n\t\t);\n\n\t\tthis.events$ = start$.pipe(\n\t\t\tswitchMap((holdStartEvent) => {\n\t\t\t\tconst failingActive$ = this.failWithActive$.pipe(\n\t\t\t\t\tfilter((isActive) => isActive),\n\t\t\t\t\tfirst(),\n\t\t\t\t);\n\n\t\t\t\tconst end$ = this.panEnd$.pipe(\n\t\t\t\t\tfirst(),\n\t\t\t\t\tmap((event) => {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\ttype: \"holdEnd\" as const,\n\t\t\t\t\t\t\t...event,\n\t\t\t\t\t\t};\n\t\t\t\t\t}),\n\t\t\t\t\ttakeUntil(failingActive$),\n\t\t\t\t);\n\n\t\t\t\t// cancelled by failWith: it ends where it started\n\t\t\t\tconst trailingEndEventIfFailed$ = failingActive$.pipe(\n\t\t\t\t\tmap(() => ({ ...holdStartEvent, type: \"holdEnd\" as const })),\n\t\t\t\t\ttakeUntil(this.panEnd$),\n\t\t\t\t);\n\n\t\t\t\treturn merge(of(holdStartEvent), end$, trailingEndEventIfFailed$);\n\t\t\t}),\n\t\t\tthis.reportFingers((event) => event.type === \"holdEnd\"),\n\t\t\tshare(),\n\t\t);\n\t}\n\n\tpublic update(options: RecognizerConfig<HoldRecognizerOptions>) {\n\t\tsuper.update(options, options.options);\n\t}\n}\n","import {\n\tfilter,\n\tfirst,\n\tmap,\n\tmerge,\n\ttype Observable,\n\tof,\n\tshare,\n\tswitchMap,\n\ttakeUntil,\n\ttap,\n\twithLatestFrom,\n} from \"rxjs\";\nimport { Recognizer, type RecognizerConfig } from \"../recognizer/Recognizer\";\nimport { omitUnset } from \"../utils/utils\";\nimport type {\n\tPanEvent,\n\tPanRecognizerInterface,\n\tPanRecognizerOptions,\n} from \"./PanRecognizerInterface\";\n\nexport type { PanEvent, PanRecognizerOptions };\n\nexport class PanRecognizer\n\textends Recognizer<PanRecognizerOptions, PanEvent>\n\timplements PanRecognizerInterface\n{\n\tpublic events$: Observable<PanEvent>;\n\tpublic start$: Observable<PanEvent>;\n\tpublic end$: Observable<PanEvent>;\n\n\tconstructor(config?: RecognizerConfig<PanRecognizerOptions>) {\n\t\tsuper(config, {\n\t\t\tposThreshold: 15,\n\t\t\t...omitUnset(config?.options),\n\t\t});\n\n\t\tconst panStart$ = this.panStart$.pipe(\n\t\t\tmap((event) => ({\n\t\t\t\ttype: \"panStart\" as const,\n\t\t\t\t...event,\n\t\t\t})),\n\t\t\twithLatestFrom(this.failWithActive$),\n\t\t\tfilter(([, failWithActive]) => !failWithActive),\n\t\t\tmap(([event]) => event),\n\t\t\tshare(),\n\t\t);\n\n\t\tconst panEnd$ = this.panEnd$.pipe(\n\t\t\tmap((event) => ({\n\t\t\t\ttype: \"panEnd\" as const,\n\t\t\t\t...event,\n\t\t\t})),\n\t\t\tshare(),\n\t\t);\n\n\t\tconst panMove$ = this.panMove$.pipe(\n\t\t\tmap((event) => ({\n\t\t\t\ttype: \"panMove\" as const,\n\t\t\t\t...event,\n\t\t\t})),\n\t\t);\n\n\t\tthis.events$ = panStart$.pipe(\n\t\t\tswitchMap((panStartEvent) => {\n\t\t\t\tlet latestEvent: PanEvent = panStartEvent;\n\n\t\t\t\tconst panStarted$ = of(panStartEvent);\n\n\t\t\t\tconst failingActive$ = this.failWithActive$.pipe(\n\t\t\t\t\tfilter((isActive) => isActive),\n\t\t\t\t\tfirst(),\n\t\t\t\t);\n\n\t\t\t\tconst events$ = merge(panStarted$, panMove$, panEnd$).pipe(\n\t\t\t\t\ttap((event) => {\n\t\t\t\t\t\tlatestEvent = event;\n\t\t\t\t\t}),\n\t\t\t\t\ttakeUntil(failingActive$),\n\t\t\t\t);\n\n\t\t\t\tconst trailingEndEventIfFailed$ = failingActive$.pipe(\n\t\t\t\t\tmap(() => ({\n\t\t\t\t\t\t...latestEvent,\n\t\t\t\t\t\ttype: \"panEnd\" as const,\n\t\t\t\t\t})),\n\t\t\t\t\ttakeUntil(panEnd$),\n\t\t\t\t);\n\n\t\t\t\treturn merge(events$, trailingEndEventIfFailed$);\n\t\t\t}),\n\t\t\tthis.reportFingers((event) => event.type === \"panEnd\"),\n\t\t\tshare(),\n\t\t);\n\n\t\tthis.start$ = this.events$.pipe(\n\t\t\tfilter((event) => event.type === \"panStart\"),\n\t\t);\n\n\t\tthis.end$ = this.events$.pipe(filter((event) => event.type === \"panEnd\"));\n\t}\n\n\tpublic update(config: RecognizerConfig<PanRecognizerOptions>) {\n\t\tsuper.update(config, config.options);\n\t}\n}\n","import { map, type Observable, scan } from \"rxjs\";\nimport type { RecognizerEvent } from \"../recognizer/RecognizerEvent\";\nimport type { PinchEvent } from \"./PinchRecognizerInterface\";\n\n/**\n * What the scale and distance are measured from: an average distance between\n * the fingers, and the scale and distance reached there.\n */\ntype Reference = Pick<\n\tPinchEvent,\n\t\"pointersAverageDistance\" | \"scale\" | \"distance\"\n>;\n\nexport const scanPanEventToPinchEvent =\n\t({\n\t\ttype,\n\t\tinitialEvent,\n\t}: {\n\t\ttype: PinchEvent[\"type\"];\n\t\tinitialEvent: PinchEvent | RecognizerEvent | undefined;\n\t}) =>\n\t(stream: Observable<RecognizerEvent | PinchEvent>) =>\n\t\tstream.pipe(\n\t\t\tscan<\n\t\t\t\tRecognizerEvent | PinchEvent,\n\t\t\t\tPinchEvent & {\n\t\t\t\t\treference: Reference;\n\t\t\t\t},\n\t\t\t\tPinchEvent | RecognizerEvent | undefined\n\t\t\t>((acc, curr) => {\n\t\t\t\tconst previousPointersLength = acc?.pointers.length ?? 0;\n\t\t\t\tconst hasChangedFingers =\n\t\t\t\t\tpreviousPointersLength !== curr.pointers.length;\n\t\t\t\tconst previousPointersAverageDistance =\n\t\t\t\t\tacc?.pointersAverageDistance ?? curr.pointersAverageDistance;\n\n\t\t\t\t/**\n\t\t\t\t * The reference is reset every time we change fingers, as the average\n\t\t\t\t * distance between 3 fingers can't be compared with the one between 2:\n\t\t\t\t * the scale and distance reached carry over. Otherwise it is the one\n\t\t\t\t * of the event we continue from (the pinch start for the first move).\n\t\t\t\t * @important in case of 1 finger, distance will be 0\n\t\t\t\t */\n\t\t\t\tconst reference: Reference =\n\t\t\t\t\t!hasChangedFingers && acc && \"reference\" in acc\n\t\t\t\t\t\t? acc.reference\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\tpointersAverageDistance: hasChangedFingers\n\t\t\t\t\t\t\t\t\t? curr.pointersAverageDistance\n\t\t\t\t\t\t\t\t\t: previousPointersAverageDistance,\n\t\t\t\t\t\t\t\tscale: acc && \"scale\" in acc ? acc.scale : 1,\n\t\t\t\t\t\t\t\tdistance: acc && \"distance\" in acc ? acc.distance : 0,\n\t\t\t\t\t\t\t};\n\n\t\t\t\t/**\n\t\t\t\t * @important When finger is 1, distance is 0\n\t\t\t\t */\n\t\t\t\tconst scale =\n\t\t\t\t\treference.pointersAverageDistance === 0\n\t\t\t\t\t\t? reference.scale\n\t\t\t\t\t\t: reference.scale *\n\t\t\t\t\t\t\t(curr.pointersAverageDistance /\n\t\t\t\t\t\t\t\treference.pointersAverageDistance);\n\n\t\t\t\tconst distance =\n\t\t\t\t\treference.distance +\n\t\t\t\t\t(curr.pointersAverageDistance - reference.pointersAverageDistance);\n\n\t\t\t\tconst deltaDistance = hasChangedFingers\n\t\t\t\t\t? 0\n\t\t\t\t\t: curr.pointersAverageDistance - previousPointersAverageDistance;\n\n\t\t\t\t/**\n\t\t\t\t * @important When finger is 1, distance is 0\n\t\t\t\t * Same when fingers change\n\t\t\t\t */\n\t\t\t\tconst deltaDistanceScale =\n\t\t\t\t\thasChangedFingers || previousPointersAverageDistance === 0\n\t\t\t\t\t\t? 1\n\t\t\t\t\t\t: curr.pointersAverageDistance / previousPointersAverageDistance;\n\n\t\t\t\treturn {\n\t\t\t\t\t...acc,\n\t\t\t\t\t...curr,\n\t\t\t\t\ttype,\n\t\t\t\t\treference,\n\t\t\t\t\tscale,\n\t\t\t\t\tdistance,\n\t\t\t\t\tdeltaDistance,\n\t\t\t\t\tdeltaDistanceScale,\n\t\t\t\t};\n\t\t\t}, initialEvent),\n\t\t\tmap(({ reference, ...rest }): PinchEvent => rest),\n\t\t);\n","import {\n\tdefaultIfEmpty,\n\tfilter,\n\tfirst,\n\tmap,\n\tmerge,\n\ttype Observable,\n\tof,\n\tshare,\n\tswitchMap,\n\ttakeUntil,\n\ttakeWhile,\n\ttap,\n\twithLatestFrom,\n} from \"rxjs\";\nimport { Recognizer, type RecognizerConfig } from \"../recognizer/Recognizer\";\nimport { shareLatest } from \"../utils/operators\";\nimport type {\n\tPinchEvent,\n\tPinchRecognizerInterface,\n\tPinchRecognizerOptions,\n} from \"./PinchRecognizerInterface\";\nimport { scanPanEventToPinchEvent } from \"./scanPanEventToPinchEvent\";\n\nexport type {\n\tPinchEvent,\n\tPinchRecognizerOptions,\n} from \"./PinchRecognizerInterface\";\n\nexport class PinchRecognizer\n\textends Recognizer<PinchRecognizerOptions, PinchEvent>\n\timplements PinchRecognizerInterface\n{\n\tpublic events$: Observable<PinchEvent>;\n\n\tpublic start$: Observable<PinchEvent>;\n\tpublic end$: Observable<PinchEvent>;\n\n\tconstructor(config?: RecognizerConfig<PinchRecognizerOptions>) {\n\t\tsuper(config, {\n\t\t\t...config?.options,\n\t\t\tnumInputs: 2,\n\t\t});\n\n\t\tthis.events$ = this.config$.pipe(\n\t\t\tswitchMap(() => {\n\t\t\t\tlet latestPinchEvent: PinchEvent | undefined;\n\n\t\t\t\tconst pinchStarted$ = this.panStart$.pipe(\n\t\t\t\t\twithLatestFrom(this.failWithActive$),\n\t\t\t\t\tfilter(([, failWithActive]) => !failWithActive),\n\t\t\t\t\tmap(([event]) => event),\n\t\t\t\t\tswitchMap((event) =>\n\t\t\t\t\t\tof(event).pipe(\n\t\t\t\t\t\t\t// we don't want a scan on pinch start\n\t\t\t\t\t\t\tscanPanEventToPinchEvent({\n\t\t\t\t\t\t\t\ttype: \"pinchStart\",\n\t\t\t\t\t\t\t\tinitialEvent: undefined,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t\tshareLatest(),\n\t\t\t\t);\n\n\t\t\t\tconst failingActive$ = this.failWithActive$.pipe(\n\t\t\t\t\tfilter((isActive) => isActive),\n\t\t\t\t\tfirst(),\n\t\t\t\t);\n\n\t\t\t\tconst pinchMove$ = pinchStarted$.pipe(\n\t\t\t\t\tswitchMap((initialEvent) => {\n\t\t\t\t\t\treturn this.pan$.pipe(\n\t\t\t\t\t\t\ttakeWhile((event) => event.type !== \"end\"),\n\t\t\t\t\t\t\tscanPanEventToPinchEvent({\n\t\t\t\t\t\t\t\ttype: \"pinchMove\",\n\t\t\t\t\t\t\t\tinitialEvent,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t// only for this pinch, the next ones may move again\n\t\t\t\t\t\t\ttakeUntil(failingActive$),\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\t\tconst pinchEnd$ = pinchStarted$.pipe(\n\t\t\t\t\tswitchMap((pinchStartEvent) =>\n\t\t\t\t\t\tthis.pan$.pipe(\n\t\t\t\t\t\t\tfilter((event) => event.type === \"end\"),\n\t\t\t\t\t\t\ttakeUntil(failingActive$),\n\t\t\t\t\t\t\tdefaultIfEmpty(null),\n\t\t\t\t\t\t\tmap((endEvent) => {\n\t\t\t\t\t\t\t\tconst latestEvent = latestPinchEvent ?? pinchStartEvent;\n\n\t\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t\t * It ends where it got to: lifting a finger leaves too few\n\t\t\t\t\t\t\t\t * to measure the distance, and a failWith cancelling it\n\t\t\t\t\t\t\t\t * moves none. So nothing changed since the latest event.\n\t\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t...(endEvent ?? latestEvent),\n\t\t\t\t\t\t\t\t\ttype: \"pinchEnd\" as const,\n\t\t\t\t\t\t\t\t\tscale: latestEvent.scale,\n\t\t\t\t\t\t\t\t\tdistance: latestEvent.distance,\n\t\t\t\t\t\t\t\t\tdeltaDistance: 0,\n\t\t\t\t\t\t\t\t\tdeltaDistanceScale: 1,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\tshare(),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\treturn merge(pinchStarted$, pinchMove$, pinchEnd$).pipe(\n\t\t\t\t\ttap((event) => {\n\t\t\t\t\t\tlatestPinchEvent = event;\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}),\n\t\t\tthis.reportFingers((event) => event.type === \"pinchEnd\"),\n\t\t\tshare(),\n\t\t);\n\n\t\tthis.start$ = this.events$.pipe(\n\t\t\tfilter((event) => event.type === \"pinchStart\"),\n\t\t);\n\n\t\tthis.end$ = this.events$.pipe(filter((event) => event.type === \"pinchEnd\"));\n\t}\n\n\tpublic update(options: RecognizerConfig<PinchRecognizerOptions>) {\n\t\tsuper.update(options, options.options);\n\t}\n}\n","import {\n\tcombineLatest,\n\tdistinctUntilChanged,\n\tmap,\n\tmerge,\n\ttype Observable,\n\ttype ObservedValueOf,\n\tshare,\n} from \"rxjs\";\nimport type { Recognizer, RecognizerConfig } from \"../recognizer/Recognizer\";\nimport type {\n\tRecognizableInterface,\n\tRecognizableState,\n} from \"./RecognizableInterface\";\n\nexport type { RecognizableState };\n\n// biome-ignore lint/suspicious/noExplicitAny: TODO\ntype RecognizableOptions<T extends Recognizer<any, any>[]> = {\n\trecognizers: T;\n\t/**\n\t * If you don't need to have text selection, set this to true\n\t * to improve dragging gesture. This will prevent accidental\n\t * text selection on your component.\n\t */\n\tdisableTextSelection?: boolean;\n} & RecognizerConfig<unknown>;\n\n// biome-ignore lint/suspicious/noExplicitAny: TODO\nexport class Recognizable<T extends Recognizer<any, any>[]>\n\timplements RecognizableInterface<T>\n{\n\tevents$: Observable<{\n\t\tevent: ObservedValueOf<T[number][\"events$\"]>;\n\t\trecognizer: T[number];\n\t}>;\n\n\trecognizers: T;\n\n\tstate$: Observable<RecognizableState>;\n\n\tconstructor(protected options: RecognizableOptions<T>) {\n\t\tthis.recognizers = options.recognizers;\n\n\t\tthis.events$ = merge(\n\t\t\t...options.recognizers.map((recognizer) =>\n\t\t\t\trecognizer.events$.pipe(map((event) => ({ event, recognizer }))),\n\t\t\t),\n\t\t).pipe(share());\n\n\t\tthis.state$ = combineLatest(\n\t\t\tthis.recognizers.map((recognizer) => recognizer.state$),\n\t\t).pipe(\n\t\t\tmap((states) =>\n\t\t\t\tstates.reduce((acc, state) => ({\n\t\t\t\t\tfingers: Math.max(acc.fingers, state.fingers),\n\t\t\t\t})),\n\t\t\t),\n\t\t\tdistinctUntilChanged(\n\t\t\t\t(previous, current) => previous.fingers === current.fingers,\n\t\t\t),\n\t\t);\n\n\t\tthis.update(options);\n\t}\n\n\tpublic update({\n\t\tdisableTextSelection,\n\t\t...rest\n\t}: Partial<Omit<RecognizableOptions<T>, \"recognizers\">>) {\n\t\tif (rest.container) {\n\t\t\t/**\n\t\t\t * We have to disable touch-action otherwise every events will be followed\n\t\t\t * by a cancel event since the browser will try to handle touch.\n\t\t\t * @see https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action\n\t\t\t */\n\t\t\trest.container.style.touchAction = \"none\";\n\n\t\t\t/**\n\t\t\t * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.\n\t\t\t */\n\t\t\tif (disableTextSelection) {\n\t\t\t\trest.container.style.userSelect = \"none\";\n\t\t\t}\n\t\t}\n\n\t\tfor (const recognizer of this.options.recognizers) {\n\t\t\trecognizer.update(rest);\n\t\t}\n\t}\n}\n","import {\n\tfilter,\n\tfirst,\n\tmap,\n\tmerge,\n\ttype Observable,\n\tscan,\n\tshare,\n\tswitchMap,\n\ttakeUntil,\n\ttap,\n\twithLatestFrom,\n} from \"rxjs\";\nimport {\n\tRecognizer,\n\ttype RecognizerConfig,\n\ttype RecognizerPanEvent,\n} from \"../recognizer/Recognizer\";\nimport { shareLatest } from \"../utils/operators\";\nimport { omitUnset } from \"../utils/utils\";\nimport type {\n\tRotateEvent,\n\tRotateRecognizerInterface,\n\tRotateRecognizerOptions,\n} from \"./RotateRecognizerInterface\";\n\nexport type { RotateEvent, RotateRecognizerOptions };\n\ntype RotatingEvent = RecognizerPanEvent & { angle: number; deltaAngle: number };\n\nexport class RotateRecognizer\n\textends Recognizer<RotateRecognizerOptions, RotateEvent>\n\timplements RotateRecognizerInterface\n{\n\tpublic events$: Observable<RotateEvent>;\n\n\tconstructor(config: RecognizerConfig<RotateRecognizerOptions> = {}) {\n\t\tsuper(config, {\n\t\t\tnumInputs: 2,\n\t\t\tposThreshold: 15,\n\t\t\t...omitUnset(config.options),\n\t\t});\n\n\t\tthis.events$ = this.config$.pipe(\n\t\t\tswitchMap(() => {\n\t\t\t\tconst rotateStart$ = this.panStart$.pipe(\n\t\t\t\t\twithLatestFrom(this.failWithActive$),\n\t\t\t\t\tfilter(([, failWithActive]) => !failWithActive),\n\t\t\t\t\tmap(([event]) => ({\n\t\t\t\t\t\t...event,\n\t\t\t\t\t\ttype: \"rotateStart\" as const,\n\t\t\t\t\t\tangle: 0,\n\t\t\t\t\t\tdeltaAngle: 0,\n\t\t\t\t\t})),\n\t\t\t\t\tshareLatest(),\n\t\t\t\t);\n\n\t\t\t\tconst rotate$ = rotateStart$.pipe(\n\t\t\t\t\tswitchMap((rotateStartEvent) => {\n\t\t\t\t\t\tlet latestEvent: RotatingEvent = {\n\t\t\t\t\t\t\t...rotateStartEvent,\n\t\t\t\t\t\t\ttype: \"start\",\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst failingActive$ = this.failWithActive$.pipe(\n\t\t\t\t\t\t\tfilter((isActive) => isActive),\n\t\t\t\t\t\t\tfirst(),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst events$ = this.pan$.pipe(\n\t\t\t\t\t\t\tscan<RecognizerPanEvent, RotatingEvent, undefined>(\n\t\t\t\t\t\t\t\t(acc, current) => {\n\t\t\t\t\t\t\t\t\tconst angle = (acc?.angle ?? 0) + current.deltaPointersAngle;\n\n\t\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t\t...acc,\n\t\t\t\t\t\t\t\t\t\t...current,\n\t\t\t\t\t\t\t\t\t\tangle,\n\t\t\t\t\t\t\t\t\t\tdeltaAngle: current.deltaPointersAngle,\n\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\ttap((event) => {\n\t\t\t\t\t\t\t\tlatestEvent = event;\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\ttakeUntil(failingActive$),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// cancelled by failWith: it ends on the angle it reached\n\t\t\t\t\t\tconst trailingEndEventIfFailed$ = failingActive$.pipe(\n\t\t\t\t\t\t\tmap(() => ({\n\t\t\t\t\t\t\t\t...latestEvent,\n\t\t\t\t\t\t\t\ttype: \"end\" as const,\n\t\t\t\t\t\t\t\tdeltaAngle: 0,\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\ttakeUntil(this.panEnd$),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn merge(events$, trailingEndEventIfFailed$);\n\t\t\t\t\t}),\n\t\t\t\t\tshare(),\n\t\t\t\t);\n\n\t\t\t\tconst rotateMove$ = rotate$.pipe(\n\t\t\t\t\tfilter((event) => event.type === \"move\"),\n\t\t\t\t\tmap((event) => ({ ...event, type: \"rotateMove\" as const })),\n\t\t\t\t);\n\n\t\t\t\tconst rotateEnd$ = rotate$.pipe(\n\t\t\t\t\tfilter((event) => event.type === \"end\"),\n\t\t\t\t\tmap((event) => ({ ...event, type: \"rotateEnd\" as const })),\n\t\t\t\t);\n\n\t\t\t\treturn merge(rotateStart$, rotateMove$, rotateEnd$);\n\t\t\t}),\n\t\t\tthis.reportFingers((event) => event.type === \"rotateEnd\"),\n\t\t\tshare(),\n\t\t);\n\t}\n\n\tpublic update(options: RecognizerConfig<RotateRecognizerOptions>) {\n\t\tsuper.update(options, options.options);\n\t}\n}\n","import { filter, type Observable } from \"rxjs\";\nimport type { RecognizerEvent } from \"../recognizer/RecognizerEvent\";\n\nexport const isRecognizedAsSwipe =\n\t(escapeVelocity: number) => (stream: Observable<RecognizerEvent>) =>\n\t\tstream.pipe(\n\t\t\tfilter((event) => {\n\t\t\t\treturn (\n\t\t\t\t\tMath.abs(event.velocityX) >= escapeVelocity ||\n\t\t\t\t\tMath.abs(event.velocityY) >= escapeVelocity\n\t\t\t\t);\n\t\t\t}),\n\t\t);\n","import {\n\tfilter,\n\tmap,\n\ttype Observable,\n\tshare,\n\tswitchMap,\n\ttakeUntil,\n\twithLatestFrom,\n} from \"rxjs\";\nimport { Recognizer, type RecognizerConfig } from \"../recognizer/Recognizer\";\nimport { calculateDegreeAngleBetweenPoints } from \"../utils/geometry\";\nimport { isRecognizedAsSwipe } from \"./operators\";\nimport type {\n\tSwipeEvent,\n\tSwipeRecognizerInterface,\n\tSwipeRecognizerOptions,\n} from \"./SwipeRecognizerInterface\";\n\nexport type { SwipeEvent, SwipeRecognizerOptions };\n\nexport class SwipeRecognizer\n\textends Recognizer<SwipeRecognizerOptions, SwipeEvent>\n\timplements SwipeRecognizerInterface\n{\n\tpublic events$: Observable<SwipeEvent>;\n\n\tconstructor(config?: RecognizerConfig<SwipeRecognizerOptions>) {\n\t\tsuper(config, {\n\t\t\tposThreshold: 0,\n\t\t\tnumInputs: 1,\n\t\t});\n\n\t\tthis.events$ = this.config$.pipe(\n\t\t\tswitchMap((initializedWith) => {\n\t\t\t\tconst { escapeVelocity = 0.9 } = initializedWith.options ?? {};\n\n\t\t\t\treturn this.panStart$.pipe(\n\t\t\t\t\twithLatestFrom(this.failWithActive$),\n\t\t\t\t\tfilter(([, failWithActive]) => !failWithActive),\n\t\t\t\t\tswitchMap(([startEvent]) => {\n\t\t\t\t\t\treturn this.panEnd$.pipe(\n\t\t\t\t\t\t\tisRecognizedAsSwipe(escapeVelocity),\n\t\t\t\t\t\t\tmap((event) => {\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\ttype: \"swipe\" as const,\n\t\t\t\t\t\t\t\t\tangle: calculateDegreeAngleBetweenPoints(\n\t\t\t\t\t\t\t\t\t\tstartEvent.event,\n\t\t\t\t\t\t\t\t\t\tevent.event,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t...event,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\ttakeUntil(\n\t\t\t\t\t\t\t\tthis.failWithActive$.pipe(filter((isActive) => isActive)),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\n\t\t\t\t\tshare(),\n\t\t\t\t);\n\t\t\t}),\n\t\t);\n\t}\n\n\tpublic update(config: RecognizerConfig<SwipeRecognizerOptions>) {\n\t\tsuper.update(config);\n\t}\n}\n","import {\n\tfilter,\n\tmergeMap,\n\ttype Observable,\n\ttakeUntil,\n\ttakeWhile,\n\ttimer,\n} from \"rxjs\";\nimport { filterPointerOff } from \"../recognizer/operators\";\nimport { isPointerOffEvent, matchPointer } from \"../utils/events\";\nimport { isWithinPosThreshold } from \"../utils/utils\";\n\nexport const takeWhenPressedTooLong =\n\t({\n\t\ttimeout,\n\t\tpointerEvent$,\n\t}: {\n\t\ttimeout: number;\n\t\tpointerEvent$: Observable<PointerEvent>;\n\t}) =>\n\t(stream: Observable<PointerEvent>) =>\n\t\tstream.pipe(\n\t\t\tmergeMap((pointerDown) =>\n\t\t\t\ttimer(timeout).pipe(\n\t\t\t\t\ttakeUntil(\n\t\t\t\t\t\tpointerEvent$.pipe(filterPointerOff, matchPointer(pointerDown)),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\nexport const takeWhenOutsideThreshold =\n\t({\n\t\tinitialPointerEvent,\n\t\tpointerEvent$,\n\t\ttolerance,\n\t}: {\n\t\tinitialPointerEvent: PointerEvent;\n\t\ttolerance: number;\n\t\tpointerEvent$: Observable<PointerEvent>;\n\t}) =>\n\t(stream: Observable<PointerEvent>) =>\n\t\tstream.pipe(\n\t\t\tmergeMap((pointerDown) =>\n\t\t\t\tpointerEvent$.pipe(\n\t\t\t\t\tmatchPointer(pointerDown),\n\t\t\t\t\ttakeWhile((event) => !isPointerOffEvent(event), true),\n\t\t\t\t\tfilter((event) =>\n\t\t\t\t\t\tisWithinPosThreshold(initialPointerEvent, event, tolerance),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n","import {\n\tbuffer,\n\tdebounceTime,\n\texhaustMap,\n\tfilter,\n\tfirst,\n\tignoreElements,\n\tmap,\n\tmerge,\n\ttype Observable,\n\tof,\n\tshare,\n\tswitchMap,\n\ttakeUntil,\n\twithLatestFrom,\n} from \"rxjs\";\nimport { Recognizer, type RecognizerConfig } from \"../recognizer/Recognizer\";\nimport { scanToRecognizerEvent } from \"../recognizer/scanToRecognizerEvent\";\nimport { trackPointers } from \"../utils/events\";\nimport { shareLatest } from \"../utils/operators\";\nimport { filterNotEmpty } from \"../utils/utils\";\nimport { takeWhenOutsideThreshold, takeWhenPressedTooLong } from \"./operators\";\nimport type {\n\tTapEvent,\n\tTapRecognizerInterface,\n\tTapRecognizerOptions,\n} from \"./TapRecognizerInterface\";\n\nexport type { TapEvent, TapRecognizerOptions };\n\nexport class TapRecognizer\n\textends Recognizer<TapRecognizerOptions, TapEvent>\n\timplements TapRecognizerInterface\n{\n\tpublic events$: Observable<TapEvent>;\n\n\tconstructor(options?: RecognizerConfig<TapRecognizerOptions>) {\n\t\tsuper(options);\n\n\t\tthis.events$ = this.config$.pipe(\n\t\t\tswitchMap((config) => {\n\t\t\t\tconst maxTaps = config.options?.maxTaps ?? 1;\n\t\t\t\t/**\n\t\t\t\t * We default to reasonable multiplier of 100 to give time\n\t\t\t\t * for each tap\n\t\t\t\t */\n\t\t\t\tconst multiTapThreshold =\n\t\t\t\t\tconfig.options?.multiTapThreshold ?? 100 * (maxTaps - 1);\n\n\t\t\t\tconst { maximumPressTime = 150, tolerance = 10 } = config.options ?? {};\n\n\t\t\t\tconst activePointers$ = this.pointerDown$.pipe(\n\t\t\t\t\ttrackPointers({\n\t\t\t\t\t\tpointerEvent$: this.pointerEvent$,\n\t\t\t\t\t\ttrackMove: true,\n\t\t\t\t\t}),\n\t\t\t\t\tshareLatest(),\n\t\t\t\t);\n\n\t\t\t\tconst hasMoreThanOneActivePointer$ = activePointers$.pipe(\n\t\t\t\t\tfilter(({ pointers }) => pointers.length > 1),\n\t\t\t\t);\n\n\t\t\t\t/**\n\t\t\t\t * Collects the presses until `multiTapThreshold` after a release\n\t\t\t\t * that no press followed: a press still down is part of the taps.\n\t\t\t\t */\n\t\t\t\tconst bufferPointerDowns = (stream: Observable<PointerEvent>) =>\n\t\t\t\t\tstream.pipe(\n\t\t\t\t\t\tbuffer(\n\t\t\t\t\t\t\tmerge(this.pointerDown$, this.pointerUp$).pipe(\n\t\t\t\t\t\t\t\tdebounceTime(multiTapThreshold),\n\t\t\t\t\t\t\t\tfilter((event) => event.type === \"pointerup\"),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t\tfirst(),\n\t\t\t\t\t);\n\n\t\t\t\tconst tap$ = merge(\n\t\t\t\t\tthis.pointerDown$,\n\t\t\t\t\tactivePointers$.pipe(ignoreElements()),\n\t\t\t\t).pipe(\n\t\t\t\t\texhaustMap((initialPointerEvent) => {\n\t\t\t\t\t\tconst pointerDowns$ = merge(\n\t\t\t\t\t\t\tof(initialPointerEvent),\n\t\t\t\t\t\t\tthis.pointerDown$,\n\t\t\t\t\t\t).pipe(shareLatest());\n\n\t\t\t\t\t\tconst pointerDownsBuffered$ =\n\t\t\t\t\t\t\tpointerDowns$.pipe(bufferPointerDowns);\n\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * Exit condition for `tolerance`\n\t\t\t\t\t\t */\n\t\t\t\t\t\tconst clickedTooFarFromOriginalTap$ = pointerDowns$.pipe(\n\t\t\t\t\t\t\ttakeWhenOutsideThreshold({\n\t\t\t\t\t\t\t\tinitialPointerEvent,\n\t\t\t\t\t\t\t\tpointerEvent$: this.pointerEvent$,\n\t\t\t\t\t\t\t\ttolerance,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * Exit condition for `maximumPressTime`\n\t\t\t\t\t\t */\n\t\t\t\t\t\tconst hasFingersPressedForTooLong$ = pointerDowns$.pipe(\n\t\t\t\t\t\t\ttakeWhenPressedTooLong({\n\t\t\t\t\t\t\t\tpointerEvent$: this.pointerEvent$,\n\t\t\t\t\t\t\t\ttimeout: maximumPressTime,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst takeUntil$ = merge(\n\t\t\t\t\t\t\tthis.failWithActive$.pipe(filter((active) => active)),\n\t\t\t\t\t\t\tthis.pointerCancel$,\n\t\t\t\t\t\t\thasMoreThanOneActivePointer$,\n\t\t\t\t\t\t\tclickedTooFarFromOriginalTap$,\n\t\t\t\t\t\t\thasFingersPressedForTooLong$,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst rawEvent$ = pointerDownsBuffered$.pipe(\n\t\t\t\t\t\t\tfilterNotEmpty,\n\t\t\t\t\t\t\tfilter((events) => events.length <= maxTaps),\n\t\t\t\t\t\t\tmap((events) => {\n\t\t\t\t\t\t\t\t// the finger, where it last pressed: `taps` counts the presses\n\t\t\t\t\t\t\t\tconst lastPress = events[events.length - 1] ?? events[0];\n\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\ttype: \"tap\" as const,\n\t\t\t\t\t\t\t\t\ttaps: events.length,\n\t\t\t\t\t\t\t\t\tlatestActivePointers: [lastPress],\n\t\t\t\t\t\t\t\t\tevent: lastPress,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\tshareLatest(),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn rawEvent$.pipe(\n\t\t\t\t\t\t\tscanToRecognizerEvent,\n\t\t\t\t\t\t\twithLatestFrom(rawEvent$),\n\t\t\t\t\t\t\tmap(([recognizerEvent, { type, taps }]) => ({\n\t\t\t\t\t\t\t\t...recognizerEvent,\n\t\t\t\t\t\t\t\ttype,\n\t\t\t\t\t\t\t\ttaps,\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\ttakeUntil(takeUntil$),\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\t\treturn tap$;\n\t\t\t}),\n\t\t\tshare(),\n\t\t);\n\t}\n\n\tpublic update(config: RecognizerConfig<TapRecognizerOptions>): void {\n\t\tsuper.update(config);\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["calculateDistance","pointB","pointA","calculateAverageDistance","n","pointerEvents","sum","i","innerSum","event1","event2","calculateRadianAngleBetweenPoints","deltaX","pointerB","pointerA","deltaY","calculateDegreeAngleBetweenPoints","calculateCentroid","points","point","acc","numPoints","calculateAngleDelta","initialPoints","newPoints","initialCentroid","newCentroid","totalAngleDelta","initialAngle","initialPoint","angleDelta","index","radianDelta","isDefined","arg","omitUnset","values","value","hasAtLeastOneItem","events","filterNotEmpty","stream","filter","isWithinPosThreshold","start","startEvent","end","endEvent","posThreshold","calculateVelocity","delay","matchPointer","newPointer","pointer","isPointerOffEvent","pointerEvent","isPrimaryButtonPress","event","fromPointerDown","fromEvent","container","map","afterEventReceived","trackPointers","pointerUp$","pointerEvent$","pointerLeave$","pointerCancel$","pointerMove$","contextMenu$","isPointerRemoved","mergeMap","pointerDown$","defer","of","pointerDown","merge","takeWhile","scan","_deleted","rest","pointers","shareLatest","shareReplay","isValidConfig","config","filterPointerOff","calculateNewDelta","newCenter","prevCenter","prevDeltaX","prevDeltaY","scanToRecognizerEvent","getCenterFromData","data","_acc$latestActivePoin","_curr$latestActivePoi","curr","prevActivePointersNumber","currActivePointersNumber","deltaPointersAngle","latestActivePointers","startTime","getPointerEvents","_typeof","o","toPrimitive","t","e","r","toPropertyKey","_defineProperty","Recognizer","BehaviorSubject","events$","tap","isEnd","finalize","switchMap","share","failWith$","failWith","distinctUntilChanged","areRunnings$","start$","recognizer","end$","startWith","combineLatest","runnings","running","_config$panConfig","_config$panConfig2","_config$panConfig3","numInputs","trackPointers$","hasEnoughFingers","hasNotEnoughFingers","exhaustMap","initialPointerEvents","panReleased$","first","delay$","timer","panStart$","withLatestFrom","takeUntil","panUpdate$","skip","panEnd$","rawEvent$","recognizerEvent","previous","current","panConfig","existingConfig","HoldRecognizer","options","failWithActive","failingActive$","isActive","trailingEndEventIfFailed$","holdStartEvent","PanRecognizer","panMove$","latestEvent","panStartEvent","panStarted$","scanPanEventToPinchEvent","hasChangedFingers","previousPointersAverageDistance","reference","scale","distance","deltaDistance","deltaDistanceScale","initialEvent","PinchRecognizer","latestPinchEvent","pinchStarted$","pinchMove$","pinchEnd$","defaultIfEmpty","pinchStartEvent","Recognizable","states","state","disableTextSelection","RotateRecognizer","rotateStart$","rotate$","rotateStartEvent","angle","rotateMove$","rotateEnd$","isRecognizedAsSwipe","escapeVelocity","SwipeRecognizer","initializedWith","takeWhenPressedTooLong","timeout","takeWhenOutsideThreshold","initialPointerEvent","tolerance","TapRecognizer","_config$options","_config$options2","maxTaps","multiTapThreshold","activePointers$","hasMoreThanOneActivePointer$","bufferPointerDowns","buffer","debounceTime","ignoreElements","pointerDowns$","pointerDownsBuffered$","clickedTooFarFromOriginalTap$","hasFingersPressedForTooLong$","maximumPressTime","takeUntil$","active","lastPress"],"sources":["../src/core/utils/geometry.ts","../src/core/utils/utils.ts","../src/core/utils/events.ts","../src/core/utils/operators.ts","../src/core/recognizer/operators.ts","../src/core/recognizer/scanToRecognizerEvent.ts","../src/core/recognizer/utils.ts","../src/core/recognizer/Recognizer.ts","../src/core/hold/HoldRecognizer.ts","../src/core/pan/PanRecognizer.ts","../src/core/pinch/scanPanEventToPinchEvent.ts","../src/core/pinch/PinchRecognizer.ts","../src/core/recognizable/Recognizable.ts","../src/core/rotate/RotateRecognizer.ts","../src/core/swipe/operators.ts","../src/core/swipe/SwipeRecognizer.ts","../src/core/tap/operators.ts","../src/core/tap/TapRecognizer.ts"],"sourcesContent":["export type Point = { x: number; y: number };\n\nexport function calculateDistance(pointA: Point, pointB: Point): number {\n\treturn Math.sqrt((pointB.x - pointA.x) ** 2 + (pointB.y - pointA.y) ** 2);\n}\n\nexport function calculateAverageDistance(pointerEvents: Point[]): number {\n\tconst n = pointerEvents.length;\n\tif (n < 2) return 0; // No distance if fewer than 2 pointers\n\n\tconst totalDistance = pointerEvents.reduce((sum, event1, i) => {\n\t\treturn (\n\t\t\tsum +\n\t\t\tpointerEvents.slice(i + 1).reduce((innerSum, event2) => {\n\t\t\t\treturn innerSum + calculateDistance(event1, event2);\n\t\t\t}, 0)\n\t\t);\n\t}, 0);\n\n\t// Number of pairs is n choose 2: n * (n - 1) / 2\n\tconst numberOfPairs = (n * (n - 1)) / 2;\n\treturn totalDistance / numberOfPairs;\n}\n\nexport function calculateRadianAngleBetweenPoints(\n\tpointerA: Point,\n\tpointerB: Point,\n): number {\n\t// Calculate the differences in coordinates\n\tconst deltaX = pointerB.x - pointerA.x;\n\tconst deltaY = pointerB.y - pointerA.y;\n\n\t// Calculate the angle in radians\n\tconst angleInRadians = Math.atan2(deltaY, deltaX);\n\n\t// Return the angle in degrees\n\treturn angleInRadians;\n}\n\nexport function calculateDegreeAngleBetweenPoints(\n\tpointerA: Point,\n\tpointerB: Point,\n): number {\n\t// Calculate the angle in radians\n\tconst angleInRadians = calculateRadianAngleBetweenPoints(pointerA, pointerB);\n\n\t// Convert the angle to degrees (optional)\n\tconst angleInDegrees = angleInRadians * (180 / Math.PI);\n\n\t// Return the angle in degrees\n\treturn angleInDegrees;\n}\n\nexport function calculateCentroid(points: Point[]) {\n\tconst sum = points.reduce(\n\t\t(acc, point) => {\n\t\t\tacc.x += point.x;\n\t\t\tacc.y += point.y;\n\n\t\t\treturn acc;\n\t\t},\n\t\t{ x: 0, y: 0 },\n\t);\n\n\tconst numPoints = points.length || 1;\n\n\treturn {\n\t\tx: sum.x / numPoints,\n\t\ty: sum.y / numPoints,\n\t};\n}\n\nexport function calculateAngleDelta(\n\tinitialPoints: Point[],\n\tnewPoints: Point[],\n) {\n\tif (initialPoints.length !== newPoints.length) {\n\t\tthrow new Error(\"Initial and new points arrays must have the same length.\");\n\t}\n\n\tconst initialCentroid = calculateCentroid(initialPoints);\n\tconst newCentroid = calculateCentroid(newPoints);\n\n\tlet totalAngleDelta = 0;\n\n\tinitialPoints.forEach((initialPoint, index) => {\n\t\tconst initialAngle = calculateRadianAngleBetweenPoints(\n\t\t\tinitialCentroid,\n\t\t\tinitialPoint,\n\t\t);\n\t\tconst newAngle = calculateRadianAngleBetweenPoints(\n\t\t\tnewCentroid,\n\t\t\tnewPoints[index] ?? initialPoint,\n\t\t);\n\n\t\tlet angleDelta = newAngle - initialAngle;\n\n\t\t// Normalize the angle delta to be within [-PI, PI]\n\t\tif (angleDelta > Math.PI) {\n\t\t\tangleDelta -= 2 * Math.PI;\n\t\t} else if (angleDelta < -Math.PI) {\n\t\t\tangleDelta += 2 * Math.PI;\n\t\t}\n\n\t\ttotalAngleDelta += angleDelta;\n\t});\n\n\t// Return the average angle delta\n\tconst radianDelta = totalAngleDelta / initialPoints.length;\n\tconst degreesDelta = radianDelta * (180 / Math.PI);\n\n\treturn { radianDelta, degreesDelta };\n}\n","import { filter, type Observable } from \"rxjs\";\nimport { calculateCentroid } from \"./geometry\";\n\nexport function isDefined<T>(\n\targ: T | null | undefined,\n): arg is T extends null | undefined ? never : T {\n\treturn arg !== null && arg !== undefined;\n}\n\n/**\n * `values` without the ones that aren't set: `undefined`, as forwarding an\n * optional value passes, or `NaN`, as `parseInt` gives for an empty field.\n * Spread over defaults or current values, they then leave them alone.\n */\nexport const omitUnset = <T extends object>(values: T | undefined) =>\n\tObject.fromEntries(\n\t\tObject.entries(values ?? {}).filter(\n\t\t\t([, value]) => value !== undefined && !Number.isNaN(value),\n\t\t),\n\t) as Partial<T>;\n\nexport const hasAtLeastOneItem = <T>(events: T[]): events is [T, ...T[]] =>\n\tevents.length > 0;\n\nexport const filterNotEmpty = <T>(\n\tstream: Observable<T[]>,\n): Observable<[T, ...T[]]> => stream.pipe(filter(hasAtLeastOneItem));\n\nexport function isWithinPosThreshold(\n\tstartEvent: PointerEvent,\n\tendEvent: PointerEvent,\n\tposThreshold: number,\n) {\n\tconst start = calculateCentroid([startEvent]);\n\tconst end = calculateCentroid([endEvent]);\n\n\t// Determines if the movement qualifies as a drag\n\treturn (\n\t\tMath.abs(end.x - start.x) >= posThreshold ||\n\t\tMath.abs(end.y - start.y) >= posThreshold\n\t);\n}\n\n/**\n * Avoid division by zero\n * Calculate velocity in pixels per millisecond\n */\nexport const calculateVelocity = (\n\tdelay: number,\n\tdeltaX: number,\n\tdeltaY: number,\n) => {\n\tconst velocityX = delay > 0 ? deltaX / delay : 0;\n\tconst velocityY = delay > 0 ? deltaY / delay : 0;\n\n\treturn {\n\t\tvelocityX,\n\t\tvelocityY,\n\t};\n};\n","import {\n\tdefer,\n\tfilter,\n\tfromEvent,\n\tmap,\n\tmerge,\n\tmergeMap,\n\ttype Observable,\n\tof,\n\tscan,\n\ttakeWhile,\n} from \"rxjs\";\nimport { isDefined } from \"./utils\";\n\nexport function matchPointer(pointer: PointerEvent) {\n\treturn (stream: Observable<PointerEvent>) =>\n\t\tstream.pipe(\n\t\t\tfilter((newPointer) => newPointer.pointerId === pointer.pointerId),\n\t\t);\n}\n\nexport const isPointerOffEvent = (pointerEvent: PointerEvent) =>\n\tpointerEvent.type === \"pointerleave\" ||\n\tpointerEvent.type === \"pointercancel\" ||\n\tpointerEvent.type === \"pointerup\";\n\n/**\n * A press of the primary button: a left click, a finger or a pen's tip. A\n * right click is for the context menu, a middle click for the browser, and a\n * pen's barrel button or eraser for the app.\n *\n * @see https://w3c.github.io/pointerevents/#the-button-property\n */\nconst isPrimaryButtonPress = (event: PointerEvent) => event.button === 0;\n\n/**\n * The presses that start a gesture. Every recognizer tracks a pointer from its\n * press, so a pointer pressed with another button starts none: no tap, pan or\n * pinch, and no share of a multi tap.\n */\nexport const fromPointerDown = ({\n\tcontainer,\n\tafterEventReceived = (event) => event,\n}: {\n\tcontainer: HTMLElement;\n\tafterEventReceived?: (event: PointerEvent) => PointerEvent;\n}) =>\n\tfromEvent<PointerEvent>(container, \"pointerdown\").pipe(\n\t\tmap(afterEventReceived),\n\t\tfilter(isPrimaryButtonPress),\n\t);\n\n/**\n * Track all pointerEvent for active fingers\n */\nexport const trackPointers =\n\t({\n\t\tpointerEvent$,\n\t}: {\n\t\tpointerEvent$: Observable<PointerEvent>;\n\t\t/**\n\t\t * Setting this value to false will not update the list\n\t\t * on pointer move. Use it if you only need to track number of active\n\t\t * fingers.\n\t\t */\n\t\ttrackMove: boolean;\n\t}) =>\n\t(stream: Observable<PointerEvent>) => {\n\t\ttype PointersState = {\n\t\t\tevent: PointerEvent;\n\t\t\tpointers: Record<number, PointerEvent | undefined>;\n\t\t};\n\n\t\tconst pointerUp$ = pointerEvent$.pipe(\n\t\t\tfilter((event) => event.type === \"pointerup\"),\n\t\t);\n\t\tconst pointerLeave$ = pointerEvent$.pipe(\n\t\t\tfilter((event) => event.type === \"pointerleave\"),\n\t\t);\n\t\tconst pointerCancel$ = pointerEvent$.pipe(\n\t\t\tfilter((event) => event.type === \"pointercancel\"),\n\t\t);\n\t\tconst pointerMove$ = pointerEvent$.pipe(\n\t\t\tfilter((event) => event.type === \"pointermove\"),\n\t\t);\n\t\tconst contextMenu$ = fromEvent<PointerEvent>(window, \"contextmenu\");\n\n\t\tconst isPointerRemoved = (event: PointerEvent) =>\n\t\t\t[\"pointercancel\", \"pointerleave\", \"pointerup\", \"contextmenu\"].includes(\n\t\t\t\tevent.type,\n\t\t\t);\n\n\t\treturn stream.pipe(\n\t\t\tmergeMap((pointerDown) => {\n\t\t\t\tconst pointerDown$ = defer(() => of(pointerDown));\n\n\t\t\t\tconst tracking$ = merge(\n\t\t\t\t\tpointerDown$,\n\t\t\t\t\tmerge(\n\t\t\t\t\t\tpointerMove$,\n\t\t\t\t\t\tpointerCancel$,\n\t\t\t\t\t\tpointerLeave$,\n\t\t\t\t\t\tpointerUp$,\n\t\t\t\t\t\tcontextMenu$,\n\t\t\t\t\t),\n\t\t\t\t).pipe(\n\t\t\t\t\tmatchPointer(pointerDown),\n\t\t\t\t\ttakeWhile((event) => !isPointerRemoved(event), true),\n\t\t\t\t);\n\n\t\t\t\treturn tracking$;\n\t\t\t}),\n\t\t\tscan<PointerEvent, PointersState, undefined>((acc, event) => {\n\t\t\t\tif (isPointerRemoved(event)) {\n\t\t\t\t\tconst { [event.pointerId]: _deleted, ...rest } = acc?.pointers ?? {};\n\n\t\t\t\t\tvoid _deleted;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tevent,\n\t\t\t\t\t\tpointers: rest,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tevent,\n\t\t\t\t\tpointers: {\n\t\t\t\t\t\t...(acc?.pointers ?? {}),\n\t\t\t\t\t\t[event.pointerId]: event,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}, undefined),\n\t\t\tmap(({ event, pointers }) => ({\n\t\t\t\tevent,\n\t\t\t\tpointers: Object.values(pointers).filter(isDefined),\n\t\t\t})),\n\t\t);\n\t};\n","import {\n\tdistinctUntilChanged,\n\tfilter,\n\ttype Observable,\n\tshareReplay,\n} from \"rxjs\";\n\nexport const emitOnceWhen =\n\t<T>(condition: (value: T) => boolean) =>\n\t(stream: Observable<T>) =>\n\t\tstream.pipe(\n\t\t\t// only emit once when we have a condition switch\n\t\t\tdistinctUntilChanged((previous, current) => {\n\t\t\t\tconst previousHasLessThan = condition(previous);\n\t\t\t\tconst currentHasLessThan = condition(current);\n\n\t\t\t\treturn previousHasLessThan === currentHasLessThan;\n\t\t\t}),\n\t\t\t// make sure to only pass true\n\t\t\tfilter(condition),\n\t\t);\n\n/**\n * Shares the latest value with late subscribers, and unsubscribes from the\n * source along with the last subscriber, which shareReplay(1) doesn't do.\n */\nexport const shareLatest = <T>() =>\n\tshareReplay<T>({ bufferSize: 1, refCount: true });\n","import { filter, type Observable } from \"rxjs\";\nimport { isPointerOffEvent } from \"../utils/events\";\n\nexport const isValidConfig = <T extends { container?: HTMLElement }>(\n\tstream: Observable<T>,\n) =>\n\tstream.pipe(\n\t\tfilter(\n\t\t\t(config): config is T & { container: HTMLElement } => !!config.container,\n\t\t),\n\t);\n\nexport const filterPointerOff = (stream: Observable<PointerEvent>) =>\n\tstream.pipe(filter(isPointerOffEvent));\n","import { map, type Observable, scan } from \"rxjs\";\nimport {\n\tcalculateAngleDelta,\n\tcalculateAverageDistance,\n\tcalculateCentroid,\n} from \"../utils/geometry\";\nimport { calculateVelocity } from \"../utils/utils\";\nimport type { RecognizerEvent } from \"./RecognizerEvent\";\n\nexport interface RecognizerEventInput {\n\tevent: PointerEvent;\n\tlatestActivePointers: PointerEvent[];\n}\n\ninterface RecognizerEventState extends RecognizerEventInput {\n\tstartTime: number;\n\tcenter: { x: number; y: number };\n\tdeltaX: number;\n\tdeltaY: number;\n\tdeltaPointersAngle: number;\n}\n\nconst calculateNewDelta = (\n\tnewCenter: { x: number; y: number },\n\tprevCenter: { x: number; y: number },\n\tprevDeltaX: number,\n\tprevDeltaY: number,\n) => {\n\tconst deltaX = newCenter.x - prevCenter.x + prevDeltaX;\n\tconst deltaY = newCenter.y - prevCenter.y + prevDeltaY;\n\n\treturn {\n\t\tdeltaX,\n\t\tdeltaY,\n\t};\n};\n\nexport const scanToRecognizerEvent = <T extends RecognizerEventInput>(\n\tstream: Observable<T>,\n): Observable<RecognizerEvent> => {\n\tconst getCenterFromData = (data: T) =>\n\t\tcalculateCentroid(\n\t\t\t!data.latestActivePointers.length\n\t\t\t\t? [data.event]\n\t\t\t\t: data.latestActivePointers,\n\t\t);\n\n\treturn stream.pipe(\n\t\tscan<T, RecognizerEventState, undefined>((acc, curr) => {\n\t\t\tconst newCenter = getCenterFromData(curr);\n\t\t\tconst prevCenter = acc?.center ?? newCenter;\n\t\t\tconst prevDeltaX = acc?.deltaX ?? 0;\n\t\t\tconst prevDeltaY = acc?.deltaY ?? 0;\n\t\t\tconst prevActivePointersNumber = acc?.latestActivePointers?.length ?? 1;\n\t\t\tconst currActivePointersNumber = curr.latestActivePointers?.length ?? 1;\n\n\t\t\tconst hasAddedOrRemovedAFinger =\n\t\t\t\t[\"pointerdown\", \"pointercancel\", \"pointerleave\", \"pointerup\"].includes(\n\t\t\t\t\tcurr.event.type,\n\t\t\t\t) && prevActivePointersNumber !== currActivePointersNumber;\n\n\t\t\tconst hasAtLeastOneFinger = currActivePointersNumber > 0;\n\n\t\t\tconst { deltaX, deltaY } =\n\t\t\t\t(hasAddedOrRemovedAFinger && hasAtLeastOneFinger) ||\n\t\t\t\t/**\n\t\t\t\t * A pointercancel cean come after a drag event and heven being completely\n\t\t\t\t * desync, leading to erroned values. We should just ignore it.\n\t\t\t\t */\n\t\t\t\tcurr.event.type === \"pointercancel\"\n\t\t\t\t\t? calculateNewDelta(newCenter, newCenter, prevDeltaX, prevDeltaY)\n\t\t\t\t\t: calculateNewDelta(newCenter, prevCenter, prevDeltaX, prevDeltaY);\n\n\t\t\tconst { degreesDelta: deltaPointersAngle } =\n\t\t\t\tprevActivePointersNumber === currActivePointersNumber &&\n\t\t\t\tprevActivePointersNumber >= 2 &&\n\t\t\t\tcurrActivePointersNumber >= 2 &&\n\t\t\t\t/**\n\t\t\t\t * A pointercancel cean come after a drag event and heven being completely\n\t\t\t\t * desync, leading to erroned values. We should just ignore it.\n\t\t\t\t */\n\t\t\t\tcurr.event.type !== \"pointercancel\"\n\t\t\t\t\t? calculateAngleDelta(\n\t\t\t\t\t\t\tacc?.latestActivePointers ?? [],\n\t\t\t\t\t\t\tcurr.latestActivePointers ?? [],\n\t\t\t\t\t\t)\n\t\t\t\t\t: { degreesDelta: 0 };\n\n\t\t\treturn {\n\t\t\t\tstartTime: Date.now(),\n\t\t\t\t...acc,\n\t\t\t\t...curr,\n\t\t\t\tcenter: newCenter,\n\t\t\t\tdeltaX,\n\t\t\t\tdeltaY,\n\t\t\t\tdeltaPointersAngle,\n\t\t\t};\n\t\t}, undefined),\n\t\tmap((data) => {\n\t\t\tconst {\n\t\t\t\tdeltaX,\n\t\t\t\tdeltaY,\n\t\t\t\tlatestActivePointers,\n\t\t\t\tstartTime,\n\t\t\t\tcenter,\n\t\t\t\tevent,\n\t\t\t\tdeltaPointersAngle,\n\t\t\t} = data;\n\t\t\tconst events = latestActivePointers ?? [];\n\n\t\t\t// Calculate the change in time\n\t\t\tconst now = Date.now();\n\t\t\tconst delay = now - startTime;\n\n\t\t\tconst { velocityX, velocityY } = calculateVelocity(delay, deltaX, deltaY);\n\t\t\tconst pointersAverageDistance =\n\t\t\t\tcalculateAverageDistance(latestActivePointers);\n\n\t\t\treturn {\n\t\t\t\tdeltaX,\n\t\t\t\tdeltaY,\n\t\t\t\tvelocityX,\n\t\t\t\tvelocityY,\n\t\t\t\tdelay,\n\t\t\t\tcenter,\n\t\t\t\tpointers: events,\n\t\t\t\tstartTime,\n\t\t\t\tevent,\n\t\t\t\tdeltaPointersAngle,\n\t\t\t\tpointersAverageDistance,\n\t\t\t} satisfies RecognizerEvent;\n\t\t}),\n\t);\n};\n","import { fromEvent, map, merge } from \"rxjs\";\nimport { fromPointerDown } from \"../utils/events\";\n\nexport const getPointerEvents = ({\n\tcontainer,\n\tafterEventReceived = (event) => event,\n}: {\n\tcontainer: HTMLElement;\n\tafterEventReceived?: (event: PointerEvent) => PointerEvent;\n}) => {\n\tconst pointerDown$ = fromPointerDown({ afterEventReceived, container });\n\tconst pointerUp$ = fromEvent<PointerEvent>(container, \"pointerup\").pipe(\n\t\tmap(afterEventReceived),\n\t);\n\tconst pointerMove$ = fromEvent<PointerEvent>(container, \"pointermove\").pipe(\n\t\tmap(afterEventReceived),\n\t);\n\t/**\n\t * Mostly used to handle cursor leaving window on mouse pointers.\n\t */\n\tconst pointerLeave$ = fromEvent<PointerEvent>(container, \"pointerleave\").pipe(\n\t\tmap(afterEventReceived),\n\t);\n\t/**\n\t * Handle things such as contextual menu popup or\n\t * native swipe navigation conflict.\n\t */\n\tconst pointerCancel$ = fromEvent<PointerEvent>(\n\t\tcontainer,\n\t\t\"pointercancel\",\n\t).pipe(map(afterEventReceived));\n\n\tconst pointerEvents$ = merge(\n\t\tpointerDown$,\n\t\tpointerCancel$,\n\t\tpointerLeave$,\n\t\tpointerUp$,\n\t\tpointerMove$,\n\t);\n\n\treturn {\n\t\tpointerEvents$,\n\t\tpointerDown$,\n\t\tpointerCancel$,\n\t\tpointerLeave$,\n\t\tpointerUp$,\n\t\tpointerMove$,\n\t};\n};\n","import {\n\tBehaviorSubject,\n\tcombineLatest,\n\tdistinctUntilChanged,\n\texhaustMap,\n\tfilter,\n\tfinalize,\n\tfirst,\n\tmap,\n\tmerge,\n\tmergeMap,\n\ttype Observable,\n\tof,\n\tshare,\n\tshareReplay,\n\tskip,\n\tstartWith,\n\tswitchMap,\n\ttakeUntil,\n\ttap,\n\ttimer,\n\twithLatestFrom,\n} from \"rxjs\";\nimport { matchPointer, trackPointers } from \"../utils/events\";\nimport { shareLatest } from \"../utils/operators\";\nimport { isWithinPosThreshold, omitUnset } from \"../utils/utils\";\nimport { filterPointerOff, isValidConfig } from \"./operators\";\nimport type { RecognizerEvent } from \"./RecognizerEvent\";\nimport { scanToRecognizerEvent } from \"./scanToRecognizerEvent\";\nimport { getPointerEvents } from \"./utils\";\n\nexport type { RecognizerEvent };\n\ntype PanConfig = {\n\tposThreshold?: number;\n\tdelay?: number;\n\t/**\n\t * Number of inputs to trigger the event.\n\t * Default to 1\n\t */\n\tnumInputs?: number;\n};\n\nexport interface FailWith {\n\tstart$: Observable<unknown>;\n\tend$: Observable<unknown>;\n}\n\nexport type RecognizerConfig<Options> = {\n\tcontainer?: HTMLElement;\n\tafterEventReceived?: (event: PointerEvent) => PointerEvent;\n\toptions?: Options;\n\tfailWith?: FailWith[];\n};\n\nexport interface RecognizerPanEvent extends RecognizerEvent {\n\ttype: \"start\" | \"move\" | \"end\";\n}\n\nexport type State = {\n\t/**\n\t * Fingers of the gesture the recognizer recognizes, as of its latest\n\t * event, from its start event until its end event. None the rest of the\n\t * time, and none for a gesture recognized once the fingers are lifted,\n\t * as a tap or a swipe.\n\t */\n\tfingers: number;\n};\n\nexport abstract class Recognizer<\n\tOptions extends object = never,\n\tEvent extends RecognizerEvent = RecognizerEvent,\n> {\n\tprotected configSubject = new BehaviorSubject<\n\t\tRecognizerConfig<Options> & {\n\t\t\tpanConfig?: PanConfig;\n\t\t}\n\t>({});\n\tprivate stateSubject = new BehaviorSubject<State>({\n\t\tfingers: 0,\n\t});\n\tprotected pan$: Observable<RecognizerPanEvent>;\n\tprotected panStart$: Observable<RecognizerEvent>;\n\tprotected panMove$: Observable<RecognizerEvent>;\n\tprotected panEnd$: Observable<RecognizerEvent>;\n\n\tprotected pointerEvent$: Observable<PointerEvent>;\n\tprotected pointerDown$: Observable<PointerEvent>;\n\tprotected pointerUp$: Observable<PointerEvent>;\n\tprotected pointerCancel$: Observable<PointerEvent>;\n\tprotected pointerMove$: Observable<PointerEvent>;\n\tprotected pointerOff$: Observable<PointerEvent>;\n\n\tpublic state$: Observable<State>;\n\tpublic config$ = this.configSubject.pipe(isValidConfig);\n\n\tabstract events$: Observable<Event>;\n\n\t/**\n\t * Track active running failWith recognizers\n\t */\n\tprotected failWithActive$: Observable<boolean>;\n\n\t/**\n\t * Reports in state$ the fingers of the gesture the recognizer's events\n\t * recognize, until `isEnd` tells its end event, or until nothing listens\n\t * to them anymore.\n\t */\n\tprotected reportFingers =\n\t\t(isEnd: (event: Event) => boolean) => (events$: Observable<Event>) =>\n\t\t\tevents$.pipe(\n\t\t\t\ttap((event) => {\n\t\t\t\t\tthis.stateSubject.next({\n\t\t\t\t\t\tfingers: isEnd(event) ? 0 : event.pointers.length,\n\t\t\t\t\t});\n\t\t\t\t}),\n\t\t\t\tfinalize(() => {\n\t\t\t\t\tthis.stateSubject.next({ fingers: 0 });\n\t\t\t\t}),\n\t\t\t);\n\n\tconstructor(config?: RecognizerConfig<Options>, panConfig?: PanConfig) {\n\t\tthis.pointerEvent$ = this.config$.pipe(\n\t\t\tswitchMap(\n\t\t\t\t({ container, afterEventReceived }) =>\n\t\t\t\t\tgetPointerEvents({\n\t\t\t\t\t\tcontainer,\n\t\t\t\t\t\tafterEventReceived,\n\t\t\t\t\t}).pointerEvents$,\n\t\t\t),\n\t\t\tshare(),\n\t\t);\n\n\t\tthis.pointerDown$ = this.pointerEvent$.pipe(\n\t\t\tfilter((event) => event.type === \"pointerdown\"),\n\t\t);\n\n\t\tthis.pointerUp$ = this.pointerEvent$.pipe(\n\t\t\tfilter((event) => event.type === \"pointerup\"),\n\t\t);\n\n\t\tthis.pointerMove$ = this.pointerEvent$.pipe(\n\t\t\tfilter((event) => event.type === \"pointermove\"),\n\t\t);\n\n\t\tthis.pointerCancel$ = this.pointerEvent$.pipe(\n\t\t\tfilter((event) => event.type === \"pointercancel\"),\n\t\t);\n\n\t\tthis.pointerOff$ = this.pointerEvent$.pipe(filterPointerOff);\n\n\t\tconst failWith$ = this.config$.pipe(\n\t\t\tmap(({ failWith }) => failWith),\n\t\t\tdistinctUntilChanged(),\n\t\t);\n\n\t\tthis.failWithActive$ = failWith$.pipe(\n\t\t\tswitchMap((failWith) => {\n\t\t\t\tconst areRunnings$ = failWith?.map((recognizer) => {\n\t\t\t\t\tconst start$ = recognizer.start$.pipe(map(() => true));\n\n\t\t\t\t\tconst end$ = recognizer.end$.pipe(map(() => false));\n\n\t\t\t\t\tconst isRunning$ = merge(start$, end$).pipe(startWith(false));\n\n\t\t\t\t\treturn isRunning$;\n\t\t\t\t});\n\n\t\t\t\tif (!areRunnings$?.length) {\n\t\t\t\t\treturn combineLatest([of(false)]);\n\t\t\t\t}\n\n\t\t\t\treturn combineLatest(areRunnings$);\n\t\t\t}),\n\t\t\tmap((runnings) => runnings.some((running) => running)),\n\t\t\t/**\n\t\t\t * Keeps following the failWith recognizers once subscribed: they can't\n\t\t\t * be asked whether they run, so a recognizer subscribing again later\n\t\t\t * would miss the gesture of one that started in between.\n\t\t\t */\n\t\t\tshareReplay(1),\n\t\t);\n\n\t\tthis.pan$ = this.configSubject.pipe(\n\t\t\tisValidConfig,\n\t\t\tswitchMap((config) => {\n\t\t\t\tconst numInputs = Math.max(1, config.panConfig?.numInputs ?? 1);\n\t\t\t\tconst posThreshold = Math.max(0, config.panConfig?.posThreshold ?? 0);\n\t\t\t\tconst delay = Math.max(0, config.panConfig?.delay ?? 0);\n\n\t\t\t\tconst trackPointers$ = this.pointerDown$.pipe(\n\t\t\t\t\ttrackPointers({\n\t\t\t\t\t\tpointerEvent$: this.pointerEvent$,\n\t\t\t\t\t\ttrackMove: true,\n\t\t\t\t\t}),\n\t\t\t\t\tshareLatest(),\n\t\t\t\t);\n\n\t\t\t\tconst hasEnoughFingers = (\n\t\t\t\t\tstream: Observable<{ event: PointerEvent; pointers: PointerEvent[] }>,\n\t\t\t\t) =>\n\t\t\t\t\tstream.pipe(\n\t\t\t\t\t\tfilter(\n\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\tevents,\n\t\t\t\t\t\t\t): events is { event: PointerEvent; pointers: [PointerEvent] } =>\n\t\t\t\t\t\t\t\tevents.pointers.length >= numInputs,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\n\t\t\t\tconst hasNotEnoughFingers = (\n\t\t\t\t\tstream: Observable<{\n\t\t\t\t\t\tevent: PointerEvent;\n\t\t\t\t\t\tpointers: PointerEvent[];\n\t\t\t\t\t}>,\n\t\t\t\t) =>\n\t\t\t\t\tstream.pipe(filter((events) => events.pointers.length < numInputs));\n\n\t\t\t\treturn trackPointers$.pipe(\n\t\t\t\t\thasEnoughFingers,\n\t\t\t\t\texhaustMap(({ pointers: initialPointerEvents }) => {\n\t\t\t\t\t\tconst panReleased$ = trackPointers$.pipe(\n\t\t\t\t\t\t\thasNotEnoughFingers,\n\t\t\t\t\t\t\tfirst(),\n\t\t\t\t\t\t\tshare(),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst delay$ = timer(delay);\n\n\t\t\t\t\t\tconst pointerDownPassingThreshold$ = merge(\n\t\t\t\t\t\t\t...initialPointerEvents.map((pointerEvent) => of(pointerEvent)),\n\t\t\t\t\t\t\tthis.pointerDown$,\n\t\t\t\t\t\t).pipe(\n\t\t\t\t\t\t\tmergeMap((pointerDown) =>\n\t\t\t\t\t\t\t\tmerge(this.pointerMove$, of(pointerDown)).pipe(\n\t\t\t\t\t\t\t\t\tmatchPointer(pointerDown),\n\t\t\t\t\t\t\t\t\tfilter((pointerEvent) =>\n\t\t\t\t\t\t\t\t\t\tisWithinPosThreshold(\n\t\t\t\t\t\t\t\t\t\t\tpointerDown,\n\t\t\t\t\t\t\t\t\t\t\tpointerEvent,\n\t\t\t\t\t\t\t\t\t\t\tposThreshold,\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tfirst(),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst panStart$ = pointerDownPassingThreshold$.pipe(\n\t\t\t\t\t\t\tswitchMap(() => delay$),\n\t\t\t\t\t\t\twithLatestFrom(trackPointers$),\n\t\t\t\t\t\t\tmap(([, { event, pointers }]) => ({\n\t\t\t\t\t\t\t\ttype: \"start\" as const,\n\t\t\t\t\t\t\t\tevent,\n\t\t\t\t\t\t\t\tlatestActivePointers: pointers,\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\tshareLatest(),\n\t\t\t\t\t\t\ttakeUntil(panReleased$),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst panUpdate$ = panStart$.pipe(\n\t\t\t\t\t\t\tmergeMap(() =>\n\t\t\t\t\t\t\t\ttrackPointers$.pipe(\n\t\t\t\t\t\t\t\t\tskip(1),\n\t\t\t\t\t\t\t\t\tmap(({ event, pointers }) => ({\n\t\t\t\t\t\t\t\t\t\ttype: \"move\" as const,\n\t\t\t\t\t\t\t\t\t\tevent,\n\t\t\t\t\t\t\t\t\t\tlatestActivePointers: pointers,\n\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\ttakeUntil(panReleased$),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst panEnd$ = panStart$.pipe(\n\t\t\t\t\t\t\tmergeMap(() =>\n\t\t\t\t\t\t\t\tpanReleased$.pipe(\n\t\t\t\t\t\t\t\t\tmap(({ event, pointers }) => ({\n\t\t\t\t\t\t\t\t\t\ttype: \"end\" as const,\n\t\t\t\t\t\t\t\t\t\tevent,\n\t\t\t\t\t\t\t\t\t\tlatestActivePointers: pointers,\n\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst rawEvent$ = merge(panStart$, panUpdate$, panEnd$).pipe(\n\t\t\t\t\t\t\tshareLatest(),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn rawEvent$.pipe(\n\t\t\t\t\t\t\tscanToRecognizerEvent,\n\t\t\t\t\t\t\twithLatestFrom(rawEvent$),\n\t\t\t\t\t\t\tmap(([recognizerEvent, { type }]) => ({\n\t\t\t\t\t\t\t\t...recognizerEvent,\n\t\t\t\t\t\t\t\ttype,\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}),\n\t\t\tshare(),\n\t\t);\n\n\t\tthis.panStart$ = this.pan$.pipe(\n\t\t\tfilter((event) => event.type === \"start\"),\n\t\t\tmap(({ type, ...rest }) => rest),\n\t\t);\n\n\t\tthis.panMove$ = this.pan$.pipe(\n\t\t\tfilter((event) => event.type === \"move\"),\n\t\t\tmap(({ type, ...rest }) => rest),\n\t\t);\n\n\t\tthis.panEnd$ = this.pan$.pipe(\n\t\t\tfilter((event) => event.type === \"end\"),\n\t\t\tmap(({ type, ...rest }) => rest),\n\t\t);\n\n\t\tthis.state$ = this.stateSubject.pipe(\n\t\t\tdistinctUntilChanged(\n\t\t\t\t(previous, current) => previous.fingers === current.fingers,\n\t\t\t),\n\t\t);\n\n\t\tthis.updateInternal(config ?? {}, panConfig);\n\t}\n\n\tprivate updateInternal(\n\t\tconfig: Partial<RecognizerConfig<Options>>,\n\t\tpanConfig?: PanConfig,\n\t) {\n\t\tconst existingConfig = this.configSubject.getValue();\n\n\t\tthis.configSubject.next({\n\t\t\t...existingConfig,\n\t\t\t...config,\n\t\t\t// unset, as when forwarding an optional value, they stay as they are\n\t\t\tfailWith: config.failWith ?? existingConfig.failWith,\n\t\t\tafterEventReceived:\n\t\t\t\tconfig.afterEventReceived ?? existingConfig.afterEventReceived,\n\t\t\toptions: config.options\n\t\t\t\t? // every option is optional, so leaving out the unset ones keeps them valid\n\t\t\t\t\t({\n\t\t\t\t\t\t...existingConfig.options,\n\t\t\t\t\t\t...omitUnset(config.options),\n\t\t\t\t\t} as Options)\n\t\t\t\t: existingConfig.options,\n\t\t\tpanConfig: {\n\t\t\t\t...existingConfig.panConfig,\n\t\t\t\t...omitUnset(panConfig),\n\t\t\t},\n\t\t});\n\t}\n\n\tpublic update(\n\t\tconfig: Partial<RecognizerConfig<Options>>,\n\t\tpanConfig?: PanConfig,\n\t) {\n\t\tthis.updateInternal(config, panConfig);\n\t}\n}\n","import {\n\tfilter,\n\tfirst,\n\tmap,\n\tmerge,\n\ttype Observable,\n\tof,\n\tshare,\n\tswitchMap,\n\ttakeUntil,\n\twithLatestFrom,\n} from \"rxjs\";\nimport { Recognizer, type RecognizerConfig } from \"../recognizer/Recognizer\";\nimport { omitUnset } from \"../utils/utils\";\nimport type {\n\tHoldEvent,\n\tHoldRecognizerInterface,\n\tHoldRecognizerOptions,\n} from \"./HoldRecognizerInterface\";\n\nexport type { HoldEvent, HoldRecognizerOptions };\n\nexport class HoldRecognizer\n\textends Recognizer<HoldRecognizerOptions, HoldEvent>\n\timplements HoldRecognizerInterface\n{\n\tpublic events$: Observable<HoldEvent>;\n\tpublic start$: Observable<HoldEvent>;\n\tpublic end$: Observable<HoldEvent>;\n\n\tconstructor(options: RecognizerConfig<HoldRecognizerOptions> = {}) {\n\t\tsuper(options, {\n\t\t\tnumInputs: 1,\n\t\t\tdelay: 0,\n\t\t\tposThreshold: 0,\n\t\t\t...omitUnset(options.options),\n\t\t});\n\n\t\tconst start$ = this.panStart$.pipe(\n\t\t\twithLatestFrom(this.failWithActive$),\n\t\t\tfilter(([, failWithActive]) => !failWithActive),\n\t\t\tmap(([event]) => {\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"holdStart\" as const,\n\t\t\t\t\t...event,\n\t\t\t\t};\n\t\t\t}),\n\t\t);\n\n\t\tthis.events$ = start$.pipe(\n\t\t\tswitchMap((holdStartEvent) => {\n\t\t\t\tconst failingActive$ = this.failWithActive$.pipe(\n\t\t\t\t\tfilter((isActive) => isActive),\n\t\t\t\t\tfirst(),\n\t\t\t\t);\n\n\t\t\t\tconst end$ = this.panEnd$.pipe(\n\t\t\t\t\tfirst(),\n\t\t\t\t\tmap((event) => {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\ttype: \"holdEnd\" as const,\n\t\t\t\t\t\t\t...event,\n\t\t\t\t\t\t};\n\t\t\t\t\t}),\n\t\t\t\t\ttakeUntil(failingActive$),\n\t\t\t\t);\n\n\t\t\t\t// cancelled by failWith: it ends where it started\n\t\t\t\tconst trailingEndEventIfFailed$ = failingActive$.pipe(\n\t\t\t\t\tmap(() => ({ ...holdStartEvent, type: \"holdEnd\" as const })),\n\t\t\t\t\ttakeUntil(this.panEnd$),\n\t\t\t\t);\n\n\t\t\t\treturn merge(of(holdStartEvent), end$, trailingEndEventIfFailed$);\n\t\t\t}),\n\t\t\tthis.reportFingers((event) => event.type === \"holdEnd\"),\n\t\t\tshare(),\n\t\t);\n\n\t\tthis.start$ = this.events$.pipe(\n\t\t\tfilter((event) => event.type === \"holdStart\"),\n\t\t);\n\t\tthis.end$ = this.events$.pipe(filter((event) => event.type === \"holdEnd\"));\n\t}\n\n\tpublic update(options: RecognizerConfig<HoldRecognizerOptions>) {\n\t\tsuper.update(options, options.options);\n\t}\n}\n","import {\n\tfilter,\n\tfirst,\n\tmap,\n\tmerge,\n\ttype Observable,\n\tof,\n\tshare,\n\tswitchMap,\n\ttakeUntil,\n\ttap,\n\twithLatestFrom,\n} from \"rxjs\";\nimport { Recognizer, type RecognizerConfig } from \"../recognizer/Recognizer\";\nimport { omitUnset } from \"../utils/utils\";\nimport type {\n\tPanEvent,\n\tPanRecognizerInterface,\n\tPanRecognizerOptions,\n} from \"./PanRecognizerInterface\";\n\nexport type { PanEvent, PanRecognizerOptions };\n\nexport class PanRecognizer\n\textends Recognizer<PanRecognizerOptions, PanEvent>\n\timplements PanRecognizerInterface\n{\n\tpublic events$: Observable<PanEvent>;\n\tpublic start$: Observable<PanEvent>;\n\tpublic end$: Observable<PanEvent>;\n\n\tconstructor(config?: RecognizerConfig<PanRecognizerOptions>) {\n\t\tsuper(config, {\n\t\t\tposThreshold: 15,\n\t\t\t...omitUnset(config?.options),\n\t\t});\n\n\t\tconst panStart$ = this.panStart$.pipe(\n\t\t\tmap((event) => ({\n\t\t\t\ttype: \"panStart\" as const,\n\t\t\t\t...event,\n\t\t\t})),\n\t\t\twithLatestFrom(this.failWithActive$),\n\t\t\tfilter(([, failWithActive]) => !failWithActive),\n\t\t\tmap(([event]) => event),\n\t\t\tshare(),\n\t\t);\n\n\t\tconst panEnd$ = this.panEnd$.pipe(\n\t\t\tmap((event) => ({\n\t\t\t\ttype: \"panEnd\" as const,\n\t\t\t\t...event,\n\t\t\t})),\n\t\t\tshare(),\n\t\t);\n\n\t\tconst panMove$ = this.panMove$.pipe(\n\t\t\tmap((event) => ({\n\t\t\t\ttype: \"panMove\" as const,\n\t\t\t\t...event,\n\t\t\t})),\n\t\t);\n\n\t\tthis.events$ = panStart$.pipe(\n\t\t\tswitchMap((panStartEvent) => {\n\t\t\t\tlet latestEvent: PanEvent = panStartEvent;\n\n\t\t\t\tconst panStarted$ = of(panStartEvent);\n\n\t\t\t\tconst failingActive$ = this.failWithActive$.pipe(\n\t\t\t\t\tfilter((isActive) => isActive),\n\t\t\t\t\tfirst(),\n\t\t\t\t);\n\n\t\t\t\tconst events$ = merge(panStarted$, panMove$, panEnd$).pipe(\n\t\t\t\t\ttap((event) => {\n\t\t\t\t\t\tlatestEvent = event;\n\t\t\t\t\t}),\n\t\t\t\t\ttakeUntil(failingActive$),\n\t\t\t\t);\n\n\t\t\t\tconst trailingEndEventIfFailed$ = failingActive$.pipe(\n\t\t\t\t\tmap(() => ({\n\t\t\t\t\t\t...latestEvent,\n\t\t\t\t\t\ttype: \"panEnd\" as const,\n\t\t\t\t\t})),\n\t\t\t\t\ttakeUntil(panEnd$),\n\t\t\t\t);\n\n\t\t\t\treturn merge(events$, trailingEndEventIfFailed$);\n\t\t\t}),\n\t\t\tthis.reportFingers((event) => event.type === \"panEnd\"),\n\t\t\tshare(),\n\t\t);\n\n\t\tthis.start$ = this.events$.pipe(\n\t\t\tfilter((event) => event.type === \"panStart\"),\n\t\t);\n\n\t\tthis.end$ = this.events$.pipe(filter((event) => event.type === \"panEnd\"));\n\t}\n\n\tpublic update(config: RecognizerConfig<PanRecognizerOptions>) {\n\t\tsuper.update(config, config.options);\n\t}\n}\n","import { map, type Observable, scan } from \"rxjs\";\nimport type { RecognizerEvent } from \"../recognizer/RecognizerEvent\";\nimport type { PinchEvent } from \"./PinchRecognizerInterface\";\n\n/**\n * What the scale and distance are measured from: an average distance between\n * the fingers, and the scale and distance reached there.\n */\ntype Reference = Pick<\n\tPinchEvent,\n\t\"pointersAverageDistance\" | \"scale\" | \"distance\"\n>;\n\nexport const scanPanEventToPinchEvent =\n\t({\n\t\ttype,\n\t\tinitialEvent,\n\t}: {\n\t\ttype: PinchEvent[\"type\"];\n\t\tinitialEvent: PinchEvent | RecognizerEvent | undefined;\n\t}) =>\n\t(stream: Observable<RecognizerEvent | PinchEvent>) =>\n\t\tstream.pipe(\n\t\t\tscan<\n\t\t\t\tRecognizerEvent | PinchEvent,\n\t\t\t\tPinchEvent & {\n\t\t\t\t\treference: Reference;\n\t\t\t\t},\n\t\t\t\tPinchEvent | RecognizerEvent | undefined\n\t\t\t>((acc, curr) => {\n\t\t\t\tconst previousPointersLength = acc?.pointers.length ?? 0;\n\t\t\t\tconst hasChangedFingers =\n\t\t\t\t\tpreviousPointersLength !== curr.pointers.length;\n\t\t\t\tconst previousPointersAverageDistance =\n\t\t\t\t\tacc?.pointersAverageDistance ?? curr.pointersAverageDistance;\n\n\t\t\t\t/**\n\t\t\t\t * The reference is reset every time we change fingers, as the average\n\t\t\t\t * distance between 3 fingers can't be compared with the one between 2:\n\t\t\t\t * the scale and distance reached carry over. Otherwise it is the one\n\t\t\t\t * of the event we continue from (the pinch start for the first move).\n\t\t\t\t * @important in case of 1 finger, distance will be 0\n\t\t\t\t */\n\t\t\t\tconst reference: Reference =\n\t\t\t\t\t!hasChangedFingers && acc && \"reference\" in acc\n\t\t\t\t\t\t? acc.reference\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\tpointersAverageDistance: hasChangedFingers\n\t\t\t\t\t\t\t\t\t? curr.pointersAverageDistance\n\t\t\t\t\t\t\t\t\t: previousPointersAverageDistance,\n\t\t\t\t\t\t\t\tscale: acc && \"scale\" in acc ? acc.scale : 1,\n\t\t\t\t\t\t\t\tdistance: acc && \"distance\" in acc ? acc.distance : 0,\n\t\t\t\t\t\t\t};\n\n\t\t\t\t/**\n\t\t\t\t * @important When finger is 1, distance is 0\n\t\t\t\t */\n\t\t\t\tconst scale =\n\t\t\t\t\treference.pointersAverageDistance === 0\n\t\t\t\t\t\t? reference.scale\n\t\t\t\t\t\t: reference.scale *\n\t\t\t\t\t\t\t(curr.pointersAverageDistance /\n\t\t\t\t\t\t\t\treference.pointersAverageDistance);\n\n\t\t\t\tconst distance =\n\t\t\t\t\treference.distance +\n\t\t\t\t\t(curr.pointersAverageDistance - reference.pointersAverageDistance);\n\n\t\t\t\tconst deltaDistance = hasChangedFingers\n\t\t\t\t\t? 0\n\t\t\t\t\t: curr.pointersAverageDistance - previousPointersAverageDistance;\n\n\t\t\t\t/**\n\t\t\t\t * @important When finger is 1, distance is 0\n\t\t\t\t * Same when fingers change\n\t\t\t\t */\n\t\t\t\tconst deltaDistanceScale =\n\t\t\t\t\thasChangedFingers || previousPointersAverageDistance === 0\n\t\t\t\t\t\t? 1\n\t\t\t\t\t\t: curr.pointersAverageDistance / previousPointersAverageDistance;\n\n\t\t\t\treturn {\n\t\t\t\t\t...acc,\n\t\t\t\t\t...curr,\n\t\t\t\t\ttype,\n\t\t\t\t\treference,\n\t\t\t\t\tscale,\n\t\t\t\t\tdistance,\n\t\t\t\t\tdeltaDistance,\n\t\t\t\t\tdeltaDistanceScale,\n\t\t\t\t};\n\t\t\t}, initialEvent),\n\t\t\tmap(({ reference, ...rest }): PinchEvent => rest),\n\t\t);\n","import {\n\tdefaultIfEmpty,\n\tfilter,\n\tfirst,\n\tmap,\n\tmerge,\n\ttype Observable,\n\tof,\n\tshare,\n\tswitchMap,\n\ttakeUntil,\n\ttakeWhile,\n\ttap,\n\twithLatestFrom,\n} from \"rxjs\";\nimport { Recognizer, type RecognizerConfig } from \"../recognizer/Recognizer\";\nimport { shareLatest } from \"../utils/operators\";\nimport type {\n\tPinchEvent,\n\tPinchRecognizerInterface,\n\tPinchRecognizerOptions,\n} from \"./PinchRecognizerInterface\";\nimport { scanPanEventToPinchEvent } from \"./scanPanEventToPinchEvent\";\n\nexport type {\n\tPinchEvent,\n\tPinchRecognizerOptions,\n} from \"./PinchRecognizerInterface\";\n\nexport class PinchRecognizer\n\textends Recognizer<PinchRecognizerOptions, PinchEvent>\n\timplements PinchRecognizerInterface\n{\n\tpublic events$: Observable<PinchEvent>;\n\n\tpublic start$: Observable<PinchEvent>;\n\tpublic end$: Observable<PinchEvent>;\n\n\tconstructor(config?: RecognizerConfig<PinchRecognizerOptions>) {\n\t\tsuper(config, {\n\t\t\t...config?.options,\n\t\t\tnumInputs: 2,\n\t\t});\n\n\t\tthis.events$ = this.config$.pipe(\n\t\t\tswitchMap(() => {\n\t\t\t\tlet latestPinchEvent: PinchEvent | undefined;\n\n\t\t\t\tconst pinchStarted$ = this.panStart$.pipe(\n\t\t\t\t\twithLatestFrom(this.failWithActive$),\n\t\t\t\t\tfilter(([, failWithActive]) => !failWithActive),\n\t\t\t\t\tmap(([event]) => event),\n\t\t\t\t\tswitchMap((event) =>\n\t\t\t\t\t\tof(event).pipe(\n\t\t\t\t\t\t\t// we don't want a scan on pinch start\n\t\t\t\t\t\t\tscanPanEventToPinchEvent({\n\t\t\t\t\t\t\t\ttype: \"pinchStart\",\n\t\t\t\t\t\t\t\tinitialEvent: undefined,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t\tshareLatest(),\n\t\t\t\t);\n\n\t\t\t\tconst failingActive$ = this.failWithActive$.pipe(\n\t\t\t\t\tfilter((isActive) => isActive),\n\t\t\t\t\tfirst(),\n\t\t\t\t);\n\n\t\t\t\tconst pinchMove$ = pinchStarted$.pipe(\n\t\t\t\t\tswitchMap((initialEvent) => {\n\t\t\t\t\t\treturn this.pan$.pipe(\n\t\t\t\t\t\t\ttakeWhile((event) => event.type !== \"end\"),\n\t\t\t\t\t\t\tscanPanEventToPinchEvent({\n\t\t\t\t\t\t\t\ttype: \"pinchMove\",\n\t\t\t\t\t\t\t\tinitialEvent,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t// only for this pinch, the next ones may move again\n\t\t\t\t\t\t\ttakeUntil(failingActive$),\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\t\tconst pinchEnd$ = pinchStarted$.pipe(\n\t\t\t\t\tswitchMap((pinchStartEvent) =>\n\t\t\t\t\t\tthis.pan$.pipe(\n\t\t\t\t\t\t\tfilter((event) => event.type === \"end\"),\n\t\t\t\t\t\t\ttakeUntil(failingActive$),\n\t\t\t\t\t\t\tdefaultIfEmpty(null),\n\t\t\t\t\t\t\tmap((endEvent) => {\n\t\t\t\t\t\t\t\tconst latestEvent = latestPinchEvent ?? pinchStartEvent;\n\n\t\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t\t * It ends where it got to: lifting a finger leaves too few\n\t\t\t\t\t\t\t\t * to measure the distance, and a failWith cancelling it\n\t\t\t\t\t\t\t\t * moves none. So nothing changed since the latest event.\n\t\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t...(endEvent ?? latestEvent),\n\t\t\t\t\t\t\t\t\ttype: \"pinchEnd\" as const,\n\t\t\t\t\t\t\t\t\tscale: latestEvent.scale,\n\t\t\t\t\t\t\t\t\tdistance: latestEvent.distance,\n\t\t\t\t\t\t\t\t\tdeltaDistance: 0,\n\t\t\t\t\t\t\t\t\tdeltaDistanceScale: 1,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\tshare(),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\treturn merge(pinchStarted$, pinchMove$, pinchEnd$).pipe(\n\t\t\t\t\ttap((event) => {\n\t\t\t\t\t\tlatestPinchEvent = event;\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}),\n\t\t\tthis.reportFingers((event) => event.type === \"pinchEnd\"),\n\t\t\tshare(),\n\t\t);\n\n\t\tthis.start$ = this.events$.pipe(\n\t\t\tfilter((event) => event.type === \"pinchStart\"),\n\t\t);\n\n\t\tthis.end$ = this.events$.pipe(filter((event) => event.type === \"pinchEnd\"));\n\t}\n\n\tpublic update(options: RecognizerConfig<PinchRecognizerOptions>) {\n\t\tsuper.update(options, options.options);\n\t}\n}\n","import {\n\tcombineLatest,\n\tdistinctUntilChanged,\n\tmap,\n\tmerge,\n\ttype Observable,\n\ttype ObservedValueOf,\n\tshare,\n} from \"rxjs\";\nimport type { Recognizer, RecognizerConfig } from \"../recognizer/Recognizer\";\nimport type {\n\tRecognizableInterface,\n\tRecognizableState,\n} from \"./RecognizableInterface\";\n\nexport type { RecognizableState };\n\n// biome-ignore lint/suspicious/noExplicitAny: TODO\ntype RecognizableOptions<T extends Recognizer<any, any>[]> = {\n\trecognizers: T;\n\t/**\n\t * If you don't need to have text selection, set this to true\n\t * to improve dragging gesture. This will prevent accidental\n\t * text selection on your component.\n\t */\n\tdisableTextSelection?: boolean;\n} & RecognizerConfig<unknown>;\n\n// biome-ignore lint/suspicious/noExplicitAny: TODO\nexport class Recognizable<T extends Recognizer<any, any>[]>\n\timplements RecognizableInterface<T>\n{\n\tevents$: Observable<{\n\t\tevent: ObservedValueOf<T[number][\"events$\"]>;\n\t\trecognizer: T[number];\n\t}>;\n\n\trecognizers: T;\n\n\tstate$: Observable<RecognizableState>;\n\n\tconstructor(protected options: RecognizableOptions<T>) {\n\t\tthis.recognizers = options.recognizers;\n\n\t\tthis.events$ = merge(\n\t\t\t...options.recognizers.map((recognizer) =>\n\t\t\t\trecognizer.events$.pipe(map((event) => ({ event, recognizer }))),\n\t\t\t),\n\t\t).pipe(share());\n\n\t\tthis.state$ = combineLatest(\n\t\t\tthis.recognizers.map((recognizer) => recognizer.state$),\n\t\t).pipe(\n\t\t\tmap((states) =>\n\t\t\t\tstates.reduce((acc, state) => ({\n\t\t\t\t\tfingers: Math.max(acc.fingers, state.fingers),\n\t\t\t\t})),\n\t\t\t),\n\t\t\tdistinctUntilChanged(\n\t\t\t\t(previous, current) => previous.fingers === current.fingers,\n\t\t\t),\n\t\t);\n\n\t\tthis.update(options);\n\t}\n\n\tpublic update({\n\t\tdisableTextSelection,\n\t\t...rest\n\t}: Partial<Omit<RecognizableOptions<T>, \"recognizers\">>) {\n\t\tif (rest.container) {\n\t\t\t/**\n\t\t\t * We have to disable touch-action otherwise every events will be followed\n\t\t\t * by a cancel event since the browser will try to handle touch.\n\t\t\t * @see https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action\n\t\t\t */\n\t\t\trest.container.style.touchAction = \"none\";\n\n\t\t\t/**\n\t\t\t * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.\n\t\t\t */\n\t\t\tif (disableTextSelection) {\n\t\t\t\trest.container.style.userSelect = \"none\";\n\t\t\t}\n\t\t}\n\n\t\tfor (const recognizer of this.options.recognizers) {\n\t\t\trecognizer.update(rest);\n\t\t}\n\t}\n}\n","import {\n\tfilter,\n\tfirst,\n\tmap,\n\tmerge,\n\ttype Observable,\n\tscan,\n\tshare,\n\tswitchMap,\n\ttakeUntil,\n\ttap,\n\twithLatestFrom,\n} from \"rxjs\";\nimport {\n\tRecognizer,\n\ttype RecognizerConfig,\n\ttype RecognizerPanEvent,\n} from \"../recognizer/Recognizer\";\nimport { shareLatest } from \"../utils/operators\";\nimport { omitUnset } from \"../utils/utils\";\nimport type {\n\tRotateEvent,\n\tRotateRecognizerInterface,\n\tRotateRecognizerOptions,\n} from \"./RotateRecognizerInterface\";\n\nexport type { RotateEvent, RotateRecognizerOptions };\n\ntype RotatingEvent = RecognizerPanEvent & { angle: number; deltaAngle: number };\n\nexport class RotateRecognizer\n\textends Recognizer<RotateRecognizerOptions, RotateEvent>\n\timplements RotateRecognizerInterface\n{\n\tpublic events$: Observable<RotateEvent>;\n\tpublic start$: Observable<RotateEvent>;\n\tpublic end$: Observable<RotateEvent>;\n\n\tconstructor(config: RecognizerConfig<RotateRecognizerOptions> = {}) {\n\t\tsuper(config, {\n\t\t\tnumInputs: 2,\n\t\t\tposThreshold: 15,\n\t\t\t...omitUnset(config.options),\n\t\t});\n\n\t\tthis.events$ = this.config$.pipe(\n\t\t\tswitchMap(() => {\n\t\t\t\tconst rotateStart$ = this.panStart$.pipe(\n\t\t\t\t\twithLatestFrom(this.failWithActive$),\n\t\t\t\t\tfilter(([, failWithActive]) => !failWithActive),\n\t\t\t\t\tmap(([event]) => ({\n\t\t\t\t\t\t...event,\n\t\t\t\t\t\ttype: \"rotateStart\" as const,\n\t\t\t\t\t\tangle: 0,\n\t\t\t\t\t\tdeltaAngle: 0,\n\t\t\t\t\t})),\n\t\t\t\t\tshareLatest(),\n\t\t\t\t);\n\n\t\t\t\tconst rotate$ = rotateStart$.pipe(\n\t\t\t\t\tswitchMap((rotateStartEvent) => {\n\t\t\t\t\t\tlet latestEvent: RotatingEvent = {\n\t\t\t\t\t\t\t...rotateStartEvent,\n\t\t\t\t\t\t\ttype: \"start\",\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst failingActive$ = this.failWithActive$.pipe(\n\t\t\t\t\t\t\tfilter((isActive) => isActive),\n\t\t\t\t\t\t\tfirst(),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst events$ = this.pan$.pipe(\n\t\t\t\t\t\t\tscan<RecognizerPanEvent, RotatingEvent, undefined>(\n\t\t\t\t\t\t\t\t(acc, current) => {\n\t\t\t\t\t\t\t\t\tconst angle = (acc?.angle ?? 0) + current.deltaPointersAngle;\n\n\t\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t\t...acc,\n\t\t\t\t\t\t\t\t\t\t...current,\n\t\t\t\t\t\t\t\t\t\tangle,\n\t\t\t\t\t\t\t\t\t\tdeltaAngle: current.deltaPointersAngle,\n\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\ttap((event) => {\n\t\t\t\t\t\t\t\tlatestEvent = event;\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\ttakeUntil(failingActive$),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// cancelled by failWith: it ends on the angle it reached\n\t\t\t\t\t\tconst trailingEndEventIfFailed$ = failingActive$.pipe(\n\t\t\t\t\t\t\tmap(() => ({\n\t\t\t\t\t\t\t\t...latestEvent,\n\t\t\t\t\t\t\t\ttype: \"end\" as const,\n\t\t\t\t\t\t\t\tdeltaAngle: 0,\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\ttakeUntil(this.panEnd$),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn merge(events$, trailingEndEventIfFailed$);\n\t\t\t\t\t}),\n\t\t\t\t\tshare(),\n\t\t\t\t);\n\n\t\t\t\tconst rotateMove$ = rotate$.pipe(\n\t\t\t\t\tfilter((event) => event.type === \"move\"),\n\t\t\t\t\tmap((event) => ({ ...event, type: \"rotateMove\" as const })),\n\t\t\t\t);\n\n\t\t\t\tconst rotateEnd$ = rotate$.pipe(\n\t\t\t\t\tfilter((event) => event.type === \"end\"),\n\t\t\t\t\tmap((event) => ({ ...event, type: \"rotateEnd\" as const })),\n\t\t\t\t);\n\n\t\t\t\treturn merge(rotateStart$, rotateMove$, rotateEnd$);\n\t\t\t}),\n\t\t\tthis.reportFingers((event) => event.type === \"rotateEnd\"),\n\t\t\tshare(),\n\t\t);\n\n\t\tthis.start$ = this.events$.pipe(\n\t\t\tfilter((event) => event.type === \"rotateStart\"),\n\t\t);\n\t\tthis.end$ = this.events$.pipe(\n\t\t\tfilter((event) => event.type === \"rotateEnd\"),\n\t\t);\n\t}\n\n\tpublic update(options: RecognizerConfig<RotateRecognizerOptions>) {\n\t\tsuper.update(options, options.options);\n\t}\n}\n","import { filter, type Observable } from \"rxjs\";\nimport type { RecognizerEvent } from \"../recognizer/RecognizerEvent\";\n\nexport const isRecognizedAsSwipe =\n\t(escapeVelocity: number) => (stream: Observable<RecognizerEvent>) =>\n\t\tstream.pipe(\n\t\t\tfilter((event) => {\n\t\t\t\treturn (\n\t\t\t\t\tMath.abs(event.velocityX) >= escapeVelocity ||\n\t\t\t\t\tMath.abs(event.velocityY) >= escapeVelocity\n\t\t\t\t);\n\t\t\t}),\n\t\t);\n","import {\n\tfilter,\n\tmap,\n\ttype Observable,\n\tshare,\n\tswitchMap,\n\ttakeUntil,\n\twithLatestFrom,\n} from \"rxjs\";\nimport { Recognizer, type RecognizerConfig } from \"../recognizer/Recognizer\";\nimport { calculateDegreeAngleBetweenPoints } from \"../utils/geometry\";\nimport { isRecognizedAsSwipe } from \"./operators\";\nimport type {\n\tSwipeEvent,\n\tSwipeRecognizerInterface,\n\tSwipeRecognizerOptions,\n} from \"./SwipeRecognizerInterface\";\n\nexport type { SwipeEvent, SwipeRecognizerOptions };\n\nexport class SwipeRecognizer\n\textends Recognizer<SwipeRecognizerOptions, SwipeEvent>\n\timplements SwipeRecognizerInterface\n{\n\tpublic events$: Observable<SwipeEvent>;\n\n\tconstructor(config?: RecognizerConfig<SwipeRecognizerOptions>) {\n\t\tsuper(config, {\n\t\t\tposThreshold: 0,\n\t\t\tnumInputs: 1,\n\t\t});\n\n\t\tthis.events$ = this.config$.pipe(\n\t\t\tswitchMap((initializedWith) => {\n\t\t\t\tconst { escapeVelocity = 0.9 } = initializedWith.options ?? {};\n\n\t\t\t\treturn this.panStart$.pipe(\n\t\t\t\t\twithLatestFrom(this.failWithActive$),\n\t\t\t\t\tfilter(([, failWithActive]) => !failWithActive),\n\t\t\t\t\tswitchMap(([startEvent]) => {\n\t\t\t\t\t\treturn this.panEnd$.pipe(\n\t\t\t\t\t\t\tisRecognizedAsSwipe(escapeVelocity),\n\t\t\t\t\t\t\tmap((event) => {\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\ttype: \"swipe\" as const,\n\t\t\t\t\t\t\t\t\tangle: calculateDegreeAngleBetweenPoints(\n\t\t\t\t\t\t\t\t\t\tstartEvent.event,\n\t\t\t\t\t\t\t\t\t\tevent.event,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t...event,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\ttakeUntil(\n\t\t\t\t\t\t\t\tthis.failWithActive$.pipe(filter((isActive) => isActive)),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\n\t\t\t\t\tshare(),\n\t\t\t\t);\n\t\t\t}),\n\t\t);\n\t}\n\n\tpublic update(config: RecognizerConfig<SwipeRecognizerOptions>) {\n\t\tsuper.update(config);\n\t}\n}\n","import {\n\tfilter,\n\tmergeMap,\n\ttype Observable,\n\ttakeUntil,\n\ttakeWhile,\n\ttimer,\n} from \"rxjs\";\nimport { filterPointerOff } from \"../recognizer/operators\";\nimport { isPointerOffEvent, matchPointer } from \"../utils/events\";\nimport { isWithinPosThreshold } from \"../utils/utils\";\n\nexport const takeWhenPressedTooLong =\n\t({\n\t\ttimeout,\n\t\tpointerEvent$,\n\t}: {\n\t\ttimeout: number;\n\t\tpointerEvent$: Observable<PointerEvent>;\n\t}) =>\n\t(stream: Observable<PointerEvent>) =>\n\t\tstream.pipe(\n\t\t\tmergeMap((pointerDown) =>\n\t\t\t\ttimer(timeout).pipe(\n\t\t\t\t\ttakeUntil(\n\t\t\t\t\t\tpointerEvent$.pipe(filterPointerOff, matchPointer(pointerDown)),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\nexport const takeWhenOutsideThreshold =\n\t({\n\t\tinitialPointerEvent,\n\t\tpointerEvent$,\n\t\ttolerance,\n\t}: {\n\t\tinitialPointerEvent: PointerEvent;\n\t\ttolerance: number;\n\t\tpointerEvent$: Observable<PointerEvent>;\n\t}) =>\n\t(stream: Observable<PointerEvent>) =>\n\t\tstream.pipe(\n\t\t\tmergeMap((pointerDown) =>\n\t\t\t\tpointerEvent$.pipe(\n\t\t\t\t\tmatchPointer(pointerDown),\n\t\t\t\t\ttakeWhile((event) => !isPointerOffEvent(event), true),\n\t\t\t\t\tfilter((event) =>\n\t\t\t\t\t\tisWithinPosThreshold(initialPointerEvent, event, tolerance),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n","import {\n\tbuffer,\n\tdebounceTime,\n\texhaustMap,\n\tfilter,\n\tfirst,\n\tignoreElements,\n\tmap,\n\tmerge,\n\ttype Observable,\n\tof,\n\tshare,\n\tswitchMap,\n\ttakeUntil,\n\twithLatestFrom,\n} from \"rxjs\";\nimport { Recognizer, type RecognizerConfig } from \"../recognizer/Recognizer\";\nimport { scanToRecognizerEvent } from \"../recognizer/scanToRecognizerEvent\";\nimport { trackPointers } from \"../utils/events\";\nimport { shareLatest } from \"../utils/operators\";\nimport { filterNotEmpty } from \"../utils/utils\";\nimport { takeWhenOutsideThreshold, takeWhenPressedTooLong } from \"./operators\";\nimport type {\n\tTapEvent,\n\tTapRecognizerInterface,\n\tTapRecognizerOptions,\n} from \"./TapRecognizerInterface\";\n\nexport type { TapEvent, TapRecognizerOptions };\n\nexport class TapRecognizer\n\textends Recognizer<TapRecognizerOptions, TapEvent>\n\timplements TapRecognizerInterface\n{\n\tpublic events$: Observable<TapEvent>;\n\n\tconstructor(options?: RecognizerConfig<TapRecognizerOptions>) {\n\t\tsuper(options);\n\n\t\tthis.events$ = this.config$.pipe(\n\t\t\tswitchMap((config) => {\n\t\t\t\tconst maxTaps = config.options?.maxTaps ?? 1;\n\t\t\t\t/**\n\t\t\t\t * We default to reasonable multiplier of 100 to give time\n\t\t\t\t * for each tap\n\t\t\t\t */\n\t\t\t\tconst multiTapThreshold =\n\t\t\t\t\tconfig.options?.multiTapThreshold ?? 100 * (maxTaps - 1);\n\n\t\t\t\tconst { maximumPressTime = 150, tolerance = 10 } = config.options ?? {};\n\n\t\t\t\tconst activePointers$ = this.pointerDown$.pipe(\n\t\t\t\t\ttrackPointers({\n\t\t\t\t\t\tpointerEvent$: this.pointerEvent$,\n\t\t\t\t\t\ttrackMove: true,\n\t\t\t\t\t}),\n\t\t\t\t\tshareLatest(),\n\t\t\t\t);\n\n\t\t\t\tconst hasMoreThanOneActivePointer$ = activePointers$.pipe(\n\t\t\t\t\tfilter(({ pointers }) => pointers.length > 1),\n\t\t\t\t);\n\n\t\t\t\t/**\n\t\t\t\t * Collects the presses until `multiTapThreshold` after a release\n\t\t\t\t * that no press followed: a press still down is part of the taps.\n\t\t\t\t */\n\t\t\t\tconst bufferPointerDowns = (stream: Observable<PointerEvent>) =>\n\t\t\t\t\tstream.pipe(\n\t\t\t\t\t\tbuffer(\n\t\t\t\t\t\t\tmerge(this.pointerDown$, this.pointerUp$).pipe(\n\t\t\t\t\t\t\t\tdebounceTime(multiTapThreshold),\n\t\t\t\t\t\t\t\tfilter((event) => event.type === \"pointerup\"),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t\tfirst(),\n\t\t\t\t\t);\n\n\t\t\t\tconst tap$ = merge(\n\t\t\t\t\tthis.pointerDown$,\n\t\t\t\t\tactivePointers$.pipe(ignoreElements()),\n\t\t\t\t).pipe(\n\t\t\t\t\texhaustMap((initialPointerEvent) => {\n\t\t\t\t\t\tconst pointerDowns$ = merge(\n\t\t\t\t\t\t\tof(initialPointerEvent),\n\t\t\t\t\t\t\tthis.pointerDown$,\n\t\t\t\t\t\t).pipe(shareLatest());\n\n\t\t\t\t\t\tconst pointerDownsBuffered$ =\n\t\t\t\t\t\t\tpointerDowns$.pipe(bufferPointerDowns);\n\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * Exit condition for `tolerance`\n\t\t\t\t\t\t */\n\t\t\t\t\t\tconst clickedTooFarFromOriginalTap$ = pointerDowns$.pipe(\n\t\t\t\t\t\t\ttakeWhenOutsideThreshold({\n\t\t\t\t\t\t\t\tinitialPointerEvent,\n\t\t\t\t\t\t\t\tpointerEvent$: this.pointerEvent$,\n\t\t\t\t\t\t\t\ttolerance,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * Exit condition for `maximumPressTime`\n\t\t\t\t\t\t */\n\t\t\t\t\t\tconst hasFingersPressedForTooLong$ = pointerDowns$.pipe(\n\t\t\t\t\t\t\ttakeWhenPressedTooLong({\n\t\t\t\t\t\t\t\tpointerEvent$: this.pointerEvent$,\n\t\t\t\t\t\t\t\ttimeout: maximumPressTime,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst takeUntil$ = merge(\n\t\t\t\t\t\t\tthis.failWithActive$.pipe(filter((active) => active)),\n\t\t\t\t\t\t\tthis.pointerCancel$,\n\t\t\t\t\t\t\thasMoreThanOneActivePointer$,\n\t\t\t\t\t\t\tclickedTooFarFromOriginalTap$,\n\t\t\t\t\t\t\thasFingersPressedForTooLong$,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst rawEvent$ = pointerDownsBuffered$.pipe(\n\t\t\t\t\t\t\tfilterNotEmpty,\n\t\t\t\t\t\t\tfilter((events) => events.length <= maxTaps),\n\t\t\t\t\t\t\tmap((events) => {\n\t\t\t\t\t\t\t\t// the finger, where it last pressed: `taps` counts the presses\n\t\t\t\t\t\t\t\tconst lastPress = events[events.length - 1] ?? events[0];\n\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\ttype: \"tap\" as const,\n\t\t\t\t\t\t\t\t\ttaps: events.length,\n\t\t\t\t\t\t\t\t\tlatestActivePointers: [lastPress],\n\t\t\t\t\t\t\t\t\tevent: lastPress,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\tshareLatest(),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn rawEvent$.pipe(\n\t\t\t\t\t\t\tscanToRecognizerEvent,\n\t\t\t\t\t\t\twithLatestFrom(rawEvent$),\n\t\t\t\t\t\t\tmap(([recognizerEvent, { type, taps }]) => ({\n\t\t\t\t\t\t\t\t...recognizerEvent,\n\t\t\t\t\t\t\t\ttype,\n\t\t\t\t\t\t\t\ttaps,\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\ttakeUntil(takeUntil$),\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\t\treturn tap$;\n\t\t\t}),\n\t\t\tshare(),\n\t\t);\n\t}\n\n\tpublic update(config: RecognizerConfig<TapRecognizerOptions>): void {\n\t\tsuper.update(config);\n\t}\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gesturx",
3
3
  "private": false,
4
- "version": "2.1.0",
4
+ "version": "2.2.1",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",
@@ -21,6 +21,7 @@
21
21
  "build:lib": "tsc && cross-env LIB_MODE=true vite build",
22
22
  "preview": "vite preview",
23
23
  "check": "npx @biomejs/biome check .",
24
+ "check:readme": "node scripts/check-readme.mjs",
24
25
  "test": "vitest",
25
26
  "coverage": "vitest run --coverage",
26
27
  "prepare": "husky"