gesturx 0.0.0 → 1.1.0
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 +17 -1
- package/dist/core/index.d.ts +4 -0
- package/dist/core/manager.d.ts +15 -0
- package/dist/core/pan/PanRecognizer.d.ts +19 -0
- package/dist/core/pinch/PinchRecognizer.d.ts +29 -0
- package/dist/core/recognizer/Recognizer.d.ts +21 -0
- package/dist/core/recognizer/RecognizerEvent.d.ts +42 -0
- package/dist/core/recognizer/mapToRecognizerEvent.d.ts +8 -0
- package/dist/core/rotate/RotateRecognizer.d.ts +24 -0
- package/dist/core/swipe/SwipeRecognizer.d.ts +30 -0
- package/dist/core/swipe/SwipeRecognizer.test.d.ts +1 -0
- package/dist/core/swipe/isRecognizedAsSwipe.d.ts +4 -0
- package/dist/core/tap/TapRecognizer.d.ts +20 -0
- package/dist/core/tap/TapRecognizer.test.d.ts +1 -0
- package/dist/core/utils/events.d.ts +40 -0
- package/dist/core/utils/geometry.d.ts +17 -0
- package/dist/core/utils/utils.d.ts +17 -0
- package/dist/core/utils/utils.test.d.ts +1 -0
- package/dist/demo/App.d.ts +2 -0
- package/dist/demo/DebugBox.d.ts +5 -0
- package/dist/demo/useManager.d.ts +11 -0
- package/dist/demo/useTap.d.ts +5 -0
- package/dist/index.js +505 -0
- package/dist/index.js.map +1 -0
- package/dist/index.umd.cjs +2 -0
- package/dist/index.umd.cjs.map +1 -0
- package/dist/main.d.ts +1 -0
- package/dist/theme.d.ts +1 -0
- package/package.json +19 -3
- package/.github/workflows/publish.yml +0 -17
- package/.prettierrc.json +0 -1
- package/eslint.config.js +0 -9
- package/index.html +0 -13
- package/src/core/manager.ts +0 -45
- package/src/core/tapRecognizer.test.ts +0 -542
- package/src/core/tapRecognizer.ts +0 -143
- package/src/core/types.ts +0 -3
- package/src/core/utils.ts +0 -211
- package/src/main.ts +0 -19
- package/src/style.css +0 -29
- package/src/vite-env.d.ts +0 -1
- package/tsconfig.json +0 -23
- package/vite.config.ts +0 -33
- package/vitest.config.ts +0 -8
- /package/{public → dist}/vite.svg +0 -0
|
@@ -1,542 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
|
-
import { createTapRecognizer } from "./tapRecognizer";
|
|
3
|
-
import { buffer, first, lastValueFrom, tap, timer } from "rxjs";
|
|
4
|
-
|
|
5
|
-
const waitFor = (time: number) =>
|
|
6
|
-
new Promise((resolve) => setTimeout(resolve, time));
|
|
7
|
-
|
|
8
|
-
describe("TapGestureRecognizer", () => {
|
|
9
|
-
let container = document.createElement("div");
|
|
10
|
-
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
container = document.createElement("div");
|
|
13
|
-
document.body.appendChild(container);
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
function createPointerEvent({
|
|
17
|
-
type,
|
|
18
|
-
x,
|
|
19
|
-
y,
|
|
20
|
-
identifier,
|
|
21
|
-
}: {
|
|
22
|
-
type: string;
|
|
23
|
-
x: number;
|
|
24
|
-
y: number;
|
|
25
|
-
identifier: number;
|
|
26
|
-
}) {
|
|
27
|
-
const event = new PointerEvent(type, {
|
|
28
|
-
clientX: x,
|
|
29
|
-
clientY: y,
|
|
30
|
-
pointerId: identifier,
|
|
31
|
-
pointerType: "touch",
|
|
32
|
-
bubbles: true,
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
return event;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function sendPointerEvent({
|
|
39
|
-
type,
|
|
40
|
-
x,
|
|
41
|
-
y,
|
|
42
|
-
container,
|
|
43
|
-
identifier,
|
|
44
|
-
}: {
|
|
45
|
-
container: HTMLElement;
|
|
46
|
-
type: string;
|
|
47
|
-
x: number;
|
|
48
|
-
y: number;
|
|
49
|
-
identifier: number;
|
|
50
|
-
}) {
|
|
51
|
-
const event = createPointerEvent({
|
|
52
|
-
type,
|
|
53
|
-
x,
|
|
54
|
-
y,
|
|
55
|
-
identifier,
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
sendPointerEventFromEvent({ event, container });
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function sendPointerEventFromEvent({
|
|
62
|
-
event,
|
|
63
|
-
container,
|
|
64
|
-
}: {
|
|
65
|
-
event: PointerEvent;
|
|
66
|
-
container: HTMLElement;
|
|
67
|
-
}) {
|
|
68
|
-
container.dispatchEvent(event);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
it("should detect a single tap", async () => {
|
|
72
|
-
const multiTapThreshold = 5;
|
|
73
|
-
const waitLongEnough$ = timer(multiTapThreshold * 2);
|
|
74
|
-
const recognizer = createTapRecognizer({ multiTapThreshold })({
|
|
75
|
-
container,
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
const values = await lastValueFrom(
|
|
79
|
-
recognizer.events$.pipe(
|
|
80
|
-
tap({
|
|
81
|
-
subscribe: async () => {
|
|
82
|
-
await waitFor(1);
|
|
83
|
-
|
|
84
|
-
sendPointerEvent({
|
|
85
|
-
container,
|
|
86
|
-
identifier: 1,
|
|
87
|
-
type: "pointerdown",
|
|
88
|
-
x: 0,
|
|
89
|
-
y: 0,
|
|
90
|
-
});
|
|
91
|
-
sendPointerEvent({
|
|
92
|
-
container,
|
|
93
|
-
identifier: 1,
|
|
94
|
-
type: "pointerup",
|
|
95
|
-
x: 0,
|
|
96
|
-
y: 0,
|
|
97
|
-
});
|
|
98
|
-
},
|
|
99
|
-
}),
|
|
100
|
-
buffer(waitLongEnough$),
|
|
101
|
-
first(),
|
|
102
|
-
),
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
expect(values).toMatchObject([{ type: "tap", taps: 1 }]);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it("should detect a double tap", async () => {
|
|
109
|
-
const multiTapThreshold = 5;
|
|
110
|
-
const waitLongEnough$ = timer(multiTapThreshold * 2);
|
|
111
|
-
const recognizer = createTapRecognizer({ multiTapThreshold, maxTaps: 2 })({
|
|
112
|
-
container,
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
const values = await lastValueFrom(
|
|
116
|
-
recognizer.events$.pipe(
|
|
117
|
-
tap({
|
|
118
|
-
subscribe: async () => {
|
|
119
|
-
await waitFor(1);
|
|
120
|
-
|
|
121
|
-
sendPointerEvent({
|
|
122
|
-
container,
|
|
123
|
-
identifier: 1,
|
|
124
|
-
type: "pointerdown",
|
|
125
|
-
x: 0,
|
|
126
|
-
y: 0,
|
|
127
|
-
});
|
|
128
|
-
sendPointerEvent({
|
|
129
|
-
container,
|
|
130
|
-
identifier: 1,
|
|
131
|
-
type: "pointerup",
|
|
132
|
-
x: 0,
|
|
133
|
-
y: 0,
|
|
134
|
-
});
|
|
135
|
-
sendPointerEvent({
|
|
136
|
-
container,
|
|
137
|
-
identifier: 2,
|
|
138
|
-
type: "pointerdown",
|
|
139
|
-
x: 0,
|
|
140
|
-
y: 0,
|
|
141
|
-
});
|
|
142
|
-
sendPointerEvent({
|
|
143
|
-
container,
|
|
144
|
-
identifier: 2,
|
|
145
|
-
type: "pointerup",
|
|
146
|
-
x: 0,
|
|
147
|
-
y: 0,
|
|
148
|
-
});
|
|
149
|
-
},
|
|
150
|
-
}),
|
|
151
|
-
buffer(waitLongEnough$),
|
|
152
|
-
first(),
|
|
153
|
-
),
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
expect(values).toMatchObject([{ type: "tap", taps: 2 }]);
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
it("should detect a triple tap", async () => {
|
|
160
|
-
const multiTapThreshold = 5;
|
|
161
|
-
const recognizer = createTapRecognizer({ multiTapThreshold, maxTaps: 3 })({
|
|
162
|
-
container,
|
|
163
|
-
});
|
|
164
|
-
const waitLongEnough$ = timer(100);
|
|
165
|
-
|
|
166
|
-
const values = await lastValueFrom(
|
|
167
|
-
recognizer.events$.pipe(
|
|
168
|
-
tap({
|
|
169
|
-
subscribe: () => {
|
|
170
|
-
setTimeout(() => {
|
|
171
|
-
sendPointerEvent({
|
|
172
|
-
container,
|
|
173
|
-
identifier: 1,
|
|
174
|
-
type: "pointerdown",
|
|
175
|
-
x: 0,
|
|
176
|
-
y: 0,
|
|
177
|
-
});
|
|
178
|
-
sendPointerEvent({
|
|
179
|
-
container,
|
|
180
|
-
identifier: 1,
|
|
181
|
-
type: "pointerup",
|
|
182
|
-
x: 0,
|
|
183
|
-
y: 0,
|
|
184
|
-
});
|
|
185
|
-
sendPointerEvent({
|
|
186
|
-
container,
|
|
187
|
-
identifier: 1,
|
|
188
|
-
type: "pointerdown",
|
|
189
|
-
x: 0,
|
|
190
|
-
y: 0,
|
|
191
|
-
});
|
|
192
|
-
sendPointerEvent({
|
|
193
|
-
container,
|
|
194
|
-
identifier: 1,
|
|
195
|
-
type: "pointerup",
|
|
196
|
-
x: 0,
|
|
197
|
-
y: 0,
|
|
198
|
-
});
|
|
199
|
-
sendPointerEvent({
|
|
200
|
-
container,
|
|
201
|
-
identifier: 1,
|
|
202
|
-
type: "pointerdown",
|
|
203
|
-
x: 0,
|
|
204
|
-
y: 0,
|
|
205
|
-
});
|
|
206
|
-
sendPointerEvent({
|
|
207
|
-
container,
|
|
208
|
-
identifier: 1,
|
|
209
|
-
type: "pointerup",
|
|
210
|
-
x: 0,
|
|
211
|
-
y: 0,
|
|
212
|
-
});
|
|
213
|
-
});
|
|
214
|
-
},
|
|
215
|
-
}),
|
|
216
|
-
buffer(waitLongEnough$),
|
|
217
|
-
first(),
|
|
218
|
-
),
|
|
219
|
-
);
|
|
220
|
-
|
|
221
|
-
expect(values).toMatchObject([{ type: "tap", taps: 3 }]);
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
it("should not detect a double tap if the second tap is after threshold", async () => {
|
|
225
|
-
const multiTapThreshold = 5;
|
|
226
|
-
const waitLongEnough$ = timer(100);
|
|
227
|
-
const recognizer = createTapRecognizer({ multiTapThreshold, maxTaps: 2 })({
|
|
228
|
-
container,
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
const values = await lastValueFrom(
|
|
232
|
-
recognizer.events$.pipe(
|
|
233
|
-
tap({
|
|
234
|
-
subscribe: async () => {
|
|
235
|
-
await waitFor(1);
|
|
236
|
-
|
|
237
|
-
sendPointerEvent({
|
|
238
|
-
container,
|
|
239
|
-
identifier: 1,
|
|
240
|
-
type: "pointerdown",
|
|
241
|
-
x: 0,
|
|
242
|
-
y: 0,
|
|
243
|
-
});
|
|
244
|
-
sendPointerEvent({
|
|
245
|
-
container,
|
|
246
|
-
identifier: 1,
|
|
247
|
-
type: "pointerup",
|
|
248
|
-
x: 0,
|
|
249
|
-
y: 0,
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
await waitFor(multiTapThreshold);
|
|
253
|
-
|
|
254
|
-
sendPointerEvent({
|
|
255
|
-
container,
|
|
256
|
-
identifier: 2,
|
|
257
|
-
type: "pointerdown",
|
|
258
|
-
x: 0,
|
|
259
|
-
y: 0,
|
|
260
|
-
});
|
|
261
|
-
sendPointerEvent({
|
|
262
|
-
container,
|
|
263
|
-
identifier: 2,
|
|
264
|
-
type: "pointerup",
|
|
265
|
-
x: 0,
|
|
266
|
-
y: 0,
|
|
267
|
-
});
|
|
268
|
-
},
|
|
269
|
-
}),
|
|
270
|
-
buffer(waitLongEnough$),
|
|
271
|
-
first(),
|
|
272
|
-
),
|
|
273
|
-
);
|
|
274
|
-
|
|
275
|
-
expect(values.length).toBe(2);
|
|
276
|
-
expect(values).toMatchObject([
|
|
277
|
-
{ type: "tap", taps: 1, srcEvent: { pointerId: 1 } },
|
|
278
|
-
{ type: "tap", taps: 1, srcEvent: { pointerId: 2 } },
|
|
279
|
-
]);
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
it("should not trigger tap if moved too much between down and up", async () => {
|
|
283
|
-
const multiTapThreshold = 5;
|
|
284
|
-
const waitLongEnough$ = timer(100);
|
|
285
|
-
const recognizer = createTapRecognizer({
|
|
286
|
-
multiTapThreshold,
|
|
287
|
-
posThreshold: 5,
|
|
288
|
-
})({ container });
|
|
289
|
-
|
|
290
|
-
const values = await lastValueFrom(
|
|
291
|
-
recognizer.events$.pipe(
|
|
292
|
-
tap({
|
|
293
|
-
subscribe: async () => {
|
|
294
|
-
await waitFor(1);
|
|
295
|
-
|
|
296
|
-
sendPointerEvent({
|
|
297
|
-
container,
|
|
298
|
-
identifier: 1,
|
|
299
|
-
type: "pointerdown",
|
|
300
|
-
x: 0,
|
|
301
|
-
y: 0,
|
|
302
|
-
});
|
|
303
|
-
sendPointerEvent({
|
|
304
|
-
container,
|
|
305
|
-
identifier: 1,
|
|
306
|
-
type: "pointerup",
|
|
307
|
-
x: 50,
|
|
308
|
-
y: 50,
|
|
309
|
-
});
|
|
310
|
-
},
|
|
311
|
-
}),
|
|
312
|
-
buffer(waitLongEnough$),
|
|
313
|
-
first(),
|
|
314
|
-
),
|
|
315
|
-
);
|
|
316
|
-
|
|
317
|
-
expect(values.length).toBe(0);
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
it("should not detect a tap if the pointer is held down too long", async () => {
|
|
321
|
-
const multiTapThreshold = 5;
|
|
322
|
-
const maximumPressTime = 10;
|
|
323
|
-
const waitLongEnough$ = timer(100);
|
|
324
|
-
const recognizer = createTapRecognizer({
|
|
325
|
-
multiTapThreshold,
|
|
326
|
-
posThreshold: 5,
|
|
327
|
-
maximumPressTime,
|
|
328
|
-
})({ container });
|
|
329
|
-
|
|
330
|
-
const values = await lastValueFrom(
|
|
331
|
-
recognizer.events$.pipe(
|
|
332
|
-
tap({
|
|
333
|
-
subscribe: async () => {
|
|
334
|
-
await waitFor(1);
|
|
335
|
-
|
|
336
|
-
sendPointerEvent({
|
|
337
|
-
container,
|
|
338
|
-
identifier: 1,
|
|
339
|
-
type: "pointerdown",
|
|
340
|
-
x: 0,
|
|
341
|
-
y: 0,
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
await waitFor(maximumPressTime - 5);
|
|
345
|
-
|
|
346
|
-
sendPointerEvent({
|
|
347
|
-
container,
|
|
348
|
-
identifier: 1,
|
|
349
|
-
type: "pointerup",
|
|
350
|
-
x: 0,
|
|
351
|
-
y: 0,
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
await waitFor(multiTapThreshold * 2);
|
|
355
|
-
|
|
356
|
-
sendPointerEvent({
|
|
357
|
-
container,
|
|
358
|
-
identifier: 2,
|
|
359
|
-
type: "pointerdown",
|
|
360
|
-
x: 0,
|
|
361
|
-
y: 0,
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
await waitFor(maximumPressTime);
|
|
365
|
-
|
|
366
|
-
sendPointerEvent({
|
|
367
|
-
container,
|
|
368
|
-
identifier: 2,
|
|
369
|
-
type: "pointerup",
|
|
370
|
-
x: 0,
|
|
371
|
-
y: 0,
|
|
372
|
-
});
|
|
373
|
-
},
|
|
374
|
-
}),
|
|
375
|
-
buffer(waitLongEnough$),
|
|
376
|
-
first(),
|
|
377
|
-
),
|
|
378
|
-
);
|
|
379
|
-
|
|
380
|
-
expect(values.length).toBe(1);
|
|
381
|
-
expect(values).toMatchObject([
|
|
382
|
-
{ type: "tap", taps: 1, srcEvent: { pointerId: 1 } },
|
|
383
|
-
]);
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
it("should ignore taps when there are simultaneous pointers active", async () => {
|
|
387
|
-
const recognizer = createTapRecognizer({})({ container });
|
|
388
|
-
const waitLongEnough$ = timer(100);
|
|
389
|
-
|
|
390
|
-
const values = await lastValueFrom(
|
|
391
|
-
recognizer.events$.pipe(
|
|
392
|
-
tap({
|
|
393
|
-
subscribe: () => {
|
|
394
|
-
setTimeout(() => {
|
|
395
|
-
sendPointerEvent({
|
|
396
|
-
container,
|
|
397
|
-
identifier: 1,
|
|
398
|
-
type: "pointerdown",
|
|
399
|
-
x: 0,
|
|
400
|
-
y: 0,
|
|
401
|
-
});
|
|
402
|
-
sendPointerEvent({
|
|
403
|
-
container,
|
|
404
|
-
identifier: 2,
|
|
405
|
-
type: "pointerdown",
|
|
406
|
-
x: 10,
|
|
407
|
-
y: 10,
|
|
408
|
-
});
|
|
409
|
-
sendPointerEvent({
|
|
410
|
-
container,
|
|
411
|
-
identifier: 1,
|
|
412
|
-
type: "pointerup",
|
|
413
|
-
x: 0,
|
|
414
|
-
y: 0,
|
|
415
|
-
});
|
|
416
|
-
sendPointerEvent({
|
|
417
|
-
container,
|
|
418
|
-
identifier: 2,
|
|
419
|
-
type: "pointerup",
|
|
420
|
-
x: 10,
|
|
421
|
-
y: 10,
|
|
422
|
-
});
|
|
423
|
-
});
|
|
424
|
-
},
|
|
425
|
-
}),
|
|
426
|
-
buffer(waitLongEnough$),
|
|
427
|
-
first(),
|
|
428
|
-
),
|
|
429
|
-
);
|
|
430
|
-
|
|
431
|
-
expect(values.length).toBe(0); // Assuming the recognizer should ignore simultaneous taps
|
|
432
|
-
});
|
|
433
|
-
|
|
434
|
-
it("should ignore one tap if there is more than one tap", async () => {
|
|
435
|
-
const recognizer = createTapRecognizer({
|
|
436
|
-
multiTapThreshold: 10,
|
|
437
|
-
maxTaps: 1,
|
|
438
|
-
})({ container });
|
|
439
|
-
const waitLongEnough$ = timer(100);
|
|
440
|
-
|
|
441
|
-
const values = await lastValueFrom(
|
|
442
|
-
recognizer.events$.pipe(
|
|
443
|
-
tap({
|
|
444
|
-
subscribe: async () => {
|
|
445
|
-
await waitFor(1);
|
|
446
|
-
|
|
447
|
-
sendPointerEvent({
|
|
448
|
-
container,
|
|
449
|
-
identifier: 1,
|
|
450
|
-
type: "pointerdown",
|
|
451
|
-
x: 0,
|
|
452
|
-
y: 0,
|
|
453
|
-
});
|
|
454
|
-
sendPointerEvent({
|
|
455
|
-
container,
|
|
456
|
-
identifier: 1,
|
|
457
|
-
type: "pointerup",
|
|
458
|
-
x: 0,
|
|
459
|
-
y: 0,
|
|
460
|
-
});
|
|
461
|
-
|
|
462
|
-
await waitFor(1);
|
|
463
|
-
|
|
464
|
-
sendPointerEvent({
|
|
465
|
-
container,
|
|
466
|
-
identifier: 2,
|
|
467
|
-
type: "pointerdown",
|
|
468
|
-
x: 0,
|
|
469
|
-
y: 0,
|
|
470
|
-
});
|
|
471
|
-
sendPointerEvent({
|
|
472
|
-
container,
|
|
473
|
-
identifier: 2,
|
|
474
|
-
type: "pointerup",
|
|
475
|
-
x: 0,
|
|
476
|
-
y: 0,
|
|
477
|
-
});
|
|
478
|
-
},
|
|
479
|
-
}),
|
|
480
|
-
buffer(waitLongEnough$),
|
|
481
|
-
first(),
|
|
482
|
-
),
|
|
483
|
-
);
|
|
484
|
-
|
|
485
|
-
expect(values.length).toBe(0);
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
it("should ignore taps when a second tap is outside of position threshold", async () => {
|
|
489
|
-
const recognizer = createTapRecognizer({
|
|
490
|
-
posThreshold: 5,
|
|
491
|
-
multiTapThreshold: 10,
|
|
492
|
-
maxTaps: Infinity,
|
|
493
|
-
})({ container });
|
|
494
|
-
const waitLongEnough$ = timer(100);
|
|
495
|
-
|
|
496
|
-
const values = await lastValueFrom(
|
|
497
|
-
recognizer.events$.pipe(
|
|
498
|
-
tap({
|
|
499
|
-
subscribe: async () => {
|
|
500
|
-
// await waitFor(1)
|
|
501
|
-
|
|
502
|
-
sendPointerEvent({
|
|
503
|
-
container,
|
|
504
|
-
identifier: 1,
|
|
505
|
-
type: "pointerdown",
|
|
506
|
-
x: 0,
|
|
507
|
-
y: 0,
|
|
508
|
-
});
|
|
509
|
-
sendPointerEvent({
|
|
510
|
-
container,
|
|
511
|
-
identifier: 1,
|
|
512
|
-
type: "pointerup",
|
|
513
|
-
x: 0,
|
|
514
|
-
y: 0,
|
|
515
|
-
});
|
|
516
|
-
|
|
517
|
-
// await waitFor(1)
|
|
518
|
-
|
|
519
|
-
sendPointerEvent({
|
|
520
|
-
container,
|
|
521
|
-
identifier: 2,
|
|
522
|
-
type: "pointerdown",
|
|
523
|
-
x: 10,
|
|
524
|
-
y: 10,
|
|
525
|
-
});
|
|
526
|
-
sendPointerEvent({
|
|
527
|
-
container,
|
|
528
|
-
identifier: 2,
|
|
529
|
-
type: "pointerup",
|
|
530
|
-
x: 10,
|
|
531
|
-
y: 10,
|
|
532
|
-
});
|
|
533
|
-
},
|
|
534
|
-
}),
|
|
535
|
-
buffer(waitLongEnough$),
|
|
536
|
-
first(),
|
|
537
|
-
),
|
|
538
|
-
);
|
|
539
|
-
|
|
540
|
-
expect(values.length).toBe(0);
|
|
541
|
-
});
|
|
542
|
-
});
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Observable,
|
|
3
|
-
buffer,
|
|
4
|
-
debounceTime,
|
|
5
|
-
exhaustMap,
|
|
6
|
-
filter,
|
|
7
|
-
first,
|
|
8
|
-
ignoreElements,
|
|
9
|
-
map,
|
|
10
|
-
merge,
|
|
11
|
-
of,
|
|
12
|
-
share,
|
|
13
|
-
shareReplay,
|
|
14
|
-
switchMap,
|
|
15
|
-
takeUntil,
|
|
16
|
-
timer,
|
|
17
|
-
withLatestFrom,
|
|
18
|
-
} from "rxjs";
|
|
19
|
-
import {
|
|
20
|
-
fromFailWith,
|
|
21
|
-
fromPointerDown,
|
|
22
|
-
getPointerEvents,
|
|
23
|
-
hasAtLeastOneItem,
|
|
24
|
-
isOUtsidePosThreshold,
|
|
25
|
-
trackActivePointers,
|
|
26
|
-
} from "./utils";
|
|
27
|
-
import { GestureEvent } from "./types";
|
|
28
|
-
|
|
29
|
-
export type TapEvent = GestureEvent & { type: "tap"; taps: number };
|
|
30
|
-
|
|
31
|
-
type Options = {
|
|
32
|
-
// Maximum time in ms between multiple taps.
|
|
33
|
-
multiTapThreshold?: number;
|
|
34
|
-
// Maximum press time in ms.
|
|
35
|
-
maximumPressTime?: number;
|
|
36
|
-
maxTaps?: number;
|
|
37
|
-
posThreshold?: number;
|
|
38
|
-
failWith?: { start$: Observable<unknown> }[];
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const mapToTapEvent = (
|
|
42
|
-
stream: Observable<[PointerEvent, ...PointerEvent[]]>,
|
|
43
|
-
): Observable<TapEvent> =>
|
|
44
|
-
stream.pipe(
|
|
45
|
-
map((events) => ({
|
|
46
|
-
type: "tap",
|
|
47
|
-
srcEvent: events[0],
|
|
48
|
-
taps: events.length,
|
|
49
|
-
})),
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
export const createTapRecognizer = ({
|
|
53
|
-
multiTapThreshold = 200,
|
|
54
|
-
maximumPressTime = 250,
|
|
55
|
-
maxTaps = 1,
|
|
56
|
-
posThreshold = 5,
|
|
57
|
-
failWith,
|
|
58
|
-
}: Options = {}) => {
|
|
59
|
-
return ({
|
|
60
|
-
container,
|
|
61
|
-
afterEventReceived = (event) => event,
|
|
62
|
-
}: {
|
|
63
|
-
container: HTMLElement;
|
|
64
|
-
afterEventReceived?: (event: PointerEvent) => PointerEvent;
|
|
65
|
-
}) => {
|
|
66
|
-
const { pointerUp$, pointerLeave$, pointerCancel$, pointerMove$ } =
|
|
67
|
-
getPointerEvents({
|
|
68
|
-
container,
|
|
69
|
-
afterEventReceived,
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
const pointerDown$ = fromPointerDown({ container, afterEventReceived });
|
|
73
|
-
const activePointers$ = trackActivePointers({ container }).pipe(
|
|
74
|
-
shareReplay(1),
|
|
75
|
-
);
|
|
76
|
-
const hasMoreThanOneActivePointer$ = activePointers$.pipe(
|
|
77
|
-
filter((pointers) => pointers.length > 1),
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
const onlyOnePointer = <T>(stream: Observable<T>) =>
|
|
81
|
-
stream.pipe(
|
|
82
|
-
withLatestFrom(activePointers$),
|
|
83
|
-
filter(([, pointers]) => pointers.length === 1),
|
|
84
|
-
map(([pointer]) => pointer),
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
const bufferPointerDowns = (stream: Observable<PointerEvent>) =>
|
|
88
|
-
stream.pipe(
|
|
89
|
-
buffer(pointerUp$.pipe(debounceTime(multiTapThreshold))),
|
|
90
|
-
first(),
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
const failWith$ = fromFailWith(failWith);
|
|
94
|
-
|
|
95
|
-
const tap$ = merge(
|
|
96
|
-
pointerDown$,
|
|
97
|
-
activePointers$.pipe(ignoreElements()),
|
|
98
|
-
).pipe(
|
|
99
|
-
onlyOnePointer,
|
|
100
|
-
exhaustMap((initialPointerEvent) => {
|
|
101
|
-
const pointerDowns$ = merge(of(initialPointerEvent), pointerDown$);
|
|
102
|
-
const subsequentPointerEvents$ = merge(
|
|
103
|
-
pointerUp$,
|
|
104
|
-
pointerLeave$,
|
|
105
|
-
pointerCancel$,
|
|
106
|
-
pointerMove$,
|
|
107
|
-
);
|
|
108
|
-
const pointerDownsBuffered$ = pointerDowns$.pipe(bufferPointerDowns);
|
|
109
|
-
const subsequentPointersOutOfPositionThreshold$ =
|
|
110
|
-
subsequentPointerEvents$.pipe(
|
|
111
|
-
filter((event) =>
|
|
112
|
-
isOUtsidePosThreshold(initialPointerEvent, event, posThreshold),
|
|
113
|
-
),
|
|
114
|
-
first(),
|
|
115
|
-
);
|
|
116
|
-
const waitedTooLong$ = activePointers$.pipe(
|
|
117
|
-
switchMap(() => timer(maximumPressTime)),
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
const takeUntil$ = merge(
|
|
121
|
-
failWith$,
|
|
122
|
-
pointerCancel$,
|
|
123
|
-
pointerLeave$,
|
|
124
|
-
hasMoreThanOneActivePointer$,
|
|
125
|
-
subsequentPointersOutOfPositionThreshold$,
|
|
126
|
-
waitedTooLong$,
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
const tap$ = pointerDownsBuffered$.pipe(
|
|
130
|
-
filter(hasAtLeastOneItem),
|
|
131
|
-
filter((events) => events.length <= maxTaps),
|
|
132
|
-
mapToTapEvent,
|
|
133
|
-
takeUntil(takeUntil$),
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
return tap$;
|
|
137
|
-
}),
|
|
138
|
-
share(),
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
return { events$: tap$ };
|
|
142
|
-
};
|
|
143
|
-
};
|
package/src/core/types.ts
DELETED