ngx-lift 1.7.2 → 1.8.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.
@@ -1,7 +1,7 @@
1
- import { startWith, Subject, combineLatest, pipe, tap, map, catchError, of, Observable, timer, EMPTY, isObservable, merge, exhaustMap, from, share, switchMap, identity, distinctUntilChanged, switchAll, mergeAll, concatAll, exhaustAll } from 'rxjs';
1
+ import { startWith, Subject, combineLatest, pipe, tap, map, catchError, of, Observable, timer, EMPTY, isObservable, merge, exhaustMap, from, share, switchMap, fromEvent, throttleTime, identity, distinctUntilChanged, switchAll, mergeAll, concatAll, exhaustAll } from 'rxjs';
2
2
  import { toObservable, toSignal } from '@angular/core/rxjs-interop';
3
3
  import * as i0 from '@angular/core';
4
- import { Pipe, inject, LOCALE_ID, assertInInjectionContext, isSignal, untracked, computed, DestroyRef, signal, effect } from '@angular/core';
4
+ import { Pipe, inject, LOCALE_ID, makeEnvironmentProviders, NgModule, Injectable, Optional, assertInInjectionContext, isSignal, untracked, computed, DestroyRef, signal, effect } from '@angular/core';
5
5
  import { Validators, FormArray } from '@angular/forms';
6
6
  import { ActivatedRoute } from '@angular/router';
7
7
 
