ngx-lift 1.0.0 → 1.2.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,6 +1,8 @@
1
- import { startWith, Subject, combineLatest, pipe, tap, map, catchError, of, Observable, merge, EMPTY, timer, exhaustMap, share, switchMap, isObservable, switchAll, mergeAll, concatAll, exhaustAll } from 'rxjs';
1
+ import { startWith, Subject, combineLatest, pipe, tap, map, catchError, of, Observable, merge, EMPTY, timer, exhaustMap, share, switchMap, identity, isObservable, distinctUntilChanged, from, switchAll, mergeAll, concatAll, exhaustAll } from 'rxjs';
2
2
  import * as i0 from '@angular/core';
3
- import { Pipe, LOCALE_ID, Inject, inject, DestroyRef, signal, effect, untracked, computed } from '@angular/core';
3
+ import { Pipe, inject, LOCALE_ID, assertInInjectionContext, isSignal, untracked, computed, DestroyRef, signal, effect } from '@angular/core';
4
+ import { toSignal, toObservable } from '@angular/core/rxjs-interop';
5
+ import { ActivatedRoute } from '@angular/router';
4
6
  import { Validators, FormArray } from '@angular/forms';
5
7
 
6
8
  /**
@@ -285,10 +287,10 @@ class ArrayJoinPipe {
285
287
  // For non-array cases or unexpected types, return the value as is
286
288
  return value;
287
289
  }
288
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: ArrayJoinPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
289
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "17.3.4", ngImport: i0, type: ArrayJoinPipe, isStandalone: true, name: "arrayJoin" }); }
290
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.10", ngImport: i0, type: ArrayJoinPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
291
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "17.3.10", ngImport: i0, type: ArrayJoinPipe, isStandalone: true, name: "arrayJoin" }); }
290
292
  }
291
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: ArrayJoinPipe, decorators: [{
293
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.10", ngImport: i0, type: ArrayJoinPipe, decorators: [{
292
294
  type: Pipe,
293
295
  args: [{
294
296
  name: 'arrayJoin',
@@ -326,8 +328,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImpor
326
328
  * export class AppModule {}
327
329
  */
328
330
  class ByteConverterPipe {
329
- constructor(locale) {
330
- this.locale = locale;
331
+ constructor() {
332
+ this.locale = inject(LOCALE_ID);
331
333
  }
332
334
  // If using navigator.language directly in the pipe, this approach directly uses the browser's language at the moment the ByteConverterPipe is constructed. If the user changes the language while using the application, it won't be automatically reflected. If dynamic language changes are a requirement, using the LOCALE_ID provider as demonstrated in the AppModule is a more Angular-centric approach.
333
335
  // private locale: string;
@@ -352,19 +354,16 @@ class ByteConverterPipe {
352
354
  formatNumber(value) {
353
355
  return new Intl.NumberFormat(this.locale, { maximumFractionDigits: 2 }).format(value);
354
356
  }
355
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: ByteConverterPipe, deps: [{ token: LOCALE_ID }], target: i0.ɵɵFactoryTarget.Pipe }); }
356
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "17.3.4", ngImport: i0, type: ByteConverterPipe, isStandalone: true, name: "byteConverter" }); }
357
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.10", ngImport: i0, type: ByteConverterPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
358
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "17.3.10", ngImport: i0, type: ByteConverterPipe, isStandalone: true, name: "byteConverter" }); }
357
359
  }
358
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: ByteConverterPipe, decorators: [{
360
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.10", ngImport: i0, type: ByteConverterPipe, decorators: [{
359
361
  type: Pipe,
360
362
  args: [{
361
363
  name: 'byteConverter',
362
364
  standalone: true,
363
365
  }]
364
- }], ctorParameters: () => [{ type: undefined, decorators: [{
365
- type: Inject,
366
- args: [LOCALE_ID]
367
- }] }] });
366
+ }] });
368
367
  const translations = {
369
368
  en: {
370
369
  BYTE: 'B',
@@ -462,10 +461,10 @@ class IsHttpsPipe {
462
461
  transform(value) {
463
462
  return httpsPattern.test(value);
464
463
  }
465
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: IsHttpsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
466
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "17.3.4", ngImport: i0, type: IsHttpsPipe, isStandalone: true, name: "isHttps" }); }
464
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.10", ngImport: i0, type: IsHttpsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
465
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "17.3.10", ngImport: i0, type: IsHttpsPipe, isStandalone: true, name: "isHttps" }); }
467
466
  }
