@dereekb/dbx-core 13.2.1 → 13.2.2
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/fesm2022/dereekb-dbx-core.mjs +3018 -257
- package/fesm2022/dereekb-dbx-core.mjs.map +1 -1
- package/package.json +4 -4
- package/types/dereekb-dbx-core.d.ts +3954 -353
|
@@ -214,29 +214,92 @@ function cleanDestroy(input) {
|
|
|
214
214
|
}
|
|
215
215
|
|
|
216
216
|
/**
|
|
217
|
-
*
|
|
217
|
+
* Abstract source that provides an observable of an {@link ActionContextStore}.
|
|
218
|
+
*
|
|
219
|
+
* This is the primary injection token used by action directives to access the action state.
|
|
220
|
+
* Implementations are typically provided via Angular's DI, either by {@link DbxActionDirective}
|
|
221
|
+
* or through secondary source providers.
|
|
222
|
+
*
|
|
223
|
+
* @typeParam T - The input value type for the action.
|
|
224
|
+
* @typeParam O - The output result type for the action.
|
|
225
|
+
*
|
|
226
|
+
* @see {@link DbxActionDirective} for the directive that provides this source.
|
|
227
|
+
* @see {@link SecondaryActionContextStoreSource} for nested action source forwarding.
|
|
218
228
|
*/
|
|
219
229
|
class ActionContextStoreSource {
|
|
220
230
|
}
|
|
221
231
|
/**
|
|
222
|
-
* Secondary source
|
|
232
|
+
* Secondary action context store source used for nested or forwarded action contexts.
|
|
233
|
+
*
|
|
234
|
+
* When a {@link DbxActionDirective} is created, it checks for the presence of this secondary
|
|
235
|
+
* source via host injection. If found, the directive reuses the existing store rather than
|
|
236
|
+
* creating its own, enabling action context sharing across component boundaries.
|
|
237
|
+
*
|
|
238
|
+
* @typeParam T - The input value type for the action.
|
|
239
|
+
* @typeParam O - The output result type for the action.
|
|
240
|
+
*
|
|
241
|
+
* @see {@link DbxActionSourceDirective} for the directive that provides this.
|
|
223
242
|
*/
|
|
224
243
|
class SecondaryActionContextStoreSource extends ActionContextStoreSource {
|
|
225
244
|
}
|
|
245
|
+
/**
|
|
246
|
+
* Filters null/undefined values from an observable of {@link ActionContextStore} instances.
|
|
247
|
+
*
|
|
248
|
+
* @typeParam T - The input value type.
|
|
249
|
+
* @typeParam O - The output result type.
|
|
250
|
+
* @param obs - The observable that may emit null/undefined store values.
|
|
251
|
+
* @returns An observable that only emits non-null store instances.
|
|
252
|
+
*/
|
|
226
253
|
function actionContextStoreSourcePipe(obs) {
|
|
227
254
|
return obs.pipe(filterMaybe());
|
|
228
255
|
}
|
|
256
|
+
/**
|
|
257
|
+
* Pipes a function through the action store from the given source.
|
|
258
|
+
*
|
|
259
|
+
* Subscribes to the source's store observable and applies the provided function
|
|
260
|
+
* via switchMap, automatically switching to the latest store.
|
|
261
|
+
*
|
|
262
|
+
* @typeParam R - The return type of the derived observable.
|
|
263
|
+
* @typeParam T - The input value type.
|
|
264
|
+
* @typeParam O - The output result type.
|
|
265
|
+
* @param source - The action context store source to read from.
|
|
266
|
+
* @param pipeFn - The function to apply to each emitted store.
|
|
267
|
+
* @returns An observable of the derived value.
|
|
268
|
+
*/
|
|
229
269
|
function pipeActionStore(source, pipeFn) {
|
|
230
270
|
return source.store$.pipe(switchMap(pipeFn));
|
|
231
271
|
}
|
|
232
272
|
/**
|
|
233
|
-
*
|
|
273
|
+
* Subscribes to the source once and invokes the provided function with the store.
|
|
274
|
+
*
|
|
275
|
+
* This is a convenience for performing one-shot imperative operations on the store,
|
|
276
|
+
* such as triggering an action or setting a value, without maintaining a long-lived subscription.
|
|
277
|
+
*
|
|
278
|
+
* @typeParam T - The input value type.
|
|
279
|
+
* @typeParam O - The output result type.
|
|
280
|
+
* @param source - The action context store source to read from.
|
|
281
|
+
* @param useFn - The function to invoke with the store.
|
|
282
|
+
* @returns The subscription (completes after first emission).
|
|
234
283
|
*/
|
|
235
284
|
function useActionStore(source, useFn) {
|
|
236
285
|
return source.store$.pipe(first()).subscribe(useFn);
|
|
237
286
|
}
|
|
238
287
|
/**
|
|
239
|
-
*
|
|
288
|
+
* Convenience wrapper around an {@link ActionContextStoreSource} that provides direct
|
|
289
|
+
* access to all the store's reactive selectors and imperative state-change methods.
|
|
290
|
+
*
|
|
291
|
+
* This class is the primary interface injected by action directives to interact with
|
|
292
|
+
* the action lifecycle. It delegates all operations through the underlying source's
|
|
293
|
+
* store observable, while also maintaining a {@link LockSet} for cleanup coordination.
|
|
294
|
+
*
|
|
295
|
+
* All reactive properties (e.g., `isWorking$`, `success$`, `error$`) are piped through
|
|
296
|
+
* the source's `store$` via switchMap, so they automatically follow store changes.
|
|
297
|
+
*
|
|
298
|
+
* @typeParam T - The input value type for the action.
|
|
299
|
+
* @typeParam O - The output result type for the action.
|
|
300
|
+
*
|
|
301
|
+
* @see {@link ActionContextStore} for the underlying store.
|
|
302
|
+
* @see {@link ActionContextStoreSource} for the source abstraction.
|
|
240
303
|
*/
|
|
241
304
|
class DbxActionContextStoreSourceInstance {
|
|
242
305
|
lockSet = new LockSet();
|
|
@@ -373,6 +436,28 @@ class DbxActionContextStoreSourceInstance {
|
|
|
373
436
|
}
|
|
374
437
|
}
|
|
375
438
|
|
|
439
|
+
/**
|
|
440
|
+
* Directive that automatically marks the parent action as modified whenever it becomes unmodified.
|
|
441
|
+
*
|
|
442
|
+
* This ensures the action is always considered "modified" and therefore always eligible for triggering.
|
|
443
|
+
* Useful in combination with {@link DbxActionAutoTriggerDirective} and {@link DbxActionEnforceModifiedDirective}
|
|
444
|
+
* when the action should be continuously available for submission.
|
|
445
|
+
*
|
|
446
|
+
* Can be disabled by setting `dbxActionAutoModify` to `false`.
|
|
447
|
+
*
|
|
448
|
+
* @example
|
|
449
|
+
* ```html
|
|
450
|
+
* <div dbxAction>
|
|
451
|
+
* <ng-container dbxActionAutoModify></ng-container>
|
|
452
|
+
* <ng-container dbxActionAutoTrigger></ng-container>
|
|
453
|
+
* </div>
|
|
454
|
+
* ```
|
|
455
|
+
*
|
|
456
|
+
* @typeParam T - The input value type for the action.
|
|
457
|
+
* @typeParam O - The output result type for the action.
|
|
458
|
+
*
|
|
459
|
+
* @see {@link DbxActionAutoTriggerDirective} for automatically triggering modified actions.
|
|
460
|
+
*/
|
|
376
461
|
class DbxActionAutoModifyDirective {
|
|
377
462
|
source = inject((DbxActionContextStoreSourceInstance), { host: true });
|
|
378
463
|
autoModifyEnabled = input(true, { ...(ngDevMode ? { debugName: "autoModifyEnabled" } : {}), alias: 'dbxActionAutoModify', transform: isNotFalse });
|
|
@@ -412,9 +497,35 @@ const MAX_ERRORS_TO_THROTTLE_ON = 6;
|
|
|
412
497
|
const DBX_ACTION_AUTO_TRIGGER_FAST_TRIGGER_DEBOUNCE = 200;
|
|
413
498
|
const DBX_ACTION_AUTO_TRIGGER_INSTANT_TRIGGER_DEBOUNCE = 10;
|
|
414
499
|
/**
|
|
415
|
-
* Directive that automatically triggers the action
|
|
500
|
+
* Directive that automatically triggers the parent action when the action becomes modified and can be triggered.
|
|
501
|
+
*
|
|
502
|
+
* Uses configurable debounce and throttle timers to prevent excessive triggering. Also
|
|
503
|
+
* supports error-aware throttling: as consecutive errors accumulate, the throttle interval
|
|
504
|
+
* increases to give transient issues time to resolve.
|
|
505
|
+
*
|
|
506
|
+
* Useful for auto-save scenarios where data changes should automatically submit without
|
|
507
|
+
* requiring an explicit user action. Use with care to avoid triggering loops.
|
|
508
|
+
*
|
|
509
|
+
* @example
|
|
510
|
+
* ```html
|
|
511
|
+
* <div dbxAction>
|
|
512
|
+
* <ng-container dbxActionAutoTrigger></ng-container>
|
|
513
|
+
* <!-- form or value source here -->
|
|
514
|
+
* </div>
|
|
515
|
+
* ```
|
|
516
|
+
*
|
|
517
|
+
* @example
|
|
518
|
+
* ```html
|
|
519
|
+
* <!-- Fast trigger preset with limit -->
|
|
520
|
+
* <div dbxAction>
|
|
521
|
+
* <ng-container dbxActionAutoTrigger useFastTriggerPreset [triggerLimit]="5"></ng-container>
|
|
522
|
+
* </div>
|
|
523
|
+
* ```
|
|
416
524
|
*
|
|
417
|
-
*
|
|
525
|
+
* @typeParam T - The input value type for the action.
|
|
526
|
+
* @typeParam O - The output result type for the action.
|
|
527
|
+
*
|
|
528
|
+
* @see {@link DbxActionAutoModifyDirective} for automatically marking the action as modified.
|
|
418
529
|
*/
|
|
419
530
|
class DbxActionAutoTriggerDirective {
|
|
420
531
|
source = inject((DbxActionContextStoreSourceInstance), { host: true });
|
|
@@ -510,7 +621,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
510
621
|
}], ctorParameters: () => [], propDecorators: { triggerDebounce: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerDebounce", required: false }] }], triggerThrottle: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerThrottle", required: false }] }], triggerErrorThrottle: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerErrorThrottle", required: false }] }], maxErrorsForThrottle: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxErrorsForThrottle", required: false }] }], triggerLimit: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerLimit", required: false }] }], triggerEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionAutoTrigger", required: false }] }], useFastTriggerPreset: [{ type: i0.Input, args: [{ isSignal: true, alias: "useFastTriggerPreset", required: false }] }], useInstantTriggerPreset: [{ type: i0.Input, args: [{ isSignal: true, alias: "useInstantTriggerPreset", required: false }] }] } });
|
|
511
622
|
|
|
512
623
|
/**
|
|
513
|
-
* WorkInstanceDelegate implementation
|
|
624
|
+
* {@link WorkInstanceDelegate} implementation that bridges the `@dereekb/rxjs` work execution
|
|
625
|
+
* system with the action context store.
|
|
626
|
+
*
|
|
627
|
+
* This delegate translates work lifecycle events (startWorking, success, reject) into
|
|
628
|
+
* corresponding state transitions on the {@link DbxActionContextStoreSourceInstance},
|
|
629
|
+
* allowing {@link workFactory} to drive the action state machine.
|
|
630
|
+
*
|
|
631
|
+
* @typeParam T - The input value type for the action.
|
|
632
|
+
* @typeParam O - The output result type for the action.
|
|
633
|
+
*
|
|
634
|
+
* @see {@link DbxActionHandlerInstance} which uses this delegate to handle value-ready events.
|
|
514
635
|
*/
|
|
515
636
|
class DbxActionWorkInstanceDelegate {
|
|
516
637
|
_source;
|
|
@@ -593,7 +714,19 @@ var DbxActionState;
|
|
|
593
714
|
*/
|
|
594
715
|
DbxActionState["RESOLVED"] = "resolved";
|
|
595
716
|
})(DbxActionState || (DbxActionState = {}));
|
|
717
|
+
/**
|
|
718
|
+
* The default disabled key used when no specific key is provided to {@link ActionContextStore.disable}.
|
|
719
|
+
*/
|
|
596
720
|
const DEFAULT_ACTION_DISABLED_KEY = 'dbx_action_disabled';
|
|
721
|
+
/**
|
|
722
|
+
* Determines whether the given action state represents an idle-like state.
|
|
723
|
+
*
|
|
724
|
+
* Idle-like states include IDLE, DISABLED, REJECTED, and RESOLVED -- any state
|
|
725
|
+
* where the action is not currently in-progress (triggered, value-ready, or working).
|
|
726
|
+
*
|
|
727
|
+
* @param actionState - The action state to check.
|
|
728
|
+
* @returns `true` if the state is idle-like, `false` if the action is in-progress.
|
|
729
|
+
*/
|
|
597
730
|
function isIdleActionState(actionState) {
|
|
598
731
|
switch (actionState) {
|
|
599
732
|
case DbxActionState.IDLE:
|
|
@@ -605,6 +738,15 @@ function isIdleActionState(actionState) {
|
|
|
605
738
|
return false;
|
|
606
739
|
}
|
|
607
740
|
}
|
|
741
|
+
/**
|
|
742
|
+
* Maps a {@link DbxActionState} to the corresponding {@link LoadingStateType}.
|
|
743
|
+
*
|
|
744
|
+
* This bridges the action state machine with the loading state system from `@dereekb/rxjs`,
|
|
745
|
+
* allowing action states to be represented as loading states for UI display.
|
|
746
|
+
*
|
|
747
|
+
* @param actionState - The action state to convert.
|
|
748
|
+
* @returns The corresponding loading state type (IDLE, LOADING, SUCCESS, or ERROR).
|
|
749
|
+
*/
|
|
608
750
|
function loadingStateTypeForActionState(actionState) {
|
|
609
751
|
let loadingStateType;
|
|
610
752
|
switch (actionState) {
|
|
@@ -625,34 +767,119 @@ function loadingStateTypeForActionState(actionState) {
|
|
|
625
767
|
return loadingStateType;
|
|
626
768
|
}
|
|
627
769
|
|
|
770
|
+
/**
|
|
771
|
+
* Checks whether the action context is enabled (not disabled by any key).
|
|
772
|
+
*
|
|
773
|
+
* @param state - The current action context state to check.
|
|
774
|
+
* @returns `true` if no disabled keys are active.
|
|
775
|
+
*/
|
|
628
776
|
function isActionContextEnabled(state) {
|
|
629
777
|
return BooleanStringKeyArrayUtility.isFalse(state.disabled);
|
|
630
778
|
}
|
|
779
|
+
/**
|
|
780
|
+
* Checks whether the action context is disabled by at least one disabled key.
|
|
781
|
+
*
|
|
782
|
+
* @param state - The current action context state to check.
|
|
783
|
+
* @returns `true` if any disabled keys are active.
|
|
784
|
+
*/
|
|
631
785
|
function isActionContextDisabled(state) {
|
|
632
786
|
return BooleanStringKeyArrayUtility.isTrue(state.disabled);
|
|
633
787
|
}
|
|
788
|
+
/**
|
|
789
|
+
* Checks whether the action context state represents an effectively disabled state.
|
|
790
|
+
*
|
|
791
|
+
* An action is considered disabled when it is both idle (not in-progress) and has
|
|
792
|
+
* at least one active disabled key.
|
|
793
|
+
*
|
|
794
|
+
* @param state - The current action context state to check.
|
|
795
|
+
* @returns `true` if the action is idle and disabled.
|
|
796
|
+
*/
|
|
634
797
|
function isDisabledActionContextState(state) {
|
|
635
798
|
return isIdleActionState(state.actionState) && isActionContextDisabled(state);
|
|
636
799
|
}
|
|
800
|
+
/**
|
|
801
|
+
* Checks whether the given action state represents an in-progress (non-idle) state.
|
|
802
|
+
*
|
|
803
|
+
* This is the inverse of {@link isIdleActionState}. Returns `true` for TRIGGERED, VALUE_READY, and WORKING states.
|
|
804
|
+
*
|
|
805
|
+
* @param actionState - The action state to check.
|
|
806
|
+
* @returns `true` if the action is in any non-idle state.
|
|
807
|
+
*/
|
|
637
808
|
function isWorkingActionState(actionState) {
|
|
638
809
|
return !isIdleActionState(actionState);
|
|
639
810
|
}
|
|
811
|
+
/**
|
|
812
|
+
* Determines whether the action state allows triggering.
|
|
813
|
+
*
|
|
814
|
+
* An action can be triggered when it is idle (but not DISABLED specifically) and
|
|
815
|
+
* not already in-progress.
|
|
816
|
+
*
|
|
817
|
+
* @param actionState - The action state to check.
|
|
818
|
+
* @returns `true` if the action can be triggered from this state.
|
|
819
|
+
*/
|
|
640
820
|
function canTriggerActionState(actionState) {
|
|
641
821
|
return actionState !== DbxActionState.DISABLED && isIdleActionState(actionState);
|
|
642
822
|
}
|
|
823
|
+
/**
|
|
824
|
+
* Determines whether the action can be triggered based on the full context state.
|
|
825
|
+
*
|
|
826
|
+
* Requires the action to be both enabled (no disabled keys) and in an idle action state.
|
|
827
|
+
*
|
|
828
|
+
* @param state - The current action context state to check.
|
|
829
|
+
* @returns `true` if the action can be triggered.
|
|
830
|
+
*/
|
|
643
831
|
function canTriggerAction(state) {
|
|
644
832
|
return isActionContextEnabled(state) && isIdleActionState(state.actionState);
|
|
645
833
|
}
|
|
834
|
+
/**
|
|
835
|
+
* Determines whether a value can be readied for the action.
|
|
836
|
+
*
|
|
837
|
+
* A value can only be readied when the action is in the TRIGGERED state,
|
|
838
|
+
* which means the trigger has been activated and the system is waiting for a value.
|
|
839
|
+
*
|
|
840
|
+
* @param state - The current action context state to check.
|
|
841
|
+
* @returns `true` if the action is in the TRIGGERED state.
|
|
842
|
+
*/
|
|
646
843
|
function canReadyValue(state) {
|
|
647
844
|
return state.actionState === DbxActionState.TRIGGERED;
|
|
648
845
|
}
|
|
846
|
+
/**
|
|
847
|
+
* Checks whether the action context is both modified and ready to be triggered.
|
|
848
|
+
*
|
|
849
|
+
* This is commonly used by auto-trigger directives to determine when to fire automatically.
|
|
850
|
+
*
|
|
851
|
+
* @param state - The current action context state to check.
|
|
852
|
+
* @returns `true` if the action is modified and can be triggered.
|
|
853
|
+
*/
|
|
649
854
|
function actionContextIsModifiedAndCanTrigger(state) {
|
|
650
855
|
// console.log('check: ', state, state.isModified, canTriggerAction(state));
|
|
651
856
|
return state.isModified && canTriggerAction(state);
|
|
652
857
|
}
|
|
858
|
+
/**
|
|
859
|
+
* Checks whether the action context has no error, is modified, and can be triggered.
|
|
860
|
+
*
|
|
861
|
+
* A stricter variant of {@link actionContextIsModifiedAndCanTrigger} that also requires
|
|
862
|
+
* no error to be present in the current state.
|
|
863
|
+
*
|
|
864
|
+
* @param state - The current action context state to check.
|
|
865
|
+
* @returns `true` if no error exists and the action is modified and triggerable.
|
|
866
|
+
*/
|
|
653
867
|
function actionContextHasNoErrorAndIsModifiedAndCanTrigger(state) {
|
|
654
868
|
return !state.error && actionContextIsModifiedAndCanTrigger(state);
|
|
655
869
|
}
|
|
870
|
+
/**
|
|
871
|
+
* Converts an {@link ActionContextState} to a {@link LoadingState} for UI consumption.
|
|
872
|
+
*
|
|
873
|
+
* Maps the action lifecycle states to loading state equivalents:
|
|
874
|
+
* - RESOLVED -> success result with the output value
|
|
875
|
+
* - REJECTED -> error result with the error
|
|
876
|
+
* - IDLE/DISABLED -> idle loading state
|
|
877
|
+
* - All other states -> loading (with optional work progress)
|
|
878
|
+
*
|
|
879
|
+
* @typeParam O - The output result type.
|
|
880
|
+
* @param state - The action context state to convert.
|
|
881
|
+
* @returns A loading state representation of the action context state.
|
|
882
|
+
*/
|
|
656
883
|
function loadingStateForActionContextState(state) {
|
|
657
884
|
let loadingState;
|
|
658
885
|
switch (state.actionState) {
|
|
@@ -672,6 +899,14 @@ function loadingStateForActionContextState(state) {
|
|
|
672
899
|
}
|
|
673
900
|
return loadingState;
|
|
674
901
|
}
|
|
902
|
+
/**
|
|
903
|
+
* Extracts the {@link LoadingStateType} from the current action context state.
|
|
904
|
+
*
|
|
905
|
+
* A convenience wrapper around {@link loadingStateTypeForActionState} that accepts the full context state.
|
|
906
|
+
*
|
|
907
|
+
* @param state - The action context state to convert.
|
|
908
|
+
* @returns The corresponding loading state type.
|
|
909
|
+
*/
|
|
675
910
|
function loadingStateTypeForActionContextState(state) {
|
|
676
911
|
return loadingStateTypeForActionState(state.actionState);
|
|
677
912
|
}
|
|
@@ -679,7 +914,33 @@ const INITIAL_STATE = {
|
|
|
679
914
|
isModified: false,
|
|
680
915
|
actionState: DbxActionState.IDLE
|
|
681
916
|
};
|
|
917
|
+
/**
|
|
918
|
+
* Delay in milliseconds before the lock set destroys the store after all locks are released.
|
|
919
|
+
* Provides a grace period for actions to finalize before the store is torn down.
|
|
920
|
+
*/
|
|
682
921
|
const ACTION_CONTEXT_STORE_LOCKSET_DESTROY_DELAY_TIME = 2000;
|
|
922
|
+
/**
|
|
923
|
+
* NgRx ComponentStore that manages the reactive state machine for a single action lifecycle.
|
|
924
|
+
*
|
|
925
|
+
* This is the central state container for the action system. It tracks the full lifecycle
|
|
926
|
+
* of an action from idle through trigger, value preparation, work execution, and resolution
|
|
927
|
+
* or rejection. Multiple selectors expose derived reactive streams for each phase.
|
|
928
|
+
*
|
|
929
|
+
* The store uses a {@link LockSet} for cleanup coordination: it delays its own destruction
|
|
930
|
+
* until all in-flight work completes (e.g., a working action finishes), preventing
|
|
931
|
+
* premature teardown of subscriptions.
|
|
932
|
+
*
|
|
933
|
+
* State transitions follow this flow:
|
|
934
|
+
* ```
|
|
935
|
+
* IDLE/DISABLED -> TRIGGERED -> VALUE_READY -> WORKING -> RESOLVED | REJECTED
|
|
936
|
+
* ```
|
|
937
|
+
*
|
|
938
|
+
* @typeParam T - The input value type provided after triggering.
|
|
939
|
+
* @typeParam O - The output result type produced on resolution.
|
|
940
|
+
*
|
|
941
|
+
* @see {@link ActionContextStoreSource} for providing store access to directives.
|
|
942
|
+
* @see {@link DbxActionContextStoreSourceInstance} for the convenience wrapper.
|
|
943
|
+
*/
|
|
683
944
|
class ActionContextStore extends ComponentStore {
|
|
684
945
|
lockSet = cleanLockSet({
|
|
685
946
|
onLockSetDestroy: () => super.ngOnDestroy(),
|
|
@@ -909,7 +1170,20 @@ function updateIsModifiedOnActionContextState(state, isModified) {
|
|
|
909
1170
|
}
|
|
910
1171
|
|
|
911
1172
|
/**
|
|
912
|
-
*
|
|
1173
|
+
* Base class for action context sources that can either reuse an existing
|
|
1174
|
+
* {@link SecondaryActionContextStoreSource} or create their own internal {@link ActionContextStore}.
|
|
1175
|
+
*
|
|
1176
|
+
* If a secondary source is provided (typically via Angular DI), it is used directly,
|
|
1177
|
+
* enabling store sharing across component boundaries. Otherwise, a new standalone store is created.
|
|
1178
|
+
*
|
|
1179
|
+
* This class also creates a {@link DbxActionContextStoreSourceInstance} for convenient access
|
|
1180
|
+
* to the store's reactive streams and imperative methods.
|
|
1181
|
+
*
|
|
1182
|
+
* @typeParam T - The input value type for the action.
|
|
1183
|
+
* @typeParam O - The output result type for the action.
|
|
1184
|
+
*
|
|
1185
|
+
* @see {@link DbxActionDirective} which extends this class.
|
|
1186
|
+
* @see {@link DbxActionContextMachine} which extends this class for programmatic use.
|
|
913
1187
|
*/
|
|
914
1188
|
class DbxActionContextBaseSource {
|
|
915
1189
|
_inputSource;
|
|
@@ -1078,7 +1352,40 @@ function provideSecondaryActionStoreSource(sourceType) {
|
|
|
1078
1352
|
}
|
|
1079
1353
|
|
|
1080
1354
|
/**
|
|
1081
|
-
*
|
|
1355
|
+
* Core directive that creates and provides an action context for its host element and descendants.
|
|
1356
|
+
*
|
|
1357
|
+
* This is the root of the action system in templates. It creates an {@link ActionContextStore}
|
|
1358
|
+
* and provides it (along with the related source tokens) via Angular's dependency injection,
|
|
1359
|
+
* making the action lifecycle available to all child action directives.
|
|
1360
|
+
*
|
|
1361
|
+
* If a {@link SecondaryActionContextStoreSource} is available on the host, the directive will
|
|
1362
|
+
* reuse that store instead of creating its own, enabling action context forwarding.
|
|
1363
|
+
*
|
|
1364
|
+
* On destruction, the directive coordinates cleanup through a {@link LockSet} to ensure
|
|
1365
|
+
* in-flight operations complete before the store is torn down.
|
|
1366
|
+
*
|
|
1367
|
+
* @example
|
|
1368
|
+
* ```html
|
|
1369
|
+
* <div dbxAction>
|
|
1370
|
+
* <button (click)="action.trigger()">Submit</button>
|
|
1371
|
+
* <div *dbxActionHasSuccess>Success!</div>
|
|
1372
|
+
* <div *dbxActionWorking>Loading...</div>
|
|
1373
|
+
* </div>
|
|
1374
|
+
* ```
|
|
1375
|
+
*
|
|
1376
|
+
* @example
|
|
1377
|
+
* ```html
|
|
1378
|
+
* <!-- As an element -->
|
|
1379
|
+
* <dbx-action>
|
|
1380
|
+
* <ng-container [dbxActionHandler]="handleAction">...</ng-container>
|
|
1381
|
+
* </dbx-action>
|
|
1382
|
+
* ```
|
|
1383
|
+
*
|
|
1384
|
+
* @typeParam T - The input value type for the action.
|
|
1385
|
+
* @typeParam O - The output result type for the action.
|
|
1386
|
+
*
|
|
1387
|
+
* @see {@link DbxActionSourceDirective} for forwarding an external action source.
|
|
1388
|
+
* @see {@link ActionContextStore} for the underlying state store.
|
|
1082
1389
|
*/
|
|
1083
1390
|
class DbxActionDirective extends DbxActionContextBaseSource {
|
|
1084
1391
|
constructor() {
|
|
@@ -1104,7 +1411,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1104
1411
|
}], ctorParameters: () => [] });
|
|
1105
1412
|
|
|
1106
1413
|
/**
|
|
1107
|
-
* Directive that
|
|
1414
|
+
* Directive that forwards an externally-provided {@link ActionContextStoreSource} as a
|
|
1415
|
+
* {@link SecondaryActionContextStoreSource}, enabling child `dbxAction` directives to
|
|
1416
|
+
* reuse an existing action context rather than creating their own.
|
|
1417
|
+
*
|
|
1418
|
+
* This is useful when an action context is created programmatically (e.g., via
|
|
1419
|
+
* {@link DbxActionContextMachine}) and needs to be shared with template-based directives.
|
|
1420
|
+
*
|
|
1421
|
+
* @example
|
|
1422
|
+
* ```html
|
|
1423
|
+
* <!-- Forward a programmatic action source to template directives -->
|
|
1424
|
+
* <div [dbxActionSource]="myActionSource">
|
|
1425
|
+
* <div dbxAction>
|
|
1426
|
+
* <button (click)="action.trigger()">Submit</button>
|
|
1427
|
+
* </div>
|
|
1428
|
+
* </div>
|
|
1429
|
+
* ```
|
|
1430
|
+
*
|
|
1431
|
+
* @see {@link DbxActionDirective} for the directive that consumes this source.
|
|
1432
|
+
* @see {@link SecondaryActionContextStoreSource}
|
|
1108
1433
|
*/
|
|
1109
1434
|
class DbxActionSourceDirective {
|
|
1110
1435
|
dbxActionSource = input(...(ngDevMode ? [undefined, { debugName: "dbxActionSource" }] : []));
|
|
@@ -1122,7 +1447,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1122
1447
|
}], propDecorators: { dbxActionSource: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionSource", required: false }] }] } });
|
|
1123
1448
|
|
|
1124
1449
|
/**
|
|
1125
|
-
*
|
|
1450
|
+
* Debug directive that logs every action context state change to the console.
|
|
1451
|
+
*
|
|
1452
|
+
* Subscribes to the parent action's full state stream and prints each state snapshot
|
|
1453
|
+
* via `console.log`. Useful during development to inspect the action lifecycle transitions.
|
|
1454
|
+
*
|
|
1455
|
+
* @example
|
|
1456
|
+
* ```html
|
|
1457
|
+
* <div dbxAction>
|
|
1458
|
+
* <ng-container dbxActionLogger></ng-container>
|
|
1459
|
+
* <!-- other action directives -->
|
|
1460
|
+
* </div>
|
|
1461
|
+
* ```
|
|
1126
1462
|
*/
|
|
1127
1463
|
class DbxActionContextLoggerDirective {
|
|
1128
1464
|
source = inject(DbxActionContextStoreSourceInstance, { host: true });
|
|
@@ -1146,7 +1482,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1146
1482
|
}], ctorParameters: () => [] });
|
|
1147
1483
|
|
|
1148
1484
|
/**
|
|
1149
|
-
*
|
|
1485
|
+
* Abstract map that associates {@link ActionKey} values with {@link ActionContextStoreSource} instances.
|
|
1486
|
+
*
|
|
1487
|
+
* This allows multiple independent actions to be registered and retrieved by key,
|
|
1488
|
+
* enabling coordination between related actions (e.g., disabling one while another is working).
|
|
1489
|
+
*
|
|
1490
|
+
* @typeParam T - The input value type for the actions.
|
|
1491
|
+
* @typeParam O - The output result type for the actions.
|
|
1492
|
+
*
|
|
1493
|
+
* @see {@link actionContextStoreSourceMap} for the factory function.
|
|
1494
|
+
* @see {@link DbxActionContextMapDirective} for the directive that provides this in templates.
|
|
1150
1495
|
*/
|
|
1151
1496
|
class ActionContextStoreSourceMap {
|
|
1152
1497
|
}
|
|
@@ -1204,9 +1549,28 @@ function actionContextStoreSourceMap() {
|
|
|
1204
1549
|
}
|
|
1205
1550
|
|
|
1206
1551
|
/**
|
|
1207
|
-
*
|
|
1552
|
+
* Directive that creates and provides an {@link ActionContextStoreSourceMap} for its descendants.
|
|
1553
|
+
*
|
|
1554
|
+
* This enables a group of related action contexts to be registered by key and looked up
|
|
1555
|
+
* by child directives. Useful when multiple actions need to coordinate (e.g., disable
|
|
1556
|
+
* all other actions while one is working).
|
|
1208
1557
|
*
|
|
1209
|
-
*
|
|
1558
|
+
* The map is exported as `actionMap` for template reference access.
|
|
1559
|
+
*
|
|
1560
|
+
* @example
|
|
1561
|
+
* ```html
|
|
1562
|
+
* <div dbxActionContextMap>
|
|
1563
|
+
* <div dbxAction [dbxActionMapSource]="'save'">...</div>
|
|
1564
|
+
* <div dbxAction [dbxActionMapSource]="'delete'">...</div>
|
|
1565
|
+
* <div [dbxActionFromMap]="'save'">
|
|
1566
|
+
* <!-- consumes the 'save' action context -->
|
|
1567
|
+
* </div>
|
|
1568
|
+
* </div>
|
|
1569
|
+
* ```
|
|
1570
|
+
*
|
|
1571
|
+
* @see {@link DbxActionFromMapDirective} for consuming actions by key.
|
|
1572
|
+
* @see {@link DbxActionMapSourceDirective} for registering actions by key.
|
|
1573
|
+
* @see {@link DbxActionMapWorkingDisableDirective} for cross-action disable coordination.
|
|
1210
1574
|
*/
|
|
1211
1575
|
class DbxActionContextMapDirective {
|
|
1212
1576
|
actionContextStoreSourceMap = clean(inject(ActionContextStoreSourceMap));
|
|
@@ -1234,7 +1598,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1234
1598
|
}] });
|
|
1235
1599
|
|
|
1236
1600
|
/**
|
|
1237
|
-
* Directive that
|
|
1601
|
+
* Directive that retrieves an {@link ActionContextStoreSource} from an ancestor
|
|
1602
|
+
* {@link DbxActionContextMapDirective} using the provided key, and provides it as
|
|
1603
|
+
* a {@link SecondaryActionContextStoreSource} for descendant `dbxAction` directives.
|
|
1604
|
+
*
|
|
1605
|
+
* This allows a child action context to bind to an action that was registered elsewhere
|
|
1606
|
+
* in the template via {@link DbxActionMapSourceDirective}.
|
|
1607
|
+
*
|
|
1608
|
+
* @example
|
|
1609
|
+
* ```html
|
|
1610
|
+
* <div dbxActionContextMap>
|
|
1611
|
+
* <div dbxAction [dbxActionMapSource]="'myAction'">...</div>
|
|
1612
|
+
* <!-- Consume the registered action elsewhere in the tree -->
|
|
1613
|
+
* <div [dbxActionFromMap]="'myAction'">
|
|
1614
|
+
* <div dbxAction>
|
|
1615
|
+
* <div *dbxActionHasSuccess>Done!</div>
|
|
1616
|
+
* </div>
|
|
1617
|
+
* </div>
|
|
1618
|
+
* </div>
|
|
1619
|
+
* ```
|
|
1620
|
+
*
|
|
1621
|
+
* @see {@link DbxActionContextMapDirective} for the parent map provider.
|
|
1622
|
+
* @see {@link DbxActionMapSourceDirective} for registering an action into the map.
|
|
1238
1623
|
*/
|
|
1239
1624
|
class DbxActionFromMapDirective {
|
|
1240
1625
|
_actionContextStoreSourceMap = inject(ActionContextStoreSourceMap);
|
|
@@ -1254,7 +1639,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1254
1639
|
}], propDecorators: { key: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionFromMap", required: false }] }] } });
|
|
1255
1640
|
|
|
1256
1641
|
/**
|
|
1257
|
-
*
|
|
1642
|
+
* Directive that registers the host element's {@link ActionContextStoreSource} into an ancestor
|
|
1643
|
+
* {@link ActionContextStoreSourceMap} under the provided key.
|
|
1644
|
+
*
|
|
1645
|
+
* When the key changes, the previous registration is removed and the new one is added.
|
|
1646
|
+
* On destroy, the registration is cleaned up automatically.
|
|
1647
|
+
*
|
|
1648
|
+
* @example
|
|
1649
|
+
* ```html
|
|
1650
|
+
* <div dbxActionContextMap>
|
|
1651
|
+
* <div dbxAction [dbxActionMapSource]="'save'">
|
|
1652
|
+
* <button (click)="action.trigger()">Save</button>
|
|
1653
|
+
* </div>
|
|
1654
|
+
* </div>
|
|
1655
|
+
* ```
|
|
1656
|
+
*
|
|
1657
|
+
* @see {@link DbxActionContextMapDirective} for the parent map provider.
|
|
1658
|
+
* @see {@link DbxActionFromMapDirective} for consuming registered actions by key.
|
|
1258
1659
|
*/
|
|
1259
1660
|
class DbxActionMapSourceDirective {
|
|
1260
1661
|
_actionContextStoreSourceMap = inject(ActionContextStoreSourceMap);
|
|
@@ -1294,9 +1695,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1294
1695
|
}], propDecorators: { key: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionMapSource", required: false }] }] } });
|
|
1295
1696
|
|
|
1296
1697
|
/**
|
|
1297
|
-
* Creates a new ActionContextStoreSourceMapReader from the
|
|
1298
|
-
|
|
1299
|
-
*
|
|
1698
|
+
* Creates a new {@link ActionContextStoreSourceMapReader} from the given action key source map.
|
|
1699
|
+
*
|
|
1700
|
+
* The reader provides reactive utility functions to aggregate data across all stores
|
|
1701
|
+
* in the map (e.g., checking if any store is working, or reducing values from all stores).
|
|
1702
|
+
*
|
|
1703
|
+
* @typeParam T - The input value type for the actions.
|
|
1704
|
+
* @typeParam O - The output result type for the actions.
|
|
1705
|
+
* @param actionKeySourceMap$ - Observable (or static value) of the action key to source map.
|
|
1706
|
+
* @returns A reader with aggregate query functions over the map's stores.
|
|
1300
1707
|
*/
|
|
1301
1708
|
function actionContextStoreSourceMapReader(actionKeySourceMap$) {
|
|
1302
1709
|
const sourceMap$ = asObservable(actionKeySourceMap$);
|
|
@@ -1327,9 +1734,33 @@ function fromAllActionContextStoreSourceMapSources(actionKeySourceMap$, mapFn) {
|
|
|
1327
1734
|
return asObservable(actionKeySourceMap$).pipe(switchMap((x) => x.actionKeySourceMap$), switchMap(combineLatestFromMapValuesObsFn((x) => x.store$.pipe(switchMap(mapFn)))));
|
|
1328
1735
|
}
|
|
1329
1736
|
|
|
1737
|
+
/**
|
|
1738
|
+
* Default disabled key used by {@link DbxActionMapWorkingDisableDirective} to track
|
|
1739
|
+
* the "another action is working" disabled reason.
|
|
1740
|
+
*/
|
|
1330
1741
|
const DEFAULT_ACTION_MAP_WORKING_DISABLED_KEY = 'action_map_working_disable';
|
|
1331
1742
|
/**
|
|
1332
|
-
*
|
|
1743
|
+
* Directive that disables the host action when any other action in the ancestor
|
|
1744
|
+
* {@link ActionContextStoreSourceMap} is currently working.
|
|
1745
|
+
*
|
|
1746
|
+
* This prevents concurrent action execution within a group of related actions.
|
|
1747
|
+
* When all other actions finish working, the host action is automatically re-enabled.
|
|
1748
|
+
*
|
|
1749
|
+
* A custom disabled key can be provided via the `dbxActionMapWorkingDisable` input.
|
|
1750
|
+
*
|
|
1751
|
+
* @example
|
|
1752
|
+
* ```html
|
|
1753
|
+
* <div dbxActionContextMap>
|
|
1754
|
+
* <div dbxAction [dbxActionMapSource]="'save'" dbxActionMapWorkingDisable>
|
|
1755
|
+
* <button (click)="action.trigger()">Save</button>
|
|
1756
|
+
* </div>
|
|
1757
|
+
* <div dbxAction [dbxActionMapSource]="'delete'" dbxActionMapWorkingDisable>
|
|
1758
|
+
* <button (click)="action.trigger()">Delete</button>
|
|
1759
|
+
* </div>
|
|
1760
|
+
* </div>
|
|
1761
|
+
* ```
|
|
1762
|
+
*
|
|
1763
|
+
* @see {@link DbxActionContextMapDirective} for the parent map provider.
|
|
1333
1764
|
*/
|
|
1334
1765
|
class DbxActionMapWorkingDisableDirective {
|
|
1335
1766
|
_actionContextStoreSourceMap = inject(ActionContextStoreSourceMap);
|
|
@@ -1355,9 +1786,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1355
1786
|
}]
|
|
1356
1787
|
}], ctorParameters: () => [], propDecorators: { disabledKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionMapWorkingDisable", required: false }] }] } });
|
|
1357
1788
|
|
|
1789
|
+
/**
|
|
1790
|
+
* Disabled key used by {@link DbxActionDisabledDirective} to track its disabled state.
|
|
1791
|
+
*/
|
|
1358
1792
|
const APP_ACTION_DISABLED_DIRECTIVE_KEY = 'dbx_action_disabled';
|
|
1359
1793
|
/**
|
|
1360
|
-
* Directive that
|
|
1794
|
+
* Directive that disables or enables the parent action based on a boolean input.
|
|
1795
|
+
*
|
|
1796
|
+
* When `dbxActionDisabled` is `true` (or an empty string, which coerces to `true`),
|
|
1797
|
+
* the action is disabled with the {@link APP_ACTION_DISABLED_DIRECTIVE_KEY}. When `false`,
|
|
1798
|
+
* the disable key is removed, re-enabling the action (assuming no other sources have disabled it).
|
|
1799
|
+
*
|
|
1800
|
+
* The disable key is automatically cleaned up on directive destruction.
|
|
1801
|
+
*
|
|
1802
|
+
* @example
|
|
1803
|
+
* ```html
|
|
1804
|
+
* <div dbxAction>
|
|
1805
|
+
* <ng-container [dbxActionDisabled]="isFormInvalid"></ng-container>
|
|
1806
|
+
* <button (click)="action.trigger()">Submit</button>
|
|
1807
|
+
* </div>
|
|
1808
|
+
* ```
|
|
1809
|
+
*
|
|
1810
|
+
* @typeParam T - The input value type.
|
|
1811
|
+
* @typeParam O - The output result type.
|
|
1812
|
+
*
|
|
1813
|
+
* @see {@link DbxActionEnforceModifiedDirective} for disabling when not modified.
|
|
1814
|
+
* @see {@link DbxActionDisabledOnSuccessDirective} for disabling after success.
|
|
1361
1815
|
*/
|
|
1362
1816
|
class DbxActionDisabledDirective {
|
|
1363
1817
|
source = inject((DbxActionContextStoreSourceInstance), { host: true });
|
|
@@ -1380,9 +1834,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1380
1834
|
}]
|
|
1381
1835
|
}], ctorParameters: () => [], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionDisabled", required: false }] }] } });
|
|
1382
1836
|
|
|
1837
|
+
/**
|
|
1838
|
+
* Disabled key used by {@link DbxActionDisabledOnSuccessDirective} to track the
|
|
1839
|
+
* "disabled after success" reason.
|
|
1840
|
+
*/
|
|
1383
1841
|
const APP_ACTION_DISABLED_ON_SUCCESS_DIRECTIVE_KEY = 'dbx_action_disabled_on_success';
|
|
1384
1842
|
/**
|
|
1385
|
-
* Directive that
|
|
1843
|
+
* Directive that disables the parent action after it resolves successfully.
|
|
1844
|
+
*
|
|
1845
|
+
* This is useful for one-shot actions where the user should not be able to re-trigger
|
|
1846
|
+
* the action after it succeeds (e.g., a confirmation dialog or a single-use form submission).
|
|
1847
|
+
*
|
|
1848
|
+
* Can be disabled by setting `dbxActionDisabledOnSuccess` to `false`.
|
|
1849
|
+
*
|
|
1850
|
+
* The disable key is automatically cleaned up on directive destruction.
|
|
1851
|
+
*
|
|
1852
|
+
* @example
|
|
1853
|
+
* ```html
|
|
1854
|
+
* <div dbxAction>
|
|
1855
|
+
* <ng-container dbxActionDisabledOnSuccess></ng-container>
|
|
1856
|
+
* <button (click)="action.trigger()">Confirm</button>
|
|
1857
|
+
* </div>
|
|
1858
|
+
* ```
|
|
1859
|
+
*
|
|
1860
|
+
* @typeParam T - The input value type.
|
|
1861
|
+
* @typeParam O - The output result type.
|
|
1862
|
+
*
|
|
1863
|
+
* @see {@link DbxActionDisabledDirective} for general-purpose disabling.
|
|
1864
|
+
* @see {@link DbxActionEnforceModifiedDirective} for disabling when not modified.
|
|
1386
1865
|
*/
|
|
1387
1866
|
class DbxActionDisabledOnSuccessDirective {
|
|
1388
1867
|
source = inject((DbxActionContextStoreSourceInstance), { host: true });
|
|
@@ -1405,9 +1884,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1405
1884
|
}]
|
|
1406
1885
|
}], ctorParameters: () => [], propDecorators: { disabledOnSuccess: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionDisabledOnSuccess", required: false }] }] } });
|
|
1407
1886
|
|
|
1887
|
+
/**
|
|
1888
|
+
* Lock key used by {@link DbxActionHandlerInstance} to prevent the source from being destroyed
|
|
1889
|
+
* while a handler's work is still in progress.
|
|
1890
|
+
*/
|
|
1408
1891
|
const DBX_ACTION_HANDLER_LOCK_KEY = 'dbxActionHandler';
|
|
1409
1892
|
/**
|
|
1410
|
-
*
|
|
1893
|
+
* Manages the execution of a {@link Work} function in response to `valueReady$` events
|
|
1894
|
+
* from an action context.
|
|
1895
|
+
*
|
|
1896
|
+
* When initialized, it subscribes to the source's `valueReady$` stream and executes
|
|
1897
|
+
* the configured handler function (or handler value) using {@link workFactory}. The handler
|
|
1898
|
+
* function drives the action through the working/success/reject lifecycle via a
|
|
1899
|
+
* {@link DbxActionWorkInstanceDelegate}.
|
|
1900
|
+
*
|
|
1901
|
+
* Supports two modes:
|
|
1902
|
+
* - **Handler function**: A full {@link Work} function that receives the value and a work context.
|
|
1903
|
+
* - **Handler value**: A simple getter or factory that returns the result directly.
|
|
1904
|
+
*
|
|
1905
|
+
* A lock is added to the source's lock set during work execution to prevent premature cleanup.
|
|
1906
|
+
*
|
|
1907
|
+
* @typeParam T - The input value type for the action.
|
|
1908
|
+
* @typeParam O - The output result type for the action.
|
|
1909
|
+
*
|
|
1910
|
+
* @see {@link DbxActionHandlerDirective} for the template directive that wraps this instance.
|
|
1911
|
+
* @see {@link DbxActionWorkInstanceDelegate} for the delegate that bridges work events to the store.
|
|
1411
1912
|
*/
|
|
1412
1913
|
class DbxActionHandlerInstance {
|
|
1413
1914
|
_delegate;
|
|
@@ -1463,7 +1964,16 @@ class DbxActionHandlerInstance {
|
|
|
1463
1964
|
}
|
|
1464
1965
|
|
|
1465
1966
|
/**
|
|
1466
|
-
* Abstract directive that
|
|
1967
|
+
* Abstract base directive that creates and manages a {@link DbxActionHandlerInstance} lifecycle.
|
|
1968
|
+
*
|
|
1969
|
+
* Subclasses configure how the handler function or value is provided to the instance.
|
|
1970
|
+
* The instance is initialized on construction and cleaned up automatically via the action's lock set.
|
|
1971
|
+
*
|
|
1972
|
+
* @typeParam T - The input value type for the action.
|
|
1973
|
+
* @typeParam O - The output result type for the action.
|
|
1974
|
+
*
|
|
1975
|
+
* @see {@link DbxActionHandlerDirective} for the work-function variant.
|
|
1976
|
+
* @see {@link DbxActionHandlerValueDirective} for the value/getter variant.
|
|
1467
1977
|
*/
|
|
1468
1978
|
class AbstractDbxActionHandlerDirective {
|
|
1469
1979
|
source = inject((DbxActionContextStoreSourceInstance), { host: true });
|
|
@@ -1478,7 +1988,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1478
1988
|
type: Directive
|
|
1479
1989
|
}], ctorParameters: () => [] });
|
|
1480
1990
|
/**
|
|
1481
|
-
* Directive that
|
|
1991
|
+
* Directive that provides a {@link Work} function to handle the action's `valueReady$` event.
|
|
1992
|
+
*
|
|
1993
|
+
* When the action is triggered and a value becomes ready, the provided work function is
|
|
1994
|
+
* called with the value and a work context. The work function is responsible for performing
|
|
1995
|
+
* the async operation and signaling success or failure through the context.
|
|
1996
|
+
*
|
|
1997
|
+
* @example
|
|
1998
|
+
* ```html
|
|
1999
|
+
* <div dbxAction>
|
|
2000
|
+
* <ng-container [dbxActionHandler]="handleSave"></ng-container>
|
|
2001
|
+
* <button (click)="action.trigger()">Save</button>
|
|
2002
|
+
* </div>
|
|
2003
|
+
* ```
|
|
2004
|
+
*
|
|
2005
|
+
* @typeParam T - The input value type for the action.
|
|
2006
|
+
* @typeParam O - The output result type for the action.
|
|
2007
|
+
*
|
|
2008
|
+
* @see {@link DbxActionHandlerValueDirective} for the simpler value/getter variant.
|
|
1482
2009
|
*/
|
|
1483
2010
|
class DbxActionHandlerDirective extends AbstractDbxActionHandlerDirective {
|
|
1484
2011
|
handlerFunction = input.required({ ...(ngDevMode ? { debugName: "handlerFunction" } : {}), alias: 'dbxActionHandler' });
|
|
@@ -1496,7 +2023,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1496
2023
|
}]
|
|
1497
2024
|
}], propDecorators: { handlerFunction: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionHandler", required: true }] }] } });
|
|
1498
2025
|
/**
|
|
1499
|
-
* Directive that
|
|
2026
|
+
* Directive that provides a static value, getter, or factory to resolve the action's `valueReady$` event.
|
|
2027
|
+
*
|
|
2028
|
+
* Unlike {@link DbxActionHandlerDirective}, this does not require a full {@link Work} function.
|
|
2029
|
+
* The provided value (or the result of calling the getter/factory) is used directly as the
|
|
2030
|
+
* action's result, with the working/success lifecycle handled automatically.
|
|
2031
|
+
*
|
|
2032
|
+
* @example
|
|
2033
|
+
* ```html
|
|
2034
|
+
* <div dbxAction>
|
|
2035
|
+
* <ng-container [dbxActionHandlerValue]="computeResult"></ng-container>
|
|
2036
|
+
* <button (click)="action.trigger()">Compute</button>
|
|
2037
|
+
* </div>
|
|
2038
|
+
* ```
|
|
2039
|
+
*
|
|
2040
|
+
* @typeParam T - The input value type for the action.
|
|
2041
|
+
* @typeParam O - The output result type for the action.
|
|
2042
|
+
*
|
|
2043
|
+
* @see {@link DbxActionHandlerDirective} for the full work-function variant.
|
|
1500
2044
|
*/
|
|
1501
2045
|
class DbxActionHandlerValueDirective extends AbstractDbxActionHandlerDirective {
|
|
1502
2046
|
handlerValue = input.required({ ...(ngDevMode ? { debugName: "handlerValue" } : {}), alias: 'dbxActionHandlerValue' });
|
|
@@ -1515,7 +2059,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1515
2059
|
}], propDecorators: { handlerValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionHandlerValue", required: true }] }] } });
|
|
1516
2060
|
|
|
1517
2061
|
/**
|
|
1518
|
-
* Abstract directive
|
|
2062
|
+
* Abstract structural directive that conditionally renders its template based on a reactive boolean observable,
|
|
2063
|
+
* similar to `*ngIf` but driven by an `Observable<boolean>`.
|
|
2064
|
+
*
|
|
2065
|
+
* Subclasses provide the `show$` observable to control visibility. The template is created
|
|
2066
|
+
* when `show$` emits `true` and cleared when it emits `false`.
|
|
2067
|
+
*
|
|
2068
|
+
* @example
|
|
2069
|
+
* ```typescript
|
|
2070
|
+
* @Directive({ selector: '[appShowIfAdmin]' })
|
|
2071
|
+
* export class ShowIfAdminDirective extends AbstractIfDirective {
|
|
2072
|
+
* readonly show$ = inject(AuthService).isAdmin$;
|
|
2073
|
+
* }
|
|
2074
|
+
* ```
|
|
2075
|
+
*
|
|
2076
|
+
* @example
|
|
2077
|
+
* ```html
|
|
2078
|
+
* <div *appShowIfAdmin>Only visible to admins</div>
|
|
2079
|
+
* ```
|
|
1519
2080
|
*/
|
|
1520
2081
|
class AbstractIfDirective {
|
|
1521
2082
|
_templateRef = inject(TemplateRef);
|
|
@@ -1539,16 +2100,46 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1539
2100
|
}] });
|
|
1540
2101
|
|
|
1541
2102
|
/**
|
|
1542
|
-
*
|
|
2103
|
+
* Angular input transform that converts an empty string to `undefined`.
|
|
1543
2104
|
*
|
|
1544
|
-
*
|
|
2105
|
+
* Useful for Angular directive inputs where the attribute can be applied without a value
|
|
2106
|
+
* (e.g., `<div myDirective>` passes `''`), and you want to treat that as "not provided".
|
|
2107
|
+
*
|
|
2108
|
+
* @example
|
|
2109
|
+
* ```typescript
|
|
2110
|
+
* @Directive({ selector: '[appHighlight]' })
|
|
2111
|
+
* export class HighlightDirective {
|
|
2112
|
+
* @Input({ alias: 'appHighlight', transform: transformEmptyStringInputToUndefined })
|
|
2113
|
+
* color?: string;
|
|
2114
|
+
* }
|
|
2115
|
+
* ```
|
|
1545
2116
|
*/
|
|
1546
2117
|
const transformEmptyStringInputToUndefined = (value) => (value === '' ? undefined : value);
|
|
1547
2118
|
|
|
1548
2119
|
/**
|
|
1549
|
-
* Structural directive that
|
|
2120
|
+
* Structural directive that conditionally renders its content when the action is idle.
|
|
1550
2121
|
*
|
|
1551
|
-
*
|
|
2122
|
+
* Optionally accepts a number (in milliseconds) to auto-hide the content after the specified
|
|
2123
|
+
* duration, even if the action is still idle. Useful for showing initial instructions that
|
|
2124
|
+
* should disappear after a timeout.
|
|
2125
|
+
*
|
|
2126
|
+
* @example
|
|
2127
|
+
* ```html
|
|
2128
|
+
* <div dbxAction>
|
|
2129
|
+
* <div *dbxActionIdle>Ready to submit.</div>
|
|
2130
|
+
* </div>
|
|
2131
|
+
* ```
|
|
2132
|
+
*
|
|
2133
|
+
* @example
|
|
2134
|
+
* ```html
|
|
2135
|
+
* <!-- Hide idle content after 5 seconds -->
|
|
2136
|
+
* <div dbxAction>
|
|
2137
|
+
* <div *dbxActionIdle="5000">Ready to submit.</div>
|
|
2138
|
+
* </div>
|
|
2139
|
+
* ```
|
|
2140
|
+
*
|
|
2141
|
+
* @see {@link DbxActionIsWorkingDirective} for showing content when working.
|
|
2142
|
+
* @see {@link DbxActionHasSuccessDirective} for showing content on success.
|
|
1552
2143
|
*/
|
|
1553
2144
|
class DbxActionIdleDirective extends AbstractIfDirective {
|
|
1554
2145
|
_store = inject(DbxActionContextStoreSourceInstance);
|
|
@@ -1573,9 +2164,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1573
2164
|
}], propDecorators: { hideAfter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionIdle", required: false }] }] } });
|
|
1574
2165
|
|
|
1575
2166
|
/**
|
|
1576
|
-
* Structural directive that
|
|
2167
|
+
* Structural directive that renders its content while the action has not yet succeeded.
|
|
2168
|
+
*
|
|
2169
|
+
* The content is visible during all states before success (IDLE, TRIGGERED, WORKING, etc.)
|
|
2170
|
+
* and is hidden once the action resolves successfully. Optionally accepts a number (in milliseconds)
|
|
2171
|
+
* specifying how long to keep the content hidden after success before showing it again.
|
|
1577
2172
|
*
|
|
1578
|
-
*
|
|
2173
|
+
* This is the inverse of {@link DbxActionHasSuccessDirective}.
|
|
2174
|
+
*
|
|
2175
|
+
* @example
|
|
2176
|
+
* ```html
|
|
2177
|
+
* <div dbxAction>
|
|
2178
|
+
* <div *dbxActionPreSuccess>Not yet saved.</div>
|
|
2179
|
+
* </div>
|
|
2180
|
+
* ```
|
|
2181
|
+
*
|
|
2182
|
+
* @example
|
|
2183
|
+
* ```html
|
|
2184
|
+
* <!-- Re-show content 2 seconds after success -->
|
|
2185
|
+
* <div dbxAction>
|
|
2186
|
+
* <div *dbxActionPreSuccess="2000">Not yet saved.</div>
|
|
2187
|
+
* </div>
|
|
2188
|
+
* ```
|
|
2189
|
+
*
|
|
2190
|
+
* @see {@link DbxActionHasSuccessDirective} for showing content on success.
|
|
1579
2191
|
*/
|
|
1580
2192
|
class DbxActionPreSuccessDirective extends AbstractIfDirective {
|
|
1581
2193
|
_store = inject(DbxActionContextStoreSourceInstance);
|
|
@@ -1600,9 +2212,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1600
2212
|
}], propDecorators: { hideFor: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionPreSuccess", required: false }] }] } });
|
|
1601
2213
|
|
|
1602
2214
|
/**
|
|
1603
|
-
* Structural directive that
|
|
2215
|
+
* Structural directive that conditionally renders its content when the action has resolved successfully.
|
|
2216
|
+
*
|
|
2217
|
+
* Optionally accepts a number (in milliseconds) to auto-hide the content after the specified
|
|
2218
|
+
* duration, useful for showing temporary success messages that fade away.
|
|
1604
2219
|
*
|
|
1605
|
-
*
|
|
2220
|
+
* @example
|
|
2221
|
+
* ```html
|
|
2222
|
+
* <div dbxAction>
|
|
2223
|
+
* <div *dbxActionHasSuccess>Saved successfully!</div>
|
|
2224
|
+
* </div>
|
|
2225
|
+
* ```
|
|
2226
|
+
*
|
|
2227
|
+
* @example
|
|
2228
|
+
* ```html
|
|
2229
|
+
* <!-- Show success message for 3 seconds -->
|
|
2230
|
+
* <div dbxAction>
|
|
2231
|
+
* <div *dbxActionHasSuccess="3000">Saved!</div>
|
|
2232
|
+
* </div>
|
|
2233
|
+
* ```
|
|
2234
|
+
*
|
|
2235
|
+
* @see {@link DbxActionPreSuccessDirective} for showing content before success.
|
|
2236
|
+
* @see {@link DbxActionSuccessHandlerDirective} for executing a function on success.
|
|
1606
2237
|
*/
|
|
1607
2238
|
class DbxActionHasSuccessDirective extends AbstractIfDirective {
|
|
1608
2239
|
_store = inject(DbxActionContextStoreSourceInstance);
|
|
@@ -1627,7 +2258,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1627
2258
|
}], propDecorators: { hideAfter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionHasSuccess", required: false }] }] } });
|
|
1628
2259
|
|
|
1629
2260
|
/**
|
|
1630
|
-
* Directive that executes a function
|
|
2261
|
+
* Directive that executes a callback function each time the action resolves successfully.
|
|
2262
|
+
*
|
|
2263
|
+
* The provided function receives the action's result value. This is useful for
|
|
2264
|
+
* performing side effects like navigation, showing notifications, or refreshing data
|
|
2265
|
+
* after a successful action.
|
|
2266
|
+
*
|
|
2267
|
+
* @example
|
|
2268
|
+
* ```html
|
|
2269
|
+
* <div dbxAction>
|
|
2270
|
+
* <ng-container [dbxActionSuccessHandler]="onSaveSuccess"></ng-container>
|
|
2271
|
+
* <button (click)="action.trigger()">Save</button>
|
|
2272
|
+
* </div>
|
|
2273
|
+
* ```
|
|
2274
|
+
*
|
|
2275
|
+
* @typeParam T - The input value type.
|
|
2276
|
+
* @typeParam O - The output result type.
|
|
2277
|
+
*
|
|
2278
|
+
* @see {@link DbxActionHasSuccessDirective} for rendering content on success.
|
|
2279
|
+
* @see {@link DbxActionErrorHandlerDirective} for handling errors.
|
|
1631
2280
|
*/
|
|
1632
2281
|
class DbxActionSuccessHandlerDirective {
|
|
1633
2282
|
source = inject((DbxActionContextStoreSourceInstance), { host: true });
|
|
@@ -1655,7 +2304,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1655
2304
|
}], ctorParameters: () => [], propDecorators: { dbxActionSuccessHandler: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionSuccessHandler", required: false }] }] } });
|
|
1656
2305
|
|
|
1657
2306
|
/**
|
|
1658
|
-
* Directive that executes a function
|
|
2307
|
+
* Directive that executes a callback function each time the action's error state changes.
|
|
2308
|
+
*
|
|
2309
|
+
* The provided function receives the {@link ReadableError} from the action context.
|
|
2310
|
+
* This is useful for performing side effects like logging, showing error toasts, or
|
|
2311
|
+
* handling specific error conditions programmatically.
|
|
2312
|
+
*
|
|
2313
|
+
* @example
|
|
2314
|
+
* ```html
|
|
2315
|
+
* <div dbxAction>
|
|
2316
|
+
* <ng-container [dbxActionErrorHandler]="onError"></ng-container>
|
|
2317
|
+
* <button (click)="action.trigger()">Submit</button>
|
|
2318
|
+
* </div>
|
|
2319
|
+
* ```
|
|
2320
|
+
*
|
|
2321
|
+
* @typeParam T - The input value type.
|
|
2322
|
+
* @typeParam O - The output result type.
|
|
2323
|
+
*
|
|
2324
|
+
* @see {@link DbxActionSuccessHandlerDirective} for handling success.
|
|
1659
2325
|
*/
|
|
1660
2326
|
class DbxActionErrorHandlerDirective {
|
|
1661
2327
|
source = inject((DbxActionContextStoreSourceInstance), { host: true });
|
|
@@ -1683,13 +2349,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1683
2349
|
}], ctorParameters: () => [], propDecorators: { dbxActionErrorHandler: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionErrorHandler", required: false }] }] } });
|
|
1684
2350
|
|
|
1685
2351
|
/**
|
|
1686
|
-
* Directive that provides a
|
|
2352
|
+
* Directive that provides a value (or value-producing function) to the action when triggered.
|
|
2353
|
+
*
|
|
2354
|
+
* The value is always available and ready to be used. When the action is triggered,
|
|
2355
|
+
* the current value is resolved (via `getValueFromGetter` if a function) and passed
|
|
2356
|
+
* to `readyValue()` on the action source.
|
|
2357
|
+
*
|
|
2358
|
+
* The input filters out null/undefined values, waiting until a non-null value is provided.
|
|
2359
|
+
* If you need to pass null/undefined as valid action values, use {@link DbxActionValueTriggerDirective} instead.
|
|
1687
2360
|
*
|
|
1688
|
-
*
|
|
2361
|
+
* @example
|
|
2362
|
+
* ```html
|
|
2363
|
+
* <div dbxAction>
|
|
2364
|
+
* <ng-container [dbxActionValue]="myValue"></ng-container>
|
|
2365
|
+
* <button (click)="action.trigger()">Submit</button>
|
|
2366
|
+
* </div>
|
|
2367
|
+
* ```
|
|
2368
|
+
*
|
|
2369
|
+
* @example
|
|
2370
|
+
* ```html
|
|
2371
|
+
* <!-- With a getter function -->
|
|
2372
|
+
* <div dbxAction>
|
|
2373
|
+
* <ng-container [dbxActionValue]="getLatestValue"></ng-container>
|
|
2374
|
+
* <button (click)="action.trigger()">Submit</button>
|
|
2375
|
+
* </div>
|
|
2376
|
+
* ```
|
|
1689
2377
|
*
|
|
1690
|
-
*
|
|
2378
|
+
* @typeParam T - The input value type.
|
|
2379
|
+
* @typeParam O - The output result type.
|
|
1691
2380
|
*
|
|
1692
|
-
*
|
|
2381
|
+
* @see {@link DbxActionValueTriggerDirective} for lazy value retrieval on trigger.
|
|
2382
|
+
* @see {@link DbxActionValueStreamDirective} for reactive stream-based values.
|
|
1693
2383
|
*/
|
|
1694
2384
|
class DbxActionValueDirective {
|
|
1695
2385
|
valueOrFunction = input('', { ...(ngDevMode ? { debugName: "valueOrFunction" } : {}), alias: 'dbxActionValue' });
|
|
@@ -1720,9 +2410,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1720
2410
|
}], ctorParameters: () => [], propDecorators: { valueOrFunction: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionValue", required: false }] }] } });
|
|
1721
2411
|
|
|
1722
2412
|
/**
|
|
1723
|
-
* Structural directive that
|
|
2413
|
+
* Structural directive that conditionally renders its content while the action is in a working state.
|
|
2414
|
+
*
|
|
2415
|
+
* Optionally accepts a number (in milliseconds) to auto-hide the content after a specified duration,
|
|
2416
|
+
* even if the action is still working. This is useful for showing brief "loading" indicators
|
|
2417
|
+
* that should disappear after a timeout.
|
|
2418
|
+
*
|
|
2419
|
+
* @example
|
|
2420
|
+
* ```html
|
|
2421
|
+
* <div dbxAction>
|
|
2422
|
+
* <div *dbxActionWorking>Loading...</div>
|
|
2423
|
+
* </div>
|
|
2424
|
+
* ```
|
|
2425
|
+
*
|
|
2426
|
+
* @example
|
|
2427
|
+
* ```html
|
|
2428
|
+
* <!-- Hide after 3 seconds even if still working -->
|
|
2429
|
+
* <div dbxAction>
|
|
2430
|
+
* <div *dbxActionIsWorking="3000">Loading...</div>
|
|
2431
|
+
* </div>
|
|
2432
|
+
* ```
|
|
1724
2433
|
*
|
|
1725
|
-
*
|
|
2434
|
+
* @see {@link DbxActionIdleDirective} for showing content when idle.
|
|
1726
2435
|
*/
|
|
1727
2436
|
class DbxActionIsWorkingDirective extends AbstractIfDirective {
|
|
1728
2437
|
_store = inject(DbxActionContextStoreSourceInstance);
|
|
@@ -1753,17 +2462,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1753
2462
|
}]
|
|
1754
2463
|
}], propDecorators: { hideAfter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionWorking", required: false }] }], hideAfterIsWorking: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionIsWorking", required: false }] }] } });
|
|
1755
2464
|
|
|
1756
|
-
const APP_ACTION_ENFORCE_MODIFIED_DIRECTIVE_KEY = 'dbx_action_enforce_modified';
|
|
1757
2465
|
/**
|
|
1758
|
-
*
|
|
2466
|
+
* Disabled key used by {@link DbxActionEnforceModifiedDirective} to track the
|
|
2467
|
+
* "not modified" disabled reason.
|
|
1759
2468
|
*/
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
2469
|
+
const APP_ACTION_ENFORCE_MODIFIED_DIRECTIVE_KEY = 'dbx_action_enforce_modified';
|
|
2470
|
+
/**
|
|
2471
|
+
* Directive that disables the parent action when the action is not marked as modified.
|
|
2472
|
+
*
|
|
2473
|
+
* When enabled (default), this enforces that the user must make changes before the action
|
|
2474
|
+
* can be triggered. Once the action is marked as modified, the disabled key is removed.
|
|
2475
|
+
* This prevents no-op submissions where nothing has actually changed.
|
|
2476
|
+
*
|
|
2477
|
+
* Can be disabled by setting `dbxActionEnforceModified` to `false`.
|
|
2478
|
+
*
|
|
2479
|
+
* The disable key is automatically cleaned up on directive destruction.
|
|
2480
|
+
*
|
|
2481
|
+
* @example
|
|
2482
|
+
* ```html
|
|
2483
|
+
* <div dbxAction>
|
|
2484
|
+
* <ng-container dbxActionEnforceModified></ng-container>
|
|
2485
|
+
* <button (click)="action.trigger()">Save</button>
|
|
2486
|
+
* </div>
|
|
2487
|
+
* ```
|
|
2488
|
+
*
|
|
2489
|
+
* @see {@link DbxActionDisabledDirective} for general-purpose disabling.
|
|
2490
|
+
* @see {@link DbxActionAutoModifyDirective} for always keeping the action modified.
|
|
2491
|
+
*/
|
|
2492
|
+
class DbxActionEnforceModifiedDirective {
|
|
2493
|
+
source = inject(DbxActionContextStoreSourceInstance, { host: true });
|
|
2494
|
+
enabled = input(true, { ...(ngDevMode ? { debugName: "enabled" } : {}), alias: 'dbxActionEnforceModified', transform: (value) => value !== false });
|
|
2495
|
+
enabled$ = toObservable(this.enabled);
|
|
2496
|
+
constructor() {
|
|
2497
|
+
cleanSubscription(combineLatest([this.source.isModified$, this.enabled$])
|
|
2498
|
+
.pipe(delay(0))
|
|
1767
2499
|
.subscribe(([modified, enableDirective]) => {
|
|
1768
2500
|
const disable = enableDirective && !modified;
|
|
1769
2501
|
this.source.disable(APP_ACTION_ENFORCE_MODIFIED_DIRECTIVE_KEY, disable);
|
|
@@ -1782,7 +2514,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1782
2514
|
}], ctorParameters: () => [], propDecorators: { enabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionEnforceModified", required: false }] }] } });
|
|
1783
2515
|
|
|
1784
2516
|
/**
|
|
1785
|
-
* Utility class that handles trigger
|
|
2517
|
+
* Utility class that handles the trigger-to-value-ready phase of the action lifecycle.
|
|
2518
|
+
*
|
|
2519
|
+
* When initialized, it subscribes to the source's `triggered$` stream. On each trigger,
|
|
2520
|
+
* it calls the configured {@link DbxActionValueGetterValueGetterFunction} to retrieve the value,
|
|
2521
|
+
* runs an optional {@link IsModifiedFunction} check, and either calls `readyValue()` with
|
|
2522
|
+
* the retrieved value or `reject()` if the value is null/undefined or an error occurred.
|
|
2523
|
+
*
|
|
2524
|
+
* This separates value retrieval from the trigger event, allowing lazy or async value computation.
|
|
2525
|
+
*
|
|
2526
|
+
* @typeParam T - The value type for the action.
|
|
2527
|
+
*
|
|
2528
|
+
* @see {@link DbxActionValueTriggerDirective} for the directive wrapper.
|
|
2529
|
+
* @see {@link DbxActionValueDirective} for the simpler always-piped-value approach.
|
|
1786
2530
|
*/
|
|
1787
2531
|
class DbxActionValueGetterInstance {
|
|
1788
2532
|
_valueGetterFunction = new BehaviorSubject(undefined);
|
|
@@ -1838,7 +2582,14 @@ class DbxActionValueGetterInstance {
|
|
|
1838
2582
|
}
|
|
1839
2583
|
|
|
1840
2584
|
/**
|
|
1841
|
-
* Abstract class for directives that
|
|
2585
|
+
* Abstract base class for directives that retrieve a value when the action is triggered.
|
|
2586
|
+
*
|
|
2587
|
+
* Creates and manages a {@link DbxActionValueGetterInstance} internally, providing
|
|
2588
|
+
* methods for subclasses to configure the value getter, isModified, and isEqual functions.
|
|
2589
|
+
*
|
|
2590
|
+
* @typeParam T - The value type for the action.
|
|
2591
|
+
*
|
|
2592
|
+
* @see {@link DbxActionValueTriggerDirective} for the concrete implementation.
|
|
1842
2593
|
*/
|
|
1843
2594
|
class AbstractDbxActionValueGetterDirective {
|
|
1844
2595
|
_injector = inject(Injector);
|
|
@@ -1878,10 +2629,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1878
2629
|
type: Directive
|
|
1879
2630
|
}], ctorParameters: () => [] });
|
|
1880
2631
|
/**
|
|
1881
|
-
*
|
|
2632
|
+
* Directive that uses a getter function to retrieve the action value only when triggered.
|
|
1882
2633
|
*
|
|
1883
|
-
*
|
|
1884
|
-
*
|
|
2634
|
+
* Unlike {@link DbxActionValueDirective} which continuously pipes the latest value,
|
|
2635
|
+
* this directive calls the getter function lazily -- only when the action is triggered.
|
|
2636
|
+
* This is useful when the value computation is expensive or depends on state that should
|
|
2637
|
+
* only be captured at trigger time.
|
|
2638
|
+
*
|
|
2639
|
+
* Supports optional `isModified` and `isEqual` functions to control whether the retrieved
|
|
2640
|
+
* value should proceed to `readyValue` or be rejected.
|
|
2641
|
+
*
|
|
2642
|
+
* @example
|
|
2643
|
+
* ```html
|
|
2644
|
+
* <div dbxAction>
|
|
2645
|
+
* <ng-container [dbxActionValueGetter]="getFormValue"></ng-container>
|
|
2646
|
+
* <button (click)="action.trigger()">Submit</button>
|
|
2647
|
+
* </div>
|
|
2648
|
+
* ```
|
|
2649
|
+
*
|
|
2650
|
+
* @typeParam T - The value type for the action.
|
|
2651
|
+
*
|
|
2652
|
+
* @see {@link DbxActionValueDirective} for the always-available value approach.
|
|
1885
2653
|
*/
|
|
1886
2654
|
class DbxActionValueTriggerDirective extends AbstractDbxActionValueGetterDirective {
|
|
1887
2655
|
dbxActionValueGetter = input(...(ngDevMode ? [undefined, { debugName: "dbxActionValueGetter" }] : []));
|
|
@@ -1908,7 +2676,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1908
2676
|
}], ctorParameters: () => [], propDecorators: { dbxActionValueGetter: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionValueGetter", required: false }] }], dbxActionValueGetterIsModified: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionValueGetterIsModified", required: false }] }], dbxActionValueGetterIsEqual: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionValueGetterIsEqual", required: false }] }] } });
|
|
1909
2677
|
|
|
1910
2678
|
/**
|
|
1911
|
-
* Directive that watches a value observable
|
|
2679
|
+
* Directive that watches a value observable stream and automatically updates the action's
|
|
2680
|
+
* modified state and provides the latest value when triggered.
|
|
2681
|
+
*
|
|
2682
|
+
* Each emission from the stream is checked against an optional `isModified` or `isEqual`
|
|
2683
|
+
* function to determine if the action should be marked as modified. When the action is
|
|
2684
|
+
* triggered, the latest value from the stream is passed to `readyValue()` only if modified.
|
|
2685
|
+
*
|
|
2686
|
+
* This is ideal for form-based workflows where the form value changes over time and
|
|
2687
|
+
* should automatically track modification state.
|
|
2688
|
+
*
|
|
2689
|
+
* @example
|
|
2690
|
+
* ```html
|
|
2691
|
+
* <div dbxAction>
|
|
2692
|
+
* <ng-container [dbxActionValueStream]="formValue$"></ng-container>
|
|
2693
|
+
* <button (click)="action.trigger()">Save</button>
|
|
2694
|
+
* </div>
|
|
2695
|
+
* ```
|
|
2696
|
+
*
|
|
2697
|
+
* @typeParam T - The input value type.
|
|
2698
|
+
* @typeParam O - The output result type.
|
|
2699
|
+
*
|
|
2700
|
+
* @see {@link DbxActionValueDirective} for static/getter-based values.
|
|
2701
|
+
* @see {@link DbxActionValueTriggerDirective} for lazy getter values on trigger.
|
|
1912
2702
|
*/
|
|
1913
2703
|
class DbxActionValueStreamDirective {
|
|
1914
2704
|
source = inject((DbxActionContextStoreSourceInstance), { host: true });
|
|
@@ -1960,9 +2750,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
1960
2750
|
}], ctorParameters: () => [], propDecorators: { dbxActionValueStream: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionValueStream", required: false }] }], dbxActionValueStreamIsEqualValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionValueStreamIsEqualValue", required: false }] }], dbxActionValueStreamIsModifiedValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxActionValueStreamIsModifiedValue", required: false }] }] } });
|
|
1961
2751
|
|
|
1962
2752
|
/**
|
|
1963
|
-
* Structural directive that
|
|
2753
|
+
* Structural directive that conditionally renders its content when the action has been triggered.
|
|
2754
|
+
*
|
|
2755
|
+
* Shows content during the TRIGGERED state (after trigger, before value-ready/working).
|
|
2756
|
+
* Optionally accepts a number (in milliseconds) to auto-hide the content after the specified duration.
|
|
2757
|
+
*
|
|
2758
|
+
* @example
|
|
2759
|
+
* ```html
|
|
2760
|
+
* <div dbxAction>
|
|
2761
|
+
* <div *dbxActionTriggered>Preparing...</div>
|
|
2762
|
+
* </div>
|
|
2763
|
+
* ```
|
|
1964
2764
|
*
|
|
1965
|
-
*
|
|
2765
|
+
* @see {@link DbxActionIsWorkingDirective} for content shown during the working state.
|
|
1966
2766
|
*/
|
|
1967
2767
|
class DbxActionTriggeredDirective extends AbstractIfDirective {
|
|
1968
2768
|
_store = inject(DbxActionContextStoreSourceInstance);
|
|
@@ -2068,6 +2868,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
2068
2868
|
}]
|
|
2069
2869
|
}] });
|
|
2070
2870
|
|
|
2871
|
+
/**
|
|
2872
|
+
* Creates a simple {@link DbxActionContextSourceReference} wrapper around a source instance.
|
|
2873
|
+
*
|
|
2874
|
+
* The returned reference has a no-op `destroy()` method, making it suitable for cases
|
|
2875
|
+
* where the caller does not own the lifecycle of the source instance.
|
|
2876
|
+
*
|
|
2877
|
+
* @typeParam T - The input value type.
|
|
2878
|
+
* @typeParam O - The output result type.
|
|
2879
|
+
* @param sourceInstance - The source instance to wrap.
|
|
2880
|
+
* @returns A destroyable reference to the source instance.
|
|
2881
|
+
*/
|
|
2071
2882
|
function makeDbxActionContextSourceReference(sourceInstance) {
|
|
2072
2883
|
return {
|
|
2073
2884
|
sourceInstance,
|
|
@@ -2075,6 +2886,15 @@ function makeDbxActionContextSourceReference(sourceInstance) {
|
|
|
2075
2886
|
};
|
|
2076
2887
|
}
|
|
2077
2888
|
|
|
2889
|
+
/**
|
|
2890
|
+
* Type guard that checks whether the given input is a {@link SegueRef} object (as opposed to a raw router link string).
|
|
2891
|
+
*
|
|
2892
|
+
* @typeParam O - The type of the transition options.
|
|
2893
|
+
* @param input - The value to test.
|
|
2894
|
+
* @returns `true` if the input is a {@link SegueRef} with a non-empty `ref` property.
|
|
2895
|
+
*
|
|
2896
|
+
* @see {@link asSegueRef} for converting an input to a SegueRef
|
|
2897
|
+
*/
|
|
2078
2898
|
function isSegueRef(input) {
|
|
2079
2899
|
return typeof input === 'object' && hasValueOrNotEmpty(input.ref);
|
|
2080
2900
|
}
|
|
@@ -2101,21 +2921,77 @@ function asSegueRefString(input) {
|
|
|
2101
2921
|
throw new Error(`asSegueRefString() failed to convert the input to a string: ${input}`);
|
|
2102
2922
|
}
|
|
2103
2923
|
}
|
|
2924
|
+
/**
|
|
2925
|
+
* Creates a {@link SegueRef} from a string ref path and optional segue options.
|
|
2926
|
+
*
|
|
2927
|
+
* @typeParam O - The type of the transition options.
|
|
2928
|
+
* @param ref - The string ref path to wrap.
|
|
2929
|
+
* @param options - Optional parameters and transition options to include.
|
|
2930
|
+
* @returns A new {@link SegueRef} containing the given ref and options.
|
|
2931
|
+
*/
|
|
2104
2932
|
function refStringToSegueRef(ref, options) {
|
|
2105
2933
|
return { ...options, ref };
|
|
2106
2934
|
}
|
|
2935
|
+
/**
|
|
2936
|
+
* Maps an observable of string ref paths to an observable of {@link SegueRef} objects.
|
|
2937
|
+
*
|
|
2938
|
+
* @typeParam O - The type of the transition options.
|
|
2939
|
+
* @param obs - The source observable emitting string ref paths.
|
|
2940
|
+
* @param options - Optional parameters and transition options to include in each emitted SegueRef.
|
|
2941
|
+
* @returns An observable that emits {@link SegueRef} objects.
|
|
2942
|
+
*
|
|
2943
|
+
* @see {@link refStringToSegueRef}
|
|
2944
|
+
*/
|
|
2107
2945
|
function mapRefStringObsToSegueRefObs(obs, options) {
|
|
2108
2946
|
return obs.pipe(map((x) => refStringToSegueRef(x, options)));
|
|
2109
2947
|
}
|
|
2110
2948
|
|
|
2111
2949
|
/**
|
|
2112
|
-
*
|
|
2950
|
+
* Abstract service that provides reactive access to the current authentication state, user roles, and lifecycle events.
|
|
2951
|
+
*
|
|
2952
|
+
* This is the primary abstraction for authentication in dbx-core. Concrete implementations
|
|
2953
|
+
* (e.g., Firebase-based auth) must provide all observable streams and the logout behavior.
|
|
2954
|
+
*
|
|
2955
|
+
* Components and services should inject this abstract class rather than a concrete implementation,
|
|
2956
|
+
* enabling the auth provider to be swapped without changing consumer code.
|
|
2957
|
+
*
|
|
2958
|
+
* @example
|
|
2959
|
+
* ```ts
|
|
2960
|
+
* @Component({ ... })
|
|
2961
|
+
* export class MyComponent {
|
|
2962
|
+
* private readonly authService = inject(DbxAuthService);
|
|
2963
|
+
*
|
|
2964
|
+
* readonly isLoggedIn$ = this.authService.isLoggedIn$;
|
|
2965
|
+
* readonly roles$ = this.authService.authRoles$;
|
|
2966
|
+
*
|
|
2967
|
+
* logout() {
|
|
2968
|
+
* this.authService.logOut();
|
|
2969
|
+
* }
|
|
2970
|
+
* }
|
|
2971
|
+
* ```
|
|
2972
|
+
*
|
|
2973
|
+
* @see {@link AuthUserState} for the possible user states.
|
|
2974
|
+
* @see {@link DbxAppAuthEffects} for how this service is bridged into the NgRx store.
|
|
2113
2975
|
*/
|
|
2114
2976
|
class DbxAuthService {
|
|
2115
2977
|
}
|
|
2116
2978
|
|
|
2117
2979
|
/**
|
|
2118
|
-
*
|
|
2980
|
+
* Creates a UIRouter `TransitionHookFn` that performs auth-based route guarding.
|
|
2981
|
+
*
|
|
2982
|
+
* The generated hook evaluates the `makeDecisionsObs` observable for each transition:
|
|
2983
|
+
* - If it emits `true`, the transition proceeds normally.
|
|
2984
|
+
* - If it emits `false`, the user is redirected to the default target or a custom redirect
|
|
2985
|
+
* specified in the state's `data.redirectTo` property.
|
|
2986
|
+
* - If it emits a route reference, the user is redirected to that specific route.
|
|
2987
|
+
* - If the observable does not emit within the configured timeout, the transition is rejected.
|
|
2988
|
+
*
|
|
2989
|
+
* @param config - The hook configuration including redirect targets and the decision observable factory.
|
|
2990
|
+
* @returns A `TransitionHookFn` suitable for registration with UIRouter's `TransitionService`.
|
|
2991
|
+
*
|
|
2992
|
+
* @see {@link enableIsLoggedInHook} for a login-based usage.
|
|
2993
|
+
* @see {@link enableHasAuthRoleHook} for a role-based usage.
|
|
2994
|
+
* @see {@link enableHasAuthStateHook} for a state-based usage.
|
|
2119
2995
|
*/
|
|
2120
2996
|
function makeAuthTransitionHook(config) {
|
|
2121
2997
|
const { defaultRedirectTarget, errorRedirectTarget = defaultRedirectTarget, timeoutTime = 1000 } = config;
|
|
@@ -2181,10 +3057,31 @@ function makeAuthTransitionHook(config) {
|
|
|
2181
3057
|
}
|
|
2182
3058
|
|
|
2183
3059
|
/**
|
|
2184
|
-
* Creates
|
|
3060
|
+
* Creates an {@link AuthTransitionRedirectTargetGetter} that dynamically determines the redirect
|
|
3061
|
+
* destination based on the current {@link AuthUserState}.
|
|
2185
3062
|
*
|
|
2186
|
-
*
|
|
2187
|
-
*
|
|
3063
|
+
* This is useful when different auth states should redirect to different routes. For example,
|
|
3064
|
+
* a `'new'` user might be redirected to an onboarding page while an `'anon'` user is sent to login.
|
|
3065
|
+
*
|
|
3066
|
+
* Each value in the `stateMap` can be either a static route reference or a dynamic getter
|
|
3067
|
+
* for more complex redirect logic.
|
|
3068
|
+
*
|
|
3069
|
+
* @param stateMap - An object map where keys are {@link AuthUserState} values and values are
|
|
3070
|
+
* redirect targets (static or dynamic) for that state.
|
|
3071
|
+
* @returns An {@link AuthTransitionRedirectTargetGetter} that resolves the redirect based on the current auth state.
|
|
3072
|
+
*
|
|
3073
|
+
* @example
|
|
3074
|
+
* ```ts
|
|
3075
|
+
* const redirectGetter = redirectBasedOnAuthUserState({
|
|
3076
|
+
* 'none': '/auth/login',
|
|
3077
|
+
* 'anon': '/auth/login',
|
|
3078
|
+
* 'new': '/onboard',
|
|
3079
|
+
* 'user': '/app'
|
|
3080
|
+
* });
|
|
3081
|
+
* ```
|
|
3082
|
+
*
|
|
3083
|
+
* @see {@link AuthTransitionRedirectTargetOrGetter}
|
|
3084
|
+
* @see {@link AuthUserState}
|
|
2188
3085
|
*/
|
|
2189
3086
|
function redirectBasedOnAuthUserState(stateMap) {
|
|
2190
3087
|
return (input) => {
|
|
@@ -2208,7 +3105,18 @@ function redirectBasedOnAuthUserState(stateMap) {
|
|
|
2208
3105
|
}
|
|
2209
3106
|
|
|
2210
3107
|
/**
|
|
2211
|
-
*
|
|
3108
|
+
* Registers a UIRouter transition hook that redirects unauthenticated users away from
|
|
3109
|
+
* states that require login.
|
|
3110
|
+
*
|
|
3111
|
+
* The hook fires on `onBefore` (priority 100) for any state whose `data` property has
|
|
3112
|
+
* `requiredLogIn: true`. If the user is not logged in (as determined by {@link DbxAuthService.isLoggedIn$}),
|
|
3113
|
+
* they are redirected to the configured `defaultRedirectTarget`.
|
|
3114
|
+
*
|
|
3115
|
+
* @param transitionService - The UIRouter `TransitionService` to register the hook with.
|
|
3116
|
+
* @param config - Configuration including redirect targets and timeout settings.
|
|
3117
|
+
*
|
|
3118
|
+
* @see {@link IsLoggedInStateData} for marking states as requiring login.
|
|
3119
|
+
* @see {@link makeAuthTransitionHook} for the underlying hook factory.
|
|
2212
3120
|
*/
|
|
2213
3121
|
function enableIsLoggedInHook(transitionService, config) {
|
|
2214
3122
|
// Matches if the destination state's data property has a truthy 'isSecure' property
|
|
@@ -2230,10 +3138,19 @@ function enableIsLoggedInHook(transitionService, config) {
|
|
|
2230
3138
|
}
|
|
2231
3139
|
|
|
2232
3140
|
/**
|
|
2233
|
-
*
|
|
3141
|
+
* Registers a UIRouter transition hook that redirects users who lack the required auth roles
|
|
3142
|
+
* away from protected states.
|
|
3143
|
+
*
|
|
3144
|
+
* The hook fires on `onBefore` (priority 100) for any state whose `data` property has an
|
|
3145
|
+
* `authRoles` value. If the user's current roles do not satisfy the requirement
|
|
3146
|
+
* (based on the configured `authRolesMode`), they are redirected.
|
|
2234
3147
|
*
|
|
2235
|
-
* -
|
|
2236
|
-
* -
|
|
3148
|
+
* @param transitionService - The UIRouter `TransitionService` to register the hook with.
|
|
3149
|
+
* @param config - Configuration including redirect targets and timeout settings.
|
|
3150
|
+
*
|
|
3151
|
+
* @see {@link HasAuthRoleStateData} for marking states with required roles.
|
|
3152
|
+
* @see {@link hasAuthRoleDecisionPipe} for the role evaluation logic.
|
|
3153
|
+
* @see {@link makeAuthTransitionHook} for the underlying hook factory.
|
|
2237
3154
|
*/
|
|
2238
3155
|
function enableHasAuthRoleHook(transitionService, config) {
|
|
2239
3156
|
// Matches if the destination state's data property has a truthy 'isSecure' property
|
|
@@ -2256,6 +3173,18 @@ function enableHasAuthRoleHook(transitionService, config) {
|
|
|
2256
3173
|
// Register the "requires auth" hook with the TransitionsService
|
|
2257
3174
|
transitionService.onBefore(isSecureCriteria, assertHasAuthRole, { priority: 100 });
|
|
2258
3175
|
}
|
|
3176
|
+
/**
|
|
3177
|
+
* Creates an RxJS operator that evaluates whether the user's {@link AuthRoleSet} satisfies
|
|
3178
|
+
* the role requirements defined in the given {@link HasAuthRoleStateData}.
|
|
3179
|
+
*
|
|
3180
|
+
* The operator processes role configurations and applies the specified `authRolesMode`
|
|
3181
|
+
* (`'all'` or `'any'`) to determine if the user has sufficient roles.
|
|
3182
|
+
*
|
|
3183
|
+
* @param stateData - The role configuration from the UIRouter state's `data` property.
|
|
3184
|
+
* @returns An `OperatorFunction` that transforms an `AuthRoleSet` stream into a `boolean` stream.
|
|
3185
|
+
*
|
|
3186
|
+
* @see {@link enableHasAuthRoleHook} for where this is used in transition hooks.
|
|
3187
|
+
*/
|
|
2259
3188
|
function hasAuthRoleDecisionPipe(stateData) {
|
|
2260
3189
|
const authRolesMode = stateData.authRolesMode || 'all';
|
|
2261
3190
|
const authRoleConfigs = asArray(stateData.authRoles).map((x) => {
|
|
@@ -2285,10 +3214,18 @@ function hasAuthRoleDecisionPipe(stateData) {
|
|
|
2285
3214
|
}
|
|
2286
3215
|
|
|
2287
3216
|
/**
|
|
2288
|
-
*
|
|
3217
|
+
* Registers a UIRouter transition hook that redirects users whose {@link AuthUserState} does not
|
|
3218
|
+
* satisfy the state's requirements.
|
|
2289
3219
|
*
|
|
2290
|
-
*
|
|
2291
|
-
* -
|
|
3220
|
+
* The hook fires on `onBefore` (priority 100) for any state whose `data` property has an
|
|
3221
|
+
* `authStates` value. It supports both allow-lists and deny-lists of auth user states.
|
|
3222
|
+
*
|
|
3223
|
+
* @param transitionService - The UIRouter `TransitionService` to register the hook with.
|
|
3224
|
+
* @param config - Configuration including redirect targets and timeout settings.
|
|
3225
|
+
*
|
|
3226
|
+
* @see {@link HasAuthStateData} for marking states with required auth states.
|
|
3227
|
+
* @see {@link HasAuthStateObjectConfig} for detailed allowed/disallowed configuration.
|
|
3228
|
+
* @see {@link makeAuthTransitionHook} for the underlying hook factory.
|
|
2292
3229
|
*/
|
|
2293
3230
|
function enableHasAuthStateHook(transitionService, config) {
|
|
2294
3231
|
// Matches if the destination state's data property has a truthy 'isSecure' property
|
|
@@ -2450,27 +3387,61 @@ class AbstractOnDbxAppContextStateEffects {
|
|
|
2450
3387
|
}
|
|
2451
3388
|
}
|
|
2452
3389
|
|
|
3390
|
+
/**
|
|
3391
|
+
* Sentinel value representing an unauthenticated or unidentifiable user.
|
|
3392
|
+
*
|
|
3393
|
+
* Used as a fallback when no valid {@link AuthUserIdentifier} is available.
|
|
3394
|
+
*/
|
|
2453
3395
|
const NO_AUTH_USER_IDENTIFIER = '0';
|
|
2454
3396
|
/**
|
|
2455
|
-
*
|
|
3397
|
+
* Normalizes an optional user identifier into a guaranteed {@link AuthUserIdentifier}.
|
|
2456
3398
|
*
|
|
2457
|
-
* @
|
|
2458
|
-
*
|
|
3399
|
+
* If the input is `undefined` or falsy, returns {@link NO_AUTH_USER_IDENTIFIER} as a safe default.
|
|
3400
|
+
* This ensures downstream consumers always receive a non-null identifier value.
|
|
3401
|
+
*
|
|
3402
|
+
* @param inputId - The user identifier to normalize, or `undefined`/`null`.
|
|
3403
|
+
* @returns The input identifier if truthy, otherwise {@link NO_AUTH_USER_IDENTIFIER}.
|
|
3404
|
+
*
|
|
3405
|
+
* @example
|
|
3406
|
+
* ```ts
|
|
3407
|
+
* authUserIdentifier('abc123'); // 'abc123'
|
|
3408
|
+
* authUserIdentifier(undefined); // '0'
|
|
3409
|
+
* ```
|
|
2459
3410
|
*/
|
|
2460
3411
|
function authUserIdentifier(inputId) {
|
|
2461
3412
|
return inputId ? inputId : NO_AUTH_USER_IDENTIFIER;
|
|
2462
3413
|
}
|
|
2463
3414
|
|
|
2464
3415
|
/**
|
|
2465
|
-
*
|
|
3416
|
+
* NgRx action dispatched when the user has successfully logged in.
|
|
3417
|
+
*
|
|
3418
|
+
* This is an event action (past tense) triggered by {@link DbxAppAuthEffects} in response
|
|
3419
|
+
* to the {@link DbxAuthService.onLogIn$} observable. It signals that authentication has been
|
|
3420
|
+
* established and downstream effects (e.g., navigation to the app) can proceed.
|
|
3421
|
+
*
|
|
3422
|
+
* @see {@link loggedOut} for the corresponding logout event.
|
|
3423
|
+
* @see {@link DbxAppAuthEffects.emitLoggedIn}
|
|
2466
3424
|
*/
|
|
2467
3425
|
const loggedIn = createAction('[App/Auth] Auth Logged In');
|
|
2468
3426
|
/**
|
|
2469
|
-
*
|
|
3427
|
+
* NgRx action dispatched when the user has logged out.
|
|
3428
|
+
*
|
|
3429
|
+
* This is an event action (past tense) triggered by {@link DbxAppAuthEffects} in response
|
|
3430
|
+
* to the {@link DbxAuthService.onLogOut$} observable. When dispatched, the user reducer
|
|
3431
|
+
* resets the auth state to its initial values (no user, no roles, not onboarded).
|
|
3432
|
+
*
|
|
3433
|
+
* @see {@link loggedIn} for the corresponding login event.
|
|
3434
|
+
* @see {@link logout} for the imperative command action to initiate logout.
|
|
2470
3435
|
*/
|
|
2471
3436
|
const loggedOut = createAction('[App/Auth] Auth Logged Out');
|
|
2472
3437
|
/**
|
|
2473
|
-
*
|
|
3438
|
+
* NgRx action that commands the application to perform a logout.
|
|
3439
|
+
*
|
|
3440
|
+
* This is a command action (imperative) that, when dispatched, triggers {@link DbxAppAuthEffects.forwardLogoutToAuthService}
|
|
3441
|
+
* to call {@link DbxAuthService.logOut}. Use this action to initiate logout from anywhere in the application
|
|
3442
|
+
* via the NgRx store rather than calling the auth service directly.
|
|
3443
|
+
*
|
|
3444
|
+
* @see {@link loggedOut} for the event action dispatched after logout completes.
|
|
2474
3445
|
*/
|
|
2475
3446
|
const logout = createAction('[App/Auth] Auth Logout');
|
|
2476
3447
|
|
|
@@ -2482,19 +3453,42 @@ var auth_action = /*#__PURE__*/Object.freeze({
|
|
|
2482
3453
|
});
|
|
2483
3454
|
|
|
2484
3455
|
/**
|
|
2485
|
-
*
|
|
3456
|
+
* NgRx action that updates the authenticated user's identifier in the store.
|
|
3457
|
+
*
|
|
3458
|
+
* Dispatched by {@link DbxAppAuthEffects.setUserIdentifier} whenever the
|
|
3459
|
+
* {@link DbxAuthService.userIdentifier$} emits a new value.
|
|
3460
|
+
*
|
|
3461
|
+
* @see {@link DbxAppAuthStateUser.userId}
|
|
2486
3462
|
*/
|
|
2487
3463
|
const setUserIdentifier = createAction('[App/Auth] Set User Identifier', props());
|
|
2488
3464
|
/**
|
|
2489
|
-
*
|
|
3465
|
+
* NgRx action that updates the authenticated user's {@link AuthUserState} in the store.
|
|
3466
|
+
*
|
|
3467
|
+
* Dispatched by {@link DbxAppAuthEffects.setUserState} whenever the
|
|
3468
|
+
* {@link DbxAuthService.authUserState$} emits a new value. The state determines
|
|
3469
|
+
* the user's lifecycle stage (none, anon, new, user, or error).
|
|
3470
|
+
*
|
|
3471
|
+
* @see {@link AuthUserState}
|
|
3472
|
+
* @see {@link DbxAppAuthStateUser.userState}
|
|
2490
3473
|
*/
|
|
2491
3474
|
const setUserState = createAction('[App/Auth] Set User State', props());
|
|
2492
3475
|
/**
|
|
2493
|
-
*
|
|
3476
|
+
* NgRx action that updates the authenticated user's auth roles in the store.
|
|
3477
|
+
*
|
|
3478
|
+
* Dispatched by {@link DbxAppAuthEffects.setUserRoles} whenever the
|
|
3479
|
+
* {@link DbxAuthService.authRoles$} emits a new role set. Roles are stored
|
|
3480
|
+
* as an array in the NgRx state.
|
|
3481
|
+
*
|
|
3482
|
+
* @see {@link DbxAppAuthStateUser.userRoles}
|
|
2494
3483
|
*/
|
|
2495
3484
|
const setUserRoles = createAction('[App/Auth] Set User Roles', props());
|
|
2496
3485
|
/**
|
|
2497
|
-
*
|
|
3486
|
+
* NgRx action that updates the authenticated user's onboarding status in the store.
|
|
3487
|
+
*
|
|
3488
|
+
* Dispatched by {@link DbxAppAuthEffects.setUserIsOnboarded} whenever the
|
|
3489
|
+
* {@link DbxAuthService.isOnboarded$} emits a new value.
|
|
3490
|
+
*
|
|
3491
|
+
* @see {@link DbxAppAuthStateUser.isOnboarded}
|
|
2498
3492
|
*/
|
|
2499
3493
|
const setUserIsOnboarded = createAction('[App/Auth] Set User Is Onboarded', props());
|
|
2500
3494
|
|
|
@@ -2512,7 +3506,16 @@ var index$1 = /*#__PURE__*/Object.freeze({
|
|
|
2512
3506
|
DbxAppAuthUserActions: user_action
|
|
2513
3507
|
});
|
|
2514
3508
|
|
|
3509
|
+
/**
|
|
3510
|
+
* NgRx feature key for the auth user sub-state within the auth feature.
|
|
3511
|
+
*/
|
|
2515
3512
|
const dbxAppAuthUserFeatureKey = 'user';
|
|
3513
|
+
/**
|
|
3514
|
+
* Initial state for the auth user reducer.
|
|
3515
|
+
*
|
|
3516
|
+
* Represents a fully unauthenticated state: no user identifier, not onboarded,
|
|
3517
|
+
* in the `'none'` auth state, with no roles assigned.
|
|
3518
|
+
*/
|
|
2516
3519
|
const initialState = {
|
|
2517
3520
|
userId: NO_AUTH_USER_IDENTIFIER,
|
|
2518
3521
|
isOnboarded: false,
|
|
@@ -2522,11 +3525,20 @@ const initialState = {
|
|
|
2522
3525
|
const reducer = createReducer(initialState, on(loggedOut, () => ({ ...initialState })), on(setUserIdentifier, (state, { id: userId }) => ({ ...state, userId })), on(setUserIsOnboarded, (state, { isOnboarded }) => ({ ...state, isOnboarded })), on(setUserState, (state, { state: userState }) => ({ ...state, userState })), on(setUserRoles, (state, { roles: userRoles }) => ({ ...state, userRoles: Array.from(userRoles) })));
|
|
2523
3526
|
|
|
2524
3527
|
/**
|
|
2525
|
-
*
|
|
3528
|
+
* NgRx feature key used to register the auth feature state in the global store.
|
|
3529
|
+
*
|
|
3530
|
+
* The auth state is registered under `'app.auth'` in the root NgRx state tree.
|
|
2526
3531
|
*/
|
|
2527
3532
|
const featureKey = 'app.auth';
|
|
2528
3533
|
/**
|
|
2529
|
-
*
|
|
3534
|
+
* Combined reducer function for the auth feature state.
|
|
3535
|
+
*
|
|
3536
|
+
* Merges all auth sub-reducers (currently just the user reducer) using NgRx's `combineReducers`.
|
|
3537
|
+
* This function is registered with `provideState` via {@link provideDbxAppAuthState}.
|
|
3538
|
+
*
|
|
3539
|
+
* @param state - The current auth feature state, or `undefined` for initialization.
|
|
3540
|
+
* @param action - The dispatched NgRx action.
|
|
3541
|
+
* @returns The updated {@link DbxAppAuthFeatureState}.
|
|
2530
3542
|
*/
|
|
2531
3543
|
function reducers(state, action) {
|
|
2532
3544
|
return combineReducers({
|
|
@@ -2534,11 +3546,15 @@ function reducers(state, action) {
|
|
|
2534
3546
|
})(state, action);
|
|
2535
3547
|
}
|
|
2536
3548
|
/**
|
|
2537
|
-
*
|
|
3549
|
+
* NgRx feature selector that retrieves the entire {@link DbxAppAuthFeatureState} from the global store.
|
|
2538
3550
|
*/
|
|
2539
3551
|
const selectAppAuthFeature = createFeatureSelector(featureKey);
|
|
2540
3552
|
/**
|
|
2541
|
-
*
|
|
3553
|
+
* NgRx selector that retrieves the {@link DbxAppAuthStateUser} from the auth feature state.
|
|
3554
|
+
*
|
|
3555
|
+
* Provides access to the user's identifier, auth state, roles, and onboarding status.
|
|
3556
|
+
*
|
|
3557
|
+
* @see {@link DbxAppAuthStateService.authStateUser$} for the observable wrapper.
|
|
2542
3558
|
*/
|
|
2543
3559
|
const selectDbxAppAuthUser = createSelector(selectAppAuthFeature, (featureState) => featureState[dbxAppAuthUserFeatureKey]);
|
|
2544
3560
|
|
|
@@ -2551,10 +3567,21 @@ var index = /*#__PURE__*/Object.freeze({
|
|
|
2551
3567
|
});
|
|
2552
3568
|
|
|
2553
3569
|
/**
|
|
2554
|
-
* Creates a
|
|
3570
|
+
* Creates a navigation function bound to the given {@link DbxRouterService}.
|
|
2555
3571
|
*
|
|
2556
|
-
* @
|
|
2557
|
-
*
|
|
3572
|
+
* The returned function accepts either a {@link SegueRef}, a router link string, or an observable of either,
|
|
3573
|
+
* resolves it to a single value, and calls `go()` on the router service.
|
|
3574
|
+
*
|
|
3575
|
+
* @param dbxRouterService - The router service to use for navigation.
|
|
3576
|
+
* @returns A function that navigates to the given route and returns a promise resolving to the navigation result.
|
|
3577
|
+
*
|
|
3578
|
+
* @example
|
|
3579
|
+
* ```ts
|
|
3580
|
+
* const navigate = goWithRouter(routerService);
|
|
3581
|
+
* await navigate({ ref: 'app.dashboard' });
|
|
3582
|
+
* ```
|
|
3583
|
+
*
|
|
3584
|
+
* @see {@link GoWithRouter}
|
|
2558
3585
|
*/
|
|
2559
3586
|
function goWithRouter(dbxRouterService) {
|
|
2560
3587
|
return (route) => {
|
|
@@ -2563,30 +3590,109 @@ function goWithRouter(dbxRouterService) {
|
|
|
2563
3590
|
}
|
|
2564
3591
|
|
|
2565
3592
|
/**
|
|
2566
|
-
*
|
|
3593
|
+
* Abstract service that provides an observable stream of router transition events.
|
|
3594
|
+
*
|
|
3595
|
+
* This is the base class for {@link DbxRouterService}, exposing only the transition
|
|
3596
|
+
* observation capability without navigation methods. Useful when a consumer only needs
|
|
3597
|
+
* to react to route changes without performing navigation.
|
|
3598
|
+
*
|
|
3599
|
+
* @example
|
|
3600
|
+
* ```ts
|
|
3601
|
+
* @Component({ ... })
|
|
3602
|
+
* class MyComponent {
|
|
3603
|
+
* private readonly transitions = inject(DbxRouterTransitionService);
|
|
3604
|
+
*
|
|
3605
|
+
* readonly onSuccess$ = this.transitions.transitions$.pipe(
|
|
3606
|
+
* filter(e => e.type === DbxRouterTransitionEventType.SUCCESS)
|
|
3607
|
+
* );
|
|
3608
|
+
* }
|
|
3609
|
+
* ```
|
|
3610
|
+
*
|
|
3611
|
+
* @see {@link DbxRouterService} for the full router service with navigation
|
|
3612
|
+
* @see {@link DbxRouterTransitionEvent} for the event type
|
|
2567
3613
|
*/
|
|
2568
3614
|
class DbxRouterTransitionService {
|
|
2569
3615
|
}
|
|
2570
3616
|
|
|
2571
3617
|
/**
|
|
2572
|
-
*
|
|
3618
|
+
* Abstract router service that provides navigation capabilities and routing state information.
|
|
3619
|
+
*
|
|
3620
|
+
* Extends {@link DbxRouterTransitionService} with navigation methods (`go`, `updateParams`) and
|
|
3621
|
+
* route inspection methods (`isActive`, `isActiveExactly`, `comparePrecision`).
|
|
3622
|
+
*
|
|
3623
|
+
* Concrete implementations include {@link DbxAngularRouterService} (Angular Router) and
|
|
3624
|
+
* {@link DbxUIRouterService} (UIRouter).
|
|
3625
|
+
*
|
|
3626
|
+
* @example
|
|
3627
|
+
* ```ts
|
|
3628
|
+
* // Inject and use in a component or service
|
|
3629
|
+
* @Component({ ... })
|
|
3630
|
+
* class MyComponent {
|
|
3631
|
+
* private readonly router = inject(DbxRouterService);
|
|
3632
|
+
*
|
|
3633
|
+
* navigateToDashboard(): void {
|
|
3634
|
+
* this.router.go({ ref: 'app.dashboard', refParams: { tab: 'overview' } });
|
|
3635
|
+
* }
|
|
3636
|
+
* }
|
|
3637
|
+
* ```
|
|
3638
|
+
*
|
|
3639
|
+
* @see {@link DbxRouterTransitionService} for transition event observables
|
|
3640
|
+
* @see {@link DbxAngularRouterService} for the Angular Router implementation
|
|
3641
|
+
* @see {@link DbxUIRouterService} for the UIRouter implementation
|
|
2573
3642
|
*/
|
|
2574
3643
|
class DbxRouterService extends DbxRouterTransitionService {
|
|
2575
3644
|
}
|
|
2576
3645
|
|
|
2577
3646
|
/**
|
|
2578
|
-
*
|
|
3647
|
+
* Abstract configuration class that defines the key authentication-related routes for an application.
|
|
3648
|
+
*
|
|
3649
|
+
* Provide a concrete instance of this class via {@link provideDbxAppAuthRouter} to configure
|
|
3650
|
+
* where the auth router service navigates during authentication lifecycle events (login, logout, onboarding).
|
|
3651
|
+
*
|
|
3652
|
+
* @example
|
|
3653
|
+
* ```ts
|
|
3654
|
+
* const authRoutes: DbxAppAuthRoutes = {
|
|
3655
|
+
* loginRef: '/auth/login',
|
|
3656
|
+
* loggedOutRef: '/auth/logged-out',
|
|
3657
|
+
* onboardRef: '/onboard',
|
|
3658
|
+
* appRef: '/app'
|
|
3659
|
+
* };
|
|
3660
|
+
* ```
|
|
3661
|
+
*
|
|
3662
|
+
* @see {@link DbxAppAuthRouterService} for the service that uses these routes for navigation.
|
|
3663
|
+
* @see {@link provideDbxAppAuthRouter} for registering this configuration.
|
|
2579
3664
|
*/
|
|
2580
3665
|
class DbxAppAuthRoutes {
|
|
2581
3666
|
}
|
|
2582
3667
|
|
|
2583
3668
|
/**
|
|
2584
|
-
*
|
|
3669
|
+
* Angular service that provides programmatic navigation to key authentication-related routes.
|
|
3670
|
+
*
|
|
3671
|
+
* This service wraps {@link DbxRouterService} and {@link DbxAppAuthRoutes} to offer
|
|
3672
|
+
* convenient methods for navigating to login, logout, onboarding, and main app routes.
|
|
3673
|
+
* It also manages an `isAuthRouterEffectsEnabled` flag that controls whether
|
|
3674
|
+
* {@link DbxAppAuthRouterEffects} should perform automatic navigation on auth events.
|
|
3675
|
+
*
|
|
3676
|
+
* @example
|
|
3677
|
+
* ```ts
|
|
3678
|
+
* @Component({ ... })
|
|
3679
|
+
* export class LogoutButtonComponent {
|
|
3680
|
+
* private readonly authRouterService = inject(DbxAppAuthRouterService);
|
|
3681
|
+
*
|
|
3682
|
+
* async onLogout() {
|
|
3683
|
+
* await this.authRouterService.goToLoggedOut();
|
|
3684
|
+
* }
|
|
3685
|
+
* }
|
|
3686
|
+
* ```
|
|
3687
|
+
*
|
|
3688
|
+
* @see {@link DbxAppAuthRoutes} for the route configuration.
|
|
3689
|
+
* @see {@link DbxAppAuthRouterEffects} for automatic navigation on auth state changes.
|
|
2585
3690
|
*/
|
|
2586
3691
|
class DbxAppAuthRouterService {
|
|
2587
3692
|
dbxRouterService = inject(DbxRouterService);
|
|
2588
3693
|
dbxAppAuthRoutes = inject(DbxAppAuthRoutes);
|
|
2589
3694
|
_isAuthRouterEffectsEnabled = new BehaviorSubject(true);
|
|
3695
|
+
/** Observable of whether auth router effects are currently enabled. */
|
|
2590
3696
|
isAuthRouterEffectsEnabled$ = this._isAuthRouterEffectsEnabled.asObservable();
|
|
2591
3697
|
ngOnDestroy() {
|
|
2592
3698
|
this._isAuthRouterEffectsEnabled.complete();
|
|
@@ -2648,13 +3754,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
2648
3754
|
}] });
|
|
2649
3755
|
|
|
2650
3756
|
/**
|
|
2651
|
-
*
|
|
3757
|
+
* Angular injection token used to configure which {@link DbxAppContextState} values
|
|
3758
|
+
* the {@link DbxAppAuthRouterEffects} should be active for.
|
|
3759
|
+
*
|
|
3760
|
+
* When provided, the effects will only trigger navigation (e.g., redirect on logout)
|
|
3761
|
+
* when the application is in one of the specified context states.
|
|
3762
|
+
* Defaults to {@link DBX_KNOWN_APP_CONTEXT_STATES} if not explicitly provided.
|
|
3763
|
+
*
|
|
3764
|
+
* @see {@link provideDbxAppAuthRouterState} for how this token is provisioned.
|
|
2652
3765
|
*/
|
|
2653
3766
|
const DBX_APP_AUTH_ROUTER_EFFECTS_TOKEN = new InjectionToken('DbxAppAuthRouterEffectsActiveStates');
|
|
2654
3767
|
/**
|
|
2655
|
-
*
|
|
3768
|
+
* NgRx effects class that performs automatic navigation when authentication state changes.
|
|
2656
3769
|
*
|
|
2657
|
-
*
|
|
3770
|
+
* This effects class handles two key navigation scenarios:
|
|
3771
|
+
* - **On logout**: Redirects the user to the login route via {@link DbxAppAuthRouterService.goToLogin}.
|
|
3772
|
+
* - **On login**: Redirects the user to the main app route via {@link DbxAppAuthRouterService.goToApp}.
|
|
3773
|
+
*
|
|
3774
|
+
* Navigation only occurs when:
|
|
3775
|
+
* 1. The app is in one of the configured active context states (see {@link DBX_APP_AUTH_ROUTER_EFFECTS_TOKEN}).
|
|
3776
|
+
* 2. The {@link DbxAppAuthRouterService.isAuthRouterEffectsEnabled} flag is `true`.
|
|
3777
|
+
*
|
|
3778
|
+
* Extends {@link AbstractOnDbxAppContextStateEffects} to scope effect activation to specific app states.
|
|
3779
|
+
*
|
|
3780
|
+
* @see {@link DbxAppAuthRouterService} for the navigation methods used.
|
|
3781
|
+
* @see {@link provideDbxAppAuthRouterState} for registration and configuration.
|
|
2658
3782
|
*/
|
|
2659
3783
|
class DbxAppAuthRouterEffects extends AbstractOnDbxAppContextStateEffects {
|
|
2660
3784
|
dbxAppAuthRouterService = inject(DbxAppAuthRouterService);
|
|
@@ -2677,10 +3801,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
2677
3801
|
}], ctorParameters: () => [] });
|
|
2678
3802
|
|
|
2679
3803
|
/**
|
|
2680
|
-
* Creates EnvironmentProviders
|
|
3804
|
+
* Creates Angular `EnvironmentProviders` that register the auth router state effects
|
|
3805
|
+
* and their configuration.
|
|
2681
3806
|
*
|
|
2682
|
-
* @
|
|
2683
|
-
* @
|
|
3807
|
+
* This provisions the {@link DBX_APP_AUTH_ROUTER_EFFECTS_TOKEN} with the active states
|
|
3808
|
+
* and registers the {@link DbxAppAuthRouterEffects} NgRx effects class.
|
|
3809
|
+
*
|
|
3810
|
+
* @param config - Configuration specifying which app context states activate the auth router effects.
|
|
3811
|
+
* @returns Angular `EnvironmentProviders` for the auth router state effects.
|
|
3812
|
+
*
|
|
3813
|
+
* @example
|
|
3814
|
+
* ```ts
|
|
3815
|
+
* provideDbxAppAuthRouterState({
|
|
3816
|
+
* activeRoutesToApplyEffects: ['root']
|
|
3817
|
+
* });
|
|
3818
|
+
* ```
|
|
3819
|
+
*
|
|
3820
|
+
* @see {@link provideDbxAppAuth} for the all-in-one provider that includes this.
|
|
3821
|
+
* @see {@link DbxAppAuthRouterEffects} for the effects that handle auth-based navigation.
|
|
2684
3822
|
*/
|
|
2685
3823
|
function provideDbxAppAuthRouterState(config) {
|
|
2686
3824
|
const { activeRoutesToApplyEffects } = config;
|
|
@@ -2697,10 +3835,25 @@ function provideDbxAppAuthRouterState(config) {
|
|
|
2697
3835
|
}
|
|
2698
3836
|
|
|
2699
3837
|
/**
|
|
2700
|
-
* Creates EnvironmentProviders
|
|
3838
|
+
* Creates Angular `EnvironmentProviders` that register the {@link DbxAppAuthRoutes} configuration.
|
|
2701
3839
|
*
|
|
2702
|
-
*
|
|
2703
|
-
* @
|
|
3840
|
+
* This makes the auth routes available for injection throughout the application,
|
|
3841
|
+
* primarily consumed by {@link DbxAppAuthRouterService} for programmatic navigation.
|
|
3842
|
+
*
|
|
3843
|
+
* @param config - Configuration containing the auth routes to register.
|
|
3844
|
+
* @returns Angular `EnvironmentProviders` for the auth router.
|
|
3845
|
+
*
|
|
3846
|
+
* @example
|
|
3847
|
+
* ```ts
|
|
3848
|
+
* provideDbxAppAuthRouter({
|
|
3849
|
+
* dbxAppAuthRoutes: {
|
|
3850
|
+
* loginRef: '/auth/login',
|
|
3851
|
+
* appRef: '/app'
|
|
3852
|
+
* }
|
|
3853
|
+
* });
|
|
3854
|
+
* ```
|
|
3855
|
+
*
|
|
3856
|
+
* @see {@link provideDbxAppAuth} for the all-in-one provider that includes this.
|
|
2704
3857
|
*/
|
|
2705
3858
|
function provideDbxAppAuthRouter(config) {
|
|
2706
3859
|
const { dbxAppAuthRoutes } = config;
|
|
@@ -2714,51 +3867,115 @@ function provideDbxAppAuthRouter(config) {
|
|
|
2714
3867
|
}
|
|
2715
3868
|
|
|
2716
3869
|
/**
|
|
2717
|
-
*
|
|
3870
|
+
* Creates an observable that emits a `void` event each time the user transitions from
|
|
3871
|
+
* logged-out to logged-in (i.e., the input observable transitions from `false` to `true`).
|
|
2718
3872
|
*
|
|
2719
|
-
*
|
|
2720
|
-
*
|
|
3873
|
+
* Useful for triggering side effects (e.g., loading user data) on login events.
|
|
3874
|
+
*
|
|
3875
|
+
* @param isLoggedInObs - An observable that emits `true` when the user is logged in and `false` otherwise.
|
|
3876
|
+
* @returns An observable that emits `void` on each false-to-true transition.
|
|
3877
|
+
*
|
|
3878
|
+
* @see {@link loggedOutObsFromIsLoggedIn} for the inverse (logout detection).
|
|
2721
3879
|
*/
|
|
2722
3880
|
function loggedInObsFromIsLoggedIn(isLoggedInObs) {
|
|
2723
3881
|
return isLoggedInObs.pipe(onFalseToTrue(), map(() => undefined));
|
|
2724
3882
|
}
|
|
2725
3883
|
/**
|
|
2726
|
-
*
|
|
3884
|
+
* Creates an observable that emits a `void` event each time the user transitions from
|
|
3885
|
+
* logged-in to logged-out (i.e., the input observable transitions from `true` to `false`).
|
|
2727
3886
|
*
|
|
2728
|
-
*
|
|
2729
|
-
*
|
|
3887
|
+
* Useful for triggering side effects (e.g., clearing cached data) on logout events.
|
|
3888
|
+
*
|
|
3889
|
+
* @param isLoggedInObs - An observable that emits `true` when the user is logged in and `false` otherwise.
|
|
3890
|
+
* @returns An observable that emits `void` on each true-to-false transition.
|
|
3891
|
+
*
|
|
3892
|
+
* @see {@link loggedInObsFromIsLoggedIn} for the inverse (login detection).
|
|
2730
3893
|
*/
|
|
2731
3894
|
function loggedOutObsFromIsLoggedIn(isLoggedInObs) {
|
|
2732
3895
|
return isLoggedInObs.pipe(onTrueToFalse(), map(() => undefined));
|
|
2733
3896
|
}
|
|
3897
|
+
/**
|
|
3898
|
+
* RxJS operator that checks whether an {@link AuthRoleSet} contains **all** roles from the given observable set.
|
|
3899
|
+
*
|
|
3900
|
+
* Emits `true` when every role in the target set is present in the source role set, `false` otherwise.
|
|
3901
|
+
*
|
|
3902
|
+
* @param roles - Observable of the required roles to check against.
|
|
3903
|
+
* @returns An `OperatorFunction` that transforms an `AuthRoleSet` stream into a `boolean` stream.
|
|
3904
|
+
*
|
|
3905
|
+
* @see {@link authRolesSetContainsAnyRoleFrom} for matching any role.
|
|
3906
|
+
* @see {@link authRolesSetContainsNoRolesFrom} for matching no roles.
|
|
3907
|
+
*/
|
|
2734
3908
|
function authRolesSetContainsAllRolesFrom(roles) {
|
|
2735
3909
|
return setContainsAllValuesFrom(roles);
|
|
2736
3910
|
}
|
|
3911
|
+
/**
|
|
3912
|
+
* RxJS operator that checks whether an {@link AuthRoleSet} contains **any** role from the given observable set.
|
|
3913
|
+
*
|
|
3914
|
+
* Emits `true` when at least one role in the target set is present in the source role set, `false` otherwise.
|
|
3915
|
+
*
|
|
3916
|
+
* @param roles - Observable of the target roles to check against.
|
|
3917
|
+
* @returns An `OperatorFunction` that transforms an `AuthRoleSet` stream into a `boolean` stream.
|
|
3918
|
+
*
|
|
3919
|
+
* @see {@link authRolesSetContainsAllRolesFrom} for matching all roles.
|
|
3920
|
+
* @see {@link authRolesSetContainsNoRolesFrom} for matching no roles.
|
|
3921
|
+
*/
|
|
2737
3922
|
function authRolesSetContainsAnyRoleFrom(roles) {
|
|
2738
3923
|
return setContainsAllValuesFrom(roles);
|
|
2739
3924
|
}
|
|
3925
|
+
/**
|
|
3926
|
+
* RxJS operator that checks whether an {@link AuthRoleSet} contains **none** of the roles from the given observable set.
|
|
3927
|
+
*
|
|
3928
|
+
* Emits `true` when no role in the target set is present in the source role set, `false` otherwise.
|
|
3929
|
+
* Useful for hiding content from users with specific roles.
|
|
3930
|
+
*
|
|
3931
|
+
* @param roles - Observable of the roles to check for absence.
|
|
3932
|
+
* @returns An `OperatorFunction` that transforms an `AuthRoleSet` stream into a `boolean` stream.
|
|
3933
|
+
*
|
|
3934
|
+
* @see {@link authRolesSetContainsAllRolesFrom} for matching all roles.
|
|
3935
|
+
* @see {@link authRolesSetContainsAnyRoleFrom} for matching any role.
|
|
3936
|
+
*/
|
|
2740
3937
|
function authRolesSetContainsNoRolesFrom(roles) {
|
|
2741
3938
|
return setContainsNoValueFrom(roles);
|
|
2742
3939
|
}
|
|
2743
3940
|
|
|
2744
3941
|
/**
|
|
2745
|
-
*
|
|
3942
|
+
* NgRx effects class that bridges the {@link DbxAuthService} observables into the NgRx store.
|
|
3943
|
+
*
|
|
3944
|
+
* This effects class serves two purposes:
|
|
3945
|
+
* 1. **Event forwarding**: Listens to the auth service's reactive streams (login/logout events,
|
|
3946
|
+
* user state, roles, onboarding status, user identifier) and dispatches corresponding NgRx actions
|
|
3947
|
+
* to keep the store in sync with the auth provider.
|
|
3948
|
+
* 2. **Command handling**: Listens for the `logout` command action and forwards it to
|
|
3949
|
+
* {@link DbxAuthService.logOut} to perform the actual logout.
|
|
3950
|
+
*
|
|
3951
|
+
* This is registered via {@link provideDbxAppAuthState} and should not be provided manually.
|
|
3952
|
+
*
|
|
3953
|
+
* @see {@link DbxAuthService} for the source observables.
|
|
3954
|
+
* @see {@link DbxAppAuthActions} for the auth lifecycle actions.
|
|
3955
|
+
* @see {@link DbxAppAuthUserActions} for the user state actions.
|
|
2746
3956
|
*/
|
|
2747
3957
|
class DbxAppAuthEffects {
|
|
2748
3958
|
dbxAuthService = inject(DbxAuthService);
|
|
2749
3959
|
actions$ = inject(Actions);
|
|
2750
3960
|
store = inject((Store));
|
|
2751
3961
|
// MARK: Auth
|
|
3962
|
+
/** Dispatches {@link DbxAppAuthActions.loggedIn} when the auth service emits a login event. */
|
|
2752
3963
|
emitLoggedIn = createEffect(() => this.dbxAuthService.onLogIn$.pipe(map(() => loggedIn())));
|
|
3964
|
+
/** Dispatches {@link DbxAppAuthActions.loggedOut} when the auth service emits a logout event. */
|
|
2753
3965
|
emitLoggedOut = createEffect(() => this.dbxAuthService.onLogOut$.pipe(map(() => loggedOut())));
|
|
3966
|
+
/** Forwards the {@link DbxAppAuthActions.logout} command to {@link DbxAuthService.logOut}. */
|
|
2754
3967
|
forwardLogoutToAuthService = createEffect(() => this.actions$.pipe(ofType(logout), tap(() => {
|
|
2755
3968
|
// Perform the logout
|
|
2756
3969
|
this.dbxAuthService.logOut();
|
|
2757
3970
|
})), { dispatch: false });
|
|
2758
|
-
// MARK:
|
|
3971
|
+
// MARK: User
|
|
3972
|
+
/** Syncs the user identifier from the auth service into the NgRx store. */
|
|
2759
3973
|
setUserIdentifier = createEffect(() => this.dbxAuthService.userIdentifier$.pipe(map((id) => setUserIdentifier({ id }))));
|
|
3974
|
+
/** Syncs the user's {@link AuthUserState} from the auth service into the NgRx store. */
|
|
2760
3975
|
setUserState = createEffect(() => this.dbxAuthService.authUserState$.pipe(map((state) => setUserState({ state }))));
|
|
3976
|
+
/** Syncs the user's auth roles from the auth service into the NgRx store. */
|
|
2761
3977
|
setUserRoles = createEffect(() => this.dbxAuthService.authRoles$.pipe(map((roles) => setUserRoles({ roles: Array.from(roles ?? []) }))));
|
|
3978
|
+
/** Syncs the user's onboarding status from the auth service into the NgRx store. */
|
|
2762
3979
|
setUserIsOnboarded = createEffect(() => this.dbxAuthService.isOnboarded$.pipe(map((isOnboarded) => setUserIsOnboarded({ isOnboarded }))));
|
|
2763
3980
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: DbxAppAuthEffects, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2764
3981
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: DbxAppAuthEffects });
|
|
@@ -2768,19 +3985,49 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
2768
3985
|
}] });
|
|
2769
3986
|
|
|
2770
3987
|
/**
|
|
2771
|
-
* Creates EnvironmentProviders
|
|
3988
|
+
* Creates Angular `EnvironmentProviders` that register the NgRx auth feature state and effects.
|
|
2772
3989
|
*
|
|
2773
|
-
* @
|
|
3990
|
+
* This provisions the `fromDbxAppAuth` feature reducer and the {@link DbxAppAuthEffects} effects class,
|
|
3991
|
+
* which together manage the auth user state (identifier, roles, onboarding status) in the NgRx store.
|
|
3992
|
+
*
|
|
3993
|
+
* Typically called internally by {@link provideDbxAppAuth}, but can be used independently
|
|
3994
|
+
* if only the state management (without router integration) is needed.
|
|
3995
|
+
*
|
|
3996
|
+
* @returns Angular `EnvironmentProviders` for the auth state feature.
|
|
3997
|
+
*
|
|
3998
|
+
* @see {@link DbxAppAuthEffects}
|
|
3999
|
+
* @see {@link fromDbxAppAuth}
|
|
2774
4000
|
*/
|
|
2775
4001
|
function provideDbxAppAuthState() {
|
|
2776
4002
|
return makeEnvironmentProviders([provideState(featureKey, reducers), provideEffects(DbxAppAuthEffects)]);
|
|
2777
4003
|
}
|
|
2778
4004
|
|
|
2779
4005
|
/**
|
|
2780
|
-
*
|
|
4006
|
+
* All-in-one provider function that registers the complete set of dbx-core auth providers.
|
|
2781
4007
|
*
|
|
2782
|
-
*
|
|
2783
|
-
* @
|
|
4008
|
+
* This is the recommended way to set up authentication in a dbx-core application. It provisions:
|
|
4009
|
+
* - The NgRx auth state and effects via {@link provideDbxAppAuthState}
|
|
4010
|
+
* - The auth router configuration via {@link provideDbxAppAuthRouter}
|
|
4011
|
+
* - The auth router state effects via {@link provideDbxAppAuthRouterState}
|
|
4012
|
+
*
|
|
4013
|
+
* @param config - Combined auth configuration including routes and active states for effects.
|
|
4014
|
+
* @returns Angular `EnvironmentProviders` to be included in the application's provider list.
|
|
4015
|
+
*
|
|
4016
|
+
* @example
|
|
4017
|
+
* ```ts
|
|
4018
|
+
* // In your app config or module:
|
|
4019
|
+
* provideDbxAppAuth({
|
|
4020
|
+
* dbxAppAuthRoutes: {
|
|
4021
|
+
* loginRef: '/login',
|
|
4022
|
+
* appRef: '/app'
|
|
4023
|
+
* },
|
|
4024
|
+
* activeRoutesToApplyEffects: ['root']
|
|
4025
|
+
* });
|
|
4026
|
+
* ```
|
|
4027
|
+
*
|
|
4028
|
+
* @see {@link provideDbxAppAuthState}
|
|
4029
|
+
* @see {@link provideDbxAppAuthRouter}
|
|
4030
|
+
* @see {@link provideDbxAppAuthRouterState}
|
|
2784
4031
|
*/
|
|
2785
4032
|
function provideDbxAppAuth(config) {
|
|
2786
4033
|
const { dbxAppAuthRoutes, activeRoutesToApplyEffects } = config;
|
|
@@ -2789,7 +4036,24 @@ function provideDbxAppAuth(config) {
|
|
|
2789
4036
|
}
|
|
2790
4037
|
|
|
2791
4038
|
/**
|
|
2792
|
-
* Structural
|
|
4039
|
+
* Structural directive that conditionally renders its host element based on whether
|
|
4040
|
+
* the currently authenticated user possesses **at least one** of the specified auth roles.
|
|
4041
|
+
*
|
|
4042
|
+
* Similar to `*ngIf`, this directive shows or hides content reactively as the user's
|
|
4043
|
+
* roles change. It uses {@link DbxAuthService.authRoles$} to observe the current role set
|
|
4044
|
+
* and checks that at least one role in the target list is present.
|
|
4045
|
+
*
|
|
4046
|
+
* @example
|
|
4047
|
+
* ```html
|
|
4048
|
+
* <!-- Show if user has either 'admin' or 'moderator' role -->
|
|
4049
|
+
* <div *dbxAuthHasAnyRole="['admin', 'moderator']">Privileged content</div>
|
|
4050
|
+
*
|
|
4051
|
+
* <!-- Show if user has the 'viewer' role -->
|
|
4052
|
+
* <div *dbxAuthHasAnyRole="'viewer'">Viewer content</div>
|
|
4053
|
+
* ```
|
|
4054
|
+
*
|
|
4055
|
+
* @see {@link DbxAuthHasRolesDirective} for requiring **all** specified roles.
|
|
4056
|
+
* @see {@link DbxAuthNotAnyRoleDirective} for excluding users with specified roles.
|
|
2793
4057
|
*/
|
|
2794
4058
|
class DbxAuthHasAnyRoleDirective extends AbstractIfDirective {
|
|
2795
4059
|
_authService = inject(DbxAuthService);
|
|
@@ -2808,7 +4072,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
2808
4072
|
}], propDecorators: { targetRoles: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxAuthHasAnyRole", required: false }] }] } });
|
|
2809
4073
|
|
|
2810
4074
|
/**
|
|
2811
|
-
* Structural
|
|
4075
|
+
* Structural directive that conditionally renders its host element based on whether
|
|
4076
|
+
* the currently authenticated user possesses **all** of the specified auth roles.
|
|
4077
|
+
*
|
|
4078
|
+
* Similar to `*ngIf`, this directive shows or hides content reactively as the user's
|
|
4079
|
+
* roles change. It uses {@link DbxAuthService.authRoles$} to observe the current role set
|
|
4080
|
+
* and checks that every role in the target list is present.
|
|
4081
|
+
*
|
|
4082
|
+
* @example
|
|
4083
|
+
* ```html
|
|
4084
|
+
* <!-- Show only if user has the 'admin' role -->
|
|
4085
|
+
* <div *dbxAuthHasRoles="'admin'">Admin-only content</div>
|
|
4086
|
+
*
|
|
4087
|
+
* <!-- Show only if user has BOTH 'editor' and 'reviewer' roles -->
|
|
4088
|
+
* <div *dbxAuthHasRoles="['editor', 'reviewer']">Editor and reviewer content</div>
|
|
4089
|
+
* ```
|
|
4090
|
+
*
|
|
4091
|
+
* @see {@link DbxAuthHasAnyRoleDirective} for matching **any** of the specified roles.
|
|
4092
|
+
* @see {@link DbxAuthNotAnyRoleDirective} for excluding users with specified roles.
|
|
2812
4093
|
*/
|
|
2813
4094
|
class DbxAuthHasRolesDirective extends AbstractIfDirective {
|
|
2814
4095
|
_authService = inject(DbxAuthService);
|
|
@@ -2827,7 +4108,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
2827
4108
|
}], propDecorators: { targetRoles: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxAuthHasRoles", required: false }] }] } });
|
|
2828
4109
|
|
|
2829
4110
|
/**
|
|
2830
|
-
* Structural
|
|
4111
|
+
* Structural directive that conditionally renders its host element based on whether
|
|
4112
|
+
* the currently authenticated user possesses **none** of the specified auth roles.
|
|
4113
|
+
*
|
|
4114
|
+
* This is the inverse of {@link DbxAuthHasAnyRoleDirective}. Content is shown only when
|
|
4115
|
+
* the user does not have any of the listed roles. Useful for hiding content from
|
|
4116
|
+
* privileged users or showing fallback UI for unprivileged users.
|
|
4117
|
+
*
|
|
4118
|
+
* @example
|
|
4119
|
+
* ```html
|
|
4120
|
+
* <!-- Show only if user does NOT have the 'admin' role -->
|
|
4121
|
+
* <div *dbxAuthNotAnyRole="'admin'">Non-admin content</div>
|
|
4122
|
+
*
|
|
4123
|
+
* <!-- Show only if user has NEITHER 'banned' nor 'suspended' role -->
|
|
4124
|
+
* <div *dbxAuthNotAnyRole="['banned', 'suspended']">Active user content</div>
|
|
4125
|
+
* ```
|
|
4126
|
+
*
|
|
4127
|
+
* @see {@link DbxAuthHasRolesDirective} for requiring **all** specified roles.
|
|
4128
|
+
* @see {@link DbxAuthHasAnyRoleDirective} for requiring **any** of the specified roles.
|
|
2831
4129
|
*/
|
|
2832
4130
|
class DbxAuthNotAnyRoleDirective extends AbstractIfDirective {
|
|
2833
4131
|
_authService = inject(DbxAuthService);
|
|
@@ -2846,10 +4144,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
2846
4144
|
}], propDecorators: { targetRoles: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxAuthNotAnyRole", required: false }] }] } });
|
|
2847
4145
|
|
|
2848
4146
|
/**
|
|
2849
|
-
*
|
|
4147
|
+
* Angular service that provides access to the current auth user state from the NgRx store.
|
|
4148
|
+
*
|
|
4149
|
+
* This service acts as a convenience wrapper around the NgRx store, exposing a selector
|
|
4150
|
+
* for the {@link DbxAppAuthStateUser} slice of the auth feature state. It is provided
|
|
4151
|
+
* at the root level and can be injected anywhere authentication state is needed.
|
|
4152
|
+
*
|
|
4153
|
+
* @example
|
|
4154
|
+
* ```ts
|
|
4155
|
+
* @Component({ ... })
|
|
4156
|
+
* export class MyComponent {
|
|
4157
|
+
* private readonly authStateService = inject(DbxAppAuthStateService);
|
|
4158
|
+
*
|
|
4159
|
+
* readonly user$ = this.authStateService.authStateUser$;
|
|
4160
|
+
* }
|
|
4161
|
+
* ```
|
|
4162
|
+
*
|
|
4163
|
+
* @see {@link DbxAppAuthFullState}
|
|
4164
|
+
* @see {@link fromDbxAppAuth.selectDbxAppAuthUser}
|
|
2850
4165
|
*/
|
|
2851
4166
|
class DbxAppAuthStateService {
|
|
4167
|
+
/** NgRx store instance typed to the full auth state. */
|
|
2852
4168
|
store = inject((Store));
|
|
4169
|
+
/** Observable of the current {@link DbxAppAuthStateUser} from the NgRx store. */
|
|
2853
4170
|
authStateUser$ = this.store.select(selectDbxAppAuthUser);
|
|
2854
4171
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: DbxAppAuthStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2855
4172
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: DbxAppAuthStateService, providedIn: 'root' });
|
|
@@ -2861,8 +4178,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
2861
4178
|
}]
|
|
2862
4179
|
}] });
|
|
2863
4180
|
|
|
4181
|
+
/**
|
|
4182
|
+
* Abstract base class defining the reactive interface for a button component.
|
|
4183
|
+
*
|
|
4184
|
+
* Provides observable streams for disabled state, working state, click events,
|
|
4185
|
+
* and display content. Implementations are provided via DI using {@link provideDbxButton}.
|
|
4186
|
+
*
|
|
4187
|
+
* @see {@link AbstractDbxButtonDirective} for the default implementation.
|
|
4188
|
+
* @see {@link DbxButtonDirective} for the concrete directive.
|
|
4189
|
+
*/
|
|
2864
4190
|
class DbxButton {
|
|
2865
4191
|
}
|
|
4192
|
+
/**
|
|
4193
|
+
* Creates Angular providers that register a {@link DbxButton} implementation for DI.
|
|
4194
|
+
*
|
|
4195
|
+
* @param sourceType - The concrete button directive or component class to provide.
|
|
4196
|
+
*
|
|
4197
|
+
* @example
|
|
4198
|
+
* ```typescript
|
|
4199
|
+
* @Directive({
|
|
4200
|
+
* selector: '[myCustomButton]',
|
|
4201
|
+
* providers: provideDbxButton(MyCustomButtonDirective),
|
|
4202
|
+
* })
|
|
4203
|
+
* export class MyCustomButtonDirective extends AbstractDbxButtonDirective {}
|
|
4204
|
+
* ```
|
|
4205
|
+
*/
|
|
2866
4206
|
function provideDbxButton(sourceType) {
|
|
2867
4207
|
return [
|
|
2868
4208
|
{
|
|
@@ -2872,17 +4212,31 @@ function provideDbxButton(sourceType) {
|
|
|
2872
4212
|
];
|
|
2873
4213
|
}
|
|
2874
4214
|
/**
|
|
2875
|
-
*
|
|
4215
|
+
* Determines whether a button display is an icon-only button or a text button.
|
|
2876
4216
|
*
|
|
2877
|
-
* @param content
|
|
2878
|
-
* @returns
|
|
4217
|
+
* @param content - The button display configuration to evaluate.
|
|
4218
|
+
* @returns `'icon_button'` if only an icon is set, otherwise `'text_button'`.
|
|
4219
|
+
*
|
|
4220
|
+
* @example
|
|
4221
|
+
* ```typescript
|
|
4222
|
+
* dbxButtonDisplayType({ icon: 'edit' }); // 'icon_button'
|
|
4223
|
+
* dbxButtonDisplayType({ icon: 'save', text: 'Save' }); // 'text_button'
|
|
4224
|
+
* ```
|
|
2879
4225
|
*/
|
|
2880
4226
|
function dbxButtonDisplayType(content) {
|
|
2881
4227
|
return !content.text && content.icon ? 'icon_button' : 'text_button';
|
|
2882
4228
|
}
|
|
2883
4229
|
|
|
2884
4230
|
/**
|
|
2885
|
-
*
|
|
4231
|
+
* Links a {@link DbxButton} click to an action context trigger, without synchronizing
|
|
4232
|
+
* disabled or working states. Use {@link DbxActionButtonDirective} for full state binding.
|
|
4233
|
+
*
|
|
4234
|
+
* @example
|
|
4235
|
+
* ```html
|
|
4236
|
+
* <div dbxAction>
|
|
4237
|
+
* <button dbxButton dbxActionButtonTrigger>Trigger Only</button>
|
|
4238
|
+
* </div>
|
|
4239
|
+
* ```
|
|
2886
4240
|
*/
|
|
2887
4241
|
class DbxActionButtonTriggerDirective {
|
|
2888
4242
|
dbxButton = inject(DbxButton, { host: true });
|
|
@@ -2907,7 +4261,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
2907
4261
|
}], ctorParameters: () => [] });
|
|
2908
4262
|
|
|
2909
4263
|
/**
|
|
2910
|
-
*
|
|
4264
|
+
* Links a {@link DbxButton} to an action context, synchronizing the button's
|
|
4265
|
+
* disabled and working states with the action's lifecycle and forwarding
|
|
4266
|
+
* button clicks as action triggers.
|
|
4267
|
+
*
|
|
4268
|
+
* Extends {@link DbxActionButtonTriggerDirective} by also binding working/disabled state.
|
|
4269
|
+
*
|
|
4270
|
+
* @example
|
|
4271
|
+
* ```html
|
|
4272
|
+
* <div dbxAction>
|
|
4273
|
+
* <button dbxButton dbxActionButton [text]="'Submit'">Submit</button>
|
|
4274
|
+
* </div>
|
|
4275
|
+
* ```
|
|
2911
4276
|
*/
|
|
2912
4277
|
class DbxActionButtonDirective extends DbxActionButtonTriggerDirective {
|
|
2913
4278
|
constructor() {
|
|
@@ -2931,6 +4296,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
2931
4296
|
}], ctorParameters: () => [] });
|
|
2932
4297
|
|
|
2933
4298
|
// MARK: Button Directives
|
|
4299
|
+
/**
|
|
4300
|
+
* Navigates to a route when the host {@link DbxButton} is clicked, using the provided {@link SegueRef}.
|
|
4301
|
+
*
|
|
4302
|
+
* @example
|
|
4303
|
+
* ```html
|
|
4304
|
+
* <button dbxButton [dbxButtonSegue]="{ ref: '/dashboard' }">Go to Dashboard</button>
|
|
4305
|
+
* ```
|
|
4306
|
+
*
|
|
4307
|
+
* @example
|
|
4308
|
+
* ```typescript
|
|
4309
|
+
* readonly segue: SegueRef = { ref: '/settings', refType: 'url' };
|
|
4310
|
+
* ```
|
|
4311
|
+
*
|
|
4312
|
+
* ```html
|
|
4313
|
+
* <button dbxButton [dbxButtonSegue]="segue">Settings</button>
|
|
4314
|
+
* ```
|
|
4315
|
+
*/
|
|
2934
4316
|
class DbxButtonSegueDirective {
|
|
2935
4317
|
dbxButton = inject(DbxButton);
|
|
2936
4318
|
dbxRouterService = inject(DbxRouterService);
|
|
@@ -2955,7 +4337,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
2955
4337
|
}], ctorParameters: () => [], propDecorators: { segueRef: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxButtonSegue", required: false }] }] } });
|
|
2956
4338
|
|
|
2957
4339
|
/**
|
|
2958
|
-
* Abstract
|
|
4340
|
+
* Abstract base directive implementing the {@link DbxButton} interface with signal-based state management.
|
|
4341
|
+
*
|
|
4342
|
+
* Manages disabled state, working/progress state, display content (icon/text),
|
|
4343
|
+
* and button click interception. Subclass this to create custom button directives.
|
|
4344
|
+
*
|
|
4345
|
+
* @example
|
|
4346
|
+
* ```typescript
|
|
4347
|
+
* @Directive({
|
|
4348
|
+
* selector: '[myButton]',
|
|
4349
|
+
* providers: provideDbxButton(MyButtonDirective),
|
|
4350
|
+
* })
|
|
4351
|
+
* export class MyButtonDirective extends AbstractDbxButtonDirective {}
|
|
4352
|
+
* ```
|
|
2959
4353
|
*/
|
|
2960
4354
|
class AbstractDbxButtonDirective {
|
|
2961
4355
|
/**
|
|
@@ -3046,7 +4440,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
3046
4440
|
}], ctorParameters: () => [], propDecorators: { buttonClick: [{ type: i0.Output, args: ["buttonClick"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], working: [{ type: i0.Input, args: [{ isSignal: true, alias: "working", required: false }] }], buttonDisplay: [{ type: i0.Input, args: [{ isSignal: true, alias: "buttonDisplay", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }] } });
|
|
3047
4441
|
// MARK: Implementation
|
|
3048
4442
|
/**
|
|
3049
|
-
*
|
|
4443
|
+
* Concrete button directive that provides a {@link DbxButton} instance via DI.
|
|
4444
|
+
*
|
|
4445
|
+
* Apply to any element to make it a managed button with reactive disabled,
|
|
4446
|
+
* working, and display state.
|
|
4447
|
+
*
|
|
4448
|
+
* @example
|
|
4449
|
+
* ```html
|
|
4450
|
+
* <button dbxButton [icon]="'save'" [text]="'Save'" [disabled]="isSaving">
|
|
4451
|
+
* Save
|
|
4452
|
+
* </button>
|
|
4453
|
+
* ```
|
|
4454
|
+
*
|
|
4455
|
+
* @example
|
|
4456
|
+
* ```html
|
|
4457
|
+
* <!-- Access the button instance via template reference: -->
|
|
4458
|
+
* <button dbxButton #btn="dbxButton" (click)="btn.clickButton()">Submit</button>
|
|
4459
|
+
* ```
|
|
3050
4460
|
*/
|
|
3051
4461
|
class DbxButtonDirective extends AbstractDbxButtonDirective {
|
|
3052
4462
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: DbxButtonDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
@@ -3063,9 +4473,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
3063
4473
|
}] });
|
|
3064
4474
|
|
|
3065
4475
|
/**
|
|
3066
|
-
*
|
|
4476
|
+
* Links a {@link DbxButton} to a {@link LoadingContext}, automatically setting the button
|
|
4477
|
+
* to a working state whenever the loading context is actively loading.
|
|
3067
4478
|
*
|
|
3068
|
-
*
|
|
4479
|
+
* @example
|
|
4480
|
+
* ```html
|
|
4481
|
+
* <button dbxButton [dbxLoadingButton]="loadingContext">
|
|
4482
|
+
* Loading...
|
|
4483
|
+
* </button>
|
|
4484
|
+
* ```
|
|
4485
|
+
*
|
|
4486
|
+
* @example
|
|
4487
|
+
* ```typescript
|
|
4488
|
+
* readonly loadingContext = cleanLoadingContext<MyData>(this.data$);
|
|
4489
|
+
* ```
|
|
3069
4490
|
*/
|
|
3070
4491
|
class DbxLoadingButtonDirective {
|
|
3071
4492
|
dbxButton = inject(DbxButton, { host: true });
|
|
@@ -3115,7 +4536,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
3115
4536
|
}] });
|
|
3116
4537
|
|
|
3117
4538
|
/**
|
|
3118
|
-
*
|
|
4539
|
+
* Service for dispatching and selecting the application's {@link DbxAppContextState} from the NgRx store.
|
|
4540
|
+
*
|
|
4541
|
+
* Provided at the root level. Use to transition between app-level context states
|
|
4542
|
+
* (e.g., public, auth, onboard, app).
|
|
4543
|
+
*
|
|
4544
|
+
* @example
|
|
4545
|
+
* ```typescript
|
|
4546
|
+
* @Component({ ... })
|
|
4547
|
+
* export class AppComponent {
|
|
4548
|
+
* private readonly contextService = inject(DbxAppContextService);
|
|
4549
|
+
*
|
|
4550
|
+
* onLogin(): void {
|
|
4551
|
+
* this.contextService.setState('app');
|
|
4552
|
+
* }
|
|
4553
|
+
* }
|
|
4554
|
+
* ```
|
|
3119
4555
|
*/
|
|
3120
4556
|
class DbxAppContextService {
|
|
3121
4557
|
store = inject((Store));
|
|
@@ -3137,7 +4573,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
3137
4573
|
}] });
|
|
3138
4574
|
|
|
3139
4575
|
/**
|
|
3140
|
-
*
|
|
4576
|
+
* Sets the application's {@link DbxAppContextState} when the input value changes.
|
|
4577
|
+
*
|
|
4578
|
+
* Dispatches to the NgRx store via {@link DbxAppContextService}. Commonly placed
|
|
4579
|
+
* on route-level components to declare which context the route belongs to.
|
|
4580
|
+
*
|
|
4581
|
+
* @example
|
|
4582
|
+
* ```html
|
|
4583
|
+
* <div [dbxAppContextState]="'app'">
|
|
4584
|
+
* <!-- App-level content rendered when context is 'app' -->
|
|
4585
|
+
* </div>
|
|
4586
|
+
* ```
|
|
4587
|
+
*
|
|
4588
|
+
* @example
|
|
4589
|
+
* ```html
|
|
4590
|
+
* <router-outlet dbxAppContextState="public"></router-outlet>
|
|
4591
|
+
* ```
|
|
3141
4592
|
*/
|
|
3142
4593
|
class DbxAppContextStateDirective {
|
|
3143
4594
|
dbxAppContextStateService = inject(DbxAppContextService);
|
|
@@ -3169,13 +4620,42 @@ function provideDbxAppContextState() {
|
|
|
3169
4620
|
}
|
|
3170
4621
|
|
|
3171
4622
|
/**
|
|
3172
|
-
*
|
|
4623
|
+
* Abstract token class representing the application's runtime environment configuration.
|
|
4624
|
+
*
|
|
4625
|
+
* Provided via DI using {@link provideDbxAppEnviroment} and accessed through {@link DbxAppEnviromentService}.
|
|
4626
|
+
* Subclass or provide a concrete instance to define environment-specific flags.
|
|
4627
|
+
*
|
|
4628
|
+
* @example
|
|
4629
|
+
* ```typescript
|
|
4630
|
+
* const env: DbxAppEnviroment = {
|
|
4631
|
+
* production: false,
|
|
4632
|
+
* testing: true,
|
|
4633
|
+
* };
|
|
4634
|
+
*
|
|
4635
|
+
* // In app config:
|
|
4636
|
+
* provideDbxAppEnviroment(env);
|
|
4637
|
+
* ```
|
|
3173
4638
|
*/
|
|
3174
4639
|
class DbxAppEnviroment {
|
|
3175
4640
|
}
|
|
3176
4641
|
|
|
3177
4642
|
/**
|
|
3178
|
-
*
|
|
4643
|
+
* Injectable service providing convenience accessors for the application's {@link DbxAppEnviroment}.
|
|
4644
|
+
*
|
|
4645
|
+
* Exposes computed properties for common environment checks (production, staging, testing)
|
|
4646
|
+
* and a typed getter for accessing custom environment properties.
|
|
4647
|
+
*
|
|
4648
|
+
* @example
|
|
4649
|
+
* ```typescript
|
|
4650
|
+
* @Component({ ... })
|
|
4651
|
+
* export class MyComponent {
|
|
4652
|
+
* private readonly envService = inject(DbxAppEnviromentService);
|
|
4653
|
+
*
|
|
4654
|
+
* get showDebugPanel(): boolean {
|
|
4655
|
+
* return !this.envService.isProduction;
|
|
4656
|
+
* }
|
|
4657
|
+
* }
|
|
4658
|
+
* ```
|
|
3179
4659
|
*/
|
|
3180
4660
|
class DbxAppEnviromentService {
|
|
3181
4661
|
environment = inject(DbxAppEnviroment);
|
|
@@ -3202,9 +4682,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
3202
4682
|
}] });
|
|
3203
4683
|
|
|
3204
4684
|
/**
|
|
3205
|
-
*
|
|
4685
|
+
* Registers {@link DbxAppEnviroment} and {@link DbxAppEnviromentService} as environment-level providers.
|
|
4686
|
+
*
|
|
4687
|
+
* @param environment - The concrete environment configuration to provide.
|
|
3206
4688
|
*
|
|
3207
|
-
* @
|
|
4689
|
+
* @example
|
|
4690
|
+
* ```typescript
|
|
4691
|
+
* // In app.config.ts:
|
|
4692
|
+
* export const appConfig: ApplicationConfig = {
|
|
4693
|
+
* providers: [
|
|
4694
|
+
* provideDbxAppEnviroment({ production: true, staging: false }),
|
|
4695
|
+
* ],
|
|
4696
|
+
* };
|
|
4697
|
+
* ```
|
|
3208
4698
|
*/
|
|
3209
4699
|
function provideDbxAppEnviroment(environment) {
|
|
3210
4700
|
const providers = [
|
|
@@ -3217,10 +4707,21 @@ function provideDbxAppEnviroment(environment) {
|
|
|
3217
4707
|
return makeEnvironmentProviders(providers);
|
|
3218
4708
|
}
|
|
3219
4709
|
|
|
4710
|
+
/**
|
|
4711
|
+
* Function that expands a single {@link ClickableAnchorLinkTree} node into a tree of {@link ExpandedClickableAnchorLinkTree} nodes.
|
|
4712
|
+
*
|
|
4713
|
+
* @see {@link expandClickableAnchorLinkTree} for the full expand-and-flatten operation
|
|
4714
|
+
*/
|
|
3220
4715
|
const expandClickableAnchorLinkTreeNode = expandTreeFunction({
|
|
3221
4716
|
getChildren: (x) => x.children
|
|
3222
4717
|
});
|
|
4718
|
+
/**
|
|
4719
|
+
* Flattens an expanded tree of {@link ExpandedClickableAnchorLinkTree} nodes into a flat array, preserving the tree node wrappers.
|
|
4720
|
+
*/
|
|
3223
4721
|
const flattenExpandedClickableAnchorLinkTree = flattenTreeToArrayFunction();
|
|
4722
|
+
/**
|
|
4723
|
+
* Flattens an expanded tree of {@link ExpandedClickableAnchorLinkTree} nodes into a flat array of the underlying {@link ClickableAnchorLinkTree} values.
|
|
4724
|
+
*/
|
|
3224
4725
|
const flattenExpandedClickableAnchorLinkTreeToLinks = flattenTreeToArrayFunction((x) => x.value);
|
|
3225
4726
|
/**
|
|
3226
4727
|
* Fully expands the given parent link and flattens the tree to a single parent link.
|
|
@@ -3235,6 +4736,15 @@ function expandClickableAnchorLinkTree(link) {
|
|
|
3235
4736
|
* Expands an array of links into an array of ExpandedClickableAnchorLinkTree tree values.
|
|
3236
4737
|
*/
|
|
3237
4738
|
const expandClickableAnchorLinkTrees = expandFlattenTreeFunction(expandClickableAnchorLinkTreeNode, flattenExpandedClickableAnchorLinkTree);
|
|
4739
|
+
/**
|
|
4740
|
+
* Determines the {@link ClickableAnchorType} for a given anchor based on its properties.
|
|
4741
|
+
*
|
|
4742
|
+
* Priority order: disabled > sref (router link) > clickable (onClick handler) > href (external URL) > plain.
|
|
4743
|
+
*
|
|
4744
|
+
* @param anchor - The anchor to evaluate.
|
|
4745
|
+
* @param disabled - An optional external disabled override; if `true`, the anchor type will be `'disabled'` regardless of the anchor's own state.
|
|
4746
|
+
* @returns The determined {@link ClickableAnchorType}.
|
|
4747
|
+
*/
|
|
3238
4748
|
function anchorTypeForAnchor(anchor, disabled) {
|
|
3239
4749
|
let type = 'disabled';
|
|
3240
4750
|
if (!disabled && anchor) {
|
|
@@ -3256,8 +4766,45 @@ function anchorTypeForAnchor(anchor, disabled) {
|
|
|
3256
4766
|
}
|
|
3257
4767
|
return type;
|
|
3258
4768
|
}
|
|
4769
|
+
/**
|
|
4770
|
+
* Abstract base class representing a reactive anchor element that exposes its state as observables.
|
|
4771
|
+
*
|
|
4772
|
+
* Subclasses provide concrete implementations that manage the anchor's disabled, selected, and type states.
|
|
4773
|
+
*
|
|
4774
|
+
* @typeParam T - The specific anchor type, defaulting to {@link ClickableAnchor}.
|
|
4775
|
+
*
|
|
4776
|
+
* @example
|
|
4777
|
+
* ```ts
|
|
4778
|
+
* @Component({ ... })
|
|
4779
|
+
* class MyAnchorComponent extends DbxAnchor {
|
|
4780
|
+
* readonly disabled$ = of(false);
|
|
4781
|
+
* readonly selected$ = of(true);
|
|
4782
|
+
* readonly anchor$ = of({ ref: 'app.home' });
|
|
4783
|
+
* readonly type$ = of('sref' as ClickableAnchorType);
|
|
4784
|
+
* }
|
|
4785
|
+
* ```
|
|
4786
|
+
*
|
|
4787
|
+
* @see {@link provideDbxAnchor} for configuring DI providers
|
|
4788
|
+
* @see {@link AbstractDbxAnchorDirective} for the directive-based implementation
|
|
4789
|
+
*/
|
|
3259
4790
|
class DbxAnchor {
|
|
3260
4791
|
}
|
|
4792
|
+
/**
|
|
4793
|
+
* Creates Angular DI providers that register the given source type as a {@link DbxAnchor} provider using `forwardRef`.
|
|
4794
|
+
*
|
|
4795
|
+
* @typeParam S - The concrete {@link DbxAnchor} subclass to provide.
|
|
4796
|
+
* @param sourceType - The class type to register as the anchor provider.
|
|
4797
|
+
* @returns An array of Angular providers.
|
|
4798
|
+
*
|
|
4799
|
+
* @example
|
|
4800
|
+
* ```ts
|
|
4801
|
+
* @Directive({
|
|
4802
|
+
* selector: '[myAnchor]',
|
|
4803
|
+
* providers: provideDbxAnchor(MyAnchorDirective)
|
|
4804
|
+
* })
|
|
4805
|
+
* class MyAnchorDirective extends DbxAnchor { ... }
|
|
4806
|
+
* ```
|
|
4807
|
+
*/
|
|
3261
4808
|
function provideDbxAnchor(sourceType) {
|
|
3262
4809
|
return [
|
|
3263
4810
|
{
|
|
@@ -3268,13 +4815,41 @@ function provideDbxAnchor(sourceType) {
|
|
|
3268
4815
|
}
|
|
3269
4816
|
|
|
3270
4817
|
/**
|
|
3271
|
-
* Abstract anchor
|
|
4818
|
+
* Abstract base directive for managing anchor state using Angular signals and model inputs.
|
|
4819
|
+
*
|
|
4820
|
+
* Provides reactive computed properties for the resolved anchor, its disabled/selected state, and its type.
|
|
4821
|
+
* Subclasses can extend this to implement framework-specific anchor rendering (e.g., UIRouter or Angular Router).
|
|
4822
|
+
*
|
|
4823
|
+
* @typeParam T - The specific anchor type, defaulting to {@link ClickableAnchor}.
|
|
4824
|
+
*
|
|
4825
|
+
* @example
|
|
4826
|
+
* ```html
|
|
4827
|
+
* <!-- Usage in a template via a concrete subclass -->
|
|
4828
|
+
* <my-anchor [ref]="'/app/dashboard'" [disabled]="isDisabled">
|
|
4829
|
+
* Dashboard
|
|
4830
|
+
* </my-anchor>
|
|
4831
|
+
* ```
|
|
4832
|
+
*
|
|
4833
|
+
* @example
|
|
4834
|
+
* ```ts
|
|
4835
|
+
* // Programmatic usage
|
|
4836
|
+
* directive.setRef('app.dashboard');
|
|
4837
|
+
* directive.setDisabled(true);
|
|
4838
|
+
* ```
|
|
4839
|
+
*
|
|
4840
|
+
* @see {@link DbxAnchor} for the abstract base class this implements
|
|
4841
|
+
* @see {@link anchorTypeForAnchor} for anchor type resolution logic
|
|
3272
4842
|
*/
|
|
3273
4843
|
class AbstractDbxAnchorDirective {
|
|
4844
|
+
/** Model input for the segue ref or router link to navigate to. */
|
|
3274
4845
|
ref = model(...(ngDevMode ? [undefined, { debugName: "ref" }] : []));
|
|
4846
|
+
/** Model input for the full anchor configuration object. */
|
|
3275
4847
|
anchor = model(...(ngDevMode ? [undefined, { debugName: "anchor" }] : []));
|
|
4848
|
+
/** Model input for externally controlling the disabled state. */
|
|
3276
4849
|
disabled = model(...(ngDevMode ? [undefined, { debugName: "disabled" }] : []));
|
|
4850
|
+
/** Model input for externally controlling the selected state. */
|
|
3277
4851
|
selected = model(...(ngDevMode ? [undefined, { debugName: "selected" }] : []));
|
|
4852
|
+
/** Computed anchor that merges the `ref` input with the `anchor` input, preferring `ref` when set. */
|
|
3278
4853
|
anchorSignal = computed(() => {
|
|
3279
4854
|
const ref = this.ref();
|
|
3280
4855
|
const anchor = this.anchor();
|
|
@@ -3284,37 +4859,46 @@ class AbstractDbxAnchorDirective {
|
|
|
3284
4859
|
}
|
|
3285
4860
|
return result;
|
|
3286
4861
|
}, ...(ngDevMode ? [{ debugName: "anchorSignal" }] : []));
|
|
4862
|
+
/** Computed selected state that combines the `selected` input with the anchor's own `selected` property. */
|
|
3287
4863
|
selectedSignal = computed(() => {
|
|
3288
4864
|
const selected = this.selected();
|
|
3289
4865
|
const anchor = this.anchorSignal();
|
|
3290
4866
|
return selected || anchor?.selected;
|
|
3291
4867
|
}, ...(ngDevMode ? [{ debugName: "selectedSignal" }] : []));
|
|
4868
|
+
/** Computed {@link ClickableAnchorType} derived from the current anchor and disabled state. */
|
|
3292
4869
|
typeSignal = computed(() => {
|
|
3293
4870
|
const anchor = this.anchorSignal();
|
|
3294
4871
|
const disabled = this.disabled();
|
|
3295
4872
|
return anchorTypeForAnchor(anchor, disabled);
|
|
3296
4873
|
}, ...(ngDevMode ? [{ debugName: "typeSignal" }] : []));
|
|
4874
|
+
/** Computed disabled state that combines the `disabled` input with the anchor's own `disabled` property. */
|
|
3297
4875
|
disabledSignal = computed(() => {
|
|
3298
4876
|
const disabled = this.disabled();
|
|
3299
4877
|
const anchor = this.anchorSignal();
|
|
3300
4878
|
return disabled || anchor?.disabled;
|
|
3301
4879
|
}, ...(ngDevMode ? [{ debugName: "disabledSignal" }] : []));
|
|
4880
|
+
/** Computed URL extracted from the current anchor's `url` property. */
|
|
3302
4881
|
urlSignal = computed(() => this.anchorSignal()?.url, ...(ngDevMode ? [{ debugName: "urlSignal" }] : []));
|
|
4882
|
+
/** Computed target (e.g., `_blank`) extracted from the current anchor's `target` property. */
|
|
3303
4883
|
targetSignal = computed(() => this.anchorSignal()?.target, ...(ngDevMode ? [{ debugName: "targetSignal" }] : []));
|
|
3304
4884
|
anchor$ = toObservable(this.anchorSignal);
|
|
3305
4885
|
disabled$ = toObservable(this.disabledSignal);
|
|
3306
4886
|
selected$ = toObservable(this.selectedSignal);
|
|
3307
4887
|
type$ = toObservable(this.typeSignal);
|
|
3308
4888
|
// MARK: Accessors
|
|
4889
|
+
/** Sets the segue ref or router link for this anchor. */
|
|
3309
4890
|
setRef(ref) {
|
|
3310
4891
|
this.ref.set(ref);
|
|
3311
4892
|
}
|
|
4893
|
+
/** Sets the full anchor configuration object. */
|
|
3312
4894
|
setAnchor(anchor) {
|
|
3313
4895
|
this.anchor.set(anchor);
|
|
3314
4896
|
}
|
|
4897
|
+
/** Sets the external disabled state override. */
|
|
3315
4898
|
setDisabled(disabled) {
|
|
3316
4899
|
this.disabled.set(disabled);
|
|
3317
4900
|
}
|
|
4901
|
+
/** Sets the external selected state override. */
|
|
3318
4902
|
setSelected(selected) {
|
|
3319
4903
|
this.selected.set(selected);
|
|
3320
4904
|
}
|
|
@@ -3325,27 +4909,65 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
3325
4909
|
type: Directive
|
|
3326
4910
|
}], propDecorators: { ref: [{ type: i0.Input, args: [{ isSignal: true, alias: "ref", required: false }] }, { type: i0.Output, args: ["refChange"] }], anchor: [{ type: i0.Input, args: [{ isSignal: true, alias: "anchor", required: false }] }, { type: i0.Output, args: ["anchorChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }, { type: i0.Output, args: ["selectedChange"] }] } });
|
|
3327
4911
|
|
|
4912
|
+
/**
|
|
4913
|
+
* Creates a {@link ClickableUrl} configured to open the given URL in a new browser tab (`target="_blank"`).
|
|
4914
|
+
*
|
|
4915
|
+
* @param url - The URL to open.
|
|
4916
|
+
* @returns A {@link ClickableUrl} with the `target` set to `'_blank'`.
|
|
4917
|
+
*/
|
|
3328
4918
|
function clickableUrlInNewTab(url) {
|
|
3329
4919
|
return {
|
|
3330
4920
|
url,
|
|
3331
4921
|
target: '_blank'
|
|
3332
4922
|
};
|
|
3333
4923
|
}
|
|
4924
|
+
/**
|
|
4925
|
+
* Creates a {@link ClickableUrl} with a `mailto:` URL from the given email configuration.
|
|
4926
|
+
*
|
|
4927
|
+
* @param mailTo - The mail-to configuration (email address, subject, body, etc.).
|
|
4928
|
+
* @returns A {@link ClickableUrl} with the URL set to a `mailto:` link.
|
|
4929
|
+
*
|
|
4930
|
+
* @see {@link mailToUrlString}
|
|
4931
|
+
*/
|
|
3334
4932
|
function clickableUrlMailTo(mailTo) {
|
|
3335
4933
|
return {
|
|
3336
4934
|
url: mailToUrlString(mailTo)
|
|
3337
4935
|
};
|
|
3338
4936
|
}
|
|
4937
|
+
/**
|
|
4938
|
+
* Creates a {@link ClickableUrl} with a `tel:` URL from the given phone number.
|
|
4939
|
+
*
|
|
4940
|
+
* @param tel - The phone number to create a tel link for.
|
|
4941
|
+
* @returns A {@link ClickableUrl} with the URL set to a `tel:` link.
|
|
4942
|
+
*
|
|
4943
|
+
* @see {@link telUrlString}
|
|
4944
|
+
*/
|
|
3339
4945
|
function clickableUrlTel(tel) {
|
|
3340
4946
|
return {
|
|
3341
4947
|
url: telUrlString(tel)
|
|
3342
4948
|
};
|
|
3343
4949
|
}
|
|
3344
4950
|
|
|
4951
|
+
/**
|
|
4952
|
+
* Default param value that indicates no specific identifier has been set, triggering a redirect to the default allowed identifier.
|
|
4953
|
+
*/
|
|
3345
4954
|
const DEFAULT_REDIRECT_FOR_IDENTIFIER_PARAM_VALUE = '0';
|
|
4955
|
+
/**
|
|
4956
|
+
* Default route parameter key used to read the model identifier from the URL.
|
|
4957
|
+
*/
|
|
3346
4958
|
const DEFAULT_REDIRECT_FOR_IDENTIFIER_PARAM_KEY = 'id';
|
|
3347
4959
|
/**
|
|
3348
|
-
*
|
|
4960
|
+
* Registers a UIRouter transition hook that asserts the user is allowed to view a route with an identifier as a state parameter.
|
|
4961
|
+
*
|
|
4962
|
+
* When a transition occurs to the target route:
|
|
4963
|
+
* 1. If the identifier param is missing or equals the default placeholder value, it redirects to the default allowed identifier.
|
|
4964
|
+
* 2. If the identifier differs from the default, it calls `canViewModelWithId` to verify access.
|
|
4965
|
+
* 3. If access is denied, it redirects to the default allowed identifier.
|
|
4966
|
+
*
|
|
4967
|
+
* @param input - Configuration specifying the route criteria, param key, and access control logic.
|
|
4968
|
+
*
|
|
4969
|
+
* @see {@link RedirectForIdentifierParamHookInput}
|
|
4970
|
+
* @see {@link redirectForUserIdentifierParamHook} for a user-specific convenience wrapper
|
|
3349
4971
|
*/
|
|
3350
4972
|
function redirectForIdentifierParamHook(input) {
|
|
3351
4973
|
const { defaultAllowedValue, idParam = DEFAULT_REDIRECT_FOR_IDENTIFIER_PARAM_KEY, defaultParamValue = DEFAULT_REDIRECT_FOR_IDENTIFIER_PARAM_VALUE, priority = 100, transitionService, canViewModelWithId: canViewUser } = input;
|
|
@@ -3394,10 +5016,25 @@ function redirectForIdentifierParamHook(input) {
|
|
|
3394
5016
|
transitionService.onBefore(criteria, assertAllowedId, { priority });
|
|
3395
5017
|
}
|
|
3396
5018
|
|
|
5019
|
+
/**
|
|
5020
|
+
* Default param value that indicates no specific user identifier has been set, triggering a redirect to the authenticated user's identifier.
|
|
5021
|
+
*/
|
|
3397
5022
|
const DEFAULT_REDIRECT_FOR_USER_IDENTIFIER_PARAM_VALUE = '0';
|
|
5023
|
+
/**
|
|
5024
|
+
* Default route parameter key used to read the user identifier from the URL.
|
|
5025
|
+
*/
|
|
3398
5026
|
const DEFAULT_REDIRECT_FOR_USER_IDENTIFIER_PARAM_KEY = 'uid';
|
|
3399
5027
|
/**
|
|
3400
|
-
*
|
|
5028
|
+
* Registers a UIRouter transition hook that asserts the current user is allowed to view a route parameterized by a user identifier.
|
|
5029
|
+
*
|
|
5030
|
+
* This is a convenience wrapper around {@link redirectForIdentifierParamHook} that automatically uses the
|
|
5031
|
+
* authenticated user's identifier from {@link DbxAuthService} as the default value when the `uid` param is
|
|
5032
|
+
* missing or matches the placeholder value.
|
|
5033
|
+
*
|
|
5034
|
+
* @param input - Configuration specifying the route criteria, access control logic, and optional parameter overrides.
|
|
5035
|
+
*
|
|
5036
|
+
* @see {@link RedirectForUserIdentifierParamHookInput}
|
|
5037
|
+
* @see {@link redirectForIdentifierParamHook}
|
|
3401
5038
|
*/
|
|
3402
5039
|
function redirectForUserIdentifierParamHook(input) {
|
|
3403
5040
|
const { uidParam = DEFAULT_REDIRECT_FOR_USER_IDENTIFIER_PARAM_KEY, defaultParamValue = DEFAULT_REDIRECT_FOR_USER_IDENTIFIER_PARAM_VALUE, criteria, priority = 100, transitionService, canViewUser } = input;
|
|
@@ -3412,6 +5049,14 @@ function redirectForUserIdentifierParamHook(input) {
|
|
|
3412
5049
|
});
|
|
3413
5050
|
}
|
|
3414
5051
|
|
|
5052
|
+
/**
|
|
5053
|
+
* Enum describing the type of a router transition event.
|
|
5054
|
+
*
|
|
5055
|
+
* Used by {@link DbxRouterTransitionEvent} to categorize transition lifecycle events.
|
|
5056
|
+
*
|
|
5057
|
+
* @see {@link DbxRouterTransitionEvent}
|
|
5058
|
+
* @see {@link DbxRouterTransitionService}
|
|
5059
|
+
*/
|
|
3415
5060
|
var DbxRouterTransitionEventType;
|
|
3416
5061
|
(function (DbxRouterTransitionEventType) {
|
|
3417
5062
|
/**
|
|
@@ -3425,7 +5070,24 @@ var DbxRouterTransitionEventType;
|
|
|
3425
5070
|
})(DbxRouterTransitionEventType || (DbxRouterTransitionEventType = {}));
|
|
3426
5071
|
|
|
3427
5072
|
/**
|
|
3428
|
-
*
|
|
5073
|
+
* Angular Router implementation of {@link DbxRouterService} and {@link DbxRouterTransitionService}.
|
|
5074
|
+
*
|
|
5075
|
+
* Maps Angular Router's `NavigationStart` and `NavigationEnd` events to {@link DbxRouterTransitionEvent} values
|
|
5076
|
+
* and provides navigation via Angular's `Router.navigate()` and `Router.navigateByUrl()` methods.
|
|
5077
|
+
*
|
|
5078
|
+
* @example
|
|
5079
|
+
* ```ts
|
|
5080
|
+
* // Register via the module
|
|
5081
|
+
* DbxCoreAngularRouterSegueModule.forRoot()
|
|
5082
|
+
*
|
|
5083
|
+
* // Or inject directly
|
|
5084
|
+
* const router = inject(DbxRouterService);
|
|
5085
|
+
* await router.go({ ref: '/dashboard' });
|
|
5086
|
+
* ```
|
|
5087
|
+
*
|
|
5088
|
+
* @see {@link DbxRouterService}
|
|
5089
|
+
* @see {@link DbxCoreAngularRouterSegueModule} for module-based registration
|
|
5090
|
+
* @see {@link DbxUIRouterService} for the UIRouter alternative
|
|
3429
5091
|
*/
|
|
3430
5092
|
class DbxAngularRouterService {
|
|
3431
5093
|
router = inject(Router);
|
|
@@ -3493,6 +5155,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
3493
5155
|
type: Injectable
|
|
3494
5156
|
}] });
|
|
3495
5157
|
|
|
5158
|
+
/**
|
|
5159
|
+
* NgModule that provides the Angular Router-based implementation of {@link DbxRouterService} and {@link DbxRouterTransitionService}.
|
|
5160
|
+
*
|
|
5161
|
+
* Use `forRoot()` to register the providers at the application root level.
|
|
5162
|
+
*
|
|
5163
|
+
* @example
|
|
5164
|
+
* ```ts
|
|
5165
|
+
* @NgModule({
|
|
5166
|
+
* imports: [
|
|
5167
|
+
* DbxCoreAngularRouterSegueModule.forRoot()
|
|
5168
|
+
* ]
|
|
5169
|
+
* })
|
|
5170
|
+
* export class AppModule {}
|
|
5171
|
+
* ```
|
|
5172
|
+
*
|
|
5173
|
+
* @see {@link DbxAngularRouterService} for the underlying service implementation
|
|
5174
|
+
* @see {@link provideDbxUIRouterService} for the UIRouter alternative
|
|
5175
|
+
*/
|
|
3496
5176
|
class DbxCoreAngularRouterSegueModule {
|
|
3497
5177
|
static forRoot() {
|
|
3498
5178
|
return {
|
|
@@ -3520,7 +5200,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
3520
5200
|
}] });
|
|
3521
5201
|
|
|
3522
5202
|
/**
|
|
3523
|
-
* UIRouter implementation of DbxRouterService and DbxRouterTransitionService.
|
|
5203
|
+
* UIRouter implementation of {@link DbxRouterService} and {@link DbxRouterTransitionService}.
|
|
5204
|
+
*
|
|
5205
|
+
* Bridges UIRouter's `TransitionService` events to {@link DbxRouterTransitionEvent} values and provides
|
|
5206
|
+
* navigation via UIRouter's `StateService.go()`. Supports state activity checks and route precision comparison.
|
|
5207
|
+
*
|
|
5208
|
+
* @example
|
|
5209
|
+
* ```ts
|
|
5210
|
+
* // Register via the provider function
|
|
5211
|
+
* provideDbxUIRouterService()
|
|
5212
|
+
*
|
|
5213
|
+
* // Or inject and use
|
|
5214
|
+
* const router = inject(DbxRouterService);
|
|
5215
|
+
* await router.go({ ref: 'app.dashboard', refParams: { id: '123' } });
|
|
5216
|
+
* ```
|
|
5217
|
+
*
|
|
5218
|
+
* @see {@link DbxRouterService}
|
|
5219
|
+
* @see {@link provideDbxUIRouterService} for provider registration
|
|
5220
|
+
* @see {@link DbxAngularRouterService} for the Angular Router alternative
|
|
3524
5221
|
*/
|
|
3525
5222
|
class DbxUIRouterService {
|
|
3526
5223
|
state = inject(StateService);
|
|
@@ -3607,9 +5304,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
3607
5304
|
}], ctorParameters: () => [] });
|
|
3608
5305
|
|
|
3609
5306
|
/**
|
|
3610
|
-
*
|
|
5307
|
+
* Creates Angular environment providers that register {@link DbxUIRouterService} as the implementation
|
|
5308
|
+
* for both {@link DbxRouterService} and {@link DbxRouterTransitionService}.
|
|
3611
5309
|
*
|
|
3612
|
-
*
|
|
5310
|
+
* Use this function in the application's `bootstrapApplication` or `provideRouter` configuration
|
|
5311
|
+
* when using UIRouter as the routing framework.
|
|
5312
|
+
*
|
|
5313
|
+
* @returns Angular `EnvironmentProviders` for the UIRouter-based router service.
|
|
5314
|
+
*
|
|
5315
|
+
* @example
|
|
5316
|
+
* ```ts
|
|
5317
|
+
* bootstrapApplication(AppComponent, {
|
|
5318
|
+
* providers: [
|
|
5319
|
+
* provideDbxUIRouterService()
|
|
5320
|
+
* ]
|
|
5321
|
+
* });
|
|
5322
|
+
* ```
|
|
5323
|
+
*
|
|
5324
|
+
* @see {@link DbxUIRouterService}
|
|
5325
|
+
* @see {@link DbxCoreAngularRouterSegueModule} for the Angular Router alternative
|
|
3613
5326
|
*/
|
|
3614
5327
|
function provideDbxUIRouterService() {
|
|
3615
5328
|
const providers = [
|
|
@@ -3627,26 +5340,49 @@ function provideDbxUIRouterService() {
|
|
|
3627
5340
|
}
|
|
3628
5341
|
|
|
3629
5342
|
/**
|
|
3630
|
-
*
|
|
5343
|
+
* Filters the given transition event observable to only emit successful transitions.
|
|
3631
5344
|
*
|
|
3632
|
-
* @
|
|
3633
|
-
*
|
|
5345
|
+
* Convenience function equivalent to applying {@link filterTransitionSuccess} as a pipe operator.
|
|
5346
|
+
*
|
|
5347
|
+
* @param obs - The source observable of router transition events.
|
|
5348
|
+
* @returns An observable that emits only successful transition events.
|
|
5349
|
+
*
|
|
5350
|
+
* @see {@link filterTransitionSuccess}
|
|
3634
5351
|
*/
|
|
3635
5352
|
function successTransition(obs) {
|
|
3636
5353
|
return obs.pipe(filterTransitionSuccess());
|
|
3637
5354
|
}
|
|
5355
|
+
/**
|
|
5356
|
+
* RxJS operator that filters transition events to only pass through successful transitions.
|
|
5357
|
+
*
|
|
5358
|
+
* @returns A `MonoTypeOperatorFunction` that filters for {@link DbxRouterTransitionEventType.SUCCESS} events.
|
|
5359
|
+
*
|
|
5360
|
+
* @see {@link filterTransitionEvent}
|
|
5361
|
+
*/
|
|
3638
5362
|
function filterTransitionSuccess() {
|
|
3639
5363
|
return filterTransitionEvent(DbxRouterTransitionEventType.SUCCESS);
|
|
3640
5364
|
}
|
|
5365
|
+
/**
|
|
5366
|
+
* RxJS operator that filters transition events to only pass through events of the specified type.
|
|
5367
|
+
*
|
|
5368
|
+
* @param type - The transition event type to filter for.
|
|
5369
|
+
* @returns A `MonoTypeOperatorFunction` that only passes matching events.
|
|
5370
|
+
*/
|
|
3641
5371
|
function filterTransitionEvent(type) {
|
|
3642
5372
|
return filter((x) => x.type === type);
|
|
3643
5373
|
}
|
|
3644
5374
|
/**
|
|
3645
|
-
* Creates
|
|
5375
|
+
* Creates an observable that emits the list of currently active routes after each successful transition.
|
|
3646
5376
|
*
|
|
3647
|
-
*
|
|
3648
|
-
*
|
|
3649
|
-
*
|
|
5377
|
+
* On each successful router transition, checks all configured routes against the router service
|
|
5378
|
+
* and emits an array of those that are active. The result is deduplicated by index and shared.
|
|
5379
|
+
*
|
|
5380
|
+
* @typeParam T - The route configuration type, extending {@link LatestSuccessfulRoutesConfigRoute}.
|
|
5381
|
+
* @param config - Configuration specifying the router services and routes to monitor.
|
|
5382
|
+
* @returns An observable emitting an array of the currently active route configurations.
|
|
5383
|
+
*
|
|
5384
|
+
* @see {@link LatestSuccessfulRoutesConfig}
|
|
5385
|
+
* @see {@link isLatestSuccessfulRoute} for a boolean variant
|
|
3650
5386
|
*/
|
|
3651
5387
|
function latestSuccessfulRoutes(config) {
|
|
3652
5388
|
const { dbxRouterTransitionService, dbxRouterService, routes: inputRoutes } = config;
|
|
@@ -3661,11 +5397,16 @@ function latestSuccessfulRoutes(config) {
|
|
|
3661
5397
|
}), distinctUntilKeysChange((x) => x.i), map((x) => x.map((y) => y.r)), shareReplay(1));
|
|
3662
5398
|
}
|
|
3663
5399
|
/**
|
|
3664
|
-
* Creates
|
|
5400
|
+
* Creates an observable that emits `true` when any of the configured routes are active after a successful transition,
|
|
5401
|
+
* and `false` otherwise.
|
|
3665
5402
|
*
|
|
3666
|
-
* @
|
|
3667
|
-
*
|
|
3668
|
-
* @
|
|
5403
|
+
* This is a simplified boolean variant of {@link latestSuccessfulRoutes}.
|
|
5404
|
+
*
|
|
5405
|
+
* @param config - Configuration specifying the router services, routes, and match mode.
|
|
5406
|
+
* @returns An observable emitting `true` when at least one configured route is active, `false` otherwise.
|
|
5407
|
+
*
|
|
5408
|
+
* @see {@link IsLatestSuccessfulRouteConfig}
|
|
5409
|
+
* @see {@link latestSuccessfulRoutes} for the full route list variant
|
|
3669
5410
|
*/
|
|
3670
5411
|
function isLatestSuccessfulRoute(config) {
|
|
3671
5412
|
const { dbxRouterTransitionService, dbxRouterService, activeExactly } = config;
|
|
@@ -3678,11 +5419,29 @@ function isLatestSuccessfulRoute(config) {
|
|
|
3678
5419
|
}
|
|
3679
5420
|
|
|
3680
5421
|
/**
|
|
3681
|
-
* Abstract directive that
|
|
5422
|
+
* Abstract directive that provides observables for reacting to successful router transitions.
|
|
5423
|
+
*
|
|
5424
|
+
* Subclasses can subscribe to `transitionSuccess$` to react to each successful navigation,
|
|
5425
|
+
* or use `initAndUpdateOnTransitionSuccess$` which also emits once immediately on initialization.
|
|
5426
|
+
*
|
|
5427
|
+
* @example
|
|
5428
|
+
* ```ts
|
|
5429
|
+
* @Directive({ selector: '[myTransitionHandler]' })
|
|
5430
|
+
* class MyTransitionHandlerDirective extends AbstractTransitionDirective {
|
|
5431
|
+
* readonly data$ = this.initAndUpdateOnTransitionSuccess$.pipe(
|
|
5432
|
+
* switchMap(() => this.loadData())
|
|
5433
|
+
* );
|
|
5434
|
+
* }
|
|
5435
|
+
* ```
|
|
5436
|
+
*
|
|
5437
|
+
* @see {@link AbstractTransitionWatcherDirective} for a variant that automatically calls a callback
|
|
5438
|
+
* @see {@link DbxRouterTransitionService}
|
|
3682
5439
|
*/
|
|
3683
5440
|
class AbstractTransitionDirective {
|
|
3684
5441
|
dbxRouterTransitionService = inject(DbxRouterTransitionService);
|
|
5442
|
+
/** Observable that emits on each successful router transition. */
|
|
3685
5443
|
transitionSuccess$ = successTransition(this.dbxRouterTransitionService.transitions$);
|
|
5444
|
+
/** Observable that emits immediately on initialization and on each subsequent successful transition. */
|
|
3686
5445
|
initAndUpdateOnTransitionSuccess$ = this.transitionSuccess$.pipe(startWith(undefined));
|
|
3687
5446
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: AbstractTransitionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3688
5447
|
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.0", type: AbstractTransitionDirective, isStandalone: true, ngImport: i0 });
|
|
@@ -3692,7 +5451,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
3692
5451
|
}] });
|
|
3693
5452
|
|
|
3694
5453
|
/**
|
|
3695
|
-
* Abstract directive that
|
|
5454
|
+
* Abstract directive that automatically calls {@link updateForSuccessfulTransition} on each successful router transition.
|
|
5455
|
+
*
|
|
5456
|
+
* Extends {@link AbstractTransitionDirective} by subscribing to successful transitions during construction
|
|
5457
|
+
* and invoking the abstract `updateForSuccessfulTransition()` method for each one.
|
|
5458
|
+
*
|
|
5459
|
+
* Also provides a `zoneUpdateForSuccessfulTransition()` method that wraps the update call in `NgZone.run()`.
|
|
5460
|
+
*
|
|
5461
|
+
* @example
|
|
5462
|
+
* ```ts
|
|
5463
|
+
* @Directive({ selector: '[myRouteWatcher]' })
|
|
5464
|
+
* class MyRouteWatcherDirective extends AbstractTransitionWatcherDirective {
|
|
5465
|
+
* protected updateForSuccessfulTransition(): void {
|
|
5466
|
+
* console.log('Route changed successfully');
|
|
5467
|
+
* }
|
|
5468
|
+
* }
|
|
5469
|
+
* ```
|
|
5470
|
+
*
|
|
5471
|
+
* @see {@link AbstractTransitionDirective}
|
|
3696
5472
|
*/
|
|
3697
5473
|
class AbstractTransitionWatcherDirective extends AbstractTransitionDirective {
|
|
3698
5474
|
ngZone = inject(NgZone);
|
|
@@ -3716,10 +5492,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
3716
5492
|
}], ctorParameters: () => [] });
|
|
3717
5493
|
|
|
3718
5494
|
/**
|
|
3719
|
-
* Creates an IsSegueRefActiveFunction
|
|
5495
|
+
* Creates an {@link IsSegueRefActiveFunction} from the given configuration.
|
|
3720
5496
|
*
|
|
3721
|
-
*
|
|
3722
|
-
*
|
|
5497
|
+
* The returned function checks whether the configured segue ref is active in the router each time it is called.
|
|
5498
|
+
* When `activeExactly` is `true`, uses `isActiveExactly`; otherwise uses `isActive`.
|
|
5499
|
+
*
|
|
5500
|
+
* @param config - The configuration containing the router service, segue ref, and match mode.
|
|
5501
|
+
* @returns A callable function that returns `true` when the route is active.
|
|
5502
|
+
*
|
|
5503
|
+
* @see {@link IsSegueRefActiveFunctionConfig}
|
|
3723
5504
|
*/
|
|
3724
5505
|
function isSegueRefActiveFunction(config) {
|
|
3725
5506
|
const { dbxRouterService, segueRef, activeExactly = false } = config;
|
|
@@ -3730,9 +5511,24 @@ function isSegueRefActiveFunction(config) {
|
|
|
3730
5511
|
}
|
|
3731
5512
|
|
|
3732
5513
|
// MARK: Transition Events
|
|
5514
|
+
/**
|
|
5515
|
+
* Filters the given transition event observable to only emit events of the specified type.
|
|
5516
|
+
*
|
|
5517
|
+
* @param events$ - The source observable of router transition events.
|
|
5518
|
+
* @param type - The transition event type to filter for.
|
|
5519
|
+
* @returns An observable that emits only events matching the given type.
|
|
5520
|
+
*/
|
|
3733
5521
|
function onRouterTransitionEventType(events$, type) {
|
|
3734
5522
|
return events$.pipe(filter((x) => x.type === type));
|
|
3735
5523
|
}
|
|
5524
|
+
/**
|
|
5525
|
+
* Filters the given transition event observable to only emit successful transition events.
|
|
5526
|
+
*
|
|
5527
|
+
* @param events$ - The source observable of router transition events.
|
|
5528
|
+
* @returns An observable that emits only {@link DbxRouterTransitionEventType.SUCCESS} events.
|
|
5529
|
+
*
|
|
5530
|
+
* @see {@link onRouterTransitionEventType}
|
|
5531
|
+
*/
|
|
3736
5532
|
function onRouterTransitionSuccessEvent(events$) {
|
|
3737
5533
|
return onRouterTransitionEventType(events$, DbxRouterTransitionEventType.SUCCESS);
|
|
3738
5534
|
}
|
|
@@ -3812,7 +5608,24 @@ function dbxRouteParamReaderInstance(dbxRouterService, defaultParamKey, defaultV
|
|
|
3812
5608
|
|
|
3813
5609
|
const DEFAULT_REDIRECT_INSTANCE_FORWARD_FACTORY = defaultForwardFunctionFactory((value) => of(value == null));
|
|
3814
5610
|
/**
|
|
3815
|
-
* Utility class
|
|
5611
|
+
* Utility class that works with a {@link DbxRouteParamReaderInstance} to automatically redirect the router
|
|
5612
|
+
* when the current parameter value is determined to require a default substitution.
|
|
5613
|
+
*
|
|
5614
|
+
* When enabled and initialized, it monitors the parameter value and, if the configured filter function
|
|
5615
|
+
* indicates the value should be replaced, updates the route to use the default value instead.
|
|
5616
|
+
*
|
|
5617
|
+
* @typeParam T - The type of the parameter value.
|
|
5618
|
+
*
|
|
5619
|
+
* @example
|
|
5620
|
+
* ```ts
|
|
5621
|
+
* const paramReader = dbxRouteParamReaderInstance<string>(routerService, 'id');
|
|
5622
|
+
* const redirect = new DbxRouteParamDefaultRedirectInstance(paramReader);
|
|
5623
|
+
* redirect.setUseDefaultFilter(value => of(value === '0'));
|
|
5624
|
+
* redirect.init();
|
|
5625
|
+
* ```
|
|
5626
|
+
*
|
|
5627
|
+
* @see {@link DbxRouteParamReaderInstance}
|
|
5628
|
+
* @see {@link dbxRouteModelIdParamRedirect} for the model-specific usage pattern
|
|
3816
5629
|
*/
|
|
3817
5630
|
class DbxRouteParamDefaultRedirectInstance {
|
|
3818
5631
|
instance;
|
|
@@ -3882,9 +5695,34 @@ const DBX_ROUTE_MODEL_ID_PARAM_DEFAULT_KEY_PARAM_KEY = 'key';
|
|
|
3882
5695
|
* Default value used by dbxRouteModelIdParamRedirect() for when a value is not available or provided.
|
|
3883
5696
|
*/
|
|
3884
5697
|
const DBX_ROUTE_MODEL_ID_PARAM_DEFAULT_USE_PARAM_VALUE = '0';
|
|
5698
|
+
/**
|
|
5699
|
+
* Creates a {@link DbxRouteModelIdParamRedirectInstance} configured to read a "key" parameter from the current route.
|
|
5700
|
+
*
|
|
5701
|
+
* This is a convenience wrapper around {@link dbxRouteModelIdParamRedirect} that defaults the parameter key to `'key'`.
|
|
5702
|
+
*
|
|
5703
|
+
* @param dbxRouterService - The router service to read parameters from.
|
|
5704
|
+
* @param defaultParamKey - The route parameter key to read. Defaults to `'key'`.
|
|
5705
|
+
* @returns A new redirect instance.
|
|
5706
|
+
*
|
|
5707
|
+
* @see {@link dbxRouteModelIdParamRedirect}
|
|
5708
|
+
*/
|
|
3885
5709
|
function dbxRouteModelKeyParamRedirect(dbxRouterService, defaultParamKey = DBX_ROUTE_MODEL_ID_PARAM_DEFAULT_KEY_PARAM_KEY) {
|
|
3886
5710
|
return dbxRouteModelIdParamRedirect(dbxRouterService, defaultParamKey);
|
|
3887
5711
|
}
|
|
5712
|
+
/**
|
|
5713
|
+
* Creates a {@link DbxRouteModelIdParamRedirectInstance} that reads a model identifier from the current route
|
|
5714
|
+
* and optionally redirects when the value matches a placeholder (defaulting to `'0'`).
|
|
5715
|
+
*
|
|
5716
|
+
* The instance must be initialized via `init()` to activate the redirect behavior, and destroyed via `destroy()`
|
|
5717
|
+
* when no longer needed.
|
|
5718
|
+
*
|
|
5719
|
+
* @param dbxRouterService - The router service to read parameters from and perform redirects with.
|
|
5720
|
+
* @param defaultParamKey - The route parameter key to read. Defaults to `'id'`.
|
|
5721
|
+
* @returns A new redirect instance.
|
|
5722
|
+
*
|
|
5723
|
+
* @see {@link DbxRouteModelIdParamRedirectInstance}
|
|
5724
|
+
* @see {@link dbxRouteModelKeyParamRedirect} for the key-based variant
|
|
5725
|
+
*/
|
|
3888
5726
|
function dbxRouteModelIdParamRedirect(dbxRouterService, defaultParamKey = DBX_ROUTE_MODEL_ID_PARAM_DEFAULT_ID_PARAM_KEY) {
|
|
3889
5727
|
const _paramReader = dbxRouteParamReaderInstance(dbxRouterService, defaultParamKey);
|
|
3890
5728
|
const _paramRedirect = new DbxRouteParamDefaultRedirectInstance(_paramReader);
|
|
@@ -3943,12 +5781,37 @@ function dbxRouteModelIdParamRedirect(dbxRouterService, defaultParamKey = DBX_RO
|
|
|
3943
5781
|
|
|
3944
5782
|
// MARK: Id
|
|
3945
5783
|
/**
|
|
3946
|
-
*
|
|
5784
|
+
* Abstract delegate that receives model identifier observables from a {@link DbxRouteModelIdDirective}.
|
|
5785
|
+
*
|
|
5786
|
+
* Implement this class and register it as a provider to receive the id parameter read from the current route.
|
|
5787
|
+
* The directive will call {@link useRouteModelIdParamsObservable} during initialization.
|
|
5788
|
+
*
|
|
5789
|
+
* @example
|
|
5790
|
+
* ```ts
|
|
5791
|
+
* @Directive({
|
|
5792
|
+
* selector: '[myModelLoader]',
|
|
5793
|
+
* providers: provideDbxRouteModelIdDirectiveDelegate(MyModelLoaderDirective)
|
|
5794
|
+
* })
|
|
5795
|
+
* class MyModelLoaderDirective extends DbxRouteModelIdDirectiveDelegate {
|
|
5796
|
+
* useRouteModelIdParamsObservable(idFromParams$: Observable<Maybe<ModelKey>>, computedId$: Observable<Maybe<ModelKey>>): Subscription {
|
|
5797
|
+
* return computedId$.subscribe(id => this.loadModel(id));
|
|
5798
|
+
* }
|
|
5799
|
+
* }
|
|
5800
|
+
* ```
|
|
5801
|
+
*
|
|
5802
|
+
* @see {@link DbxRouteModelIdDirective} for the directive that provides the id observables
|
|
5803
|
+
* @see {@link provideDbxRouteModelIdDirectiveDelegate} for registering the delegate provider
|
|
3947
5804
|
*/
|
|
3948
5805
|
class DbxRouteModelIdDirectiveDelegate {
|
|
3949
5806
|
}
|
|
3950
5807
|
/**
|
|
3951
|
-
*
|
|
5808
|
+
* Creates Angular DI providers that register the given source type as a {@link DbxRouteModelIdDirectiveDelegate}.
|
|
5809
|
+
*
|
|
5810
|
+
* @typeParam S - The concrete delegate class type to register.
|
|
5811
|
+
* @param sourceType - The class to provide as the delegate.
|
|
5812
|
+
* @returns An array of Angular providers.
|
|
5813
|
+
*
|
|
5814
|
+
* @see {@link DbxRouteModelIdDirectiveDelegate}
|
|
3952
5815
|
*/
|
|
3953
5816
|
function provideDbxRouteModelIdDirectiveDelegate(sourceType) {
|
|
3954
5817
|
const providers = [
|
|
@@ -3961,12 +5824,37 @@ function provideDbxRouteModelIdDirectiveDelegate(sourceType) {
|
|
|
3961
5824
|
}
|
|
3962
5825
|
// MARK: Key
|
|
3963
5826
|
/**
|
|
3964
|
-
*
|
|
5827
|
+
* Abstract delegate that receives model key observables from a {@link DbxRouteModelKeyDirective}.
|
|
5828
|
+
*
|
|
5829
|
+
* Implement this class and register it as a provider to receive the key parameter read from the current route.
|
|
5830
|
+
* The directive will call {@link useRouteModelKeyParamsObservable} during initialization.
|
|
5831
|
+
*
|
|
5832
|
+
* @example
|
|
5833
|
+
* ```ts
|
|
5834
|
+
* @Directive({
|
|
5835
|
+
* selector: '[myModelKeyLoader]',
|
|
5836
|
+
* providers: provideDbxRouteModelKeyDirectiveDelegate(MyModelKeyLoaderDirective)
|
|
5837
|
+
* })
|
|
5838
|
+
* class MyModelKeyLoaderDirective extends DbxRouteModelKeyDirectiveDelegate {
|
|
5839
|
+
* useRouteModelKeyParamsObservable(keyFromParams$: Observable<Maybe<ModelKey>>, computedKey$: Observable<Maybe<ModelKey>>): Subscription {
|
|
5840
|
+
* return computedKey$.subscribe(key => this.loadModel(key));
|
|
5841
|
+
* }
|
|
5842
|
+
* }
|
|
5843
|
+
* ```
|
|
5844
|
+
*
|
|
5845
|
+
* @see {@link DbxRouteModelKeyDirective} for the directive that provides the key observables
|
|
5846
|
+
* @see {@link provideDbxRouteModelKeyDirectiveDelegate} for registering the delegate provider
|
|
3965
5847
|
*/
|
|
3966
5848
|
class DbxRouteModelKeyDirectiveDelegate {
|
|
3967
5849
|
}
|
|
3968
5850
|
/**
|
|
3969
|
-
*
|
|
5851
|
+
* Creates Angular DI providers that register the given source type as a {@link DbxRouteModelKeyDirectiveDelegate}.
|
|
5852
|
+
*
|
|
5853
|
+
* @typeParam S - The concrete delegate class type to register.
|
|
5854
|
+
* @param sourceType - The class to provide as the delegate.
|
|
5855
|
+
* @returns An array of Angular providers.
|
|
5856
|
+
*
|
|
5857
|
+
* @see {@link DbxRouteModelKeyDirectiveDelegate}
|
|
3970
5858
|
*/
|
|
3971
5859
|
function provideDbxRouteModelKeyDirectiveDelegate(sourceType) {
|
|
3972
5860
|
const providers = [
|
|
@@ -3979,7 +5867,19 @@ function provideDbxRouteModelKeyDirectiveDelegate(sourceType) {
|
|
|
3979
5867
|
}
|
|
3980
5868
|
|
|
3981
5869
|
/**
|
|
3982
|
-
*
|
|
5870
|
+
* Directive that retrieves the currently authenticated user's identifier from {@link DbxAuthService}
|
|
5871
|
+
* and passes it directly to a {@link DbxRouteModelIdDirectiveDelegate}.
|
|
5872
|
+
*
|
|
5873
|
+
* This is useful for routes that should always use the current user's ID, bypassing route parameter reading entirely.
|
|
5874
|
+
*
|
|
5875
|
+
* @example
|
|
5876
|
+
* ```html
|
|
5877
|
+
* <!-- Automatically provides the authenticated user's ID to the delegate -->
|
|
5878
|
+
* <div dbxRouteModelIdFromAuthUserId></div>
|
|
5879
|
+
* ```
|
|
5880
|
+
*
|
|
5881
|
+
* @see {@link DbxRouteModelIdDirectiveDelegate} for the delegate that receives the id observables
|
|
5882
|
+
* @see {@link DbxAuthService} for the authentication service providing the user identifier
|
|
3983
5883
|
*/
|
|
3984
5884
|
class DbxRouteModelIdFromAuthUserIdDirective {
|
|
3985
5885
|
dbxAuthService = inject(DbxAuthService);
|
|
@@ -3999,7 +5899,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
3999
5899
|
}], ctorParameters: () => [] });
|
|
4000
5900
|
|
|
4001
5901
|
/**
|
|
4002
|
-
*
|
|
5902
|
+
* Directive that reads a model identifier from the current route's parameters and passes it to a {@link DbxRouteModelIdDirectiveDelegate}.
|
|
5903
|
+
*
|
|
5904
|
+
* Supports configurable parameter key, default value, redirect behavior, and custom decision logic for determining
|
|
5905
|
+
* when to use the default value vs. the route parameter.
|
|
5906
|
+
*
|
|
5907
|
+
* @example
|
|
5908
|
+
* ```html
|
|
5909
|
+
* <!-- Basic usage: reads "id" param from route and passes to delegate -->
|
|
5910
|
+
* <div dbxRouteModelId></div>
|
|
5911
|
+
*
|
|
5912
|
+
* <!-- Custom param key -->
|
|
5913
|
+
* <div [dbxRouteModelId]="'modelId'"></div>
|
|
5914
|
+
*
|
|
5915
|
+
* <!-- With default value and redirect disabled -->
|
|
5916
|
+
* <div dbxRouteModelId [dbxRouteModelIdDefault]="defaultId$" [dbxRouteModelIdDefaultRedirect]="false"></div>
|
|
5917
|
+
* ```
|
|
5918
|
+
*
|
|
5919
|
+
* @see {@link DbxRouteModelIdDirectiveDelegate} for the delegate that receives the id observables
|
|
5920
|
+
* @see {@link dbxRouteModelIdParamRedirect} for the underlying redirect logic
|
|
4003
5921
|
*/
|
|
4004
5922
|
class DbxRouteModelIdDirective {
|
|
4005
5923
|
dbxRouterService = inject(DbxRouterService);
|
|
@@ -4051,9 +5969,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4051
5969
|
}] } });
|
|
4052
5970
|
|
|
4053
5971
|
/**
|
|
4054
|
-
*
|
|
5972
|
+
* Directive that reads a model key from the current route's parameters and passes it to a {@link DbxRouteModelKeyDirectiveDelegate}.
|
|
5973
|
+
*
|
|
5974
|
+
* Functions identically to {@link DbxRouteModelIdDirective} but uses a "key" parameter (defaulting to `'key'`)
|
|
5975
|
+
* instead of "id". Supports configurable parameter key, default value, redirect behavior, and custom decision logic.
|
|
5976
|
+
*
|
|
5977
|
+
* @example
|
|
5978
|
+
* ```html
|
|
5979
|
+
* <!-- Basic usage: reads "key" param from route and passes to delegate -->
|
|
5980
|
+
* <div dbxRouteModelKey></div>
|
|
4055
5981
|
*
|
|
4056
|
-
*
|
|
5982
|
+
* <!-- Custom param key -->
|
|
5983
|
+
* <div [dbxRouteModelKey]="'slug'"></div>
|
|
5984
|
+
*
|
|
5985
|
+
* <!-- With default value and redirect disabled -->
|
|
5986
|
+
* <div dbxRouteModelKey [dbxRouteModelKeyDefault]="defaultKey$" [dbxRouteModelKeyDefaultRedirect]="false"></div>
|
|
5987
|
+
* ```
|
|
5988
|
+
*
|
|
5989
|
+
* @see {@link DbxRouteModelKeyDirectiveDelegate} for the delegate that receives the key observables
|
|
5990
|
+
* @see {@link dbxRouteModelKeyParamRedirect} for the underlying redirect logic
|
|
5991
|
+
* @see {@link DbxRouteModelIdDirective} for the id-based equivalent
|
|
4057
5992
|
*/
|
|
4058
5993
|
class DbxRouteModelKeyDirective {
|
|
4059
5994
|
dbxRouterService = inject(DbxRouterService);
|
|
@@ -4105,7 +6040,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4105
6040
|
}] } });
|
|
4106
6041
|
|
|
4107
6042
|
/**
|
|
4108
|
-
*
|
|
6043
|
+
* Converts an {@link ObservableOrValueGetter} into an {@link Observable}.
|
|
6044
|
+
*
|
|
6045
|
+
* Useful for normalizing values that may be plain values, getter functions, or Observables
|
|
6046
|
+
* into a consistent Observable stream for use with the `async` pipe.
|
|
6047
|
+
*
|
|
6048
|
+
* @example
|
|
6049
|
+
* ```html
|
|
6050
|
+
* <span>{{ valueOrGetter | asObservable | async }}</span>
|
|
6051
|
+
* ```
|
|
4109
6052
|
*/
|
|
4110
6053
|
class AsObservablePipe {
|
|
4111
6054
|
transform(input) {
|
|
@@ -4122,6 +6065,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4122
6065
|
}]
|
|
4123
6066
|
}] });
|
|
4124
6067
|
|
|
6068
|
+
/**
|
|
6069
|
+
* Formats a {@link DateRange} as a human-readable day range string using {@link formatToDayRangeString}.
|
|
6070
|
+
*
|
|
6071
|
+
* Displays only the date portion (no times). Returns a fallback string when the input is `null` or `undefined`.
|
|
6072
|
+
*
|
|
6073
|
+
* @example
|
|
6074
|
+
* ```html
|
|
6075
|
+
* <span>{{ dateRange | dateDayRange }}</span>
|
|
6076
|
+
* <!-- Output: "Jan 5 - Jan 8" -->
|
|
6077
|
+
*
|
|
6078
|
+
* <span>{{ nullRange | dateDayRange:'No dates' }}</span>
|
|
6079
|
+
* <!-- Output: "No dates" -->
|
|
6080
|
+
* ```
|
|
6081
|
+
*/
|
|
4125
6082
|
class DateDayRangePipe {
|
|
4126
6083
|
transform(input, unavailable = 'Not Available') {
|
|
4127
6084
|
if (input) {
|
|
@@ -4143,6 +6100,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4143
6100
|
}]
|
|
4144
6101
|
}] });
|
|
4145
6102
|
|
|
6103
|
+
/**
|
|
6104
|
+
* Converts a {@link DateOrDateString} value to a JavaScript {@link Date} object using {@link toJsDate}.
|
|
6105
|
+
*
|
|
6106
|
+
* Returns `undefined` if the input is `null`, `undefined`, or results in an invalid date.
|
|
6107
|
+
* Also provides a static `toJsDate()` method used by other pipes in this package.
|
|
6108
|
+
*
|
|
6109
|
+
* @example
|
|
6110
|
+
* ```html
|
|
6111
|
+
* <span>{{ '2024-01-05T12:00:00Z' | toJsDate | date:'short' }}</span>
|
|
6112
|
+
* <!-- Output: "1/5/24, 12:00 PM" -->
|
|
6113
|
+
*
|
|
6114
|
+
* <span>{{ dateOrString | toJsDate | date:'fullDate' }}</span>
|
|
6115
|
+
* ```
|
|
6116
|
+
*/
|
|
4146
6117
|
class ToJsDatePipe {
|
|
4147
6118
|
static toJsDate(input) {
|
|
4148
6119
|
let date;
|
|
@@ -4169,6 +6140,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4169
6140
|
}]
|
|
4170
6141
|
}] });
|
|
4171
6142
|
|
|
6143
|
+
/**
|
|
6144
|
+
* Formats a date as a human-readable distance string relative to another date (or now) using {@link formatDateDistance}.
|
|
6145
|
+
*
|
|
6146
|
+
* Accepts an optional comparison date (defaults to now) and a fallback string for `null`/`undefined` input.
|
|
6147
|
+
*
|
|
6148
|
+
* @example
|
|
6149
|
+
* ```html
|
|
6150
|
+
* <span>{{ someDate | dateDistance }}</span>
|
|
6151
|
+
* <!-- Output: "3 hours ago" -->
|
|
6152
|
+
*
|
|
6153
|
+
* <span>{{ someDate | dateDistance:referenceDate }}</span>
|
|
6154
|
+
* <!-- Output: "2 days ago" -->
|
|
6155
|
+
*
|
|
6156
|
+
* <span>{{ nullDate | dateDistance:null:'Unknown' }}</span>
|
|
6157
|
+
* <!-- Output: "Unknown" -->
|
|
6158
|
+
* ```
|
|
6159
|
+
*/
|
|
4172
6160
|
class DateDistancePipe {
|
|
4173
6161
|
transform(input, inputTo, unavailable = 'Not Available') {
|
|
4174
6162
|
if (input != null) {
|
|
@@ -4193,7 +6181,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4193
6181
|
}] });
|
|
4194
6182
|
|
|
4195
6183
|
/**
|
|
4196
|
-
*
|
|
6184
|
+
* Formats a date using a locale-aware format string and appends the relative distance to now in parentheses.
|
|
6185
|
+
*
|
|
6186
|
+
* Returns `undefined` if the input is falsy or not a valid date.
|
|
6187
|
+
*
|
|
6188
|
+
* @example
|
|
6189
|
+
* ```html
|
|
6190
|
+
* <span>{{ someDate | dateFormatDistance:'MMM d, y' }}</span>
|
|
6191
|
+
* <!-- Output: "Jan 5, 2024 (3 days ago)" -->
|
|
6192
|
+
*
|
|
6193
|
+
* <span>{{ someDate | dateFormatDistance:'short':true }}</span>
|
|
6194
|
+
* <!-- Output: "1/5/24, 2:30 PM (about 3 days ago)" with includeSeconds enabled -->
|
|
6195
|
+
* ```
|
|
4197
6196
|
*/
|
|
4198
6197
|
class DateFormatDistancePipe {
|
|
4199
6198
|
locale = inject(LOCALE_ID);
|
|
@@ -4224,7 +6223,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4224
6223
|
}] });
|
|
4225
6224
|
|
|
4226
6225
|
/**
|
|
4227
|
-
*
|
|
6226
|
+
* Formats a date as a "from - to" time range string given a start date, format string, and duration in minutes.
|
|
6227
|
+
*
|
|
6228
|
+
* The start date is formatted using the Angular locale-aware {@link formatDate}, and the end time
|
|
6229
|
+
* is computed by adding the given minutes and formatted as a time-only string.
|
|
6230
|
+
*
|
|
6231
|
+
* @example
|
|
6232
|
+
* ```html
|
|
6233
|
+
* <span>{{ eventStart | dateFormatFromTo:'MMM d, h:mm a':90 }}</span>
|
|
6234
|
+
* <!-- Output: "Jan 5, 2:00 PM - 3:30 PM" -->
|
|
6235
|
+
* ```
|
|
4228
6236
|
*/
|
|
4229
6237
|
class DateFormatFromToPipe {
|
|
4230
6238
|
locale = inject(LOCALE_ID);
|
|
@@ -4252,6 +6260,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4252
6260
|
}]
|
|
4253
6261
|
}] });
|
|
4254
6262
|
|
|
6263
|
+
/**
|
|
6264
|
+
* Formats a {@link DateRange} as a human-readable day and time range string using {@link formatToDayTimeRangeString}.
|
|
6265
|
+
*
|
|
6266
|
+
* Includes both the date and time portions. Returns a fallback string when the input is `null` or `undefined`.
|
|
6267
|
+
*
|
|
6268
|
+
* @example
|
|
6269
|
+
* ```html
|
|
6270
|
+
* <span>{{ dateRange | dateDayTimeRange }}</span>
|
|
6271
|
+
* <!-- Output: "Jan 5, 2:00 PM - Jan 8, 4:00 PM" -->
|
|
6272
|
+
*
|
|
6273
|
+
* <span>{{ nullRange | dateDayTimeRange:'No dates' }}</span>
|
|
6274
|
+
* <!-- Output: "No dates" -->
|
|
6275
|
+
* ```
|
|
6276
|
+
*/
|
|
4255
6277
|
class DateDayTimeRangePipe {
|
|
4256
6278
|
transform(input, unavailable = 'Not Available') {
|
|
4257
6279
|
if (input) {
|
|
@@ -4273,6 +6295,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4273
6295
|
}]
|
|
4274
6296
|
}] });
|
|
4275
6297
|
|
|
6298
|
+
/**
|
|
6299
|
+
* Formats a {@link DateRange} as a time range string using {@link formatToTimeRangeString}.
|
|
6300
|
+
*
|
|
6301
|
+
* Displays the date and time of both the start and end. Returns a fallback string when the input is `null` or `undefined`.
|
|
6302
|
+
*
|
|
6303
|
+
* @example
|
|
6304
|
+
* ```html
|
|
6305
|
+
* <span>{{ dateRange | dateTimeRange }}</span>
|
|
6306
|
+
* <!-- Output: "Jan 5, 2:00 PM - 4:00 PM" -->
|
|
6307
|
+
*
|
|
6308
|
+
* <span>{{ nullRange | dateTimeRange:'TBD' }}</span>
|
|
6309
|
+
* <!-- Output: "TBD" -->
|
|
6310
|
+
* ```
|
|
6311
|
+
*/
|
|
4276
6312
|
class DateTimeRangePipe {
|
|
4277
6313
|
transform(input, unavailable = 'Not Available') {
|
|
4278
6314
|
if (input) {
|
|
@@ -4294,6 +6330,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4294
6330
|
}]
|
|
4295
6331
|
}] });
|
|
4296
6332
|
|
|
6333
|
+
/**
|
|
6334
|
+
* Formats a {@link Date} or {@link DateRange} as a human-readable distance string relative to now using {@link formatDateDistance}.
|
|
6335
|
+
*
|
|
6336
|
+
* This is an impure pipe that recalculates on every change detection cycle to keep the distance up to date.
|
|
6337
|
+
* Returns a fallback string when the input is `null` or `undefined`.
|
|
6338
|
+
*
|
|
6339
|
+
* @example
|
|
6340
|
+
* ```html
|
|
6341
|
+
* <span>{{ someDate | dateRangeDistance }}</span>
|
|
6342
|
+
* <!-- Output: "3 hours ago" -->
|
|
6343
|
+
*
|
|
6344
|
+
* <span>{{ nullDate | dateRangeDistance:'Unknown' }}</span>
|
|
6345
|
+
* <!-- Output: "Unknown" -->
|
|
6346
|
+
* ```
|
|
6347
|
+
*/
|
|
4297
6348
|
class DateRangeDistancePipe {
|
|
4298
6349
|
transform(input, unavailable = 'Not Available') {
|
|
4299
6350
|
if (input != null) {
|
|
@@ -4315,6 +6366,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4315
6366
|
}]
|
|
4316
6367
|
}] });
|
|
4317
6368
|
|
|
6369
|
+
/**
|
|
6370
|
+
* Formats a {@link DateRange} as a time-only range string using {@link formatToTimeRangeString} with the time-only flag enabled.
|
|
6371
|
+
*
|
|
6372
|
+
* Displays only the time portion (no date). Returns a fallback string when the input is `null` or `undefined`.
|
|
6373
|
+
*
|
|
6374
|
+
* @example
|
|
6375
|
+
* ```html
|
|
6376
|
+
* <span>{{ dateRange | dateTimeRangeOnly }}</span>
|
|
6377
|
+
* <!-- Output: "2:00 PM - 4:00 PM" -->
|
|
6378
|
+
*
|
|
6379
|
+
* <span>{{ nullRange | dateTimeRangeOnly:'TBD' }}</span>
|
|
6380
|
+
* <!-- Output: "TBD" -->
|
|
6381
|
+
* ```
|
|
6382
|
+
*/
|
|
4318
6383
|
class DateTimeRangeOnlyPipe {
|
|
4319
6384
|
transform(input, unavailable = 'Not Available') {
|
|
4320
6385
|
if (input) {
|
|
@@ -4337,7 +6402,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4337
6402
|
}] });
|
|
4338
6403
|
|
|
4339
6404
|
/**
|
|
4340
|
-
* Converts
|
|
6405
|
+
* Converts a target timezone date back to the equivalent system (UTC-based) date using {@link dateTimezoneUtcNormal}.
|
|
6406
|
+
*
|
|
6407
|
+
* This is the inverse of {@link SystemDateToTargetDatePipe}. Useful when you have a date representing
|
|
6408
|
+
* local time in a target timezone and need to convert it back to the system timezone.
|
|
6409
|
+
* Returns `undefined` if either the input date or timezone is falsy.
|
|
6410
|
+
*
|
|
6411
|
+
* @example
|
|
6412
|
+
* ```html
|
|
6413
|
+
* <span>{{ targetDate | targetDateToSystemDate:'America/New_York' | date:'short' }}</span>
|
|
6414
|
+
* <!-- Output: the date/time converted back to the system timezone -->
|
|
6415
|
+
* ```
|
|
4341
6416
|
*/
|
|
4342
6417
|
class TargetDateToSystemDatePipe {
|
|
4343
6418
|
transform(input, timezone) {
|
|
@@ -4360,6 +6435,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4360
6435
|
}]
|
|
4361
6436
|
}] });
|
|
4362
6437
|
|
|
6438
|
+
/**
|
|
6439
|
+
* Formats a {@link DateRange} as a human-readable distance string using {@link formatDateRangeDistance}.
|
|
6440
|
+
*
|
|
6441
|
+
* Accepts an optional {@link FormatDateRangeDistanceFunctionConfig} to customize the output format.
|
|
6442
|
+
* Returns a fallback string when the input is `null` or `undefined`.
|
|
6443
|
+
*
|
|
6444
|
+
* @example
|
|
6445
|
+
* ```html
|
|
6446
|
+
* <span>{{ dateRange | dateTimeRangeOnlyDistance }}</span>
|
|
6447
|
+
* <!-- Output: "3 hours" -->
|
|
6448
|
+
*
|
|
6449
|
+
* <span>{{ dateRange | dateTimeRangeOnlyDistance:config }}</span>
|
|
6450
|
+
* <!-- Output varies based on config -->
|
|
6451
|
+
*
|
|
6452
|
+
* <span>{{ nullRange | dateTimeRangeOnlyDistance:null:'TBD' }}</span>
|
|
6453
|
+
* <!-- Output: "TBD" -->
|
|
6454
|
+
* ```
|
|
6455
|
+
*/
|
|
4363
6456
|
class DateTimeRangeOnlyDistancePipe {
|
|
4364
6457
|
transform(input, config, unavailable = 'Not Available') {
|
|
4365
6458
|
if (input) {
|
|
@@ -4382,7 +6475,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4382
6475
|
}] });
|
|
4383
6476
|
|
|
4384
6477
|
/**
|
|
4385
|
-
*
|
|
6478
|
+
* Returns the abbreviated name for a timezone string (e.g., "EST", "PDT") using {@link getTimezoneAbbreviation}.
|
|
6479
|
+
*
|
|
6480
|
+
* Optionally accepts a reference date to determine the correct abbreviation (e.g., for daylight saving time).
|
|
6481
|
+
* Defaults to the current date if no reference date is provided.
|
|
6482
|
+
* Returns `undefined` if the timezone is falsy.
|
|
6483
|
+
*
|
|
6484
|
+
* @example
|
|
6485
|
+
* ```html
|
|
6486
|
+
* <span>{{ 'America/New_York' | timezoneAbbreviation }}</span>
|
|
6487
|
+
* <!-- Output: "EST" or "EDT" depending on the current date -->
|
|
6488
|
+
*
|
|
6489
|
+
* <span>{{ timezone | timezoneAbbreviation:referenceDate }}</span>
|
|
6490
|
+
* <!-- Output: abbreviation for the timezone at the given reference date -->
|
|
6491
|
+
* ```
|
|
4386
6492
|
*/
|
|
4387
6493
|
class TimezoneAbbreviationPipe {
|
|
4388
6494
|
transform(timezone, input) {
|
|
@@ -4406,7 +6512,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4406
6512
|
}] });
|
|
4407
6513
|
|
|
4408
6514
|
/**
|
|
4409
|
-
* Converts
|
|
6515
|
+
* Converts a system (UTC-based) date to the equivalent local date in the given timezone using {@link dateTimezoneUtcNormal}.
|
|
6516
|
+
*
|
|
6517
|
+
* This is useful when you have a date in the system's timezone and need to display it as if it were in the target timezone.
|
|
6518
|
+
* Returns `undefined` if either the input date or timezone is falsy.
|
|
6519
|
+
*
|
|
6520
|
+
* @example
|
|
6521
|
+
* ```html
|
|
6522
|
+
* <span>{{ systemDate | systemDateToTargetDate:'America/New_York' | date:'short' }}</span>
|
|
6523
|
+
* <!-- Output: the date/time as it appears in the New York timezone -->
|
|
6524
|
+
* ```
|
|
4410
6525
|
*/
|
|
4411
6526
|
class SystemDateToTargetDatePipe {
|
|
4412
6527
|
transform(input, timezone) {
|
|
@@ -4429,6 +6544,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4429
6544
|
}]
|
|
4430
6545
|
}] });
|
|
4431
6546
|
|
|
6547
|
+
/**
|
|
6548
|
+
* Converts a numeric minute value into a human-readable duration string with automatic unit scaling.
|
|
6549
|
+
*
|
|
6550
|
+
* - Values over 3600 minutes are displayed as days (e.g., "~2 days")
|
|
6551
|
+
* - Values over 180 minutes are displayed as hours (e.g., "~4 hours")
|
|
6552
|
+
* - Values at or below 180 minutes are displayed as minutes (e.g., "90 minutes")
|
|
6553
|
+
*
|
|
6554
|
+
* A `~` prefix is added when the value is rounded up. Returns `undefined` for `null` or non-numeric input.
|
|
6555
|
+
*
|
|
6556
|
+
* @example
|
|
6557
|
+
* ```html
|
|
6558
|
+
* <span>{{ 90 | minutesString }}</span>
|
|
6559
|
+
* <!-- Output: "90 minutes" -->
|
|
6560
|
+
*
|
|
6561
|
+
* <span>{{ 250 | minutesString }}</span>
|
|
6562
|
+
* <!-- Output: "~5 hours" -->
|
|
6563
|
+
*
|
|
6564
|
+
* <span>{{ 5000 | minutesString }}</span>
|
|
6565
|
+
* <!-- Output: "~2 days" -->
|
|
6566
|
+
* ```
|
|
6567
|
+
*/
|
|
4432
6568
|
class MinutesStringPipe {
|
|
4433
6569
|
transform(input) {
|
|
4434
6570
|
const minutes = Number(input);
|
|
@@ -4463,6 +6599,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4463
6599
|
}]
|
|
4464
6600
|
}] });
|
|
4465
6601
|
|
|
6602
|
+
/**
|
|
6603
|
+
* Formats the distance from now to a future date as a countdown string.
|
|
6604
|
+
*
|
|
6605
|
+
* If the target date is in the past, returns the `soonString` (defaults to `"Soon"`).
|
|
6606
|
+
* Otherwise, returns a human-readable distance string with suffix (e.g., "in 3 hours").
|
|
6607
|
+
* Returns the `unavailable` string when the input is falsy.
|
|
6608
|
+
*
|
|
6609
|
+
* @example
|
|
6610
|
+
* ```html
|
|
6611
|
+
* <span>{{ futureDate | timeCountdownDistance }}</span>
|
|
6612
|
+
* <!-- Output: "in 3 hours" or "Soon" if past -->
|
|
6613
|
+
*
|
|
6614
|
+
* <span>{{ futureDate | timeCountdownDistance:'Imminent':'N/A' }}</span>
|
|
6615
|
+
* <!-- Output: "Imminent" if past, "N/A" if null -->
|
|
6616
|
+
* ```
|
|
6617
|
+
*/
|
|
4466
6618
|
class TimeDistanceCountdownPipe {
|
|
4467
6619
|
transform(input, soonString = 'Soon', unavailable = 'Not Available') {
|
|
4468
6620
|
if (input) {
|
|
@@ -4492,6 +6644,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4492
6644
|
pure: false
|
|
4493
6645
|
}]
|
|
4494
6646
|
}] });
|
|
6647
|
+
/**
|
|
6648
|
+
* Formats the distance between a date and a reference date (defaults to now) as a human-readable string with suffix.
|
|
6649
|
+
*
|
|
6650
|
+
* Uses date-fns {@link formatDistance} to produce output like "3 hours ago" or "in 2 days".
|
|
6651
|
+
* Returns the `unavailable` string when the input is falsy.
|
|
6652
|
+
*
|
|
6653
|
+
* @example
|
|
6654
|
+
* ```html
|
|
6655
|
+
* <span>{{ someDate | timeDistance }}</span>
|
|
6656
|
+
* <!-- Output: "3 hours ago" -->
|
|
6657
|
+
*
|
|
6658
|
+
* <span>{{ someDate | timeDistance:referenceDate }}</span>
|
|
6659
|
+
* <!-- Output: "2 days ago" (relative to referenceDate) -->
|
|
6660
|
+
*
|
|
6661
|
+
* <span>{{ nullDate | timeDistance:null:'Unknown' }}</span>
|
|
6662
|
+
* <!-- Output: "Unknown" -->
|
|
6663
|
+
* ```
|
|
6664
|
+
*/
|
|
4495
6665
|
class TimeDistancePipe {
|
|
4496
6666
|
transform(input, to, unavailable = 'Not Available') {
|
|
4497
6667
|
if (input) {
|
|
@@ -4516,6 +6686,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4516
6686
|
}]
|
|
4517
6687
|
}] });
|
|
4518
6688
|
|
|
6689
|
+
/**
|
|
6690
|
+
* Converts a duration in milliseconds to whole minutes by dividing by 60,000 and flooring the result.
|
|
6691
|
+
*
|
|
6692
|
+
* Returns the original value (0 or falsy) if the input is falsy.
|
|
6693
|
+
*
|
|
6694
|
+
* @example
|
|
6695
|
+
* ```html
|
|
6696
|
+
* <span>{{ 180000 | toMinutes }}</span>
|
|
6697
|
+
* <!-- Output: 3 -->
|
|
6698
|
+
*
|
|
6699
|
+
* <span>{{ durationMs | toMinutes }} min</span>
|
|
6700
|
+
* <!-- Output: "5 min" -->
|
|
6701
|
+
* ```
|
|
6702
|
+
*/
|
|
4519
6703
|
class ToMinutesPipe {
|
|
4520
6704
|
transform(milliseconds) {
|
|
4521
6705
|
if (milliseconds) {
|
|
@@ -4535,6 +6719,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4535
6719
|
}]
|
|
4536
6720
|
}] });
|
|
4537
6721
|
|
|
6722
|
+
/**
|
|
6723
|
+
* Formats a value as a pretty-printed JSON string using {@link JSON.stringify} with configurable indentation.
|
|
6724
|
+
*
|
|
6725
|
+
* Returns `undefined` for falsy input. If serialization fails, returns `'ERROR'` and logs the error to the console.
|
|
6726
|
+
*
|
|
6727
|
+
* @example
|
|
6728
|
+
* ```html
|
|
6729
|
+
* <pre>{{ myObject | prettyjson }}</pre>
|
|
6730
|
+
* <!-- Output: formatted JSON with 2-space indentation -->
|
|
6731
|
+
*
|
|
6732
|
+
* <pre>{{ myObject | prettyjson:4 }}</pre>
|
|
6733
|
+
* <!-- Output: formatted JSON with 4-space indentation -->
|
|
6734
|
+
* ```
|
|
6735
|
+
*/
|
|
4538
6736
|
class PrettyJsonPipe {
|
|
4539
6737
|
static toPrettyJson(input, spacing = 2) {
|
|
4540
6738
|
let json;
|
|
@@ -4564,7 +6762,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4564
6762
|
}] });
|
|
4565
6763
|
|
|
4566
6764
|
/**
|
|
4567
|
-
*
|
|
6765
|
+
* Truncates the input string to a maximum length and appends an ellipsis (or custom suffix) using {@link cutString}.
|
|
6766
|
+
*
|
|
6767
|
+
* Returns the original value if the input is `null` or `undefined`.
|
|
6768
|
+
*
|
|
6769
|
+
* @example
|
|
6770
|
+
* ```html
|
|
6771
|
+
* <span>{{ 'Hello World' | cutText:5 }}</span>
|
|
6772
|
+
* <!-- Output: "Hello..." -->
|
|
6773
|
+
*
|
|
6774
|
+
* <span>{{ longText | cutText:20:'--' }}</span>
|
|
6775
|
+
* <!-- Output: "Some long text here--" -->
|
|
6776
|
+
* ```
|
|
4568
6777
|
*/
|
|
4569
6778
|
class CutTextPipe {
|
|
4570
6779
|
transform(input, maxLength, endText) {
|
|
@@ -4583,7 +6792,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4583
6792
|
}] });
|
|
4584
6793
|
|
|
4585
6794
|
/**
|
|
4586
|
-
*
|
|
6795
|
+
* Resolves a {@link GetterOrValue} to its underlying value using {@link getValueFromGetter}.
|
|
6796
|
+
*
|
|
6797
|
+
* This is an impure pipe that re-evaluates on every change detection cycle, making it suitable
|
|
6798
|
+
* for getter functions whose return value may change over time.
|
|
6799
|
+
* Use {@link GetValueOncePipe} (`getValueOnce`) for a pure alternative when the value is static.
|
|
6800
|
+
*
|
|
6801
|
+
* @example
|
|
6802
|
+
* ```html
|
|
6803
|
+
* <span>{{ myGetterOrValue | getValue }}</span>
|
|
6804
|
+
* <span>{{ myGetterFn | getValue:someArg }}</span>
|
|
6805
|
+
* ```
|
|
4587
6806
|
*/
|
|
4588
6807
|
class GetValuePipe {
|
|
4589
6808
|
transform(input, args) {
|
|
@@ -4601,7 +6820,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4601
6820
|
}]
|
|
4602
6821
|
}] });
|
|
4603
6822
|
/**
|
|
4604
|
-
*
|
|
6823
|
+
* Resolves a {@link GetterOrValue} to its underlying value using {@link getValueFromGetter}.
|
|
6824
|
+
*
|
|
6825
|
+
* This is a pure pipe that only re-evaluates when the input reference changes.
|
|
6826
|
+
* Use {@link GetValuePipe} (`getValue`) if the getter function's return value may change between cycles.
|
|
6827
|
+
*
|
|
6828
|
+
* @example
|
|
6829
|
+
* ```html
|
|
6830
|
+
* <span>{{ myGetterOrValue | getValueOnce }}</span>
|
|
6831
|
+
* ```
|
|
4605
6832
|
*/
|
|
4606
6833
|
class GetValueOncePipe {
|
|
4607
6834
|
transform(input, args) {
|
|
@@ -4620,9 +6847,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4620
6847
|
}] });
|
|
4621
6848
|
|
|
4622
6849
|
/**
|
|
4623
|
-
*
|
|
6850
|
+
* Formats a numeric value as a US dollar currency string using {@link dollarAmountString}.
|
|
6851
|
+
*
|
|
6852
|
+
* Optionally accepts a default string to display when the input is `null` or `undefined`.
|
|
6853
|
+
*
|
|
6854
|
+
* @example
|
|
6855
|
+
* ```html
|
|
6856
|
+
* <span>{{ 19.5 | dollarAmount }}</span>
|
|
6857
|
+
* <!-- Output: "$19.50" -->
|
|
4624
6858
|
*
|
|
4625
|
-
*
|
|
6859
|
+
* <span>{{ nullValue | dollarAmount:'N/A' }}</span>
|
|
6860
|
+
* <!-- Output: "N/A" -->
|
|
6861
|
+
* ```
|
|
4626
6862
|
*/
|
|
4627
6863
|
class DollarAmountPipe {
|
|
4628
6864
|
transform(input, defaultIfNull) {
|
|
@@ -4641,7 +6877,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4641
6877
|
}] });
|
|
4642
6878
|
|
|
4643
6879
|
/**
|
|
4644
|
-
* Abstract FilterSourceConnector
|
|
6880
|
+
* Abstract directive implementing both {@link FilterSourceConnector} and {@link FilterSource}.
|
|
6881
|
+
*
|
|
6882
|
+
* Receives a filter source via {@link connectWithSource} and re-emits its filter values.
|
|
6883
|
+
* Subclass to create concrete connector directives.
|
|
6884
|
+
*
|
|
6885
|
+
* @typeParam F - The filter type.
|
|
6886
|
+
*
|
|
6887
|
+
* @example
|
|
6888
|
+
* ```html
|
|
6889
|
+
* <div dbxFilterSourceConnector>
|
|
6890
|
+
* <!-- Child components can inject FilterSource to read the connected filter -->
|
|
6891
|
+
* </div>
|
|
6892
|
+
* ```
|
|
4645
6893
|
*/
|
|
4646
6894
|
class AbstractFilterSourceConnectorDirective {
|
|
4647
6895
|
_source = completeOnDestroy(new BehaviorSubject(undefined));
|
|
@@ -4657,7 +6905,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4657
6905
|
}] });
|
|
4658
6906
|
|
|
4659
6907
|
/**
|
|
4660
|
-
* Angular
|
|
6908
|
+
* Creates Angular providers that register a {@link FilterSource} implementation for DI.
|
|
6909
|
+
*
|
|
6910
|
+
* @param sourceType - The concrete filter source class to provide.
|
|
6911
|
+
*
|
|
6912
|
+
* @example
|
|
6913
|
+
* ```typescript
|
|
6914
|
+
* @Directive({
|
|
6915
|
+
* selector: '[myFilterSource]',
|
|
6916
|
+
* providers: provideFilterSource(MyFilterSourceDirective),
|
|
6917
|
+
* })
|
|
6918
|
+
* export class MyFilterSourceDirective { ... }
|
|
6919
|
+
* ```
|
|
4661
6920
|
*/
|
|
4662
6921
|
function provideFilterSource(sourceType) {
|
|
4663
6922
|
return [
|
|
@@ -4668,7 +6927,9 @@ function provideFilterSource(sourceType) {
|
|
|
4668
6927
|
];
|
|
4669
6928
|
}
|
|
4670
6929
|
/**
|
|
4671
|
-
* Angular
|
|
6930
|
+
* Creates Angular providers that register both a {@link FilterSourceConnector} and {@link FilterSource} for DI.
|
|
6931
|
+
*
|
|
6932
|
+
* @param sourceType - The concrete connector class to provide.
|
|
4672
6933
|
*/
|
|
4673
6934
|
function provideFilterSourceConnector(sourceType) {
|
|
4674
6935
|
return [
|
|
@@ -4683,11 +6944,32 @@ function provideFilterSourceConnector(sourceType) {
|
|
|
4683
6944
|
];
|
|
4684
6945
|
}
|
|
4685
6946
|
|
|
6947
|
+
/**
|
|
6948
|
+
* DI token for providing a default filter value to {@link AbstractFilterSourceDirective}.
|
|
6949
|
+
*/
|
|
4686
6950
|
const FILTER_SOURCE_DIRECTIVE_DEFAULT_FILTER_TOKEN = new InjectionToken('FILTER_SOURCE_DIRECTIVE_DEFAULT_FILTER_SOURCE_TOKEN');
|
|
6951
|
+
/**
|
|
6952
|
+
* Abstract class defining the contract for a filter source directive that can be set, reset, and initialized with filters.
|
|
6953
|
+
*
|
|
6954
|
+
* @typeParam F - The filter type.
|
|
6955
|
+
*/
|
|
4687
6956
|
class FilterSourceDirective {
|
|
4688
6957
|
}
|
|
4689
6958
|
/**
|
|
4690
|
-
* Angular
|
|
6959
|
+
* Creates Angular providers for a {@link FilterSourceDirective} implementation,
|
|
6960
|
+
* with an optional factory for providing a default filter value.
|
|
6961
|
+
*
|
|
6962
|
+
* @param sourceType - The concrete directive class.
|
|
6963
|
+
* @param defaultFilterFactory - Optional factory to provide an initial filter value via DI.
|
|
6964
|
+
*
|
|
6965
|
+
* @example
|
|
6966
|
+
* ```typescript
|
|
6967
|
+
* @Directive({
|
|
6968
|
+
* selector: '[myFilterSource]',
|
|
6969
|
+
* providers: provideFilterSourceDirective(MyFilterSourceDirective),
|
|
6970
|
+
* })
|
|
6971
|
+
* export class MyFilterSourceDirective extends AbstractFilterSourceDirective<MyFilter> {}
|
|
6972
|
+
* ```
|
|
4691
6973
|
*/
|
|
4692
6974
|
function provideFilterSourceDirective(sourceType, defaultFilterFactory) {
|
|
4693
6975
|
const providers = [
|
|
@@ -4707,7 +6989,12 @@ function provideFilterSourceDirective(sourceType, defaultFilterFactory) {
|
|
|
4707
6989
|
return providers;
|
|
4708
6990
|
}
|
|
4709
6991
|
/**
|
|
4710
|
-
* Abstract FilterSource implementation
|
|
6992
|
+
* Abstract directive providing a complete {@link FilterSource} implementation backed by a {@link FilterSourceInstance}.
|
|
6993
|
+
*
|
|
6994
|
+
* Supports setting/resetting filters, initializing from an external observable, and providing
|
|
6995
|
+
* a default filter via the {@link FILTER_SOURCE_DIRECTIVE_DEFAULT_FILTER_TOKEN} DI token.
|
|
6996
|
+
*
|
|
6997
|
+
* @typeParam F - The filter type.
|
|
4711
6998
|
*/
|
|
4712
6999
|
class AbstractFilterSourceDirective {
|
|
4713
7000
|
_defaultFilter = inject(FILTER_SOURCE_DIRECTIVE_DEFAULT_FILTER_TOKEN, { optional: true });
|
|
@@ -4742,7 +7029,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4742
7029
|
}] });
|
|
4743
7030
|
|
|
4744
7031
|
/**
|
|
4745
|
-
* Connects the host FilterSource to
|
|
7032
|
+
* Connects the host element's {@link FilterSource} to an ancestor {@link FilterSourceConnector} on initialization.
|
|
7033
|
+
*
|
|
7034
|
+
* Place on an element that has a `FilterSource` (via `host: true`) to automatically
|
|
7035
|
+
* wire it up to a parent `FilterSourceConnector`.
|
|
7036
|
+
*
|
|
7037
|
+
* @example
|
|
7038
|
+
* ```html
|
|
7039
|
+
* <div dbxFilterSourceConnector>
|
|
7040
|
+
* <my-filter-form dbxFilterSource dbxFilterConnectSource></my-filter-form>
|
|
7041
|
+
* </div>
|
|
7042
|
+
* ```
|
|
4746
7043
|
*/
|
|
4747
7044
|
class DbxFilterConnectSourceDirective {
|
|
4748
7045
|
filterSource = inject((FilterSource), { host: true });
|
|
@@ -4762,7 +7059,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4762
7059
|
}] });
|
|
4763
7060
|
|
|
4764
7061
|
/**
|
|
4765
|
-
*
|
|
7062
|
+
* Concrete directive that acts as both a {@link FilterSource} and {@link FilterSourceConnector}.
|
|
7063
|
+
*
|
|
7064
|
+
* Place on an element to bridge a filter source from one part of the template to another.
|
|
7065
|
+
*
|
|
7066
|
+
* @example
|
|
7067
|
+
* ```html
|
|
7068
|
+
* <div dbxFilterSourceConnector>
|
|
7069
|
+
* <my-list-component></my-list-component>
|
|
7070
|
+
* </div>
|
|
7071
|
+
* ```
|
|
4766
7072
|
*/
|
|
4767
7073
|
class DbxFilterSourceConnectorDirective extends AbstractFilterSourceConnectorDirective {
|
|
4768
7074
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: DbxFilterSourceConnectorDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
@@ -4778,7 +7084,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4778
7084
|
}] });
|
|
4779
7085
|
|
|
4780
7086
|
/**
|
|
4781
|
-
*
|
|
7087
|
+
* Abstract directive that resolves a specific filter instance from a parent {@link FilterMap} by key.
|
|
7088
|
+
*
|
|
7089
|
+
* Subclasses set the key via {@link setFilterMapKey} and access the resolved instance via `instance$`.
|
|
7090
|
+
*
|
|
7091
|
+
* @typeParam F - The filter type.
|
|
4782
7092
|
*/
|
|
4783
7093
|
class AbstractDbxFilterMapInstanceDirective {
|
|
4784
7094
|
dbxFilterMap = inject((FilterMap));
|
|
@@ -4799,7 +7109,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4799
7109
|
}] });
|
|
4800
7110
|
|
|
4801
7111
|
/**
|
|
4802
|
-
* Abstract directive that extends AbstractDbxFilterMapInstanceDirective
|
|
7112
|
+
* Abstract directive that extends {@link AbstractDbxFilterMapInstanceDirective} to also implement {@link FilterSource},
|
|
7113
|
+
* emitting the filter values from the resolved filter map instance.
|
|
7114
|
+
*
|
|
7115
|
+
* @typeParam F - The filter type.
|
|
4803
7116
|
*/
|
|
4804
7117
|
class AbstractDbxFilterMapSourceDirective extends AbstractDbxFilterMapInstanceDirective {
|
|
4805
7118
|
filter$ = this.instance$.pipe(switchMap((x) => x.filter$));
|
|
@@ -4813,7 +7126,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4813
7126
|
type: Directive
|
|
4814
7127
|
}] });
|
|
4815
7128
|
/**
|
|
4816
|
-
*
|
|
7129
|
+
* Concrete directive that provides a {@link FilterSource} from a keyed entry in a parent {@link FilterMap}.
|
|
7130
|
+
*
|
|
7131
|
+
* @example
|
|
7132
|
+
* ```html
|
|
7133
|
+
* <div dbxFilterMap>
|
|
7134
|
+
* <div [dbxFilterMapSource]="'listFilter'">
|
|
7135
|
+
* <my-filtered-list></my-filtered-list>
|
|
7136
|
+
* </div>
|
|
7137
|
+
* </div>
|
|
7138
|
+
* ```
|
|
4817
7139
|
*/
|
|
4818
7140
|
class DbxFilterMapSourceDirective extends AbstractDbxFilterMapSourceDirective {
|
|
4819
7141
|
dbxFilterMapSource = input(...(ngDevMode ? [undefined, { debugName: "dbxFilterMapSource" }] : []));
|
|
@@ -4832,7 +7154,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4832
7154
|
}], propDecorators: { dbxFilterMapSource: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxFilterMapSource", required: false }] }] } });
|
|
4833
7155
|
|
|
4834
7156
|
/**
|
|
4835
|
-
*
|
|
7157
|
+
* Directive that acts as both a {@link FilterSourceConnector} and {@link FilterSource} for a keyed entry in a parent {@link FilterMap}.
|
|
7158
|
+
*
|
|
7159
|
+
* Connects an external filter source to a specific filter map entry and re-emits that entry's filter.
|
|
7160
|
+
*
|
|
7161
|
+
* @example
|
|
7162
|
+
* ```html
|
|
7163
|
+
* <div dbxFilterMap>
|
|
7164
|
+
* <div [dbxFilterMapSourceConnector]="'myList'">
|
|
7165
|
+
* <my-list-component></my-list-component>
|
|
7166
|
+
* </div>
|
|
7167
|
+
* </div>
|
|
7168
|
+
* ```
|
|
4836
7169
|
*/
|
|
4837
7170
|
class DbxFilterMapSourceConnectorDirective extends AbstractDbxFilterMapSourceDirective {
|
|
4838
7171
|
dbxFilterMapSourceConnector = input(...(ngDevMode ? [undefined, { debugName: "dbxFilterMapSourceConnector" }] : []));
|
|
@@ -4860,7 +7193,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4860
7193
|
}], propDecorators: { dbxFilterMapSourceConnector: [{ type: i0.Input, args: [{ isSignal: true, alias: "dbxFilterMapSourceConnector", required: false }] }] } });
|
|
4861
7194
|
|
|
4862
7195
|
/**
|
|
4863
|
-
*
|
|
7196
|
+
* Directive that provides a {@link FilterMap} instance for managing multiple named filter sources.
|
|
7197
|
+
*
|
|
7198
|
+
* Child directives like `dbxFilterMapSource` and `dbxFilterMapSourceConnector` look up this
|
|
7199
|
+
* map via DI to register and retrieve filter instances by key.
|
|
7200
|
+
*
|
|
7201
|
+
* @example
|
|
7202
|
+
* ```html
|
|
7203
|
+
* <div dbxFilterMap>
|
|
7204
|
+
* <div [dbxFilterMapSource]="'listA'">...</div>
|
|
7205
|
+
* <div [dbxFilterMapSource]="'listB'">...</div>
|
|
7206
|
+
* </div>
|
|
7207
|
+
* ```
|
|
4864
7208
|
*/
|
|
4865
7209
|
class DbxFilterMapDirective {
|
|
4866
7210
|
filterMap = clean(inject((FilterMap)));
|
|
@@ -4877,15 +7221,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4877
7221
|
}]
|
|
4878
7222
|
}] });
|
|
4879
7223
|
|
|
7224
|
+
/**
|
|
7225
|
+
* Type guard that checks if an object is a {@link ClickableFilterPreset}.
|
|
7226
|
+
*/
|
|
4880
7227
|
function isClickableFilterPreset(preset) {
|
|
4881
7228
|
return objectHasKey(preset, 'presetValue');
|
|
4882
7229
|
}
|
|
7230
|
+
/**
|
|
7231
|
+
* Type guard that checks if an object is a {@link ClickablePartialFilterPreset}.
|
|
7232
|
+
*/
|
|
4883
7233
|
function isClickablePartialFilterPreset(preset) {
|
|
4884
7234
|
return objectHasKeys(preset, ['partialPresetValue', 'isActive']);
|
|
4885
7235
|
}
|
|
4886
7236
|
|
|
4887
7237
|
/**
|
|
4888
|
-
*
|
|
7238
|
+
* Provides a {@link FilterSource} in the DI tree, allowing child components to inject and consume filter state.
|
|
7239
|
+
*
|
|
7240
|
+
* @example
|
|
7241
|
+
* ```html
|
|
7242
|
+
* <div dbxFilterSource>
|
|
7243
|
+
* <my-list-component></my-list-component>
|
|
7244
|
+
* </div>
|
|
7245
|
+
* ```
|
|
4889
7246
|
*/
|
|
4890
7247
|
class DbxFilterSourceDirective extends AbstractFilterSourceDirective {
|
|
4891
7248
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: DbxFilterSourceDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
|
|
@@ -4914,12 +7271,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
4914
7271
|
}]
|
|
4915
7272
|
}] });
|
|
4916
7273
|
|
|
7274
|
+
/**
|
|
7275
|
+
* Injection token used to provide arbitrary data to dynamically created components.
|
|
7276
|
+
*
|
|
7277
|
+
* Components created via {@link DbxInjectionComponentConfig} can inject this token
|
|
7278
|
+
* to access the `data` property from their configuration.
|
|
7279
|
+
*
|
|
7280
|
+
* @example
|
|
7281
|
+
* ```typescript
|
|
7282
|
+
* // In a dynamically injected component:
|
|
7283
|
+
* readonly data = inject(DBX_INJECTION_COMPONENT_DATA);
|
|
7284
|
+
* ```
|
|
7285
|
+
*/
|
|
4917
7286
|
const DBX_INJECTION_COMPONENT_DATA = new InjectionToken('DbxInjectionComponentConfigData');
|
|
4918
7287
|
/**
|
|
4919
|
-
* Merges multiple
|
|
7288
|
+
* Merges multiple partial {@link DbxInjectionComponentConfig} objects into a single configuration.
|
|
4920
7289
|
*
|
|
4921
|
-
*
|
|
4922
|
-
*
|
|
7290
|
+
* Provider arrays are concatenated (not overwritten) so that all providers from all configs
|
|
7291
|
+
* are preserved. All other properties are merged with later values taking precedence.
|
|
7292
|
+
*
|
|
7293
|
+
* @typeParam T - The component type for the configuration.
|
|
7294
|
+
* @param configs - An array of partial configs (may contain `undefined`/`null` entries which are filtered out).
|
|
7295
|
+
* @returns A single merged partial configuration.
|
|
4923
7296
|
*/
|
|
4924
7297
|
function mergeDbxInjectionComponentConfigs(configs) {
|
|
4925
7298
|
const providers = mergeArrays(filterMaybeArrayValues(configs).map((x) => x.providers));
|
|
@@ -4929,17 +7302,46 @@ function mergeDbxInjectionComponentConfigs(configs) {
|
|
|
4929
7302
|
}
|
|
4930
7303
|
|
|
4931
7304
|
/**
|
|
4932
|
-
*
|
|
7305
|
+
* Flattens and merges multiple provider sources into a single `StaticProvider[]` array.
|
|
4933
7306
|
*
|
|
4934
|
-
*
|
|
4935
|
-
*
|
|
7307
|
+
* Each argument can be a single `StaticProvider`, an array of providers, or `undefined`/`null`.
|
|
7308
|
+
* All values are flattened into a single array with nullish entries removed.
|
|
7309
|
+
*
|
|
7310
|
+
* @param providers - Any number of provider values or arrays to merge.
|
|
7311
|
+
* @returns A flat array of all non-nullish static providers.
|
|
7312
|
+
*
|
|
7313
|
+
* @example
|
|
7314
|
+
* ```typescript
|
|
7315
|
+
* const providers = mergeStaticProviders(
|
|
7316
|
+
* { provide: TOKEN_A, useValue: 'a' },
|
|
7317
|
+
* undefined,
|
|
7318
|
+
* [{ provide: TOKEN_B, useValue: 'b' }]
|
|
7319
|
+
* );
|
|
7320
|
+
* // Result: [{ provide: TOKEN_A, useValue: 'a' }, { provide: TOKEN_B, useValue: 'b' }]
|
|
7321
|
+
* ```
|
|
4936
7322
|
*/
|
|
4937
7323
|
function mergeStaticProviders(...providers) {
|
|
4938
7324
|
return flattenArrayOrValueArray(providers);
|
|
4939
7325
|
}
|
|
4940
7326
|
|
|
4941
7327
|
/**
|
|
4942
|
-
*
|
|
7328
|
+
* Core runtime engine for the dbx-injection system. Manages the lifecycle of dynamically injected
|
|
7329
|
+
* components and templates within an Angular `ViewContainerRef`.
|
|
7330
|
+
*
|
|
7331
|
+
* This class reactively listens to configuration and template observables. When a new
|
|
7332
|
+
* {@link DbxInjectionComponentConfig} or {@link DbxInjectionTemplateConfig} is emitted, it tears
|
|
7333
|
+
* down the previous content and creates the new component or template in the target view container.
|
|
7334
|
+
*
|
|
7335
|
+
* Component configs take precedence over template configs when both are provided.
|
|
7336
|
+
*
|
|
7337
|
+
* Typically used internally by {@link AbstractDbxInjectionDirective} and {@link DbxInjectionComponent}
|
|
7338
|
+
* rather than consumed directly.
|
|
7339
|
+
*
|
|
7340
|
+
* @typeParam T - The type of the dynamically created component.
|
|
7341
|
+
*
|
|
7342
|
+
* @see {@link DbxInjectionComponentConfig}
|
|
7343
|
+
* @see {@link DbxInjectionTemplateConfig}
|
|
7344
|
+
* @see {@link AbstractDbxInjectionDirective}
|
|
4943
7345
|
*/
|
|
4944
7346
|
class DbxInjectionInstance {
|
|
4945
7347
|
_subscriptionObject = new SubscriptionObject();
|
|
@@ -5055,7 +7457,16 @@ class DbxInjectionInstance {
|
|
|
5055
7457
|
}
|
|
5056
7458
|
|
|
5057
7459
|
/**
|
|
5058
|
-
* Abstract directive
|
|
7460
|
+
* Abstract base directive for dynamically injecting components or templates into a view.
|
|
7461
|
+
*
|
|
7462
|
+
* Manages a {@link DbxInjectionInstance} lifecycle, initializing it on `ngOnInit` and
|
|
7463
|
+
* destroying it on `ngOnDestroy`. Subclasses are responsible for wiring their inputs
|
|
7464
|
+
* (config, template, content) to the corresponding setter methods.
|
|
7465
|
+
*
|
|
7466
|
+
* @typeParam T - The type of the dynamically created component.
|
|
7467
|
+
*
|
|
7468
|
+
* @see {@link DbxInjectionComponent} - The concrete standalone component implementation.
|
|
7469
|
+
* @see {@link DbxInjectionInstance}
|
|
5059
7470
|
*/
|
|
5060
7471
|
class AbstractDbxInjectionDirective {
|
|
5061
7472
|
_instance = new DbxInjectionInstance(inject(Injector));
|
|
@@ -5065,12 +7476,27 @@ class AbstractDbxInjectionDirective {
|
|
|
5065
7476
|
ngOnDestroy() {
|
|
5066
7477
|
this._instance.destroy();
|
|
5067
7478
|
}
|
|
7479
|
+
/**
|
|
7480
|
+
* Sets the component injection configuration on the underlying {@link DbxInjectionInstance}.
|
|
7481
|
+
*
|
|
7482
|
+
* @param config - The component config, observable, or getter to use.
|
|
7483
|
+
*/
|
|
5068
7484
|
setConfig(config) {
|
|
5069
7485
|
this._instance.config = config;
|
|
5070
7486
|
}
|
|
7487
|
+
/**
|
|
7488
|
+
* Sets the template injection configuration on the underlying {@link DbxInjectionInstance}.
|
|
7489
|
+
*
|
|
7490
|
+
* @param template - The template config, observable, or getter to use.
|
|
7491
|
+
*/
|
|
5071
7492
|
setTemplate(template) {
|
|
5072
7493
|
this._instance.template = template;
|
|
5073
7494
|
}
|
|
7495
|
+
/**
|
|
7496
|
+
* Sets the target `ViewContainerRef` where dynamic content will be inserted.
|
|
7497
|
+
*
|
|
7498
|
+
* @param content - The view container reference for content projection.
|
|
7499
|
+
*/
|
|
5074
7500
|
setContent(content) {
|
|
5075
7501
|
this._instance.content = content;
|
|
5076
7502
|
}
|
|
@@ -5082,11 +7508,46 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
5082
7508
|
}] });
|
|
5083
7509
|
|
|
5084
7510
|
/**
|
|
5085
|
-
*
|
|
7511
|
+
* Standalone component for dynamically injecting a component or template into the DOM.
|
|
7512
|
+
*
|
|
7513
|
+
* Accepts a {@link DbxInjectionComponentConfig} (to create a component) or a
|
|
7514
|
+
* {@link DbxInjectionTemplateConfig} (to embed a template/view). When the config changes,
|
|
7515
|
+
* the previous content is destroyed and the new content is created in its place.
|
|
7516
|
+
*
|
|
7517
|
+
* Can be used as an element (`<dbx-injection>`) or as an attribute directive
|
|
7518
|
+
* (`[dbxInjection]` / `[dbx-injection]`).
|
|
7519
|
+
*
|
|
7520
|
+
* @typeParam T - The type of the dynamically created component.
|
|
7521
|
+
*
|
|
7522
|
+
* @example
|
|
7523
|
+
* ```html
|
|
7524
|
+
* <!-- Element usage with a component config -->
|
|
7525
|
+
* <dbx-injection [config]="myComponentConfig"></dbx-injection>
|
|
7526
|
+
*
|
|
7527
|
+
* <!-- Element usage with a template config -->
|
|
7528
|
+
* <dbx-injection [template]="myTemplateConfig"></dbx-injection>
|
|
7529
|
+
*
|
|
7530
|
+
* <!-- Attribute usage -->
|
|
7531
|
+
* <div dbxInjection [config]="myComponentConfig"></div>
|
|
7532
|
+
* ```
|
|
7533
|
+
*
|
|
7534
|
+
* @see {@link DbxInjectionComponentConfig}
|
|
7535
|
+
* @see {@link DbxInjectionTemplateConfig}
|
|
7536
|
+
* @see {@link AbstractDbxInjectionDirective}
|
|
5086
7537
|
*/
|
|
5087
7538
|
class DbxInjectionComponent extends AbstractDbxInjectionDirective {
|
|
7539
|
+
/**
|
|
7540
|
+
* Reference to the internal view container where dynamic content is projected.
|
|
7541
|
+
*/
|
|
5088
7542
|
content = viewChild('content', { ...(ngDevMode ? { debugName: "content" } : {}), read: ViewContainerRef });
|
|
7543
|
+
/**
|
|
7544
|
+
* The component injection configuration. Accepts an observable, getter, or static value.
|
|
7545
|
+
*/
|
|
5089
7546
|
config = input(...(ngDevMode ? [undefined, { debugName: "config" }] : []));
|
|
7547
|
+
/**
|
|
7548
|
+
* The template injection configuration. Accepts an observable, getter, or static value.
|
|
7549
|
+
* Only used when `config` is not provided.
|
|
7550
|
+
*/
|
|
5090
7551
|
template = input(...(ngDevMode ? [undefined, { debugName: "template" }] : []));
|
|
5091
7552
|
// allow signal writes for each as during their initialization they may write to a signal in some cases when initializing
|
|
5092
7553
|
_contentEffect = effect(() => this.setContent(this.content()), ...(ngDevMode ? [{ debugName: "_contentEffect" }] : []));
|
|
@@ -5110,9 +7571,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
5110
7571
|
}], propDecorators: { content: [{ type: i0.ViewChild, args: ['content', { ...{ read: ViewContainerRef }, isSignal: true }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], template: [{ type: i0.Input, args: [{ isSignal: true, alias: "template", required: false }] }] } });
|
|
5111
7572
|
|
|
5112
7573
|
/**
|
|
5113
|
-
*
|
|
7574
|
+
* Renders a list of dynamically injected components from an array of {@link DbxInjectionArrayEntry} items.
|
|
7575
|
+
*
|
|
7576
|
+
* Each entry is tracked by its `key` property for efficient change detection, and rendered
|
|
7577
|
+
* using a nested {@link DbxInjectionComponent}.
|
|
7578
|
+
*
|
|
7579
|
+
* @example
|
|
7580
|
+
* ```html
|
|
7581
|
+
* <dbx-injection-array [entries]="myEntries" />
|
|
7582
|
+
* ```
|
|
7583
|
+
*
|
|
7584
|
+
* @example
|
|
7585
|
+
* ```typescript
|
|
7586
|
+
* // In the host component:
|
|
7587
|
+
* myEntries: DbxInjectionArrayEntry[] = [
|
|
7588
|
+
* { key: 'chart', injectionConfig: { componentClass: ChartComponent } },
|
|
7589
|
+
* { key: 'table', injectionConfig: { componentClass: TableComponent } }
|
|
7590
|
+
* ];
|
|
7591
|
+
* ```
|
|
7592
|
+
*
|
|
7593
|
+
* @see {@link DbxInjectionArrayEntry}
|
|
7594
|
+
* @see {@link DbxInjectionComponent}
|
|
5114
7595
|
*/
|
|
5115
7596
|
class DbxInjectionArrayComponent {
|
|
7597
|
+
/**
|
|
7598
|
+
* The array of keyed injection entries to render. Each entry produces a `<dbx-injection>` component.
|
|
7599
|
+
*/
|
|
5116
7600
|
entries = input(undefined, ...(ngDevMode ? [{ debugName: "entries" }] : []));
|
|
5117
7601
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: DbxInjectionArrayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5118
7602
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: DbxInjectionArrayComponent, isStandalone: true, selector: "dbx-injection-array", inputs: { entries: { classPropertyName: "entries", publicName: "entries", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
@@ -5137,15 +7621,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
5137
7621
|
}], propDecorators: { entries: [{ type: i0.Input, args: [{ isSignal: true, alias: "entries", required: false }] }] } });
|
|
5138
7622
|
|
|
5139
7623
|
/**
|
|
5140
|
-
*
|
|
7624
|
+
* Abstract service for temporarily replacing a view's content with a dynamically injected component,
|
|
7625
|
+
* then restoring the original content when done.
|
|
7626
|
+
*
|
|
7627
|
+
* Unlike `*ngIf` or `*ngSwitch`, the original child content is **hidden** rather than destroyed,
|
|
7628
|
+
* preserving component state. Once the injected context's promise resolves (or is reset), the
|
|
7629
|
+
* original content is re-displayed.
|
|
5141
7630
|
*
|
|
5142
|
-
*
|
|
5143
|
-
* and
|
|
7631
|
+
* This is useful for overlay-like workflows such as inline editors, confirmation dialogs,
|
|
7632
|
+
* or multi-step flows where destroying and recreating the underlying view would lose state.
|
|
7633
|
+
*
|
|
7634
|
+
* @see {@link DbxInjectionContextConfig}
|
|
7635
|
+
* @see {@link DbxInjectionContextDirective} - The concrete structural directive implementation.
|
|
5144
7636
|
*/
|
|
5145
7637
|
class DbxInjectionContext {
|
|
5146
7638
|
}
|
|
5147
7639
|
/**
|
|
5148
|
-
*
|
|
7640
|
+
* Creates Angular providers that register a concrete {@link DbxInjectionContext} implementation
|
|
7641
|
+
* under the abstract `DbxInjectionContext` token via `useExisting`.
|
|
7642
|
+
*
|
|
7643
|
+
* This enables dependency injection consumers to request `DbxInjectionContext` and receive
|
|
7644
|
+
* the specific directive or service implementation.
|
|
7645
|
+
*
|
|
7646
|
+
* @typeParam T - The concrete type that extends {@link DbxInjectionContext}.
|
|
7647
|
+
* @param type - The concrete class to register as the existing provider.
|
|
7648
|
+
* @returns An array of Angular providers.
|
|
5149
7649
|
*/
|
|
5150
7650
|
function provideDbxInjectionContext(type) {
|
|
5151
7651
|
return [
|
|
@@ -5157,7 +7657,37 @@ function provideDbxInjectionContext(type) {
|
|
|
5157
7657
|
}
|
|
5158
7658
|
|
|
5159
7659
|
/**
|
|
5160
|
-
*
|
|
7660
|
+
* Structural directive that implements {@link DbxInjectionContext}, allowing its host content
|
|
7661
|
+
* to be temporarily replaced with a dynamically injected component and then restored.
|
|
7662
|
+
*
|
|
7663
|
+
* Unlike `*ngIf` or `*ngSwitch`, the original child content is **detached** (hidden) rather than
|
|
7664
|
+
* destroyed, so component state is preserved while the injected context is active. When the
|
|
7665
|
+
* context's promise resolves or {@link resetContext} is called, the original view is re-attached.
|
|
7666
|
+
*
|
|
7667
|
+
* The directive also accepts an optional `[dbxInjectionContext]` input to set a static component
|
|
7668
|
+
* config directly, which replaces the default content until cleared.
|
|
7669
|
+
*
|
|
7670
|
+
* @typeParam O - The output type produced by {@link showContext}.
|
|
7671
|
+
*
|
|
7672
|
+
* @example
|
|
7673
|
+
* ```html
|
|
7674
|
+
* <!-- Wrap content that should be temporarily replaceable -->
|
|
7675
|
+
* <div *dbxInjectionContext>
|
|
7676
|
+
* <p>Original content preserved while context is active</p>
|
|
7677
|
+
* </div>
|
|
7678
|
+
* ```
|
|
7679
|
+
*
|
|
7680
|
+
* @example
|
|
7681
|
+
* ```typescript
|
|
7682
|
+
* // Programmatically show a temporary editor overlay:
|
|
7683
|
+
* const result = await injectionContext.showContext({
|
|
7684
|
+
* config: { componentClass: InlineEditorComponent },
|
|
7685
|
+
* use: (editor) => editor.waitForSave()
|
|
7686
|
+
* });
|
|
7687
|
+
* ```
|
|
7688
|
+
*
|
|
7689
|
+
* @see {@link DbxInjectionContext}
|
|
7690
|
+
* @see {@link DbxInjectionContextConfig}
|
|
5161
7691
|
*/
|
|
5162
7692
|
class DbxInjectionContextDirective {
|
|
5163
7693
|
_injector = inject(Injector);
|
|
@@ -5167,6 +7697,10 @@ class DbxInjectionContextDirective {
|
|
|
5167
7697
|
_currentPromise;
|
|
5168
7698
|
_embeddedView;
|
|
5169
7699
|
_isDetached = false;
|
|
7700
|
+
/**
|
|
7701
|
+
* Optional static component config input. When set, the directive replaces its content
|
|
7702
|
+
* with the specified component. When cleared (`undefined`), the original content is restored.
|
|
7703
|
+
*/
|
|
5170
7704
|
config = input(...(ngDevMode ? [undefined, { debugName: "config" }] : []));
|
|
5171
7705
|
_configEffect = effect(() => {
|
|
5172
7706
|
this.setConfig(this.config());
|
|
@@ -5189,6 +7723,9 @@ class DbxInjectionContextDirective {
|
|
|
5189
7723
|
this._instance.destroy();
|
|
5190
7724
|
this._embeddedView?.destroy(); // destroy our embedded view too if it is set.
|
|
5191
7725
|
}
|
|
7726
|
+
/**
|
|
7727
|
+
* {@inheritDoc DbxInjectionContext.showContext}
|
|
7728
|
+
*/
|
|
5192
7729
|
async showContext(config) {
|
|
5193
7730
|
// clear the current context before showing something new.
|
|
5194
7731
|
this.resetContext();
|
|
@@ -5237,6 +7774,9 @@ class DbxInjectionContextDirective {
|
|
|
5237
7774
|
return result;
|
|
5238
7775
|
}
|
|
5239
7776
|
}
|
|
7777
|
+
/**
|
|
7778
|
+
* {@inheritDoc DbxInjectionContext.resetContext}
|
|
7779
|
+
*/
|
|
5240
7780
|
resetContext() {
|
|
5241
7781
|
let clearedValue = false;
|
|
5242
7782
|
if (this._currentPromise) {
|
|
@@ -5251,6 +7791,14 @@ class DbxInjectionContextDirective {
|
|
|
5251
7791
|
}
|
|
5252
7792
|
return clearedValue;
|
|
5253
7793
|
}
|
|
7794
|
+
/**
|
|
7795
|
+
* Sets or clears the active component configuration.
|
|
7796
|
+
*
|
|
7797
|
+
* When a config is provided, the original embedded view is detached and the component is injected.
|
|
7798
|
+
* When `undefined` is provided, the injected component is removed and the original view is re-attached.
|
|
7799
|
+
*
|
|
7800
|
+
* @param config - The component config to display, or `undefined` to restore the original content.
|
|
7801
|
+
*/
|
|
5254
7802
|
setConfig(config) {
|
|
5255
7803
|
let reattach = false;
|
|
5256
7804
|
if (config) {
|
|
@@ -5282,17 +7830,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
5282
7830
|
}], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }] } });
|
|
5283
7831
|
|
|
5284
7832
|
/**
|
|
5285
|
-
* Abstract
|
|
7833
|
+
* Abstract directive that delegates {@link DbxInjectionContext} operations to a host-level
|
|
7834
|
+
* `DbxInjectionContext` obtained via Angular's dependency injection (`{ host: true }`).
|
|
7835
|
+
*
|
|
7836
|
+
* This is useful for creating specialized injection context subtypes that can be injected
|
|
7837
|
+
* by their own token while still forwarding the actual show/reset behavior to a parent
|
|
7838
|
+
* {@link DbxInjectionContextDirective}.
|
|
5286
7839
|
*
|
|
5287
|
-
*
|
|
5288
|
-
*
|
|
7840
|
+
* @example
|
|
7841
|
+
* ```typescript
|
|
7842
|
+
* @Directive({ providers: [{ provide: MySpecialContext, useExisting: MyForwardDirective }] })
|
|
7843
|
+
* class MyForwardDirective extends AbstractForwardDbxInjectionContextDirective {}
|
|
7844
|
+
* ```
|
|
7845
|
+
*
|
|
7846
|
+
* @see {@link DbxInjectionContext}
|
|
7847
|
+
* @see {@link DbxInjectionContextDirective}
|
|
5289
7848
|
*/
|
|
5290
7849
|
class AbstractForwardDbxInjectionContextDirective {
|
|
7850
|
+
/**
|
|
7851
|
+
* The host-level {@link DbxInjectionContext} that all operations are forwarded to.
|
|
7852
|
+
*/
|
|
5291
7853
|
dbxInjectionContext = inject(DbxInjectionContext, { host: true });
|
|
5292
7854
|
// MARK: DbxInjectionContext
|
|
7855
|
+
/**
|
|
7856
|
+
* {@inheritDoc DbxInjectionContext.showContext}
|
|
7857
|
+
*/
|
|
5293
7858
|
showContext(config) {
|
|
5294
7859
|
return this.dbxInjectionContext.showContext(config);
|
|
5295
7860
|
}
|
|
7861
|
+
/**
|
|
7862
|
+
* {@inheritDoc DbxInjectionContext.resetContext}
|
|
7863
|
+
*/
|
|
5296
7864
|
resetContext() {
|
|
5297
7865
|
return this.dbxInjectionContext.resetContext();
|
|
5298
7866
|
}
|
|
@@ -5304,10 +7872,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
5304
7872
|
}] });
|
|
5305
7873
|
|
|
5306
7874
|
/**
|
|
5307
|
-
*
|
|
7875
|
+
* Creates an RxJS operator that switches between injection component configs, falling back to a
|
|
7876
|
+
* default config when the source emits `null`, `undefined`, or `true`.
|
|
5308
7877
|
*
|
|
5309
|
-
*
|
|
5310
|
-
*
|
|
7878
|
+
* If the `defaultConfig` resolves to a class (function), it is automatically wrapped into a
|
|
7879
|
+
* `{ componentClass }` config object.
|
|
7880
|
+
*
|
|
7881
|
+
* This is useful for reactive streams where an upstream value may indicate "use the default component"
|
|
7882
|
+
* rather than providing an explicit configuration.
|
|
7883
|
+
*
|
|
7884
|
+
* @typeParam T - The specific {@link DbxInjectionComponentConfig} subtype.
|
|
7885
|
+
* @typeParam X - The component type.
|
|
7886
|
+
* @param defaultConfig - A static value, getter, or component class to use as the fallback config.
|
|
7887
|
+
* @returns An RxJS operator compatible with `pipe()`.
|
|
7888
|
+
*
|
|
7889
|
+
* @see {@link DbxInjectionComponentConfig}
|
|
7890
|
+
*
|
|
7891
|
+
* @example
|
|
7892
|
+
* ```typescript
|
|
7893
|
+
* config$.pipe(
|
|
7894
|
+
* switchMapDbxInjectionComponentConfig(MyDefaultComponent)
|
|
7895
|
+
* ).subscribe(config => {
|
|
7896
|
+
* // config is always a DbxInjectionComponentConfig or undefined
|
|
7897
|
+
* });
|
|
7898
|
+
* ```
|
|
5311
7899
|
*/
|
|
5312
7900
|
function switchMapDbxInjectionComponentConfig(defaultConfig) {
|
|
5313
7901
|
const defaultAsGetter = asGetter(defaultConfig);
|
|
@@ -5326,11 +7914,21 @@ function switchMapDbxInjectionComponentConfig(defaultConfig) {
|
|
|
5326
7914
|
}
|
|
5327
7915
|
|
|
5328
7916
|
/**
|
|
5329
|
-
* Creates a
|
|
7917
|
+
* Creates a child injector with the given `type` as its sole provider and immediately
|
|
7918
|
+
* resolves an instance of that type.
|
|
5330
7919
|
*
|
|
5331
|
-
*
|
|
5332
|
-
*
|
|
5333
|
-
*
|
|
7920
|
+
* This is a convenience for one-off instantiation of an injectable class using a specific
|
|
7921
|
+
* parent injector, without needing to manually configure `Injector.create()`.
|
|
7922
|
+
*
|
|
7923
|
+
* @typeParam T - The type to instantiate.
|
|
7924
|
+
* @param type - The injectable class to provide and resolve.
|
|
7925
|
+
* @param parent - The parent injector that supplies the type's dependencies.
|
|
7926
|
+
* @returns A new instance of `T`.
|
|
7927
|
+
*
|
|
7928
|
+
* @example
|
|
7929
|
+
* ```typescript
|
|
7930
|
+
* const service = newWithInjector(MyService, parentInjector);
|
|
7931
|
+
* ```
|
|
5334
7932
|
*/
|
|
5335
7933
|
function newWithInjector(type, parent) {
|
|
5336
7934
|
const injector = Injector.create({ providers: [type], parent });
|
|
@@ -5338,7 +7936,26 @@ function newWithInjector(type, parent) {
|
|
|
5338
7936
|
}
|
|
5339
7937
|
|
|
5340
7938
|
/**
|
|
5341
|
-
* Abstract ComponentStore extension that
|
|
7939
|
+
* Abstract NgRx `ComponentStore` extension that integrates a {@link LockSet} for coordinating
|
|
7940
|
+
* async operations and delays destruction until all locks are released.
|
|
7941
|
+
*
|
|
7942
|
+
* Subclasses call {@link setupLockSet} to register parent lock sets and named locks.
|
|
7943
|
+
* On destroy, the store waits for all locks to unlock before completing cleanup,
|
|
7944
|
+
* preventing premature teardown of in-flight operations.
|
|
7945
|
+
*
|
|
7946
|
+
* @typeParam S - The shape of the component store's state object.
|
|
7947
|
+
*
|
|
7948
|
+
* @example
|
|
7949
|
+
* ```typescript
|
|
7950
|
+
* interface MyState { items: string[]; }
|
|
7951
|
+
*
|
|
7952
|
+
* @Injectable()
|
|
7953
|
+
* export class MyStore extends LockSetComponentStore<MyState> {
|
|
7954
|
+
* constructor() {
|
|
7955
|
+
* super({ items: [] });
|
|
7956
|
+
* }
|
|
7957
|
+
* }
|
|
7958
|
+
* ```
|
|
5342
7959
|
*/
|
|
5343
7960
|
class LockSetComponentStore extends ComponentStore {
|
|
5344
7961
|
initialState;
|
|
@@ -5383,7 +8000,8 @@ class LockSetComponentStore extends ComponentStore {
|
|
|
5383
8000
|
}, this.lockSetDestroyDelayMs);
|
|
5384
8001
|
}
|
|
5385
8002
|
/**
|
|
5386
|
-
*
|
|
8003
|
+
* Immediately completes cleanup by destroying the lock set.
|
|
8004
|
+
* Called after all locks are released during the deferred destruction process.
|
|
5387
8005
|
*/
|
|
5388
8006
|
_destroyNow() {
|
|
5389
8007
|
this.lockSet.destroy();
|
|
@@ -5400,6 +8018,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
5400
8018
|
type: Optional
|
|
5401
8019
|
}] }] });
|
|
5402
8020
|
|
|
8021
|
+
/**
|
|
8022
|
+
* Default {@link SimpleStorageAccessorConverter} that uses `JSON.stringify`/`JSON.parse` for conversion.
|
|
8023
|
+
*
|
|
8024
|
+
* @typeParam T - The type of value being converted.
|
|
8025
|
+
*/
|
|
5403
8026
|
class StringifySimpleStorageAccessorConverter {
|
|
5404
8027
|
stringifyValue(value) {
|
|
5405
8028
|
return JSON.stringify(value);
|
|
@@ -5408,6 +8031,12 @@ class StringifySimpleStorageAccessorConverter {
|
|
|
5408
8031
|
return JSON.parse(data);
|
|
5409
8032
|
}
|
|
5410
8033
|
}
|
|
8034
|
+
/**
|
|
8035
|
+
* Composes a {@link StorageAccessor} and a {@link SimpleStorageAccessorConverter} into a single
|
|
8036
|
+
* {@link SimpleStorageAccessorDelegate} implementation.
|
|
8037
|
+
*
|
|
8038
|
+
* @typeParam T - The type of value being stored.
|
|
8039
|
+
*/
|
|
5411
8040
|
class WrapperSimpleStorageAccessorDelegate {
|
|
5412
8041
|
_delegate;
|
|
5413
8042
|
_converter;
|
|
@@ -5440,6 +8069,11 @@ class WrapperSimpleStorageAccessorDelegate {
|
|
|
5440
8069
|
return this._converter.parseValue(data);
|
|
5441
8070
|
}
|
|
5442
8071
|
}
|
|
8072
|
+
/**
|
|
8073
|
+
* Validates that a storage key prefix is non-empty and does not contain the prefix splitter character.
|
|
8074
|
+
*
|
|
8075
|
+
* @throws {Error} If the prefix is invalid or the splitter is empty.
|
|
8076
|
+
*/
|
|
5443
8077
|
function assertValidStorageKeyPrefix(prefix, prefixSplitter) {
|
|
5444
8078
|
if (!prefixSplitter) {
|
|
5445
8079
|
throw new Error('Invalid storage key prefix splitter. Must be defined and not empty.'); // TODO(FUTURE): Consider changing to a concrete error type
|
|
@@ -5448,11 +8082,34 @@ function assertValidStorageKeyPrefix(prefix, prefixSplitter) {
|
|
|
5448
8082
|
throw new Error('Invalid storage key prefix.');
|
|
5449
8083
|
}
|
|
5450
8084
|
}
|
|
8085
|
+
/**
|
|
8086
|
+
* Checks whether a storage key prefix is valid (non-empty and does not contain the splitter).
|
|
8087
|
+
*/
|
|
5451
8088
|
function isValidStorageKeyPrefix(prefix, prefixSpltter) {
|
|
5452
8089
|
return Boolean(prefix && prefix.indexOf(prefixSpltter) === -1);
|
|
5453
8090
|
}
|
|
5454
8091
|
/**
|
|
5455
|
-
*
|
|
8092
|
+
* Full-featured {@link StorageAccessor} that adds key namespacing, JSON serialization,
|
|
8093
|
+
* and optional time-based expiration on top of a raw string storage backend.
|
|
8094
|
+
*
|
|
8095
|
+
* Values are stored as JSON with metadata (timestamp) and automatically checked
|
|
8096
|
+
* for expiration on read.
|
|
8097
|
+
*
|
|
8098
|
+
* @typeParam T - The type of values stored.
|
|
8099
|
+
*
|
|
8100
|
+
* @throws {DataDoesNotExistError} When reading a key that does not exist.
|
|
8101
|
+
* @throws {DataIsExpiredError} When reading a key whose stored data has expired.
|
|
8102
|
+
*
|
|
8103
|
+
* @example
|
|
8104
|
+
* ```typescript
|
|
8105
|
+
* const accessor = factory.createStorageAccessor<UserSettings>({
|
|
8106
|
+
* prefix: 'user_prefs',
|
|
8107
|
+
* expiresIn: 3600000,
|
|
8108
|
+
* });
|
|
8109
|
+
*
|
|
8110
|
+
* accessor.set('theme', { dark: true }).subscribe();
|
|
8111
|
+
* accessor.get('theme').subscribe(settings => console.log(settings));
|
|
8112
|
+
* ```
|
|
5456
8113
|
*/
|
|
5457
8114
|
class SimpleStorageAccessor {
|
|
5458
8115
|
static PREFIX_SPLITTER = '::';
|
|
@@ -5571,7 +8228,16 @@ class SimpleStorageAccessor {
|
|
|
5571
8228
|
}
|
|
5572
8229
|
|
|
5573
8230
|
/**
|
|
5574
|
-
*
|
|
8231
|
+
* {@link StorageAccessor} implementation that wraps a {@link FullStorageObject} and stores raw strings.
|
|
8232
|
+
*
|
|
8233
|
+
* Each operation completes synchronously within an observable wrapper.
|
|
8234
|
+
*
|
|
8235
|
+
* @example
|
|
8236
|
+
* ```typescript
|
|
8237
|
+
* const accessor = new StringStorageAccessor(localStorage);
|
|
8238
|
+
* accessor.set('key', 'value').subscribe();
|
|
8239
|
+
* accessor.get('key').subscribe(value => console.log(value)); // 'value'
|
|
8240
|
+
* ```
|
|
5575
8241
|
*/
|
|
5576
8242
|
class StringStorageAccessor {
|
|
5577
8243
|
_storage;
|
|
@@ -5618,11 +8284,34 @@ class StringStorageAccessor {
|
|
|
5618
8284
|
}
|
|
5619
8285
|
}
|
|
5620
8286
|
|
|
8287
|
+
/**
|
|
8288
|
+
* DI token for the application's default {@link FullStorageObject} instance.
|
|
8289
|
+
*
|
|
8290
|
+
* Provided by {@link provideDbxStorage}.
|
|
8291
|
+
*/
|
|
5621
8292
|
const DEFAULT_STORAGE_OBJECT_TOKEN = new InjectionToken('DBX_CORE_DEFAULT_STORAGE_OBJECT');
|
|
8293
|
+
/**
|
|
8294
|
+
* DI token for the application's default {@link SimpleStorageAccessorFactory} instance.
|
|
8295
|
+
*
|
|
8296
|
+
* Provided by {@link provideDbxStorage}.
|
|
8297
|
+
*/
|
|
5622
8298
|
const DEFAULT_STORAGE_ACCESSOR_FACTORY_TOKEN = new InjectionToken('DBX_CORE_DEFAULT_STORAGE_ACCESSOR_FACTORY');
|
|
5623
8299
|
|
|
5624
8300
|
/**
|
|
5625
|
-
*
|
|
8301
|
+
* Injectable factory for creating namespaced {@link SimpleStorageAccessor} instances
|
|
8302
|
+
* backed by the application's default storage object.
|
|
8303
|
+
*
|
|
8304
|
+
* @example
|
|
8305
|
+
* ```typescript
|
|
8306
|
+
* @Injectable()
|
|
8307
|
+
* export class UserPrefsService {
|
|
8308
|
+
* private readonly storage = inject(SimpleStorageAccessorFactory)
|
|
8309
|
+
* .createStorageAccessor<UserPrefs>({ prefix: 'user_prefs' });
|
|
8310
|
+
*
|
|
8311
|
+
* save(prefs: UserPrefs) { return this.storage.set('current', prefs); }
|
|
8312
|
+
* load() { return this.storage.get('current'); }
|
|
8313
|
+
* }
|
|
8314
|
+
* ```
|
|
5626
8315
|
*/
|
|
5627
8316
|
class SimpleStorageAccessorFactory {
|
|
5628
8317
|
storageObject = inject(DEFAULT_STORAGE_OBJECT_TOKEN);
|
|
@@ -5643,23 +8332,45 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
5643
8332
|
}] });
|
|
5644
8333
|
|
|
5645
8334
|
/**
|
|
5646
|
-
*
|
|
8335
|
+
* Abstract storage accessor providing key-value get/set/remove operations and a clear-all method.
|
|
8336
|
+
*
|
|
8337
|
+
* All operations return observables for consistency across sync and async storage backends.
|
|
8338
|
+
*
|
|
8339
|
+
* @typeParam T - The type of values stored.
|
|
8340
|
+
*
|
|
8341
|
+
* @see {@link StorageAccessor} for extended functionality including key/value enumeration.
|
|
5647
8342
|
*/
|
|
5648
8343
|
class LimitedStorageAccessor {
|
|
5649
8344
|
}
|
|
5650
8345
|
/**
|
|
5651
|
-
*
|
|
8346
|
+
* Extended storage accessor that adds the ability to enumerate all stored keys and values,
|
|
8347
|
+
* optionally filtered by a key prefix.
|
|
8348
|
+
*
|
|
8349
|
+
* @typeParam T - The type of values stored.
|
|
5652
8350
|
*/
|
|
5653
8351
|
class StorageAccessor extends LimitedStorageAccessor {
|
|
5654
8352
|
}
|
|
5655
8353
|
/**
|
|
5656
|
-
*
|
|
8354
|
+
* Synchronous storage accessor for scenarios where blocking get/set/remove is acceptable.
|
|
8355
|
+
*
|
|
8356
|
+
* @typeParam T - The type of values stored.
|
|
5657
8357
|
*/
|
|
5658
8358
|
class InstantStorageAccessor {
|
|
5659
8359
|
}
|
|
5660
8360
|
|
|
5661
8361
|
/**
|
|
5662
|
-
*
|
|
8362
|
+
* {@link FullStorageObject} implementation backed by the browser's `localStorage`.
|
|
8363
|
+
*
|
|
8364
|
+
* Wraps a `StorageObject` (the Web Storage API interface) and adds availability checking
|
|
8365
|
+
* and a `removeAll` operation.
|
|
8366
|
+
*
|
|
8367
|
+
* @example
|
|
8368
|
+
* ```typescript
|
|
8369
|
+
* const storage = new FullLocalStorageObject(window.localStorage);
|
|
8370
|
+
* if (storage.isAvailable) {
|
|
8371
|
+
* storage.setItem('key', 'value');
|
|
8372
|
+
* }
|
|
8373
|
+
* ```
|
|
5663
8374
|
*/
|
|
5664
8375
|
class FullLocalStorageObject {
|
|
5665
8376
|
_localStorage;
|
|
@@ -5705,7 +8416,16 @@ class FullLocalStorageObject {
|
|
|
5705
8416
|
}
|
|
5706
8417
|
|
|
5707
8418
|
/**
|
|
5708
|
-
* FullStorageObject implementation that
|
|
8419
|
+
* In-memory {@link FullStorageObject} implementation that does not persist across page loads.
|
|
8420
|
+
*
|
|
8421
|
+
* Used as a fallback when `localStorage` is unavailable (e.g., private browsing, SSR)
|
|
8422
|
+
* or for testing scenarios.
|
|
8423
|
+
*
|
|
8424
|
+
* @example
|
|
8425
|
+
* ```typescript
|
|
8426
|
+
* const storage = new MemoryStorageObject();
|
|
8427
|
+
* storage.setItem('temp', 'data'); // stored only in memory
|
|
8428
|
+
* ```
|
|
5709
8429
|
*/
|
|
5710
8430
|
class MemoryStorageObject extends FullLocalStorageObject {
|
|
5711
8431
|
get isLastingStorage() {
|
|
@@ -5720,8 +8440,14 @@ class MemoryStorageObject extends FullLocalStorageObject {
|
|
|
5720
8440
|
}
|
|
5721
8441
|
|
|
5722
8442
|
/**
|
|
5723
|
-
*
|
|
5724
|
-
* falling back to
|
|
8443
|
+
* Creates the default {@link FullStorageObject}, preferring `localStorage` and
|
|
8444
|
+
* falling back to an in-memory store if `localStorage` is unavailable.
|
|
8445
|
+
*
|
|
8446
|
+
* @example
|
|
8447
|
+
* ```typescript
|
|
8448
|
+
* const storage = defaultStorageObjectFactory();
|
|
8449
|
+
* storage.setItem('key', 'value');
|
|
8450
|
+
* ```
|
|
5725
8451
|
*/
|
|
5726
8452
|
function defaultStorageObjectFactory() {
|
|
5727
8453
|
let storageObject = new FullLocalStorageObject(localStorage);
|
|
@@ -5731,9 +8457,16 @@ function defaultStorageObjectFactory() {
|
|
|
5731
8457
|
return storageObject;
|
|
5732
8458
|
}
|
|
5733
8459
|
/**
|
|
5734
|
-
*
|
|
8460
|
+
* Registers the default storage object and {@link SimpleStorageAccessorFactory} as environment-level providers.
|
|
5735
8461
|
*
|
|
5736
|
-
*
|
|
8462
|
+
* Call in your application config to enable storage-based services throughout the app.
|
|
8463
|
+
*
|
|
8464
|
+
* @example
|
|
8465
|
+
* ```typescript
|
|
8466
|
+
* export const appConfig: ApplicationConfig = {
|
|
8467
|
+
* providers: [provideDbxStorage()],
|
|
8468
|
+
* };
|
|
8469
|
+
* ```
|
|
5737
8470
|
*/
|
|
5738
8471
|
function provideDbxStorage() {
|
|
5739
8472
|
const providers = [
|
|
@@ -5756,55 +8489,69 @@ function provideDbxStorage() {
|
|
|
5756
8489
|
}
|
|
5757
8490
|
|
|
5758
8491
|
/**
|
|
5759
|
-
*
|
|
8492
|
+
* RxJS operator that triggers `detectChanges()` on a `ChangeDetectorRef` after each emission.
|
|
5760
8493
|
*
|
|
5761
|
-
*
|
|
8494
|
+
* Wraps the detection call in a `setTimeout` to avoid triggering it during change detection cycles.
|
|
5762
8495
|
*
|
|
5763
|
-
* @
|
|
5764
|
-
*
|
|
5765
|
-
* @
|
|
8496
|
+
* @deprecated Use Angular signals instead.
|
|
8497
|
+
*
|
|
8498
|
+
* @param cdRef - The change detector to trigger. If `null`/`undefined`, the operator is a no-op.
|
|
8499
|
+
* @param timeout - Delay in milliseconds before calling `detectChanges`.
|
|
8500
|
+
*
|
|
8501
|
+
* @example
|
|
8502
|
+
* ```typescript
|
|
8503
|
+
* this.data$.pipe(tapDetectChanges(this.cdRef)).subscribe();
|
|
8504
|
+
* ```
|
|
5766
8505
|
*/
|
|
5767
8506
|
function tapDetectChanges(cdRef, timeout = 0) {
|
|
5768
8507
|
return cdRef ? tap(() => setTimeout(() => safeDetectChanges(cdRef), timeout)) : tap();
|
|
5769
8508
|
}
|
|
5770
8509
|
/**
|
|
5771
|
-
*
|
|
8510
|
+
* Safely calls `detectChanges()` on a `ChangeDetectorRef`, skipping the call if the view is already destroyed.
|
|
5772
8511
|
*
|
|
5773
|
-
* @deprecated
|
|
8512
|
+
* @deprecated Use Angular signals instead.
|
|
5774
8513
|
*
|
|
5775
|
-
* @param cdRef
|
|
8514
|
+
* @param cdRef - The change detector to trigger.
|
|
5776
8515
|
*/
|
|
5777
8516
|
function safeDetectChanges(cdRef) {
|
|
5778
8517
|
safeUseCdRef(cdRef, () => cdRef.detectChanges());
|
|
5779
8518
|
}
|
|
5780
8519
|
/**
|
|
5781
|
-
*
|
|
8520
|
+
* RxJS operator that calls `markForCheck()` on a `ChangeDetectorRef` after each emission.
|
|
5782
8521
|
*
|
|
5783
|
-
*
|
|
8522
|
+
* Intended for components using `OnPush` change detection that subscribe to observables
|
|
8523
|
+
* outside of the `async` pipe. Not needed when using the `async` pipe.
|
|
5784
8524
|
*
|
|
5785
|
-
* @deprecated
|
|
5786
|
-
*
|
|
5787
|
-
* @param
|
|
5788
|
-
* @
|
|
8525
|
+
* @deprecated Use Angular signals instead.
|
|
8526
|
+
*
|
|
8527
|
+
* @param cdRef - The change detector to mark. If `null`/`undefined`, the operator is a no-op.
|
|
8528
|
+
* @param timeout - Delay in milliseconds before calling `markForCheck`.
|
|
8529
|
+
*
|
|
8530
|
+
* @example
|
|
8531
|
+
* ```typescript
|
|
8532
|
+
* this.data$.pipe(tapSafeMarkForCheck(this.cdRef)).subscribe();
|
|
8533
|
+
* ```
|
|
5789
8534
|
*/
|
|
5790
8535
|
function tapSafeMarkForCheck(cdRef, timeout = 0) {
|
|
5791
8536
|
return cdRef ? tap(() => setTimeout(() => safeMarkForCheck(cdRef), timeout)) : tap();
|
|
5792
8537
|
}
|
|
5793
8538
|
/**
|
|
5794
|
-
*
|
|
8539
|
+
* Safely calls `markForCheck()` on a `ChangeDetectorRef`, skipping the call if the view is already destroyed.
|
|
5795
8540
|
*
|
|
5796
|
-
* @deprecated
|
|
8541
|
+
* @deprecated Use Angular signals instead.
|
|
5797
8542
|
*
|
|
5798
|
-
* @param cdRef
|
|
8543
|
+
* @param cdRef - The change detector to mark.
|
|
5799
8544
|
*/
|
|
5800
8545
|
function safeMarkForCheck(cdRef) {
|
|
5801
8546
|
safeUseCdRef(cdRef, () => cdRef.markForCheck());
|
|
5802
8547
|
}
|
|
5803
8548
|
/**
|
|
5804
|
-
*
|
|
8549
|
+
* Executes a callback with the given `ChangeDetectorRef` only if its view has not been destroyed.
|
|
5805
8550
|
*
|
|
5806
|
-
* @deprecated
|
|
5807
|
-
*
|
|
8551
|
+
* @deprecated Use Angular signals instead.
|
|
8552
|
+
*
|
|
8553
|
+
* @param cdRef - The change detector to guard.
|
|
8554
|
+
* @param use - Callback to invoke with the change detector.
|
|
5808
8555
|
*/
|
|
5809
8556
|
function safeUseCdRef(cdRef, use) {
|
|
5810
8557
|
if (!cdRef.destroyed) {
|
|
@@ -5812,17 +8559,31 @@ function safeUseCdRef(cdRef, use) {
|
|
|
5812
8559
|
}
|
|
5813
8560
|
}
|
|
5814
8561
|
/**
|
|
5815
|
-
*
|
|
5816
|
-
*
|
|
5817
|
-
*
|
|
8562
|
+
* Checks whether an `ng-content` wrapper element received any projected content from its parent.
|
|
8563
|
+
*
|
|
8564
|
+
* Returns `true` if the element has any child nodes, even if the projected content is empty.
|
|
8565
|
+
* Useful for conditionally showing fallback content when no projection is provided.
|
|
5818
8566
|
*
|
|
5819
|
-
*
|
|
5820
|
-
* @ViewChild('customLoading', { static: false }) customCustom: ElementRef;
|
|
8567
|
+
* @param ref - Reference to the wrapper element around `ng-content`.
|
|
5821
8568
|
*
|
|
5822
|
-
*
|
|
5823
|
-
*
|
|
5824
|
-
*
|
|
8569
|
+
* @example
|
|
8570
|
+
* ```typescript
|
|
8571
|
+
* // In the component class:
|
|
8572
|
+
* @ViewChild('contentWrapper', { static: false }) contentRef: ElementRef;
|
|
8573
|
+
*
|
|
8574
|
+
* get hasContent(): boolean {
|
|
8575
|
+
* return checkNgContentWrapperHasContent(this.contentRef);
|
|
8576
|
+
* }
|
|
8577
|
+
* ```
|
|
8578
|
+
*
|
|
8579
|
+
* @example
|
|
8580
|
+
* ```html
|
|
8581
|
+
* <!-- In the component template: -->
|
|
8582
|
+
* <div #contentWrapper>
|
|
8583
|
+
* <ng-content select="[content]"></ng-content>
|
|
5825
8584
|
* </div>
|
|
8585
|
+
* <div *ngIf="!hasContent">No content provided</div>
|
|
8586
|
+
* ```
|
|
5826
8587
|
*/
|
|
5827
8588
|
function checkNgContentWrapperHasContent(ref) {
|
|
5828
8589
|
// https://github.com/angular/angular/issues/26083
|