@ngutil/aria 0.0.69 → 0.0.71
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/esm2022/gestures/gesture-drag.mjs +93 -0
- package/esm2022/gestures/gesture-event.mjs +44 -0
- package/esm2022/gestures/gesture-longtap.mjs +36 -0
- package/esm2022/gestures/gesture-tap.mjs +33 -0
- package/esm2022/gestures/gesture.mjs +29 -0
- package/esm2022/gestures/gesture.service.mjs +279 -0
- package/esm2022/gestures/index.mjs +7 -3
- package/esm2022/ui-state/progress-state.mjs +2 -2
- package/fesm2022/ngutil-aria.mjs +408 -115
- package/fesm2022/ngutil-aria.mjs.map +1 -1
- package/gestures/gesture-drag.d.ts +20 -0
- package/gestures/gesture-event.d.ts +44 -0
- package/gestures/gesture-longtap.d.ts +12 -0
- package/gestures/gesture-tap.d.ts +12 -0
- package/gestures/gesture.d.ts +35 -0
- package/gestures/gesture.service.d.ts +22 -0
- package/gestures/index.d.ts +6 -2
- package/package.json +4 -3
- package/esm2022/gestures/gestures/_base.mjs +0 -55
- package/esm2022/gestures/gestures/dragging.mjs +0 -14
- package/esm2022/gestures/gestures/index.mjs +0 -3
- package/esm2022/gestures/gestures.service.mjs +0 -146
- package/gestures/gestures/_base.d.ts +0 -63
- package/gestures/gestures/dragging.d.ts +0 -4
- package/gestures/gestures/index.d.ts +0 -2
- package/gestures/gestures.service.d.ts +0 -10
package/fesm2022/ngutil-aria.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { DOCUMENT } from '@angular/common';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
3
|
import { inject, NgZone, Injectable, Inject, ElementRef, effect, Directive, input, computed, signal, untracked, NgModule } from '@angular/core';
|
|
4
|
-
import { merge, fromEvent, map, share, filter, shareReplay, startWith, throttleTime, switchMap, timer, take, distinctUntilChanged, combineLatest, BehaviorSubject, of, debounceTime, Observable, EMPTY, from, tap,
|
|
4
|
+
import { merge, fromEvent, map, share, filter, shareReplay, startWith, throttleTime, switchMap, timer, take, distinctUntilChanged, combineLatest, BehaviorSubject, of, debounceTime, Observable, EMPTY, from, tap, Subject, connect, scan, takeWhile, finalize, animationFrames } from 'rxjs';
|
|
5
5
|
import { FocusTrapFactory } from '@angular/cdk/a11y';
|
|
6
6
|
import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
|
7
7
|
import { focusable, isFocusable } from 'tabbable';
|
|
8
|
-
import { coerceElement, Destructible, isElementInput, deepClone, coerceBoolAttr } from '@ngutil/common';
|
|
9
|
-
import {
|
|
8
|
+
import { coerceElement, Destructible, isElementInput, __zone_symbol__, isFalsy, isTruthy, deepClone, coerceBoolAttr } from '@ngutil/common';
|
|
9
|
+
import { clamp } from 'lodash-es';
|
|
10
10
|
|
|
11
11
|
const EVENT_OPTIONS$1 = {
|
|
12
12
|
capture: true,
|
|
@@ -356,167 +356,463 @@ function eventToKeystroke(event) {
|
|
|
356
356
|
};
|
|
357
357
|
}
|
|
358
358
|
|
|
359
|
-
function stateToEvent(state, type) {
|
|
360
|
-
return {
|
|
361
|
-
type: type,
|
|
362
|
-
origin: state.origin,
|
|
363
|
-
target: state.target,
|
|
364
|
-
pointerType: state.pointerType,
|
|
365
|
-
phase: state.phase,
|
|
366
|
-
pointers: state.pointers
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
359
|
const Listeners = {
|
|
370
360
|
mousedown: {
|
|
371
|
-
target: "element" /* ListenerTarget.Element */,
|
|
372
361
|
pointerType: "mouse" /* GesturePointerType.Mouse */,
|
|
373
362
|
phase: "start" /* GesturePhase.Start */,
|
|
374
363
|
options: { capture: true, passive: false }
|
|
375
364
|
},
|
|
376
365
|
mousemove: {
|
|
377
|
-
target: "document" /* ListenerTarget.Document */,
|
|
378
366
|
pointerType: "mouse" /* GesturePointerType.Mouse */,
|
|
379
367
|
phase: "moving" /* GesturePhase.Moving */,
|
|
380
368
|
options: { capture: true, passive: false }
|
|
381
369
|
},
|
|
382
370
|
mouseup: {
|
|
383
|
-
target: "document" /* ListenerTarget.Document */,
|
|
384
371
|
pointerType: "mouse" /* GesturePointerType.Mouse */,
|
|
385
372
|
phase: "end" /* GesturePhase.End */,
|
|
386
|
-
options: { capture: true, passive:
|
|
373
|
+
options: { capture: true, passive: false }
|
|
387
374
|
},
|
|
388
375
|
touchstart: {
|
|
389
|
-
target: "element" /* ListenerTarget.Element */,
|
|
390
376
|
pointerType: "touch" /* GesturePointerType.Touch */,
|
|
391
377
|
phase: "start" /* GesturePhase.Start */,
|
|
392
378
|
options: { capture: true, passive: false }
|
|
393
379
|
},
|
|
394
380
|
touchmove: {
|
|
395
|
-
target: "document" /* ListenerTarget.Document */,
|
|
396
381
|
pointerType: "touch" /* GesturePointerType.Touch */,
|
|
397
382
|
phase: "moving" /* GesturePhase.Moving */,
|
|
398
383
|
options: { capture: true, passive: false }
|
|
399
384
|
},
|
|
400
385
|
touchend: {
|
|
401
|
-
target: "document" /* ListenerTarget.Document */,
|
|
402
386
|
pointerType: "touch" /* GesturePointerType.Touch */,
|
|
403
387
|
phase: "end" /* GesturePhase.End */,
|
|
404
388
|
options: { capture: true, passive: false }
|
|
405
389
|
},
|
|
406
390
|
touchcancel: {
|
|
407
|
-
target: "document" /* ListenerTarget.Document */,
|
|
408
391
|
pointerType: "touch" /* GesturePointerType.Touch */,
|
|
409
392
|
phase: "end" /* GesturePhase.End */,
|
|
410
|
-
options: { capture: true, passive:
|
|
393
|
+
options: { capture: true, passive: false }
|
|
411
394
|
}
|
|
395
|
+
// ,
|
|
396
|
+
// contextmenu: {
|
|
397
|
+
// pointerType: GesturePointerType.Mouse,
|
|
398
|
+
// phase: GesturePhase.Start,
|
|
399
|
+
// options: { capture: true, passive: false }
|
|
400
|
+
// }
|
|
412
401
|
};
|
|
413
402
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
403
|
+
class Gesture {
|
|
404
|
+
constructor(name, listeners, options = {}) {
|
|
405
|
+
this.name = name;
|
|
406
|
+
// TODO maybe global option
|
|
407
|
+
this.distanceInclusion = 10;
|
|
408
|
+
// TODO maybe global option
|
|
409
|
+
this.timeWithin = 300;
|
|
410
|
+
this.priority = 0;
|
|
411
|
+
this.includeScrollDistance = false;
|
|
412
|
+
this.filterPointerTypes = ["mouse" /* GesturePointerType.Mouse */, "touch" /* GesturePointerType.Touch */];
|
|
413
|
+
this.filterMouseButtons = [0];
|
|
414
|
+
this.filterByEvent = (event) => this.filterPointerTypes.includes(event.pointerType) &&
|
|
415
|
+
// this.filterListeners.includes(event.origin.type as any) &&
|
|
416
|
+
(event.pointerType !== "mouse" /* GesturePointerType.Mouse */ ||
|
|
417
|
+
(event.origin instanceof MouseEvent && this.filterMouseButtons.includes(event.origin.button)));
|
|
418
|
+
Object.assign(this, options);
|
|
419
|
+
this.filterListeners = listeners.filter(v => this.filterPointerTypes.includes(Listeners[v].pointerType));
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Transform input event, to gesture event
|
|
423
|
+
* ! important, dont rely on this object state, because not always create a new object
|
|
424
|
+
*/
|
|
425
|
+
handle(events) {
|
|
426
|
+
return events.pipe(tap(event => (event.type = this.name)));
|
|
427
|
+
}
|
|
428
|
+
}
|
|
425
429
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
430
|
+
const DRAG_LISTENERS = [
|
|
431
|
+
"mousedown",
|
|
432
|
+
"mousemove",
|
|
433
|
+
"mouseup",
|
|
434
|
+
"touchstart",
|
|
435
|
+
"touchmove",
|
|
436
|
+
"touchend",
|
|
437
|
+
"touchcancel"
|
|
438
|
+
];
|
|
439
|
+
class GestureDragImpl extends Gesture {
|
|
440
|
+
constructor(options) {
|
|
441
|
+
super("gesture-drag", DRAG_LISTENERS, { includeScrollDistance: true, ...options });
|
|
442
|
+
if (this.horizontal == null && this.vertical == null) {
|
|
443
|
+
this.horizontal = true;
|
|
444
|
+
this.vertical = true;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
capture(events) {
|
|
448
|
+
return events.pipe(map(state => {
|
|
449
|
+
if (state.pointers.length !== 1) {
|
|
450
|
+
return 2 /* GestureCaptureState.Skip */;
|
|
451
|
+
}
|
|
452
|
+
if (Math.abs(state.pointers[0].distance.x) > this.distanceInclusion) {
|
|
453
|
+
return this.horizontal ? 3 /* GestureCaptureState.Maybe */ : 2 /* GestureCaptureState.Skip */;
|
|
454
|
+
}
|
|
455
|
+
if (Math.abs(state.pointers[0].distance.y) > this.distanceInclusion) {
|
|
456
|
+
return this.vertical ? 3 /* GestureCaptureState.Maybe */ : 2 /* GestureCaptureState.Skip */;
|
|
457
|
+
}
|
|
458
|
+
return 1 /* GestureCaptureState.Pending */;
|
|
459
|
+
}));
|
|
460
|
+
}
|
|
461
|
+
handle(events) {
|
|
462
|
+
const updater = this.horizontal && this.vertical
|
|
463
|
+
? updateAnyDirection
|
|
464
|
+
: this.horizontal
|
|
465
|
+
? updateHorizontalOnly
|
|
466
|
+
: updateVerticalOnly;
|
|
467
|
+
return super.handle(events).pipe(tap(updater));
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
function updateVerticalOnly(event) {
|
|
471
|
+
const pointer = event.pointers[0];
|
|
472
|
+
pointer.distance.x = 0;
|
|
473
|
+
pointer.direction.x = 0;
|
|
474
|
+
pointer.current.x = pointer.start.x;
|
|
475
|
+
updateEvent(event, updateByScrollDistanceVertical);
|
|
476
|
+
}
|
|
477
|
+
function updateHorizontalOnly(event) {
|
|
478
|
+
console.log("updateHorizontalOnly");
|
|
479
|
+
const pointer = event.pointers[0];
|
|
480
|
+
pointer.distance.y = 0;
|
|
481
|
+
pointer.direction.y = 0;
|
|
482
|
+
pointer.current.y = pointer.start.y;
|
|
483
|
+
updateEvent(event, updateByScrollDistanceHorizontal);
|
|
484
|
+
}
|
|
485
|
+
function updateAnyDirection(event) {
|
|
486
|
+
updateEvent(event, updateByScrollDistanceBoth);
|
|
487
|
+
}
|
|
488
|
+
function updateEvent(event, scrollUpdate) {
|
|
489
|
+
event.moveBy = { ...event.pointers[0].distance };
|
|
490
|
+
scrollUpdate(event);
|
|
491
|
+
}
|
|
492
|
+
function updateByScrollDistanceVertical(event) {
|
|
493
|
+
const sd = event.scrollDistance;
|
|
494
|
+
if (sd == null) {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
event.moveBy.y += sd.y;
|
|
498
|
+
}
|
|
499
|
+
function updateByScrollDistanceHorizontal(event) {
|
|
500
|
+
const sd = event.scrollDistance;
|
|
501
|
+
if (sd == null) {
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
event.moveBy.x += sd.x;
|
|
505
|
+
}
|
|
506
|
+
function updateByScrollDistanceBoth(event) {
|
|
507
|
+
const sd = event.scrollDistance;
|
|
508
|
+
if (sd == null) {
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
event.moveBy.x += sd.x;
|
|
512
|
+
event.moveBy.y += sd.y;
|
|
513
|
+
}
|
|
514
|
+
function gestureDrag(options) {
|
|
515
|
+
return new GestureDragImpl(options);
|
|
516
|
+
}
|
|
517
|
+
const GestureDarg = gestureDrag();
|
|
518
|
+
const GestureDargHorizontal = gestureDrag({ horizontal: true, vertical: false });
|
|
519
|
+
const GestureDargVertical = gestureDrag({ horizontal: false, vertical: true });
|
|
520
|
+
|
|
521
|
+
class GestureLongTapImpl extends Gesture {
|
|
522
|
+
constructor(options) {
|
|
523
|
+
super("gesture-longtap", ["touchstart", "touchmove", "touchend", "touchcancel"], {
|
|
524
|
+
filterPointerTypes: ["touch" /* GesturePointerType.Touch */],
|
|
525
|
+
...options
|
|
444
526
|
});
|
|
445
527
|
}
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
const conf = Listeners[name];
|
|
451
|
-
const container = conf.phase === "start" /* GesturePhase.Start */
|
|
452
|
-
? triggers
|
|
453
|
-
: (watches[conf.pointerType] = watches[conf.pointerType] || []);
|
|
454
|
-
if (container.indexOf(name) === -1) {
|
|
455
|
-
container.push(name);
|
|
528
|
+
capture(events) {
|
|
529
|
+
return combineLatest({ timeWithin: timer(this.timeWithin).pipe(startWith(null)), event: events }).pipe(map(({ timeWithin, event }) => {
|
|
530
|
+
if (event.pointers.length !== 1 || event.elapsed > this.timeWithin) {
|
|
531
|
+
return 2 /* GestureCaptureState.Skip */;
|
|
456
532
|
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
throw Error("Missing start events");
|
|
460
|
-
}
|
|
461
|
-
const observable = (names) => {
|
|
462
|
-
if (names.length === 0) {
|
|
463
|
-
return of();
|
|
533
|
+
if (event.phase === "end" /* GesturePhase.End */ && event.elapsed > this.timeWithin) {
|
|
534
|
+
return 2 /* GestureCaptureState.Skip */;
|
|
464
535
|
}
|
|
465
|
-
|
|
466
|
-
|
|
536
|
+
const distance = event.pointers[0].distance;
|
|
537
|
+
if (Math.abs(distance.x) < this.distanceInclusion && Math.abs(distance.y) < this.distanceInclusion) {
|
|
538
|
+
// maybe is ok event.phase === GesturePhase.End
|
|
539
|
+
return timeWithin !== null ? 4 /* GestureCaptureState.Instant */ : 1 /* GestureCaptureState.Pending */;
|
|
467
540
|
}
|
|
468
541
|
else {
|
|
469
|
-
return
|
|
542
|
+
return 2 /* GestureCaptureState.Skip */;
|
|
470
543
|
}
|
|
471
|
-
};
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
544
|
+
}));
|
|
545
|
+
}
|
|
546
|
+
handle(events) {
|
|
547
|
+
return super.handle(events.pipe(filter(event => event.phase === "start" /* GesturePhase.Start */ || event.phase === "end" /* GesturePhase.End */)));
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
function gestureLongTap(options) {
|
|
551
|
+
return new GestureLongTapImpl(options);
|
|
552
|
+
}
|
|
553
|
+
const GestureLongTap = gestureLongTap();
|
|
554
|
+
|
|
555
|
+
class GestureTapImpl extends Gesture {
|
|
556
|
+
constructor(options) {
|
|
557
|
+
super("gesture-tap", ["touchstart", "touchmove", "touchend", "touchcancel", "mousedown", "mousemove", "mouseup"], {
|
|
558
|
+
filterPointerTypes: ["mouse" /* GesturePointerType.Mouse */, "touch" /* GesturePointerType.Touch */],
|
|
559
|
+
...options
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
// TODO
|
|
563
|
+
capture(events) {
|
|
564
|
+
return events.pipe(map(event => {
|
|
565
|
+
if (event.pointers.length !== 1) {
|
|
566
|
+
return 2 /* GestureCaptureState.Skip */;
|
|
477
567
|
}
|
|
478
|
-
|
|
568
|
+
const distance = event.pointers[0].distance;
|
|
569
|
+
if (Math.abs(distance.x) < this.distanceInclusion && Math.abs(distance.y) < this.distanceInclusion) {
|
|
570
|
+
return event.phase === "end" /* GesturePhase.End */ ? 4 /* GestureCaptureState.Instant */ : 1 /* GestureCaptureState.Pending */;
|
|
571
|
+
}
|
|
572
|
+
else {
|
|
573
|
+
return 2 /* GestureCaptureState.Skip */;
|
|
574
|
+
}
|
|
575
|
+
}));
|
|
576
|
+
}
|
|
577
|
+
handle(events) {
|
|
578
|
+
return super.handle(events.pipe(filter(event => event.phase === "start" /* GesturePhase.Start */ || event.phase === "end" /* GesturePhase.End */)));
|
|
479
579
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
580
|
+
}
|
|
581
|
+
function gestureTap(options) {
|
|
582
|
+
return new GestureTapImpl(options);
|
|
583
|
+
}
|
|
584
|
+
const GestureTap = gestureTap();
|
|
585
|
+
|
|
586
|
+
const ADD_EVENT_LISTENER = __zone_symbol__("addEventListener");
|
|
587
|
+
const REMOVE_EVENT_LISTENER = __zone_symbol__("removeEventListener");
|
|
588
|
+
const DISPATCH_EVENT = __zone_symbol__("dispatchEvent");
|
|
589
|
+
const SCROLL_LISTENER_OPTIONS = { passive: true };
|
|
590
|
+
class GestureService {
|
|
591
|
+
#zone = inject(NgZone);
|
|
592
|
+
#document = inject(DOCUMENT);
|
|
593
|
+
#watchers = [];
|
|
594
|
+
#trigger = new Subject();
|
|
595
|
+
#moving = merge(...Object.keys(Listeners)
|
|
596
|
+
.filter(name => Listeners[name].phase === "moving" /* GesturePhase.Moving */)
|
|
597
|
+
.map(name => this.#listen(name, Listeners[name]))).pipe(share());
|
|
598
|
+
#end = merge(...Object.keys(Listeners)
|
|
599
|
+
.filter(name => Listeners[name].phase === "end" /* GesturePhase.End */)
|
|
600
|
+
.map(name => this.#listen(name, Listeners[name]))).pipe(share());
|
|
601
|
+
#eventStream = merge(this.#moving, this.#end).pipe(share());
|
|
602
|
+
#begin = new Observable((dst) => {
|
|
603
|
+
let pointerType;
|
|
604
|
+
return this.#trigger
|
|
605
|
+
.pipe(filter(event => {
|
|
606
|
+
if (pointerType == null) {
|
|
607
|
+
pointerType = event.pointerType;
|
|
488
608
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
609
|
+
return event.pointerType === pointerType;
|
|
610
|
+
}), connect(events => merge(events,
|
|
611
|
+
// reset pointerType on end, after 200ms, because touchend is maybe followed by a mouse event
|
|
612
|
+
this.#end.pipe(debounceTime(200), tap(() => {
|
|
613
|
+
pointerType = undefined;
|
|
614
|
+
this.#enableTouchAction();
|
|
615
|
+
}), filter(() => false)))),
|
|
616
|
+
// Select active watchers
|
|
617
|
+
map(event => {
|
|
618
|
+
const eventTarget = event.target;
|
|
619
|
+
let includeScrollDistance = false;
|
|
620
|
+
const gestures = this.#watchers
|
|
621
|
+
.filter(({ gesture, el }) => gesture.filterByEvent(event) &&
|
|
622
|
+
(el === eventTarget || ("contains" in el && el.contains(eventTarget))))
|
|
623
|
+
.reduce((gestures, { gesture }) => {
|
|
624
|
+
if (!gestures.has(gesture)) {
|
|
625
|
+
includeScrollDistance = includeScrollDistance || gesture.includeScrollDistance;
|
|
626
|
+
gestures.set(gesture, 0 /* GestureCaptureState.Unchecked */);
|
|
506
627
|
}
|
|
507
|
-
|
|
508
|
-
|
|
628
|
+
return gestures;
|
|
629
|
+
}, new Map());
|
|
630
|
+
return { startEvent: event, gestures, includeScrollDistance };
|
|
631
|
+
}), filter(({ gestures }) => gestures.size > 0), tap(this.#disableTouchAction)
|
|
632
|
+
// finalize(() => console.log("FINALIZE BEGIN"))
|
|
633
|
+
)
|
|
634
|
+
.subscribe(dst);
|
|
635
|
+
});
|
|
636
|
+
#gesture = this.#begin.pipe(switchMap(({ startEvent, gestures, includeScrollDistance }) => {
|
|
637
|
+
const pointerType = startEvent.pointerType;
|
|
638
|
+
const startAt = startEvent.origin.timeStamp;
|
|
639
|
+
const dispatchEvent = startEvent.target[DISPATCH_EVENT].bind(startEvent.target);
|
|
640
|
+
const eventStreamInit = this.#eventStream.pipe(startWith(startEvent), filter(event => event.pointerType === pointerType));
|
|
641
|
+
const eventStreamSource = !includeScrollDistance
|
|
642
|
+
? eventStreamInit
|
|
643
|
+
: combineLatest([
|
|
644
|
+
eventStreamInit,
|
|
645
|
+
this.#scrollDistance(startEvent.target).pipe(startWith({ x: 0, y: 0 }))
|
|
646
|
+
]).pipe(map(([src, distance]) => {
|
|
647
|
+
;
|
|
648
|
+
src.scrollDistance = distance;
|
|
649
|
+
return src;
|
|
650
|
+
}));
|
|
651
|
+
const eventStream = eventStreamSource.pipe(scan((state, curr) => updatePointers({
|
|
652
|
+
...state,
|
|
653
|
+
...curr,
|
|
654
|
+
elapsed: curr.origin.timeStamp - startAt
|
|
655
|
+
}), startEvent), takeWhile(event => event.phase !== "end" /* GesturePhase.End */, true),
|
|
656
|
+
// finalize(() => console.log("FINALIZE WATCH")),
|
|
657
|
+
share());
|
|
658
|
+
const captureState = eventStream.pipe(connect(src => {
|
|
659
|
+
const state = { events: [], gestures, includeScrollDistance };
|
|
660
|
+
return merge(src.pipe(tap(event => state.events.push(event))), ...Array.from(gestures.keys()).map(gesture => gesture.capture(src.pipe(filter(gesture.filterByEvent))).pipe(takeWhile(result => result !== 2 /* GestureCaptureState.Skip */, true), tap(result => gestures.set(gesture, result))))).pipe(map(() => state));
|
|
661
|
+
})
|
|
662
|
+
// ,finalize(() => console.log("FINALIZE CAPTURE"))
|
|
663
|
+
);
|
|
664
|
+
const selectGesture = captureState.pipe(map(state => {
|
|
665
|
+
const partitions = {};
|
|
666
|
+
for (const [gesture, captureState] of state.gestures) {
|
|
667
|
+
const partition = (partitions[captureState] ??= []);
|
|
668
|
+
partition.push(gesture);
|
|
509
669
|
}
|
|
510
|
-
|
|
511
|
-
|
|
670
|
+
if (partitions[4 /* GestureCaptureState.Instant */] != null) {
|
|
671
|
+
return {
|
|
672
|
+
gesture: partitions[4 /* GestureCaptureState.Instant */].sort(sortByPripority)[0],
|
|
673
|
+
events: state.events
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
// while not all gestures return from Gesture.capture
|
|
677
|
+
if (partitions[0 /* GestureCaptureState.Unchecked */] != null) {
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
680
|
+
// while has pending, the capture is continued
|
|
681
|
+
if (partitions[1 /* GestureCaptureState.Pending */] != null) {
|
|
682
|
+
return null;
|
|
683
|
+
}
|
|
684
|
+
// no pendig & has maybe
|
|
685
|
+
if (partitions[3 /* GestureCaptureState.Maybe */] != null) {
|
|
686
|
+
return {
|
|
687
|
+
gesture: partitions[3 /* GestureCaptureState.Maybe */].sort(sortByPripority)[0],
|
|
688
|
+
events: state.events
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
// no pending & no maybe & no terminate
|
|
692
|
+
// so, nothign matched
|
|
693
|
+
return { events: state.events };
|
|
694
|
+
}), takeWhile(isFalsy, true), filter(isTruthy), takeWhile(v => v.gesture != null, false)
|
|
695
|
+
// finalize(() => console.log("FINALIZE SELECT"))
|
|
696
|
+
);
|
|
697
|
+
return selectGesture.pipe(switchMap(({ events, gesture }) => gesture.handle(eventStream.pipe(startWith(...events), filter(gesture.filterByEvent))).pipe(takeWhile(v => v.phase !== "end" /* GesturePhase.End */, true), tap((e) => dispatchEvent(new CustomEvent(e.type, { detail: e, bubbles: true, cancelable: true })))
|
|
698
|
+
// finalize(() => console.log("GESTURE FINALIZE")),
|
|
699
|
+
)),
|
|
700
|
+
// finalize(() => console.log("FINALIZE RESULT")),
|
|
701
|
+
finalize(this.#enableTouchAction));
|
|
702
|
+
}), share());
|
|
703
|
+
constructor() {
|
|
704
|
+
const triggers = merge(...Object.keys(Listeners)
|
|
705
|
+
.filter(name => Listeners[name].phase === "start" /* GesturePhase.Start */)
|
|
706
|
+
.map(name => this.#listen(name, Listeners[name])));
|
|
707
|
+
triggers.pipe(takeUntilDestroyed()).subscribe(this.#trigger);
|
|
708
|
+
}
|
|
709
|
+
listen(el, ...gestures) {
|
|
710
|
+
return new Observable((dst) => this.#zone.runOutsideAngular(() => {
|
|
711
|
+
const element = coerceElement(el);
|
|
712
|
+
const next = dst.next.bind(dst);
|
|
713
|
+
for (const gesture of gestures) {
|
|
714
|
+
element[ADD_EVENT_LISTENER](gesture.name, next);
|
|
715
|
+
dst.add(element[REMOVE_EVENT_LISTENER].bind(element, gesture.name, next));
|
|
716
|
+
}
|
|
717
|
+
dst.add(this.watch(element, ...gestures).subscribe());
|
|
718
|
+
}));
|
|
512
719
|
}
|
|
513
|
-
|
|
514
|
-
|
|
720
|
+
watch(el, ...gestures) {
|
|
721
|
+
return new Observable((dst) => this.#zone.runOutsideAngular(() => {
|
|
722
|
+
const element = coerceElement(el);
|
|
723
|
+
const watchers = gestures.map(gesture => {
|
|
724
|
+
return { gesture, el: element };
|
|
725
|
+
});
|
|
726
|
+
this.#add(watchers);
|
|
727
|
+
dst.add(this.#gesture.subscribe(dst));
|
|
728
|
+
return () => {
|
|
729
|
+
this.#remove(watchers);
|
|
730
|
+
};
|
|
731
|
+
}));
|
|
732
|
+
}
|
|
733
|
+
#add(watchers) {
|
|
734
|
+
this.#watchers = this.#watchers.concat(watchers);
|
|
735
|
+
}
|
|
736
|
+
#remove(watchers) {
|
|
737
|
+
this.#watchers = this.#watchers.filter(v => !watchers.includes(v));
|
|
738
|
+
}
|
|
739
|
+
#listen(name, config) {
|
|
740
|
+
const { phase, pointerType, options } = config;
|
|
741
|
+
const toResult = phase === "start" /* GesturePhase.Start */
|
|
742
|
+
? (origin) => ({
|
|
743
|
+
origin,
|
|
744
|
+
phase,
|
|
745
|
+
pointerType,
|
|
746
|
+
target: origin.target
|
|
747
|
+
})
|
|
748
|
+
: (origin) => {
|
|
749
|
+
if (origin.cancelable) {
|
|
750
|
+
origin.preventDefault();
|
|
751
|
+
}
|
|
752
|
+
return { origin, phase, pointerType };
|
|
753
|
+
};
|
|
754
|
+
return new Observable((dst) => this.#zone.runOutsideAngular(() => {
|
|
755
|
+
const listener = (origin) => {
|
|
756
|
+
if (origin.defaultPrevented) {
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
dst.next(toResult(origin));
|
|
760
|
+
};
|
|
761
|
+
// console.log("addEventListener", name)
|
|
762
|
+
this.#document[ADD_EVENT_LISTENER](name, listener, options);
|
|
763
|
+
return () => {
|
|
764
|
+
// console.log("removeEventListener", name)
|
|
765
|
+
this.#document[REMOVE_EVENT_LISTENER](name, listener, options);
|
|
766
|
+
};
|
|
767
|
+
}));
|
|
768
|
+
}
|
|
769
|
+
#scrollDistance(element) {
|
|
770
|
+
const scrollPosition = () => {
|
|
771
|
+
let x = 0;
|
|
772
|
+
let y = 0;
|
|
773
|
+
let p = element;
|
|
774
|
+
do {
|
|
775
|
+
x += p.scrollLeft ?? 0;
|
|
776
|
+
y += p.scrollTop ?? 0;
|
|
777
|
+
p = p.parentNode;
|
|
778
|
+
} while (p != null);
|
|
779
|
+
return { x, y };
|
|
780
|
+
};
|
|
781
|
+
return new Observable((dst) => this.#zone.runOutsideAngular(() => {
|
|
782
|
+
const initial = scrollPosition();
|
|
783
|
+
const listener = () => {
|
|
784
|
+
const current = scrollPosition();
|
|
785
|
+
dst.next({ x: current.x - initial.x, y: current.y - initial.y });
|
|
786
|
+
};
|
|
787
|
+
this.#document[ADD_EVENT_LISTENER]("scroll", listener, SCROLL_LISTENER_OPTIONS);
|
|
788
|
+
return () => {
|
|
789
|
+
this.#document[REMOVE_EVENT_LISTENER]("scroll", listener, SCROLL_LISTENER_OPTIONS);
|
|
790
|
+
};
|
|
791
|
+
}));
|
|
792
|
+
}
|
|
793
|
+
#lastTouchAction;
|
|
794
|
+
#disableTouchAction = () => {
|
|
795
|
+
if (this.#lastTouchAction == null) {
|
|
796
|
+
this.#lastTouchAction = window.getComputedStyle(this.#document.body).touchAction;
|
|
797
|
+
this.#document.body.style.touchAction = "none";
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
#enableTouchAction = () => {
|
|
801
|
+
if (this.#lastTouchAction != null) {
|
|
802
|
+
this.#document.body.style.touchAction = this.#lastTouchAction;
|
|
803
|
+
this.#lastTouchAction = undefined;
|
|
804
|
+
}
|
|
805
|
+
};
|
|
806
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: GestureService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
807
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: GestureService, providedIn: "root" }); }
|
|
515
808
|
}
|
|
516
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type:
|
|
809
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: GestureService, decorators: [{
|
|
517
810
|
type: Injectable,
|
|
518
811
|
args: [{ providedIn: "root" }]
|
|
519
|
-
}] });
|
|
812
|
+
}], ctorParameters: () => [] });
|
|
813
|
+
function sortByPripority(a, b) {
|
|
814
|
+
return b.priority - a.priority;
|
|
815
|
+
}
|
|
520
816
|
function pointersFromEvent(event) {
|
|
521
817
|
if (event instanceof MouseEvent) {
|
|
522
818
|
return [
|
|
@@ -558,9 +854,6 @@ function updatePointers(state) {
|
|
|
558
854
|
function direction(prev, curr) {
|
|
559
855
|
return curr > prev ? 1 : curr < prev ? -1 : 0;
|
|
560
856
|
}
|
|
561
|
-
// const svc = new GesturesService()
|
|
562
|
-
// const w = svc.watch(document.createElement("div"), DragAndDrop)
|
|
563
|
-
function noop() { }
|
|
564
857
|
|
|
565
858
|
const COMPILE_CACHE = {};
|
|
566
859
|
function compile(selector) {
|
|
@@ -1217,5 +1510,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.6", ngImpor
|
|
|
1217
1510
|
* Generated bundle index. Do not edit.
|
|
1218
1511
|
*/
|
|
1219
1512
|
|
|
1220
|
-
export { AbstractUiState, ActivityService, BusyDirective, DisabledDirective,
|
|
1513
|
+
export { AbstractUiState, ActivityService, BusyDirective, DisabledDirective, FocusService, FocusState, FocusTrap, Focusable, Gesture, GestureDarg, GestureDargHorizontal, GestureDargVertical, GestureDragImpl, GestureLongTap, GestureLongTapImpl, GestureService, GestureTap, GestureTapImpl, KeystrokeService, Listeners, NOTSET, ProgressSegmentRef, ProgressState, ReadonlyDirective, UiState, UiStateModule, gestureDrag, gestureLongTap, gestureTap };
|
|
1221
1514
|
//# sourceMappingURL=ngutil-aria.mjs.map
|