468
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: IsHttpsPipe, decorators: [{
467
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.10", ngImport: i0, type: IsHttpsPipe, decorators: [{
469
468
  type: Pipe,
470
469
  args: [{
471
470
  name: 'isHttps',
@@ -496,10 +495,10 @@ class MaskPipe {
496
495
  .map((char, i) => (i < unmaskedPrefixLength || i > value.length - unmaskedSuffixLength - 1 ? char : maskChar))
497
496
  .join('');
498
497
  }
499
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: MaskPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
500
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "17.3.4", ngImport: i0, type: MaskPipe, isStandalone: true, name: "mask" }); }
498
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.10", ngImport: i0, type: MaskPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
499
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "17.3.10", ngImport: i0, type: MaskPipe, isStandalone: true, name: "mask" }); }
501
500
  }
502
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: MaskPipe, decorators: [{
501
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.10", ngImport: i0, type: MaskPipe, decorators: [{
503
502
  type: Pipe,
504
503
  args: [{
505
504
  name: 'mask',
@@ -507,6 +506,84 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImpor
507
506
  }]
508
507
  }] });
509
508
 
509
+ /* eslint-disable @typescript-eslint/no-explicit-any */
510
+ /**
511
+ * Combines multiple `Observable` or `Signal` sources into a `Signal` that emits their values. It's like combineLatest.
512
+ *
513
+ * @param {ObservableSignalInputTuple} sources - Array or object of `Observable` or `Signal` values
514
+ * @param {OperatorFunction} [operator] - Operator to apply to the combined values
515
+ * @param {CombineFromOptions} [options] - Options including `initialValue` and `injector`
516
+ * @returns Signal emitting the combined values
517
+ *
518
+ * @example
519
+ * ```ts
520
+ * export class Component {
521
+ * private readonly userService = inject(UserService);
522
+ * page = signal(2);
523
+ *
524
+ * data = combineFrom(
525
+ * [this.page, this.userService.users$],
526
+ * pipe(
527
+ * switchMap(([page, users]) => this.dataService.getData(page, users)),
528
+ * startWith([])
529
+ * )
530
+ * );
531
+ * }
532
+ * ```
533
+ */
534
+ function combineFrom(...args) {
535
+ assertInInjectionContext(combineFrom);
536
+ const { normalizedSources, hasInitValue, operator, options } = normalizeArgs(args);
537
+ const ret = hasInitValue
538
+ ? toSignal(combineLatest(normalizedSources).pipe(operator), {
539
+ initialValue: options.initialValue,
540
+ injector: options?.injector,
541
+ })
542
+ : toSignal(combineLatest(normalizedSources).pipe(operator), {
543
+ injector: options?.injector,
544
+ // requireSync: true,
545
+ });
546
+ return ret;
547
+ }
548
+ function normalizeArgs(args) {
549
+ if (!args || args.length < 1 || typeof args[0] !== 'object') {
550
+ throw new TypeError('combineFrom needs sources');
551
+ }
552
+ const hasOperator = typeof args[1] === 'function';
553
+ if (args.length === 3 && !hasOperator) {
554
+ throw new TypeError('combineFrom needs a pipe operator as the second argument');
555
+ }
556
+ // pass sources and options
557
+ if (!hasOperator) {
558
+ // add identity function to args at index 1 as operator function as x=>x
559
+ args.splice(1, 0, identity);
560
+ }
561
+ // if no operator passed, identity will be operator
562
+ const [sources, operator, options] = args;
563
+ const hasInitValue = options?.initialValue !== undefined;
564
+ const normalizedSources = Object.entries(sources).reduce((acc, [keyOrIndex, source]) => {
565
+ if (isSignal(source)) {
566
+ acc[keyOrIndex] = toObservable(source, { injector: options?.injector }).pipe(
567
+ // toObservable doesn't immediately emit initialValue of the signal
568
+ startWith(untracked(source)));
569
+ }
570
+ else if (isObservable(source)) {
571
+ acc[keyOrIndex] = source.pipe(distinctUntilChanged());
572
+ }
573
+ else if (typeof source === 'function') {
574
+ // seldom use: pass function like () => 5
575
+ const computedRes = computed(source);
576
+ acc[keyOrIndex] = toObservable(computedRes, { injector: options?.injector }).pipe(startWith(source()));
577
+ }
578
+ else {
579
+ // seldom use: pass promise, Map, array, etc that from accepts
580
+ acc[keyOrIndex] = from(source).pipe(distinctUntilChanged());
581
+ }
582
+ return acc;
583
+ }, (Array.isArray(sources) ? [] : {}));
584
+ return { normalizedSources, operator, hasInitValue, options };
585
+ }
586
+
510
587
  /* eslint-disable @typescript-eslint/no-explicit-any */