@@ -210,26 +210,26 @@ function isPromise$1(obj) {
210
210
  function poll(options) {
211
211
  const timerEmitValue = '__timer__emission__';
212
212
  const timer$ = timer(0, options.interval).pipe(map((i) => `${timerEmitValue}${i}`));
213
- const trigger$ = options.trigger === undefined
213
+ const trigger$ = options.forceRefresh === undefined
214
214
  ? EMPTY
215
- : isObservable(options.trigger)
216
- ? options.trigger
217
- : toObservable(options.trigger);
218
- let inputByTrigger = undefined; // if trigger is not provided, input will be undefined
215
+ : isObservable(options.forceRefresh)
216
+ ? options.forceRefresh
217
+ : toObservable(options.forceRefresh);
218
+ let inputByForceRefresh = undefined; // if forceRefresh is not provided, input will be undefined
219
219
  return merge(trigger$, timer$).pipe(exhaustMap((input) => {
220
- // input can be either by trigger or timer
220
+ // input can be either by forceRefresh or timer
221
221
  const isTimerTrigger = typeof input === 'string' && input.includes(timerEmitValue);
222
222
  const isManualTrigger = !isTimerTrigger;
223
223
  if (isManualTrigger) {
224
- inputByTrigger = input;
224
+ inputByForceRefresh = input;
225
225
  }
226
- // build params by trigger input
226
+ // build params by input
227
227
  // if paramsBuilder is provided, params will be the value of this function call
228
- // if paramsBuilder is not provided, params will be the value emitted by the trigger
229
- const params = options.paramsBuilder ? options.paramsBuilder(inputByTrigger) : inputByTrigger;
230
- // NOTE: using exhaustMap will NOT emit ${timerEmitValue}0 if trigger is not provided
231
- // using concatMap will emit ${timerEmitValue}0 if trigger is not provided
232
- const isFirstRequest = input === `${timerEmitValue}0`; // timer first emission when trigger is not provided
228
+ // if paramsBuilder is not provided, params will be the value emitted by the forceRefresh
229
+ const params = options.paramsBuilder ? options.paramsBuilder(inputByForceRefresh) : inputByForceRefresh;
230
+ // NOTE: using exhaustMap will NOT emit ${timerEmitValue}0 if forceRefresh is not provided
231
+ // using concatMap will emit ${timerEmitValue}0 if forceRefresh is not provided
232
+ const isFirstRequest = input === `${timerEmitValue}0`; // timer first emission when forceRefresh is not provided
233
233
  const shouldShowLoading = isManualTrigger || isFirstRequest;
234
234
  const fnResult = options.pollingFn(params);
235
235
  const fnResult$ = isObservable(fnResult) ? fnResult : isPromise$1(fnResult) ? from(fnResult) : of(fnResult);
@@ -295,10 +295,10 @@ class ArrayJoinPipe {
295
295
  // For non-array cases or unexpected types, return the value as is
296
296
  return value;
297
297
  }
298
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.2", ngImport: i0, type: ArrayJoinPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
299
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.2", ngImport: i0, type: ArrayJoinPipe, isStandalone: true, name: "arrayJoin" }); }
298
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: ArrayJoinPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
299
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.7", ngImport: i0, type: ArrayJoinPipe, isStandalone: true, name: "arrayJoin" }); }
300
300
  }
301
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.2", ngImport: i0, type: ArrayJoinPipe, decorators: [{
301
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: ArrayJoinPipe, decorators: [{
302
302
  type: Pipe,
303
303
  args: [{
304
304
  name: 'arrayJoin',
@@ -356,10 +356,10 @@ class ByteConverterPipe {
356
356
  formatNumber(value) {
357
357
  return new Intl.NumberFormat(this.locale, { maximumFractionDigits: 2 }).format(value);
358
358
  }
359
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.2", ngImport: i0, type: ByteConverterPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
360
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.2", ngImport: i0, type: ByteConverterPipe, isStandalone: true, name: "byteConverter" }); }
359
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: ByteConverterPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
360
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.7", ngImport: i0, type: ByteConverterPipe, isStandalone: true, name: "byteConverter" }); }
361
361
  }
362
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.2", ngImport: i0, type: ByteConverterPipe, decorators: [{
362
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: ByteConverterPipe, decorators: [{
363
363
  type: Pipe,
364
364
  args: [{
365
365
  name: 'byteConverter',
@@ -533,6 +533,220 @@ function composeValidators(control, validatorFn) {
533
533
  return Validators.compose(validatorFns)?.(control) || null;
534
534
  }
535
535
 
536
+ class IdleDetectionConfig {
537
+ }
538
+ function provideIdleDetectionConfig(config) {
539
+ return makeEnvironmentProviders([{ provide: IdleDetectionConfig, useValue: config }]);
540
+ }
541
+
542
+ /**
543
+ * Idle detection module.
544
+ * @deprecated use provideIdleDetectionConfig(config: IdleDetectionConfig) instead
545
+ */
546
+ class IdleDetectionModule {
547
+ static forRoot(config) {
548
+ return {
549
+ ngModule: IdleDetectionModule,
550
+ providers: [provideIdleDetectionConfig(config)],
551
+ };
552
+ }
553
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: IdleDetectionModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
554
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.7", ngImport: i0, type: IdleDetectionModule }); }
555
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: IdleDetectionModule }); }
556
+ }
557
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: IdleDetectionModule, decorators: [{
558
+ type: NgModule,
559
+ args: [{
560
+ imports: [],
561
+ }]
562
+ }] });
563
+
564
+ /**
565
+ * Service for detecting user idle time and implementing a countdown.
566
+ */
567
+ class IdleDetectionService {
568
+ /**
569
+ * Constructs the IdleDetectionService.
570
+ * @param config - Optional configuration for idle and timeout durations.
571
+ */
572
+ constructor(config) {
573
+ /**
574
+ * The list of interruption events that will end the idle detection.
575
+ */
576
+ this.interruptionEvents = [
577
+ 'click',
578
+ 'keydown',
579
+ 'keypress',
580
+ 'mousemove',
581
+ 'mousedown',
582
+ 'scroll',
583
+ 'wheel',
584
+ 'touchmove',
585
+ 'pointermove',
586
+ 'resize',
587
+ ];
588
+ /**
589
+ * The default idle duration in seconds (19 minutes).
590
+ */
591
+ this.idleDuration = 19 * 60;
592
+ /**
593
+ * The default timeout duration in seconds (1 minute).
594
+ */
595
+ this.timeoutDuration = 60;
596
+ /**
597
+ * Flag to indicate if countdown is in progress.
598
+ */
599
+ this.isCountingDown = false;
600
+ /**
601
+ * The current countdown value.
602
+ */
603
+ this.countdown = this.timeoutDuration;
604
+ /**
605
+ * Subject to emit when idle period ends.
606
+ */
607
+ this.idleEndSubject = new Subject();
608
+ /**
609
+ * Subject to emit the countdown value.
610
+ */
611
+ this.countdownSubject = new Subject();
612
+ /**
613
+ * Subject to emit when countdown ends.
614
+ */
615
+ this.countdownEndSubject = new Subject();
616
+ if (config) {
617
+ this.setConfig(config);
618
+ }
619
+ }
620
+ /**
621
+ * Starts to watch for user inactivity.
622
+ */
623
+ startWatching() {
624
+ this.setupInterruptionEvents();
625
+ this.startIdleTimer();
626
+ }
627
+ /**
628
+ * Resets the idle timer when user activity is detected.
629
+ * @param withCountdownReset - Flag to indicate if countdown should be reset.
630
+ * By default, it only reset the idle-detection timer. If you enter the countdown phase, it won't stop the countdown.
631
+ * Pass true when you want to reset the countdown as well. This is useful when you click "Keep Me Signed In" button in cll-idle-detection component
632
+ */
633
+ resetTimer(withCountdownReset = false) {
634
+ this.startIdleTimer();
635
+ if (withCountdownReset && this.isCountingDown) {
636
+ this.stopCountdown();
637
+ }
638
+ }
639
+ /**
640
+ * Sets up the interruption events that will end the idle detection.
641
+ * Listens to a set of events on the document (e.g. click, keydown, mousemove, etc.).
642
+ * When any of these events is triggered, the idle timer is reset.
643
+ * Uses `throttleTime` operator to only trigger the reset when the events are spaced
644
+ * out by at least 1000ms (1 second).
645
+ * @private
646
+ */
647
+ setupInterruptionEvents() {
648
+ if (!this.interruptionSubscription) {
649
+ const throttledInterruptionEvents = this.interruptionEvents.map((eventName) => fromEvent(document, eventName).pipe(throttleTime(1000)));
650
+ this.interruptionSubscription = merge(...throttledInterruptionEvents).subscribe(() => this.resetTimer());
651
+ }
652
+ }
653
+ /**
654
+ * Starts the idle timer.
655
+ * When the timer expires, it emits an event through onIdleEnd() and starts the countdown.
656
+ */
657
+ startIdleTimer() {
658
+ clearTimeout(this.idleTimer);
659
+ this.idleTimer = window.setTimeout(() => {
660
+ // after idle period, user inactivity detected
661
+ this.idleEndSubject.next();
662
+ this.startCountdown();
663
+ }, this.idleDuration * 1000);
664
+ }
665
+ /**
666
+ * Starts the countdown.
667
+ */
668
+ startCountdown() {
669
+ this.isCountingDown = true;
670
+ this.countdownSubject.next(this.countdown);
671
+ this.countdownTimer = window.setInterval(() => {
672
+ this.countdown--;
673
+ this.countdownSubject.next(this.countdown);
674
+ if (this.countdown <= 0) {
675
+ this.stopCountdown();
676
+ this.countdownEndSubject.next();
677
+ }
678
+ }, 1000);
679
+ }
680
+ /**
681
+ * Stops the countdown.
682
+ */
683
+ stopCountdown() {
684
+ clearInterval(this.countdownTimer);
685
+ this.isCountingDown = false;
686
+ // reset countdown
687
+ this.countdown = this.timeoutDuration;
688
+ }
689
+ /**
690
+ * Returns an observable that emits when the user has been idle for a long period.
691
+ * Developers can use this to perform actions like opening a dialog.
692
+ *
693
+ * user has been inactive for a long period (idleDuration), at this moment, idle detection phase ends, onIdleEnd event is emitted, and then enter countdown/timeout phase.
694
+ * During the countdown phase:
695
+ * - if user has any activity, countdown phase immediately ends and restart the idle detection phase.
696
+ * - else, countdownEnd event will be emitted when timeoutDuration is over.
697
+ * @returns {Observable<void>} - Observable for idle end event.
698
+ */
699
+ onIdleEnd() {
700
+ return this.idleEndSubject.asObservable();
701
+ }
702
+ /**
703
+ * Returns an observable that emits when the countdown ends.
704
+ * Usually means the user has been inactive for a very long time and should be logged out.
705
+ * @returns {Observable<void>} - Observable for countdown end event.
706
+ */
707
+ onTimeoutEnd() {
708
+ return this.countdownEndSubject.asObservable();
709
+ }
710
+ /**
711
+ * Returns an observable that emits the countdown value every second.
712
+ * @returns {Observable<number>} - Observable for countdown value.
713
+ */
714
+ onCountDown() {
715
+ return this.countdownSubject.asObservable();
716
+ }
717
+ /**
718
+ * Clears all timers when the component is destroyed.
719
+ */
720
+ clearTimers() {
721
+ clearTimeout(this.idleTimer);
722
+ clearInterval(this.countdownTimer);
723
+ this.interruptionSubscription?.unsubscribe();
724
+ this.interruptionSubscription = undefined;
725
+ }
726
+ /**
727
+ * Sets the idle and timeout durations based on the provided configuration.
728
+ * @param config - Configuration object with idle and timeout durations.
729
+ */
730
+ setConfig(config) {
731
+ if (config.idleDurationInSeconds) {
732
+ this.idleDuration = config.idleDurationInSeconds;
733
+ }
734
+ if (config.timeoutDurationInSeconds) {
735
+ this.countdown = this.timeoutDuration = config.timeoutDurationInSeconds;
736
+ }
737
+ }
738
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: IdleDetectionService, deps: [{ token: IdleDetectionConfig, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
739
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: IdleDetectionService, providedIn: 'root' }); }
740
+ }
741
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: IdleDetectionService, decorators: [{
742
+ type: Injectable,
743
+ args: [{
744
+ providedIn: 'root',
745
+ }]
746
+ }], ctorParameters: () => [{ type: IdleDetectionConfig, decorators: [{
747
+ type: Optional
748
+ }] }] });
749
+
536
750
  /**
537
751
  * Check if a value is empty.
538
752
  * @param {T | undefined | null} value - The value to check for emptiness.
@@ -676,10 +890,10 @@ class IsHttpsPipe {
676
890
  transform(value) {
677
891
  return isHttps(value);
678
892
  }
679
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.2", ngImport: i0, type: IsHttpsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
680
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.2", ngImport: i0, type: IsHttpsPipe, isStandalone: true, name: "isHttps" }); }
893
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: IsHttpsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
894
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.7", ngImport: i0, type: IsHttpsPipe, isStandalone: true, name: "isHttps" }); }
681
895
  }
682
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.2", ngImport: i0, type: IsHttpsPipe, decorators: [{
896
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: IsHttpsPipe, decorators: [{
683
897
  type: Pipe,
684
898
  args: [{
685
899
  name: 'isHttps',
@@ -710,10 +924,10 @@ class MaskPipe {
710
924
  .map((char, i) => (i < unmaskedPrefixLength || i > value.length - unmaskedSuffixLength - 1 ? char : maskChar))
711
925
  .join('');
712
926
  }
713
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.2", ngImport: i0, type: MaskPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
714
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.2", ngImport: i0, type: MaskPipe, isStandalone: true, name: "mask" }); }
927
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: MaskPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
928
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.7", ngImport: i0, type: MaskPipe, isStandalone: true, name: "mask" }); }
715
929
  }
716
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.2", ngImport: i0, type: MaskPipe, decorators: [{
930
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: MaskPipe, decorators: [{
717
931
  type: Pipe,
718
932
  args: [{
719
933
  name: 'mask',
@@ -726,10 +940,10 @@ class RangePipe {
726
940
  const input = value;
727
941
  return range(...input);
728
942
  }
729
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.2", ngImport: i0, type: RangePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
730
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.2", ngImport: i0, type: RangePipe, isStandalone: true, name: "range" }); }
943
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: RangePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
944
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.7", ngImport: i0, type: RangePipe, isStandalone: true, name: "range" }); }
731
945
  }
732
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.2", ngImport: i0, type: RangePipe, decorators: [{
946
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: RangePipe, decorators: [{
733
947
  type: Pipe,
734
948
  args: [{
735
949
  name: 'range',
@@ -1209,5 +1423,5 @@ function httpsValidator(control) {
1209
1423
  * Generated bundle index. Do not edit.
1210
1424
  */
1211
1425
 
1212
- export { ArrayJoinPipe, ByteConverterPipe, IsHttpsPipe, MaskPipe, RangePipe, UniqueValidator, combineFrom, combineLatestEager, computedAsync, createAsyncState, createTrigger, dateRangeValidator, differenceInDays, distinctOnChange, httpsValidator, ifAsyncValidator, ifValidator, injectParams, injectQueryParams, intersectionValidator, isEmpty, isEqual, isFQDN, isHttps, isIP, isURL, logger, mergeFrom, omitBy, pickBy, poll, range, startWithTap, switchMapWithAsyncState, urlValidator };
1426
+ export { ArrayJoinPipe, ByteConverterPipe, IdleDetectionConfig, IdleDetectionModule, IdleDetectionService, IsHttpsPipe, MaskPipe, RangePipe, UniqueValidator, combineFrom, combineLatestEager, computedAsync, createAsyncState, createTrigger, dateRangeValidator, differenceInDays, distinctOnChange, httpsValidator, ifAsyncValidator, ifValidator, injectParams, injectQueryParams, intersectionValidator, isEmpty, isEqual, isFQDN, isHttps, isIP, isURL, logger, mergeFrom, omitBy, pickBy, poll, provideIdleDetectionConfig, range, startWithTap, switchMapWithAsyncState, urlValidator };
1213
1427
  //# sourceMappingURL=ngx-lift.mjs.map