511
588
  function computedAsync(computeFn, options = {}) {
512
589
  const destroyRef = inject(DestroyRef);
@@ -578,6 +655,154 @@ function createNotifier() {
578
655
  };
579
656
  }
580
657
 
658
+ function injectParams(keyOrParamsTransform, options = {}) {
659
+ assertInInjectionContext(injectParams);
660
+ const route = inject(ActivatedRoute);
661
+ const initialParams = route.snapshot.params;
662
+ const { transform, initialValue } = options;
663
+ // injectParams(): Signal<Params>
664
+ if (!keyOrParamsTransform) {
665
+ return toSignal(route.params, { initialValue: initialParams });
666
+ }
667
+ // injectParams<Output>(fn: ParamsTransformFn<Output>): Signal<Output>
668
+ if (typeof keyOrParamsTransform === 'function') {
669
+ return toSignal(route.params.pipe(map(keyOrParamsTransform)), { initialValue: keyOrParamsTransform(initialParams) });
670
+ }
671
+ // keyOrParamsTransform is string.
672
+ // export function injectParams(key: string): Signal<string | null>;
673
+ // export function injectParams(key: string, options: { transform: (v: string) => boolean; initialValue: boolean }): Signal<boolean>;
674
+ // export function injectParams(key: string, options: { transform: (v: string) => number; initialValue: number }): Signal<number>;
675
+ // export function injectParams(key: string, options: { transform?: (v: string) => string; initialValue: string }): Signal<string>;
676
+ // export function injectParams(key: string, options: { transform: (v: string) => boolean; initialValue?: undefined }): Signal<boolean | null>;
677
+ // export function injectParams(key: string, options: { transform: (v: string) => number; initialValue?: undefined }): Signal<number | null>;
678
+ // export function injectParams(key: string, options: { transform: (v: string) => string; initialValue?: undefined }): Signal<string | null>;
679
+ const getParam = (params) => {
680
+ const param = params?.[keyOrParamsTransform];
681
+ if (!param) {
682
+ return initialValue ?? null;
683
+ }
684
+ return transform ? transform(param) : param;
685
+ };
686
+ return toSignal(route.params.pipe(map(getParam)), { initialValue: getParam(initialParams) });
687
+ }
688
+
689
+ /**
690
+ * The `injectQueryParams` function allows you to access and manipulate query parameters from the current route.
691
+ *
692
+ * @template Output - The expected type of the read value.
693
+ * @param {string} keyOrParamsTransform - The name of the query parameter to retrieve, or a transform function to apply to the query parameters object.
694
+ * @param {QueryParamsOptions} options - Optional configuration options for the query parameter.
695
+ * @returns {QueryParamsOptions} A `Signal` that emits the transformed value of the specified query parameter, or the entire query parameters object if no key is provided.
696
+ *
697
+ * @example
698
+ * const search = injectQueryParams('search'); // returns the value of the 'search' query param
699
+ * const search = injectQueryParams(p => p['search'] as string); // same as above but can be used with a custom transform function
700
+ * const idParam = injectQueryParams('id', {transform: numberAttribute}); // returns the value fo the 'id' query params and transforms it into a number
701
+ * const idParam = injectQueryParams(p => numberAttribute(p['id'])); // same as above but can be used with a custom transform function
702
+ * const queryParams = injectQueryParams(); // returns the entire query params object
703
+ */
704
+ function injectQueryParams(keyOrParamsTransform, options = {}) {
705
+ assertInInjectionContext(injectQueryParams);
706
+ const route = inject(ActivatedRoute);
707
+ const initialQueryParams = route.snapshot.queryParams;
708
+ const { transform, initialValue } = options;
709
+ // injectQueryParams(): Signal<Params>
710
+ if (!keyOrParamsTransform) {
711
+ return toSignal(route.queryParams, { initialValue: initialQueryParams });
712
+ }
713
+ // injectQueryParams<Output>(fn: QueryParamsTransformFn<Output>): Signal<Output>
714
+ if (typeof keyOrParamsTransform === 'function') {
715
+ return toSignal(route.queryParams.pipe(map(keyOrParamsTransform)), {
716
+ initialValue: keyOrParamsTransform(initialQueryParams),
717
+ });
718
+ }
719
+ // keyOrParamsTransform is string.
720
+ const getParam = (params) => {
721
+ const param = params?.[keyOrParamsTransform];
722
+ if (!param) {
723
+ return initialValue ?? null;
724
+ }
725
+ if (Array.isArray(param)) {
726
+ if (param.length < 1) {
727
+ return initialValue ?? null;
728
+ }
729
+ return transform ? transform(param[0]) : param[0];
730
+ }
731
+ return transform ? transform(param) : param;
732
+ };
733
+ return toSignal(route.queryParams.pipe(map(getParam)), {
734
+ initialValue: getParam(initialQueryParams),
735
+ });
736
+ }
737
+
738
+ // No object inputs
739
+ /**
740
+ * merge multiple `Observable` or `Signal` sources into a `Signal` that emits the last value. It's like merge.
741
+ *
742
+ * @param {ObservableSignalInputTuple} sources - Array of `Observable` or `Signal` values
743
+ * @param {OperatorFunction} [operator] - Operator to apply to the merge
744
+ * @param {MergeFromOptions} [options] - Options including `initialValue` and `injector`
745
+ * @returns Signal emitting the latest merge result
746
+ *
747
+ * @example
748
+ * ```ts
749
+ * export class Component {
750
+ * e$ = of(1).pipe(delay(1000));
751
+ * f = signal(2);
752
+ *
753
+ * data = mergeFrom(
754
+ * [this.e$, this.f],
755
+ * pipe(
756
+ * switchMap((res) => of(`${res} is coming~`)),
757
+ * startWith(0),
758
+ * ),
759
+ * );
760
+ * }
761
+ * ```
762
+ */
763
+ function mergeFrom(...args) {
764
+ assertInInjectionContext(mergeFrom);
765
+ const [sources, operator = identity, options = {}] = parseArgs(args);
766
+ const normalizedSources = sources.map((source) => {
767
+ if (isSignal(source)) {
768
+ return toObservable(source, { injector: options.injector }).pipe(startWith(untracked(source)));
769
+ }
770
+ if (!isObservable(source)) {
771
+ source = from(source);
772
+ }
773
+ return source.pipe(distinctUntilChanged());
774
+ });
775
+ const merged$ = merge(...normalizedSources).pipe(operator);
776
+ if (options.initialValue !== undefined) {
777
+ return toSignal(merged$, { initialValue: options.initialValue, injector: options.injector });
778
+ }
779
+ return toSignal(merged$, { requireSync: true, injector: options.injector });
780
+ }
781
+ function parseArgs(args) {
782
+ if (!args || args.length < 1) {
783
+ throw new TypeError('mergeFrom needs sources');
784
+ }
785
+ if (args.length === 1) {
786
+ return [args[0], undefined, undefined];
787
+ }
788
+ if (args.length === 2) {
789
+ const hasOperator = typeof args[1] === 'function';
790
+ if (hasOperator) {
791
+ return [
792
+ args[0],
793
+ args[1],
794
+ undefined,
795
+ ];
796
+ }
797
+ return [
798
+ args[0],
799
+ undefined,
800
+ args[1],
801
+ ];
802
+ }
803
+ return args;
804
+ }
805
+
581
806
  /**
582
807
  * Calculates the difference in whole days between two dates.
583
808
  *
@@ -795,5 +1020,5 @@ function httpsValidator(control) {
795
1020
  * Generated bundle index. Do not edit.
796
1021
  */
797
1022
 
798
- export { ArrayJoinPipe, ByteConverterPipe, IsHttpsPipe, MaskPipe, UniqueValidator, combineLatestEager, computedAsync, createAsyncState, createNotifier, differenceInDays, distinctOnChange, httpsValidator, ifAsyncValidator, ifValidator, isEmpty, isEqual, logger, pickBy, poll, startWithTap, switchMapWithAsyncState, urlValidator };
1023
+ export { ArrayJoinPipe, ByteConverterPipe, IsHttpsPipe, MaskPipe, UniqueValidator, combineFrom, combineLatestEager, computedAsync, createAsyncState, createNotifier, differenceInDays, distinctOnChange, httpsValidator, ifAsyncValidator, ifValidator, injectParams, injectQueryParams, isEmpty, isEqual, logger, mergeFrom, pickBy, poll, startWithTap, switchMapWithAsyncState, urlValidator };
799
1024
  //# sourceMappingURL=ngx-lift.mjs.map