angular-material-wrap 0.1.0-beta.8 → 0.1.0-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, model, output, ViewEncapsulation, Component, computed, signal, effect, ContentChild, viewChild, Directive, forwardRef, ViewChild, contentChildren, Injectable, contentChild, Injector, Optional, Inject, Pipe, inject, InjectionToken } from '@angular/core';
2
+ import { input, model, output, ViewEncapsulation, Component, computed, signal, effect, ContentChild, viewChild, Directive, Injectable, inject, ElementRef, Renderer2, HostListener, forwardRef, ViewChild, contentChildren, contentChild, Injector, Optional, Inject, Pipe, InjectionToken } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import { CommonModule, NgTemplateOutlet } from '@angular/common';
5
5
  import * as i2 from '@angular/material/button';
@@ -42,7 +42,7 @@ import * as i1$9 from '@angular/cdk/overlay';
42
42
  import { OverlayModule } from '@angular/cdk/overlay';
43
43
  import * as i7 from '@angular/material/menu';
44
44
  import { MatMenuModule, MatMenuTrigger } from '@angular/material/menu';
45
- import { Subject, debounceTime, distinctUntilChanged, takeUntil, Subscription, fromEvent, BehaviorSubject, defer, from, of } from 'rxjs';
45
+ import { Subject, debounceTime, distinctUntilChanged, takeUntil, Subscription, fromEvent, Observable, BehaviorSubject, defer, from, of } from 'rxjs';
46
46
  import { ComponentPortal, TemplatePortal } from '@angular/cdk/portal';
47
47
  import * as i1$a from '@angular/material/divider';
48
48
  import { MatDividerModule } from '@angular/material/divider';
@@ -3476,6 +3476,610 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
3476
3476
  }]
3477
3477
  }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { amwBadge: [{ type: i0.Input, args: [{ isSignal: true, alias: "amwBadge", required: true }] }], amwBadgeColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "amwBadgeColor", required: false }] }], amwBadgePosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "amwBadgePosition", required: false }] }], amwBadgeSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "amwBadgeSize", required: false }] }], amwBadgeHidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "amwBadgeHidden", required: false }] }], amwBadgeOverlap: [{ type: i0.Input, args: [{ isSignal: true, alias: "amwBadgeOverlap", required: false }] }], amwBadgeClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "amwBadgeClass", required: false }] }] } });
3478
3478
 
3479
+ const DEFAULT_CONFIG$1 = {
3480
+ autoReevaluate: true,
3481
+ debounceTime: 300,
3482
+ disableOnErrors: true,
3483
+ disableOnWarnings: false
3484
+ };
3485
+ /**
3486
+ * AMW Validation Service
3487
+ *
3488
+ * Provides centralized validation management for components.
3489
+ * Components can create validation contexts, add/remove violations,
3490
+ * and automatically reevaluate when associated controls change.
3491
+ *
3492
+ * @example
3493
+ * ```typescript
3494
+ * // In your component
3495
+ * export class MyFormComponent implements OnInit {
3496
+ * private validationContext!: ValidationContext;
3497
+ *
3498
+ * constructor(private validationService: AmwValidationService) {}
3499
+ *
3500
+ * ngOnInit() {
3501
+ * this.validationContext = this.validationService.createContext({
3502
+ * disableOnErrors: true
3503
+ * });
3504
+ *
3505
+ * // Add a violation
3506
+ * this.validationService.addViolation(this.validationContext.id, {
3507
+ * id: 'name-required',
3508
+ * message: 'Name is required',
3509
+ * severity: 'error',
3510
+ * field: 'name',
3511
+ * control: this.form.get('name'),
3512
+ * validator: () => !!this.form.get('name')?.value
3513
+ * });
3514
+ * }
3515
+ * }
3516
+ * ```
3517
+ */
3518
+ class AmwValidationService {
3519
+ /** Map of all validation contexts by ID */
3520
+ contexts = new Map();
3521
+ /** Counter for generating unique IDs */
3522
+ idCounter = 0;
3523
+ /** Map of control subscriptions for cleanup */
3524
+ controlSubscriptions = new Map();
3525
+ constructor() { }
3526
+ /**
3527
+ * Create a new validation context for a component
3528
+ * @param config Optional configuration
3529
+ * @returns The created validation context
3530
+ */
3531
+ createContext(config) {
3532
+ const id = this.generateId();
3533
+ const violations = signal([], ...(ngDevMode ? [{ debugName: "violations" }] : []));
3534
+ const mergedConfig = { ...DEFAULT_CONFIG$1, ...config };
3535
+ const hasErrors = computed(() => violations().some(v => v.severity === 'error'), ...(ngDevMode ? [{ debugName: "hasErrors" }] : []));
3536
+ const hasWarnings = computed(() => violations().some(v => v.severity === 'warning'), ...(ngDevMode ? [{ debugName: "hasWarnings" }] : []));
3537
+ const isSubmitDisabled = computed(() => {
3538
+ if (mergedConfig.disableOnErrors && hasErrors())
3539
+ return true;
3540
+ if (mergedConfig.disableOnWarnings && hasWarnings())
3541
+ return true;
3542
+ return false;
3543
+ }, ...(ngDevMode ? [{ debugName: "isSubmitDisabled" }] : []));
3544
+ const context = {
3545
+ id,
3546
+ violations,
3547
+ hasErrors,
3548
+ hasWarnings,
3549
+ isSubmitDisabled,
3550
+ config: mergedConfig
3551
+ };
3552
+ this.contexts.set(id, context);
3553
+ return context;
3554
+ }
3555
+ /**
3556
+ * Destroy a validation context and clean up subscriptions
3557
+ * @param contextId The context ID to destroy
3558
+ */
3559
+ destroyContext(contextId) {
3560
+ // Clean up control subscriptions
3561
+ const subscriptions = this.controlSubscriptions.get(contextId);
3562
+ if (subscriptions) {
3563
+ subscriptions.forEach(unsub => unsub());
3564
+ this.controlSubscriptions.delete(contextId);
3565
+ }
3566
+ this.contexts.delete(contextId);
3567
+ }
3568
+ /**
3569
+ * Add a violation to a context
3570
+ * @param contextId The context ID
3571
+ * @param violation The violation to add (without ID, one will be generated)
3572
+ * @returns The violation ID
3573
+ */
3574
+ addViolation(contextId, violation) {
3575
+ const context = this.contexts.get(contextId);
3576
+ if (!context) {
3577
+ throw new Error(`Validation context ${contextId} not found`);
3578
+ }
3579
+ const violationId = violation.id || this.generateViolationId();
3580
+ const fullViolation = {
3581
+ ...violation,
3582
+ id: violationId
3583
+ };
3584
+ // Check if violation with same ID already exists
3585
+ const existing = context.violations().find(v => v.id === violationId);
3586
+ if (existing) {
3587
+ // Update existing violation
3588
+ context.violations.update(violations => violations.map(v => v.id === violationId ? fullViolation : v));
3589
+ }
3590
+ else {
3591
+ // Add new violation
3592
+ context.violations.update(violations => [...violations, fullViolation]);
3593
+ }
3594
+ // Set up control subscription for auto-reevaluation
3595
+ if (context.config.autoReevaluate && fullViolation.control) {
3596
+ this.setupControlSubscription(contextId, fullViolation);
3597
+ }
3598
+ return violationId;
3599
+ }
3600
+ /**
3601
+ * Remove a violation from a context
3602
+ * @param contextId The context ID
3603
+ * @param violationId The violation ID to remove
3604
+ */
3605
+ removeViolation(contextId, violationId) {
3606
+ const context = this.contexts.get(contextId);
3607
+ if (!context)
3608
+ return;
3609
+ context.violations.update(violations => violations.filter(v => v.id !== violationId));
3610
+ }
3611
+ /**
3612
+ * Clear all violations from a context
3613
+ * @param contextId The context ID
3614
+ */
3615
+ clearViolations(contextId) {
3616
+ const context = this.contexts.get(contextId);
3617
+ if (!context)
3618
+ return;
3619
+ context.violations.set([]);
3620
+ }
3621
+ /**
3622
+ * Get all violations for a context
3623
+ * @param contextId The context ID
3624
+ * @returns Array of violations
3625
+ */
3626
+ getViolations(contextId) {
3627
+ const context = this.contexts.get(contextId);
3628
+ return context?.violations() || [];
3629
+ }
3630
+ /**
3631
+ * Get violations for a specific field
3632
+ * @param contextId The context ID
3633
+ * @param field The field name
3634
+ * @returns Array of violations for the field
3635
+ */
3636
+ getFieldViolations(contextId, field) {
3637
+ return this.getViolations(contextId).filter(v => v.field === field);
3638
+ }
3639
+ /**
3640
+ * Check if a context has any violations
3641
+ * @param contextId The context ID
3642
+ * @returns True if violations exist
3643
+ */
3644
+ hasViolations(contextId) {
3645
+ return this.getViolations(contextId).length > 0;
3646
+ }
3647
+ /**
3648
+ * Reevaluate all violations in a context
3649
+ * @param contextId The context ID
3650
+ */
3651
+ reevaluate(contextId) {
3652
+ const context = this.contexts.get(contextId);
3653
+ if (!context)
3654
+ return;
3655
+ context.violations.update(violations => violations.filter(v => {
3656
+ if (v.validator) {
3657
+ return !v.validator(); // Keep violation if validator returns false
3658
+ }
3659
+ if (v.control) {
3660
+ return v.control.invalid; // Keep violation if control is invalid
3661
+ }
3662
+ return true; // Keep violations without validator or control
3663
+ }));
3664
+ }
3665
+ /**
3666
+ * Get a context by ID
3667
+ * @param contextId The context ID
3668
+ * @returns The validation context or undefined
3669
+ */
3670
+ getContext(contextId) {
3671
+ return this.contexts.get(contextId);
3672
+ }
3673
+ /**
3674
+ * Set up a subscription to a control for auto-reevaluation
3675
+ */
3676
+ setupControlSubscription(contextId, violation) {
3677
+ if (!violation.control)
3678
+ return;
3679
+ let debounceTimer = null;
3680
+ const context = this.contexts.get(contextId);
3681
+ if (!context)
3682
+ return;
3683
+ const subscription = violation.control.valueChanges.subscribe(() => {
3684
+ if (debounceTimer) {
3685
+ clearTimeout(debounceTimer);
3686
+ }
3687
+ debounceTimer = setTimeout(() => {
3688
+ // Reevaluate this specific violation
3689
+ const shouldKeep = violation.validator
3690
+ ? !violation.validator()
3691
+ : violation.control?.invalid;
3692
+ if (!shouldKeep) {
3693
+ this.removeViolation(contextId, violation.id);
3694
+ }
3695
+ }, context.config.debounceTime);
3696
+ });
3697
+ // Store unsubscribe function
3698
+ const subscriptions = this.controlSubscriptions.get(contextId) || [];
3699
+ subscriptions.push(() => subscription.unsubscribe());
3700
+ this.controlSubscriptions.set(contextId, subscriptions);
3701
+ }
3702
+ generateId() {
3703
+ return `vc_${Date.now()}_${++this.idCounter}`;
3704
+ }
3705
+ generateViolationId() {
3706
+ return `vv_${Date.now()}_${++this.idCounter}`;
3707
+ }
3708
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AmwValidationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
3709
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AmwValidationService, providedIn: 'root' });
3710
+ }
3711
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AmwValidationService, decorators: [{
3712
+ type: Injectable,
3713
+ args: [{
3714
+ providedIn: 'root'
3715
+ }]
3716
+ }], ctorParameters: () => [] });
3717
+ /**
3718
+ * Mixin/base class functionality for components that need validation
3719
+ * This can be used via composition or inheritance
3720
+ */
3721
+ class ValidationMixin {
3722
+ validationService;
3723
+ validationContext;
3724
+ /**
3725
+ * Initialize validation for this component
3726
+ * Call this in ngOnInit
3727
+ */
3728
+ initializeValidation(service, config) {
3729
+ this.validationService = service;
3730
+ this.validationContext = service.createContext(config);
3731
+ }
3732
+ /**
3733
+ * Clean up validation context
3734
+ * Call this in ngOnDestroy
3735
+ */
3736
+ destroyValidation() {
3737
+ if (this.validationContext) {
3738
+ this.validationService.destroyContext(this.validationContext.id);
3739
+ }
3740
+ }
3741
+ /**
3742
+ * Add a validation violation
3743
+ */
3744
+ addViolation(violation) {
3745
+ return this.validationService.addViolation(this.validationContext.id, violation);
3746
+ }
3747
+ /**
3748
+ * Remove a validation violation
3749
+ */
3750
+ removeViolation(violationId) {
3751
+ this.validationService.removeViolation(this.validationContext.id, violationId);
3752
+ }
3753
+ /**
3754
+ * Clear all violations
3755
+ */
3756
+ clearViolations() {
3757
+ this.validationService.clearViolations(this.validationContext.id);
3758
+ }
3759
+ /**
3760
+ * Get all violations
3761
+ */
3762
+ get violations() {
3763
+ return this.validationContext?.violations() || [];
3764
+ }
3765
+ /**
3766
+ * Check if submit should be disabled
3767
+ */
3768
+ get isSubmitDisabled() {
3769
+ return this.validationContext?.isSubmitDisabled() || false;
3770
+ }
3771
+ /**
3772
+ * Check if there are any errors
3773
+ */
3774
+ get hasErrors() {
3775
+ return this.validationContext?.hasErrors() || false;
3776
+ }
3777
+ /**
3778
+ * Check if there are any warnings
3779
+ */
3780
+ get hasWarnings() {
3781
+ return this.validationContext?.hasWarnings() || false;
3782
+ }
3783
+ }
3784
+
3785
+ /**
3786
+ * AMW Validation Tooltip Directive
3787
+ *
3788
+ * Displays validation violations in a tooltip when hovering over a submit button.
3789
+ * Works with the AmwValidationService to show relevant validation messages.
3790
+ *
3791
+ * When violations exist and the user hovers over the button, a tooltip appears
3792
+ * showing all current validation messages. The button is also automatically
3793
+ * disabled based on the validation context configuration.
3794
+ *
3795
+ * @example
3796
+ * ```html
3797
+ * <!-- Basic usage with validation context ID -->
3798
+ * <button [amwValidationTooltip]="validationContext.id">
3799
+ * Submit
3800
+ * </button>
3801
+ *
3802
+ * <!-- With validation context object -->
3803
+ * <button [amwValidationTooltip]="validationContext">
3804
+ * Submit
3805
+ * </button>
3806
+ *
3807
+ * <!-- Auto-disable based on validation state -->
3808
+ * <amw-button
3809
+ * [amwValidationTooltip]="validationContext"
3810
+ * [disabled]="validationContext.isSubmitDisabled()">
3811
+ * Submit
3812
+ * </amw-button>
3813
+ * ```
3814
+ */
3815
+ class AmwValidationTooltipDirective {
3816
+ elementRef = inject(ElementRef);
3817
+ renderer = inject(Renderer2);
3818
+ validationService = inject(AmwValidationService);
3819
+ /**
3820
+ * The validation context (ID string or context object)
3821
+ */
3822
+ amwValidationTooltip = input.required(...(ngDevMode ? [{ debugName: "amwValidationTooltip" }] : []));
3823
+ /**
3824
+ * Position of the tooltip
3825
+ */
3826
+ tooltipPosition = input('top', ...(ngDevMode ? [{ debugName: "tooltipPosition" }] : []));
3827
+ /**
3828
+ * Whether to auto-disable the element when validation fails
3829
+ */
3830
+ autoDisable = input(true, ...(ngDevMode ? [{ debugName: "autoDisable" }] : []));
3831
+ /** The tooltip element */
3832
+ tooltipElement = null;
3833
+ /** Whether tooltip is currently visible */
3834
+ isTooltipVisible = false;
3835
+ /** Timeout for delayed show */
3836
+ showTimeout = null;
3837
+ /** Timeout for delayed hide */
3838
+ hideTimeout = null;
3839
+ constructor() {
3840
+ // Set up effect to auto-disable based on validation state
3841
+ effect(() => {
3842
+ if (this.autoDisable()) {
3843
+ const context = this.getContext();
3844
+ if (context && context.isSubmitDisabled()) {
3845
+ this.renderer.setAttribute(this.elementRef.nativeElement, 'disabled', 'true');
3846
+ }
3847
+ else {
3848
+ this.renderer.removeAttribute(this.elementRef.nativeElement, 'disabled');
3849
+ }
3850
+ }
3851
+ });
3852
+ }
3853
+ ngOnInit() {
3854
+ this.createTooltipElement();
3855
+ }
3856
+ ngOnDestroy() {
3857
+ this.removeTooltip();
3858
+ if (this.showTimeout)
3859
+ clearTimeout(this.showTimeout);
3860
+ if (this.hideTimeout)
3861
+ clearTimeout(this.hideTimeout);
3862
+ }
3863
+ onMouseEnter() {
3864
+ const violations = this.getViolations();
3865
+ if (violations.length > 0) {
3866
+ if (this.hideTimeout) {
3867
+ clearTimeout(this.hideTimeout);
3868
+ this.hideTimeout = null;
3869
+ }
3870
+ this.showTimeout = setTimeout(() => this.showTooltip(), 200);
3871
+ }
3872
+ }
3873
+ onMouseLeave() {
3874
+ if (this.showTimeout) {
3875
+ clearTimeout(this.showTimeout);
3876
+ this.showTimeout = null;
3877
+ }
3878
+ this.hideTimeout = setTimeout(() => this.hideTooltip(), 100);
3879
+ }
3880
+ onFocus() {
3881
+ const violations = this.getViolations();
3882
+ if (violations.length > 0) {
3883
+ this.showTooltip();
3884
+ }
3885
+ }
3886
+ onBlur() {
3887
+ this.hideTooltip();
3888
+ }
3889
+ /**
3890
+ * Get the validation context
3891
+ */
3892
+ getContext() {
3893
+ const input = this.amwValidationTooltip();
3894
+ if (typeof input === 'string') {
3895
+ return this.validationService.getContext(input);
3896
+ }
3897
+ return input;
3898
+ }
3899
+ /**
3900
+ * Get current violations
3901
+ */
3902
+ getViolations() {
3903
+ const context = this.getContext();
3904
+ return context?.violations() || [];
3905
+ }
3906
+ /**
3907
+ * Create the tooltip element
3908
+ */
3909
+ createTooltipElement() {
3910
+ this.tooltipElement = this.renderer.createElement('div');
3911
+ this.renderer.addClass(this.tooltipElement, 'amw-validation-tooltip');
3912
+ this.renderer.setStyle(this.tooltipElement, 'position', 'fixed');
3913
+ this.renderer.setStyle(this.tooltipElement, 'z-index', '10000');
3914
+ this.renderer.setStyle(this.tooltipElement, 'pointer-events', 'none');
3915
+ this.renderer.setStyle(this.tooltipElement, 'opacity', '0');
3916
+ this.renderer.setStyle(this.tooltipElement, 'visibility', 'hidden');
3917
+ this.renderer.setStyle(this.tooltipElement, 'transition', 'opacity 200ms, visibility 200ms');
3918
+ // Use softer info-style colors for less jarring appearance
3919
+ this.renderer.setStyle(this.tooltipElement, 'background-color', '#e3f2fd');
3920
+ this.renderer.setStyle(this.tooltipElement, 'color', '#002171');
3921
+ this.renderer.setStyle(this.tooltipElement, 'padding', '8px 12px');
3922
+ this.renderer.setStyle(this.tooltipElement, 'border-radius', '4px');
3923
+ this.renderer.setStyle(this.tooltipElement, 'font-size', '12px');
3924
+ this.renderer.setStyle(this.tooltipElement, 'max-width', '300px');
3925
+ this.renderer.setStyle(this.tooltipElement, 'box-shadow', '0 2px 8px rgba(0,0,0,0.15)');
3926
+ if (this.tooltipElement) {
3927
+ document.body.appendChild(this.tooltipElement);
3928
+ }
3929
+ }
3930
+ /**
3931
+ * Show the tooltip
3932
+ */
3933
+ showTooltip() {
3934
+ if (!this.tooltipElement)
3935
+ return;
3936
+ const violations = this.getViolations();
3937
+ if (violations.length === 0)
3938
+ return;
3939
+ // Build tooltip content
3940
+ const content = this.buildTooltipContent(violations);
3941
+ this.tooltipElement.innerHTML = content;
3942
+ // Position the tooltip
3943
+ this.positionTooltip();
3944
+ // Show with animation
3945
+ this.renderer.setStyle(this.tooltipElement, 'opacity', '1');
3946
+ this.renderer.setStyle(this.tooltipElement, 'visibility', 'visible');
3947
+ this.isTooltipVisible = true;
3948
+ }
3949
+ /**
3950
+ * Hide the tooltip
3951
+ */
3952
+ hideTooltip() {
3953
+ if (!this.tooltipElement)
3954
+ return;
3955
+ this.renderer.setStyle(this.tooltipElement, 'opacity', '0');
3956
+ this.renderer.setStyle(this.tooltipElement, 'visibility', 'hidden');
3957
+ this.isTooltipVisible = false;
3958
+ }
3959
+ /**
3960
+ * Build tooltip HTML content
3961
+ */
3962
+ buildTooltipContent(violations) {
3963
+ const errors = violations.filter(v => v.severity === 'error');
3964
+ const warnings = violations.filter(v => v.severity === 'warning');
3965
+ const infos = violations.filter(v => v.severity === 'info');
3966
+ let html = '<div class="amw-validation-tooltip__content">';
3967
+ if (errors.length > 0) {
3968
+ html += '<div class="amw-validation-tooltip__section amw-validation-tooltip__section--error">';
3969
+ html += '<strong>Errors:</strong>';
3970
+ html += '<ul style="margin: 4px 0 0 0; padding-left: 16px;">';
3971
+ errors.forEach(e => {
3972
+ html += `<li>${this.escapeHtml(e.message)}</li>`;
3973
+ });
3974
+ html += '</ul></div>';
3975
+ }
3976
+ if (warnings.length > 0) {
3977
+ html += '<div class="amw-validation-tooltip__section amw-validation-tooltip__section--warning" style="margin-top: 8px;">';
3978
+ html += '<strong>Warnings:</strong>';
3979
+ html += '<ul style="margin: 4px 0 0 0; padding-left: 16px;">';
3980
+ warnings.forEach(w => {
3981
+ html += `<li>${this.escapeHtml(w.message)}</li>`;
3982
+ });
3983
+ html += '</ul></div>';
3984
+ }
3985
+ if (infos.length > 0) {
3986
+ html += '<div class="amw-validation-tooltip__section amw-validation-tooltip__section--info" style="margin-top: 8px;">';
3987
+ html += '<strong>Info:</strong>';
3988
+ html += '<ul style="margin: 4px 0 0 0; padding-left: 16px;">';
3989
+ infos.forEach(i => {
3990
+ html += `<li>${this.escapeHtml(i.message)}</li>`;
3991
+ });
3992
+ html += '</ul></div>';
3993
+ }
3994
+ html += '</div>';
3995
+ return html;
3996
+ }
3997
+ /**
3998
+ * Position the tooltip relative to the host element
3999
+ */
4000
+ positionTooltip() {
4001
+ if (!this.tooltipElement)
4002
+ return;
4003
+ const hostRect = this.elementRef.nativeElement.getBoundingClientRect();
4004
+ const tooltipRect = this.tooltipElement.getBoundingClientRect();
4005
+ const position = this.tooltipPosition();
4006
+ const offset = 8;
4007
+ let top;
4008
+ let left;
4009
+ switch (position) {
4010
+ case 'top':
4011
+ top = hostRect.top - tooltipRect.height - offset;
4012
+ left = hostRect.left + (hostRect.width - tooltipRect.width) / 2;
4013
+ break;
4014
+ case 'bottom':
4015
+ top = hostRect.bottom + offset;
4016
+ left = hostRect.left + (hostRect.width - tooltipRect.width) / 2;
4017
+ break;
4018
+ case 'left':
4019
+ top = hostRect.top + (hostRect.height - tooltipRect.height) / 2;
4020
+ left = hostRect.left - tooltipRect.width - offset;
4021
+ break;
4022
+ case 'right':
4023
+ top = hostRect.top + (hostRect.height - tooltipRect.height) / 2;
4024
+ left = hostRect.right + offset;
4025
+ break;
4026
+ }
4027
+ // Keep tooltip within viewport
4028
+ const viewportWidth = window.innerWidth;
4029
+ const viewportHeight = window.innerHeight;
4030
+ if (left < 8)
4031
+ left = 8;
4032
+ if (left + tooltipRect.width > viewportWidth - 8) {
4033
+ left = viewportWidth - tooltipRect.width - 8;
4034
+ }
4035
+ if (top < 8)
4036
+ top = 8;
4037
+ if (top + tooltipRect.height > viewportHeight - 8) {
4038
+ top = viewportHeight - tooltipRect.height - 8;
4039
+ }
4040
+ this.renderer.setStyle(this.tooltipElement, 'top', `${top}px`);
4041
+ this.renderer.setStyle(this.tooltipElement, 'left', `${left}px`);
4042
+ }
4043
+ /**
4044
+ * Remove tooltip element from DOM
4045
+ */
4046
+ removeTooltip() {
4047
+ if (this.tooltipElement && this.tooltipElement.parentNode) {
4048
+ this.tooltipElement.parentNode.removeChild(this.tooltipElement);
4049
+ this.tooltipElement = null;
4050
+ }
4051
+ }
4052
+ /**
4053
+ * Escape HTML to prevent XSS
4054
+ */
4055
+ escapeHtml(text) {
4056
+ const div = document.createElement('div');
4057
+ div.textContent = text;
4058
+ return div.innerHTML;
4059
+ }
4060
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AmwValidationTooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
4061
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.0", type: AmwValidationTooltipDirective, isStandalone: true, selector: "[amwValidationTooltip]", inputs: { amwValidationTooltip: { classPropertyName: "amwValidationTooltip", publicName: "amwValidationTooltip", isSignal: true, isRequired: true, transformFunction: null }, tooltipPosition: { classPropertyName: "tooltipPosition", publicName: "tooltipPosition", isSignal: true, isRequired: false, transformFunction: null }, autoDisable: { classPropertyName: "autoDisable", publicName: "autoDisable", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()", "focus": "onFocus()", "blur": "onBlur()" } }, ngImport: i0 });
4062
+ }
4063
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AmwValidationTooltipDirective, decorators: [{
4064
+ type: Directive,
4065
+ args: [{
4066
+ selector: '[amwValidationTooltip]',
4067
+ standalone: true
4068
+ }]
4069
+ }], ctorParameters: () => [], propDecorators: { amwValidationTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "amwValidationTooltip", required: true }] }], tooltipPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipPosition", required: false }] }], autoDisable: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoDisable", required: false }] }], onMouseEnter: [{
4070
+ type: HostListener,
4071
+ args: ['mouseenter']
4072
+ }], onMouseLeave: [{
4073
+ type: HostListener,
4074
+ args: ['mouseleave']
4075
+ }], onFocus: [{
4076
+ type: HostListener,
4077
+ args: ['focus']
4078
+ }], onBlur: [{
4079
+ type: HostListener,
4080
+ args: ['blur']
4081
+ }] } });
4082
+
3479
4083
  /**
3480
4084
  * Angular Material Wrap Divider Component
3481
4085
  *
@@ -12177,6 +12781,891 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
12177
12781
  ], encapsulation: ViewEncapsulation.None, template: "<mat-paginator\n [class]=\"paginatorClasses()\"\n [length]=\"length()\"\n [pageSize]=\"pageSize()\"\n [pageSizeOptions]=\"pageSizeOptions()\"\n [pageIndex]=\"pageIndex()\"\n [showFirstLastButtons]=\"showFirstLastButtons()\"\n [hidePageSize]=\"hidePageSize()\"\n [disabled]=\"disabled()\"\n (page)=\"onPageChange($event)\"\n aria-label=\"Select page\">\n</mat-paginator>\n", styles: [".amw-paginator{display:flex;align-items:center}.amw-paginator--disabled{opacity:.5;pointer-events:none}.amw-paginator--hide-page-size .mat-mdc-paginator-page-size{display:none}.amw-paginator .mat-mdc-paginator-container{padding:0 8px;min-height:56px}.amw-paginator .mat-mdc-paginator-page-size-label{margin:0 4px}.amw-paginator .mat-mdc-paginator-range-label{margin:0 16px}.amw-paginator .mat-mdc-paginator-navigation-first:disabled,.amw-paginator .mat-mdc-paginator-navigation-previous:disabled,.amw-paginator .mat-mdc-paginator-navigation-next:disabled,.amw-paginator .mat-mdc-paginator-navigation-last:disabled{opacity:.38}\n"] }]
12178
12782
  }], propDecorators: { length: [{ type: i0.Input, args: [{ isSignal: true, alias: "length", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }, { type: i0.Output, args: ["pageSizeChange"] }], pageSizeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSizeOptions", required: false }] }], pageIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageIndex", required: false }] }, { type: i0.Output, args: ["pageIndexChange"] }], showFirstLastButtons: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFirstLastButtons", required: false }] }], hidePageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "hidePageSize", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], paginatorClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginatorClass", required: false }] }], page: [{ type: i0.Output, args: ["page"] }] } });
12179
12783
 
12784
+ /**
12785
+ * Full Screen Loading Service
12786
+ *
12787
+ * Manages a queue of loading messages that can be driven by observables.
12788
+ * Each observable can add its own message, and when the observable completes
12789
+ * or emits a value, the message is dismissed with animation.
12790
+ *
12791
+ * @example
12792
+ * ```typescript
12793
+ * // Using the loading() operator
12794
+ * this.userService.getUser(id)
12795
+ * .pipe(loading('Loading user...'))
12796
+ * .subscribe(user => this.user = user);
12797
+ *
12798
+ * // Multiple simultaneous operations
12799
+ * forkJoin([
12800
+ * this.service1.getData().pipe(loading('Loading data 1...')),
12801
+ * this.service2.getData().pipe(loading('Loading data 2...'))
12802
+ * ]).subscribe(results => this.results = results);
12803
+ * ```
12804
+ */
12805
+ class AmwFullScreenLoadingService {
12806
+ /** Internal signal holding all loading items */
12807
+ loadingItemsSignal = signal([], ...(ngDevMode ? [{ debugName: "loadingItemsSignal" }] : []));
12808
+ /** Signal indicating whether the overlay is visible */
12809
+ overlayVisibleSignal = signal(false, ...(ngDevMode ? [{ debugName: "overlayVisibleSignal" }] : []));
12810
+ /** Timeout for overlay dismiss animation */
12811
+ overlayDismissTimeout = null;
12812
+ /** Animation duration for items dismissing (ms) */
12813
+ itemDismissAnimationDuration = 300;
12814
+ /** Animation duration for overlay appearing/disappearing (ms) */
12815
+ overlayAnimationDuration = 300;
12816
+ /** Read-only computed signal of loading items */
12817
+ loadingItems = computed(() => this.loadingItemsSignal(), ...(ngDevMode ? [{ debugName: "loadingItems" }] : []));
12818
+ /** Read-only computed signal of whether any loading is active */
12819
+ isLoading = computed(() => this.loadingItemsSignal().length > 0, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
12820
+ /** Read-only signal of whether overlay is visible (for animation timing) */
12821
+ overlayVisible = computed(() => this.overlayVisibleSignal(), ...(ngDevMode ? [{ debugName: "overlayVisible" }] : []));
12822
+ /** Counter for generating unique IDs */
12823
+ idCounter = 0;
12824
+ constructor() { }
12825
+ /**
12826
+ * Add a loading item to the queue
12827
+ * @param message The message to display
12828
+ * @returns The unique ID of the loading item
12829
+ */
12830
+ add(message) {
12831
+ const id = this.generateId();
12832
+ const item = {
12833
+ id,
12834
+ message,
12835
+ dismissing: false,
12836
+ timestamp: Date.now()
12837
+ };
12838
+ // Clear any pending overlay dismiss
12839
+ if (this.overlayDismissTimeout) {
12840
+ clearTimeout(this.overlayDismissTimeout);
12841
+ this.overlayDismissTimeout = null;
12842
+ }
12843
+ // Show overlay if this is the first item
12844
+ if (this.loadingItemsSignal().length === 0) {
12845
+ this.overlayVisibleSignal.set(true);
12846
+ }
12847
+ this.loadingItemsSignal.update(items => [...items, item]);
12848
+ return id;
12849
+ }
12850
+ /**
12851
+ * Dismiss a loading item from the queue with animation
12852
+ * @param id The ID of the loading item to dismiss
12853
+ */
12854
+ dismiss(id) {
12855
+ // First, mark the item as dismissing to trigger animation
12856
+ this.loadingItemsSignal.update(items => items.map(item => item.id === id ? { ...item, dismissing: true } : item));
12857
+ // After animation completes, remove the item
12858
+ setTimeout(() => {
12859
+ this.loadingItemsSignal.update(items => items.filter(item => item.id !== id));
12860
+ // If no more items, start overlay dismiss
12861
+ if (this.loadingItemsSignal().length === 0) {
12862
+ this.overlayDismissTimeout = setTimeout(() => {
12863
+ this.overlayVisibleSignal.set(false);
12864
+ }, this.overlayAnimationDuration);
12865
+ }
12866
+ }, this.itemDismissAnimationDuration);
12867
+ }
12868
+ /**
12869
+ * Clear all loading items immediately
12870
+ */
12871
+ clear() {
12872
+ this.loadingItemsSignal.set([]);
12873
+ if (this.overlayDismissTimeout) {
12874
+ clearTimeout(this.overlayDismissTimeout);
12875
+ }
12876
+ this.overlayDismissTimeout = setTimeout(() => {
12877
+ this.overlayVisibleSignal.set(false);
12878
+ }, this.overlayAnimationDuration);
12879
+ }
12880
+ /**
12881
+ * Update the message for an existing loading item
12882
+ * @param id The ID of the loading item
12883
+ * @param message The new message
12884
+ */
12885
+ updateMessage(id, message) {
12886
+ this.loadingItemsSignal.update(items => items.map(item => item.id === id ? { ...item, message } : item));
12887
+ }
12888
+ /**
12889
+ * Generate a unique ID for a loading item
12890
+ */
12891
+ generateId() {
12892
+ return `fsl_${Date.now()}_${++this.idCounter}`;
12893
+ }
12894
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AmwFullScreenLoadingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
12895
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AmwFullScreenLoadingService, providedIn: 'root' });
12896
+ }
12897
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AmwFullScreenLoadingService, decorators: [{
12898
+ type: Injectable,
12899
+ args: [{
12900
+ providedIn: 'root'
12901
+ }]
12902
+ }], ctorParameters: () => [] });
12903
+ /**
12904
+ * RxJS operator that adds a loading message while the observable is active.
12905
+ * The message is dismissed when the observable emits its first value (for single-emission observables)
12906
+ * or when it completes/errors.
12907
+ *
12908
+ * @param message The loading message to display
12909
+ * @param options Configuration options
12910
+ * @returns A MonoTypeOperatorFunction that can be used with .pipe()
12911
+ *
12912
+ * @example
12913
+ * ```typescript
12914
+ * // Basic usage
12915
+ * this.http.get('/api/data')
12916
+ * .pipe(loading('Loading data...'))
12917
+ * .subscribe(data => this.data = data);
12918
+ *
12919
+ * // With multiple operations
12920
+ * this.service.doAThing()
12921
+ * .pipe(loading('Processing...'))
12922
+ * .subscribe(result => console.log(result));
12923
+ * ```
12924
+ */
12925
+ function loading(message, options) {
12926
+ const dismissOnComplete = options?.dismissOnComplete ?? false;
12927
+ return (source) => {
12928
+ let loadingId = null;
12929
+ let dismissed = false;
12930
+ let service = options?.service ?? null;
12931
+ // Lazy inject the service if not provided
12932
+ const getService = () => {
12933
+ if (!service) {
12934
+ // Dynamic import to get the injector
12935
+ const injector = globalThis.__amwFullScreenLoadingInjector;
12936
+ if (injector) {
12937
+ service = injector.get(AmwFullScreenLoadingService);
12938
+ }
12939
+ else {
12940
+ throw new Error('AmwFullScreenLoadingService not available. ' +
12941
+ 'Make sure AmwFullScreenLoadingComponent is included in your app.');
12942
+ }
12943
+ }
12944
+ return service;
12945
+ };
12946
+ return new Observable(subscriber => {
12947
+ // Add loading item when subscription starts
12948
+ try {
12949
+ loadingId = getService().add(message);
12950
+ }
12951
+ catch (e) {
12952
+ console.warn('Full screen loading service not available:', e);
12953
+ }
12954
+ const dismissLoading = () => {
12955
+ if (!dismissed && loadingId) {
12956
+ dismissed = true;
12957
+ try {
12958
+ getService().dismiss(loadingId);
12959
+ }
12960
+ catch (e) {
12961
+ // Service may not be available
12962
+ }
12963
+ }
12964
+ };
12965
+ const subscription = source.subscribe({
12966
+ next: (value) => {
12967
+ if (!dismissOnComplete) {
12968
+ dismissLoading();
12969
+ }
12970
+ subscriber.next(value);
12971
+ },
12972
+ error: (err) => {
12973
+ dismissLoading();
12974
+ subscriber.error(err);
12975
+ },
12976
+ complete: () => {
12977
+ dismissLoading();
12978
+ subscriber.complete();
12979
+ }
12980
+ });
12981
+ // Cleanup on unsubscribe
12982
+ return () => {
12983
+ dismissLoading();
12984
+ subscription.unsubscribe();
12985
+ };
12986
+ });
12987
+ };
12988
+ }
12989
+
12990
+ /**
12991
+ * AMW Full Screen Loading Component
12992
+ *
12993
+ * Displays a full-screen loading overlay with multiple animated messages.
12994
+ * Each message is keyed to an observable and dismisses with a smooth animation
12995
+ * when the observable completes.
12996
+ *
12997
+ * Add this component once at the root of your application (e.g., in app.component.html):
12998
+ *
12999
+ * @example
13000
+ * ```html
13001
+ * <!-- In app.component.html -->
13002
+ * <router-outlet></router-outlet>
13003
+ * <amw-full-screen-loading></amw-full-screen-loading>
13004
+ * ```
13005
+ *
13006
+ * Then use the loading() operator in your services:
13007
+ *
13008
+ * @example
13009
+ * ```typescript
13010
+ * // In your component/service
13011
+ * import { loading } from '@angular-material-wrap';
13012
+ *
13013
+ * this.userService.getUser(id)
13014
+ * .pipe(loading('Loading user profile...'))
13015
+ * .subscribe(user => this.user = user);
13016
+ *
13017
+ * // Multiple simultaneous operations
13018
+ * this.dataService.fetchData()
13019
+ * .pipe(loading('Fetching data...'))
13020
+ * .subscribe();
13021
+ *
13022
+ * this.otherService.process()
13023
+ * .pipe(loading('Processing...'))
13024
+ * .subscribe();
13025
+ * ```
13026
+ *
13027
+ * Features:
13028
+ * - Smooth 300ms transitions for overlay appearance/disappearance
13029
+ * - Multiple messages can display simultaneously
13030
+ * - Messages dismiss with a slide-right + fade animation
13031
+ * - Centered spinner and message display
13032
+ * - Subtle pulse animation on the spinner
13033
+ */
13034
+ class AmwFullScreenLoadingComponent {
13035
+ injector = inject(Injector);
13036
+ loadingService = inject(AmwFullScreenLoadingService);
13037
+ /** Computed signal for loading items */
13038
+ items = computed(() => this.loadingService.loadingItems(), ...(ngDevMode ? [{ debugName: "items" }] : []));
13039
+ /** Computed signal for overlay visibility */
13040
+ isVisible = computed(() => this.loadingService.overlayVisible(), ...(ngDevMode ? [{ debugName: "isVisible" }] : []));
13041
+ /** Computed signal for whether loading is active (items exist) */
13042
+ isLoading = computed(() => this.loadingService.isLoading(), ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
13043
+ ngOnInit() {
13044
+ // Register the injector globally for the loading() operator to use
13045
+ globalThis.__amwFullScreenLoadingInjector = this.injector;
13046
+ }
13047
+ ngOnDestroy() {
13048
+ // Clean up global injector reference
13049
+ if (globalThis.__amwFullScreenLoadingInjector === this.injector) {
13050
+ delete globalThis.__amwFullScreenLoadingInjector;
13051
+ }
13052
+ }
13053
+ /**
13054
+ * Track by function for ngFor
13055
+ */
13056
+ trackByItem(index, item) {
13057
+ return item.id;
13058
+ }
13059
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AmwFullScreenLoadingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
13060
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: AmwFullScreenLoadingComponent, isStandalone: true, selector: "amw-full-screen-loading", ngImport: i0, template: "@if (isVisible()) {\n<div class=\"amw-full-screen-loading\" [class.amw-full-screen-loading--visible]=\"isLoading()\"\n [class.amw-full-screen-loading--hiding]=\"!isLoading()\">\n <!-- Overlay backdrop -->\n <div class=\"amw-full-screen-loading__backdrop\"></div>\n\n <!-- Spinner container (fixed position) -->\n <div class=\"amw-full-screen-loading__content\">\n <div class=\"amw-fsl-spinner\">\n <div class=\"amw-fsl-spinner__ring amw-fsl-spinner__ring--1\"></div>\n <div class=\"amw-fsl-spinner__ring amw-fsl-spinner__ring--2\"></div>\n </div>\n </div>\n\n <!-- Messages container (fixed position below spinner) -->\n <div class=\"amw-full-screen-loading__messages\">\n @for (item of items(); track trackByItem($index, item)) {\n <div class=\"amw-full-screen-loading__message\"\n [class.amw-full-screen-loading__message--dismissing]=\"item.dismissing\">\n <span class=\"amw-full-screen-loading__message-text\">{{ item.message }}</span>\n </div>\n }\n </div>\n</div>\n}", styles: [".amw-full-screen-loading{position:fixed;top:0;left:0;width:100%;height:100%;z-index:9999;display:flex;align-items:center;justify-content:center;pointer-events:all;opacity:0}.amw-full-screen-loading--visible{animation:amw-fsl-fade-in .6s cubic-bezier(0,0,.2,1) forwards}.amw-full-screen-loading--hiding{animation:amw-fsl-fade-out .5s cubic-bezier(.4,0,1,1) forwards}.amw-full-screen-loading__backdrop{position:absolute;top:0;left:0;width:100%;height:100%;background-color:#0009;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);transition:backdrop-filter .6s ease-out}.amw-full-screen-loading__content{position:absolute;top:30%;left:50%;transform:translate(-50%);z-index:1;display:flex;flex-direction:column;align-items:center}.amw-full-screen-loading__messages{position:absolute;top:calc(30% + 375px);left:50%;transform:translate(-50%);z-index:1;display:flex;flex-direction:column;align-items:center;gap:8px;min-width:200px}.amw-full-screen-loading__message{display:flex;align-items:center;justify-content:center;padding:12px 24px;background-color:#fffffff2;border-radius:24px;opacity:1;transform:translate(0);box-shadow:0 4px 20px #00000026;transition:opacity .4s cubic-bezier(.4,0,.2,1),transform .4s cubic-bezier(.4,0,.2,1);animation:amw-fsl-message-enter .45s cubic-bezier(0,0,.2,1)}.amw-full-screen-loading__message--dismissing{opacity:0;transform:translate(40px);transition:opacity .5s cubic-bezier(.4,0,1,1),transform .5s cubic-bezier(.4,0,1,1)}.amw-full-screen-loading__message-text{font-size:14px;font-weight:500;color:#333;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:400px}.amw-fsl-spinner{position:relative;width:350px;height:350px}.amw-fsl-spinner__ring{position:absolute;top:50%;left:50%;border-radius:50%;box-sizing:border-box}.amw-fsl-spinner__ring--1{width:360px;height:360px;margin-left:-180px;margin-top:-180px;background:conic-gradient(var(--mdc-theme-primary, #6200ee) 0deg 100deg,transparent 100deg 120deg,var(--mdc-theme-primary, #6200ee) 120deg 220deg,transparent 220deg 240deg,var(--mdc-theme-primary, #6200ee) 240deg 340deg,transparent 340deg 360deg);mask:radial-gradient(circle,transparent 50%,black 50%);-webkit-mask:radial-gradient(circle,transparent 50%,black 50%);animation:amw-fsl-rotate-cw-1 25s cubic-bezier(.4,0,.2,1) infinite}.amw-fsl-spinner__ring--2{width:250px;height:250px;margin-left:-125px;margin-top:-125px;background:conic-gradient(var(--mdc-theme-secondary, #03dac6) 0deg 92deg,transparent 92deg 120deg,var(--mdc-theme-secondary, #03dac6) 120deg 212deg,transparent 212deg 240deg,var(--mdc-theme-secondary, #03dac6) 240deg 332deg,transparent 332deg 360deg);mask:radial-gradient(circle,transparent 40%,black 40%);-webkit-mask:radial-gradient(circle,transparent 40%,black 40%);animation:amw-fsl-rotate-ccw-1 22s cubic-bezier(.25,.1,.25,1) infinite}@keyframes amw-fsl-rotate-cw-1{0%{transform:rotate(0)}25%{transform:rotate(120deg)}50%{transform:rotate(180deg)}75%{transform:rotate(300deg)}to{transform:rotate(360deg)}}@keyframes amw-fsl-rotate-ccw-1{0%{transform:rotate(0)}20%{transform:rotate(-90deg)}40%{transform:rotate(-120deg)}60%{transform:rotate(-240deg)}80%{transform:rotate(-300deg)}to{transform:rotate(-360deg)}}@keyframes amw-fsl-fade-in{0%{opacity:0}to{opacity:1}}@keyframes amw-fsl-fade-out{0%{opacity:1}to{opacity:0}}@keyframes amw-fsl-message-enter{0%{opacity:0;transform:translateY(15px) scale(.98)}60%{opacity:.8;transform:translateY(-2px) scale(1)}to{opacity:1;transform:translateY(0) scale(1)}}.dark-theme .amw-full-screen-loading__backdrop{background-color:#000000bf}.dark-theme .amw-full-screen-loading__message{background-color:#1e1e1ef2;box-shadow:0 4px 20px #0006}.dark-theme .amw-full-screen-loading__message-text{color:#fff}.dark-theme .amw-fsl-spinner__ring--1{background:conic-gradient(var(--mdc-theme-primary, #bb86fc) 0deg 100deg,transparent 100deg 120deg,var(--mdc-theme-primary, #bb86fc) 120deg 220deg,transparent 220deg 240deg,var(--mdc-theme-primary, #bb86fc) 240deg 340deg,transparent 340deg 360deg)}.dark-theme .amw-fsl-spinner__ring--2{background:conic-gradient(var(--mdc-theme-secondary, #03dac6) 0deg 92deg,transparent 92deg 120deg,var(--mdc-theme-secondary, #03dac6) 120deg 212deg,transparent 212deg 240deg,var(--mdc-theme-secondary, #03dac6) 240deg 332deg,transparent 332deg 360deg)}@media(prefers-reduced-motion:reduce){.amw-full-screen-loading--visible{animation:amw-fsl-fade-in .4s linear forwards}.amw-full-screen-loading--hiding{animation:amw-fsl-fade-out .4s linear forwards}.amw-full-screen-loading__message{transition:opacity .2s linear;animation:none}.amw-full-screen-loading__message--dismissing{transform:none;transition:opacity .3s linear}.amw-fsl-spinner__ring{animation-duration:20s!important;animation-timing-function:linear!important}.amw-fsl-spinner__ring--1{animation-name:amw-fsl-rotate-simple-cw}.amw-fsl-spinner__ring--2{animation-name:amw-fsl-rotate-simple-ccw}@keyframes amw-fsl-rotate-simple-cw{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes amw-fsl-rotate-simple-ccw{0%{transform:rotate(0)}to{transform:rotate(-360deg)}}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], encapsulation: i0.ViewEncapsulation.None });
13061
+ }
13062
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AmwFullScreenLoadingComponent, decorators: [{
13063
+ type: Component,
13064
+ args: [{ selector: 'amw-full-screen-loading', standalone: true, imports: [CommonModule], encapsulation: ViewEncapsulation.None, template: "@if (isVisible()) {\n<div class=\"amw-full-screen-loading\" [class.amw-full-screen-loading--visible]=\"isLoading()\"\n [class.amw-full-screen-loading--hiding]=\"!isLoading()\">\n <!-- Overlay backdrop -->\n <div class=\"amw-full-screen-loading__backdrop\"></div>\n\n <!-- Spinner container (fixed position) -->\n <div class=\"amw-full-screen-loading__content\">\n <div class=\"amw-fsl-spinner\">\n <div class=\"amw-fsl-spinner__ring amw-fsl-spinner__ring--1\"></div>\n <div class=\"amw-fsl-spinner__ring amw-fsl-spinner__ring--2\"></div>\n </div>\n </div>\n\n <!-- Messages container (fixed position below spinner) -->\n <div class=\"amw-full-screen-loading__messages\">\n @for (item of items(); track trackByItem($index, item)) {\n <div class=\"amw-full-screen-loading__message\"\n [class.amw-full-screen-loading__message--dismissing]=\"item.dismissing\">\n <span class=\"amw-full-screen-loading__message-text\">{{ item.message }}</span>\n </div>\n }\n </div>\n</div>\n}", styles: [".amw-full-screen-loading{position:fixed;top:0;left:0;width:100%;height:100%;z-index:9999;display:flex;align-items:center;justify-content:center;pointer-events:all;opacity:0}.amw-full-screen-loading--visible{animation:amw-fsl-fade-in .6s cubic-bezier(0,0,.2,1) forwards}.amw-full-screen-loading--hiding{animation:amw-fsl-fade-out .5s cubic-bezier(.4,0,1,1) forwards}.amw-full-screen-loading__backdrop{position:absolute;top:0;left:0;width:100%;height:100%;background-color:#0009;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);transition:backdrop-filter .6s ease-out}.amw-full-screen-loading__content{position:absolute;top:30%;left:50%;transform:translate(-50%);z-index:1;display:flex;flex-direction:column;align-items:center}.amw-full-screen-loading__messages{position:absolute;top:calc(30% + 375px);left:50%;transform:translate(-50%);z-index:1;display:flex;flex-direction:column;align-items:center;gap:8px;min-width:200px}.amw-full-screen-loading__message{display:flex;align-items:center;justify-content:center;padding:12px 24px;background-color:#fffffff2;border-radius:24px;opacity:1;transform:translate(0);box-shadow:0 4px 20px #00000026;transition:opacity .4s cubic-bezier(.4,0,.2,1),transform .4s cubic-bezier(.4,0,.2,1);animation:amw-fsl-message-enter .45s cubic-bezier(0,0,.2,1)}.amw-full-screen-loading__message--dismissing{opacity:0;transform:translate(40px);transition:opacity .5s cubic-bezier(.4,0,1,1),transform .5s cubic-bezier(.4,0,1,1)}.amw-full-screen-loading__message-text{font-size:14px;font-weight:500;color:#333;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:400px}.amw-fsl-spinner{position:relative;width:350px;height:350px}.amw-fsl-spinner__ring{position:absolute;top:50%;left:50%;border-radius:50%;box-sizing:border-box}.amw-fsl-spinner__ring--1{width:360px;height:360px;margin-left:-180px;margin-top:-180px;background:conic-gradient(var(--mdc-theme-primary, #6200ee) 0deg 100deg,transparent 100deg 120deg,var(--mdc-theme-primary, #6200ee) 120deg 220deg,transparent 220deg 240deg,var(--mdc-theme-primary, #6200ee) 240deg 340deg,transparent 340deg 360deg);mask:radial-gradient(circle,transparent 50%,black 50%);-webkit-mask:radial-gradient(circle,transparent 50%,black 50%);animation:amw-fsl-rotate-cw-1 25s cubic-bezier(.4,0,.2,1) infinite}.amw-fsl-spinner__ring--2{width:250px;height:250px;margin-left:-125px;margin-top:-125px;background:conic-gradient(var(--mdc-theme-secondary, #03dac6) 0deg 92deg,transparent 92deg 120deg,var(--mdc-theme-secondary, #03dac6) 120deg 212deg,transparent 212deg 240deg,var(--mdc-theme-secondary, #03dac6) 240deg 332deg,transparent 332deg 360deg);mask:radial-gradient(circle,transparent 40%,black 40%);-webkit-mask:radial-gradient(circle,transparent 40%,black 40%);animation:amw-fsl-rotate-ccw-1 22s cubic-bezier(.25,.1,.25,1) infinite}@keyframes amw-fsl-rotate-cw-1{0%{transform:rotate(0)}25%{transform:rotate(120deg)}50%{transform:rotate(180deg)}75%{transform:rotate(300deg)}to{transform:rotate(360deg)}}@keyframes amw-fsl-rotate-ccw-1{0%{transform:rotate(0)}20%{transform:rotate(-90deg)}40%{transform:rotate(-120deg)}60%{transform:rotate(-240deg)}80%{transform:rotate(-300deg)}to{transform:rotate(-360deg)}}@keyframes amw-fsl-fade-in{0%{opacity:0}to{opacity:1}}@keyframes amw-fsl-fade-out{0%{opacity:1}to{opacity:0}}@keyframes amw-fsl-message-enter{0%{opacity:0;transform:translateY(15px) scale(.98)}60%{opacity:.8;transform:translateY(-2px) scale(1)}to{opacity:1;transform:translateY(0) scale(1)}}.dark-theme .amw-full-screen-loading__backdrop{background-color:#000000bf}.dark-theme .amw-full-screen-loading__message{background-color:#1e1e1ef2;box-shadow:0 4px 20px #0006}.dark-theme .amw-full-screen-loading__message-text{color:#fff}.dark-theme .amw-fsl-spinner__ring--1{background:conic-gradient(var(--mdc-theme-primary, #bb86fc) 0deg 100deg,transparent 100deg 120deg,var(--mdc-theme-primary, #bb86fc) 120deg 220deg,transparent 220deg 240deg,var(--mdc-theme-primary, #bb86fc) 240deg 340deg,transparent 340deg 360deg)}.dark-theme .amw-fsl-spinner__ring--2{background:conic-gradient(var(--mdc-theme-secondary, #03dac6) 0deg 92deg,transparent 92deg 120deg,var(--mdc-theme-secondary, #03dac6) 120deg 212deg,transparent 212deg 240deg,var(--mdc-theme-secondary, #03dac6) 240deg 332deg,transparent 332deg 360deg)}@media(prefers-reduced-motion:reduce){.amw-full-screen-loading--visible{animation:amw-fsl-fade-in .4s linear forwards}.amw-full-screen-loading--hiding{animation:amw-fsl-fade-out .4s linear forwards}.amw-full-screen-loading__message{transition:opacity .2s linear;animation:none}.amw-full-screen-loading__message--dismissing{transform:none;transition:opacity .3s linear}.amw-fsl-spinner__ring{animation-duration:20s!important;animation-timing-function:linear!important}.amw-fsl-spinner__ring--1{animation-name:amw-fsl-rotate-simple-cw}.amw-fsl-spinner__ring--2{animation-name:amw-fsl-rotate-simple-ccw}@keyframes amw-fsl-rotate-simple-cw{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes amw-fsl-rotate-simple-ccw{0%{transform:rotate(0)}to{transform:rotate(-360deg)}}}\n"] }]
13065
+ }] });
13066
+
13067
+ const DEFAULT_CONFIG = {
13068
+ maxErrors: 50,
13069
+ autoDismissAfter: 0,
13070
+ logToConsole: true,
13071
+ trackHistory: true,
13072
+ maxHistory: 100
13073
+ };
13074
+ /**
13075
+ * AMW Error State Service
13076
+ *
13077
+ * Provides centralized error state management for components and applications.
13078
+ * Components can create error contexts, add/remove errors, and display them
13079
+ * in a consistent manner.
13080
+ *
13081
+ * @example
13082
+ * ```typescript
13083
+ * // In your component
13084
+ * export class MyComponent implements OnInit, OnDestroy {
13085
+ * private errorContext!: ErrorContext;
13086
+ *
13087
+ * constructor(private errorStateService: AmwErrorStateService) {}
13088
+ *
13089
+ * ngOnInit() {
13090
+ * this.errorContext = this.errorStateService.createContext({
13091
+ * autoDismissAfter: 5000
13092
+ * });
13093
+ * }
13094
+ *
13095
+ * ngOnDestroy() {
13096
+ * this.errorStateService.destroyContext(this.errorContext.id);
13097
+ * }
13098
+ *
13099
+ * handleApiError(error: HttpErrorResponse) {
13100
+ * this.errorStateService.addError(this.errorContext.id, {
13101
+ * message: error.message,
13102
+ * code: error.status.toString(),
13103
+ * severity: 'error',
13104
+ * source: 'API',
13105
+ * originalError: error,
13106
+ * retryAction: () => this.retryRequest()
13107
+ * });
13108
+ * }
13109
+ * }
13110
+ * ```
13111
+ */
13112
+ class AmwErrorStateService {
13113
+ /** Map of all error contexts by ID */
13114
+ contexts = new Map();
13115
+ /** Global error history */
13116
+ errorHistory = signal([], ...(ngDevMode ? [{ debugName: "errorHistory" }] : []));
13117
+ /** Counter for generating unique IDs */
13118
+ idCounter = 0;
13119
+ /** Map of auto-dismiss timers */
13120
+ dismissTimers = new Map();
13121
+ /** Subject for error events */
13122
+ errorSubject = new Subject();
13123
+ /** Observable for error events */
13124
+ errors$ = this.errorSubject.asObservable();
13125
+ /** Global config */
13126
+ globalConfig = { ...DEFAULT_CONFIG };
13127
+ constructor() { }
13128
+ /**
13129
+ * Configure global error state settings
13130
+ */
13131
+ configure(config) {
13132
+ this.globalConfig = { ...this.globalConfig, ...config };
13133
+ }
13134
+ /**
13135
+ * Create a new error context for a component
13136
+ * @param config Optional configuration
13137
+ * @returns The created error context
13138
+ */
13139
+ createContext(config) {
13140
+ const id = this.generateId();
13141
+ const errors = signal([], ...(ngDevMode ? [{ debugName: "errors" }] : []));
13142
+ const mergedConfig = { ...this.globalConfig, ...config };
13143
+ const hasErrors = computed(() => errors().some(e => e.severity === 'error' && !e.dismissed), ...(ngDevMode ? [{ debugName: "hasErrors" }] : []));
13144
+ const hasWarnings = computed(() => errors().some(e => e.severity === 'warning' && !e.dismissed), ...(ngDevMode ? [{ debugName: "hasWarnings" }] : []));
13145
+ const errorCount = computed(() => errors().filter(e => !e.dismissed).length, ...(ngDevMode ? [{ debugName: "errorCount" }] : []));
13146
+ const context = {
13147
+ id,
13148
+ errors,
13149
+ hasErrors,
13150
+ hasWarnings,
13151
+ errorCount,
13152
+ config: mergedConfig
13153
+ };
13154
+ this.contexts.set(id, context);
13155
+ return context;
13156
+ }
13157
+ /**
13158
+ * Destroy an error context and clean up timers
13159
+ * @param contextId The context ID to destroy
13160
+ */
13161
+ destroyContext(contextId) {
13162
+ // Clean up any dismiss timers
13163
+ const context = this.contexts.get(contextId);
13164
+ if (context) {
13165
+ context.errors().forEach(error => {
13166
+ const timerKey = `${contextId}_${error.id}`;
13167
+ const timer = this.dismissTimers.get(timerKey);
13168
+ if (timer) {
13169
+ clearTimeout(timer);
13170
+ this.dismissTimers.delete(timerKey);
13171
+ }
13172
+ });
13173
+ }
13174
+ this.contexts.delete(contextId);
13175
+ }
13176
+ /**
13177
+ * Add an error to a context
13178
+ * @param contextId The context ID
13179
+ * @param error The error to add (without ID, one will be generated)
13180
+ * @returns The error ID
13181
+ */
13182
+ addError(contextId, error) {
13183
+ const context = this.contexts.get(contextId);
13184
+ if (!context) {
13185
+ throw new Error(`Error context ${contextId} not found`);
13186
+ }
13187
+ const errorId = error.id || this.generateErrorId();
13188
+ const fullError = {
13189
+ ...error,
13190
+ id: errorId,
13191
+ timestamp: Date.now(),
13192
+ dismissed: false,
13193
+ dismissible: error.dismissible ?? true
13194
+ };
13195
+ // Log to console if configured
13196
+ if (context.config.logToConsole) {
13197
+ this.logError(fullError);
13198
+ }
13199
+ // Check max errors
13200
+ let currentErrors = context.errors();
13201
+ if (context.config.maxErrors && currentErrors.length >= context.config.maxErrors) {
13202
+ // Remove oldest error
13203
+ currentErrors = currentErrors.slice(1);
13204
+ }
13205
+ // Add new error
13206
+ context.errors.set([...currentErrors, fullError]);
13207
+ // Add to history if configured
13208
+ if (context.config.trackHistory) {
13209
+ this.addToHistory(fullError);
13210
+ }
13211
+ // Emit error event
13212
+ this.errorSubject.next(fullError);
13213
+ // Set up auto-dismiss if configured
13214
+ if (context.config.autoDismissAfter && context.config.autoDismissAfter > 0) {
13215
+ this.setupAutoDismiss(contextId, errorId, context.config.autoDismissAfter);
13216
+ }
13217
+ return errorId;
13218
+ }
13219
+ /**
13220
+ * Add an error from a caught exception
13221
+ * @param contextId The context ID
13222
+ * @param error The caught error
13223
+ * @param options Additional options
13224
+ */
13225
+ addFromException(contextId, error, options) {
13226
+ const message = error instanceof Error ? error.message : String(error);
13227
+ const code = error instanceof Error ? error.name : 'UNKNOWN';
13228
+ return this.addError(contextId, {
13229
+ message,
13230
+ code,
13231
+ severity: options?.severity || 'error',
13232
+ source: options?.source,
13233
+ field: options?.field,
13234
+ originalError: error,
13235
+ retryAction: options?.retryAction
13236
+ });
13237
+ }
13238
+ /**
13239
+ * Dismiss an error
13240
+ * @param contextId The context ID
13241
+ * @param errorId The error ID to dismiss
13242
+ */
13243
+ dismissError(contextId, errorId) {
13244
+ const context = this.contexts.get(contextId);
13245
+ if (!context)
13246
+ return;
13247
+ context.errors.update(errors => errors.map(e => e.id === errorId ? { ...e, dismissed: true } : e));
13248
+ // Clear auto-dismiss timer
13249
+ const timerKey = `${contextId}_${errorId}`;
13250
+ const timer = this.dismissTimers.get(timerKey);
13251
+ if (timer) {
13252
+ clearTimeout(timer);
13253
+ this.dismissTimers.delete(timerKey);
13254
+ }
13255
+ }
13256
+ /**
13257
+ * Remove an error completely
13258
+ * @param contextId The context ID
13259
+ * @param errorId The error ID to remove
13260
+ */
13261
+ removeError(contextId, errorId) {
13262
+ const context = this.contexts.get(contextId);
13263
+ if (!context)
13264
+ return;
13265
+ context.errors.update(errors => errors.filter(e => e.id !== errorId));
13266
+ // Clear auto-dismiss timer
13267
+ const timerKey = `${contextId}_${errorId}`;
13268
+ const timer = this.dismissTimers.get(timerKey);
13269
+ if (timer) {
13270
+ clearTimeout(timer);
13271
+ this.dismissTimers.delete(timerKey);
13272
+ }
13273
+ }
13274
+ /**
13275
+ * Clear all errors from a context
13276
+ * @param contextId The context ID
13277
+ */
13278
+ clearErrors(contextId) {
13279
+ const context = this.contexts.get(contextId);
13280
+ if (!context)
13281
+ return;
13282
+ // Clear all timers for this context
13283
+ context.errors().forEach(error => {
13284
+ const timerKey = `${contextId}_${error.id}`;
13285
+ const timer = this.dismissTimers.get(timerKey);
13286
+ if (timer) {
13287
+ clearTimeout(timer);
13288
+ this.dismissTimers.delete(timerKey);
13289
+ }
13290
+ });
13291
+ context.errors.set([]);
13292
+ }
13293
+ /**
13294
+ * Get all errors for a context
13295
+ * @param contextId The context ID
13296
+ * @returns Array of errors
13297
+ */
13298
+ getErrors(contextId) {
13299
+ const context = this.contexts.get(contextId);
13300
+ return context?.errors() || [];
13301
+ }
13302
+ /**
13303
+ * Get active (non-dismissed) errors
13304
+ * @param contextId The context ID
13305
+ * @returns Array of active errors
13306
+ */
13307
+ getActiveErrors(contextId) {
13308
+ return this.getErrors(contextId).filter(e => !e.dismissed);
13309
+ }
13310
+ /**
13311
+ * Get errors for a specific field
13312
+ * @param contextId The context ID
13313
+ * @param field The field name
13314
+ * @returns Array of errors for the field
13315
+ */
13316
+ getFieldErrors(contextId, field) {
13317
+ return this.getErrors(contextId).filter(e => e.field === field && !e.dismissed);
13318
+ }
13319
+ /**
13320
+ * Check if a context has any active errors
13321
+ * @param contextId The context ID
13322
+ * @returns True if active errors exist
13323
+ */
13324
+ hasActiveErrors(contextId) {
13325
+ return this.getActiveErrors(contextId).length > 0;
13326
+ }
13327
+ /**
13328
+ * Get the error history
13329
+ * @returns Array of historical errors
13330
+ */
13331
+ getErrorHistory() {
13332
+ return this.errorHistory();
13333
+ }
13334
+ /**
13335
+ * Clear the error history
13336
+ */
13337
+ clearHistory() {
13338
+ this.errorHistory.set([]);
13339
+ }
13340
+ /**
13341
+ * Get a context by ID
13342
+ * @param contextId The context ID
13343
+ * @returns The error context or undefined
13344
+ */
13345
+ getContext(contextId) {
13346
+ return this.contexts.get(contextId);
13347
+ }
13348
+ /**
13349
+ * Retry an error's action if available
13350
+ * @param contextId The context ID
13351
+ * @param errorId The error ID
13352
+ */
13353
+ retryError(contextId, errorId) {
13354
+ const context = this.contexts.get(contextId);
13355
+ if (!context)
13356
+ return;
13357
+ const error = context.errors().find(e => e.id === errorId);
13358
+ if (error?.retryAction) {
13359
+ // Dismiss the error before retrying
13360
+ this.dismissError(contextId, errorId);
13361
+ // Execute retry action
13362
+ error.retryAction();
13363
+ }
13364
+ }
13365
+ /**
13366
+ * Add error to history
13367
+ */
13368
+ addToHistory(error) {
13369
+ let history = this.errorHistory();
13370
+ if (this.globalConfig.maxHistory && history.length >= this.globalConfig.maxHistory) {
13371
+ history = history.slice(1);
13372
+ }
13373
+ this.errorHistory.set([...history, error]);
13374
+ }
13375
+ /**
13376
+ * Log error to console
13377
+ */
13378
+ logError(error) {
13379
+ const prefix = `[AMW Error State] [${error.severity.toUpperCase()}]`;
13380
+ const message = `${prefix} ${error.message}`;
13381
+ switch (error.severity) {
13382
+ case 'error':
13383
+ console.error(message, error.originalError || '');
13384
+ break;
13385
+ case 'warning':
13386
+ console.warn(message, error.originalError || '');
13387
+ break;
13388
+ case 'info':
13389
+ console.info(message);
13390
+ break;
13391
+ }
13392
+ }
13393
+ /**
13394
+ * Set up auto-dismiss timer
13395
+ */
13396
+ setupAutoDismiss(contextId, errorId, duration) {
13397
+ const timerKey = `${contextId}_${errorId}`;
13398
+ const timer = setTimeout(() => {
13399
+ this.dismissError(contextId, errorId);
13400
+ this.dismissTimers.delete(timerKey);
13401
+ }, duration);
13402
+ this.dismissTimers.set(timerKey, timer);
13403
+ }
13404
+ generateId() {
13405
+ return `ec_${Date.now()}_${++this.idCounter}`;
13406
+ }
13407
+ generateErrorId() {
13408
+ return `err_${Date.now()}_${++this.idCounter}`;
13409
+ }
13410
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AmwErrorStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
13411
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AmwErrorStateService, providedIn: 'root' });
13412
+ }
13413
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AmwErrorStateService, decorators: [{
13414
+ type: Injectable,
13415
+ args: [{
13416
+ providedIn: 'root'
13417
+ }]
13418
+ }], ctorParameters: () => [] });
13419
+ /**
13420
+ * Mixin/base class functionality for components that need error state management
13421
+ * This can be used via composition or inheritance
13422
+ */
13423
+ class ErrorStateMixin {
13424
+ errorStateService;
13425
+ errorContext;
13426
+ /**
13427
+ * Initialize error state for this component
13428
+ * Call this in ngOnInit
13429
+ */
13430
+ initializeErrorState(service, config) {
13431
+ this.errorStateService = service;
13432
+ this.errorContext = service.createContext(config);
13433
+ }
13434
+ /**
13435
+ * Clean up error context
13436
+ * Call this in ngOnDestroy
13437
+ */
13438
+ destroyErrorState() {
13439
+ if (this.errorContext) {
13440
+ this.errorStateService.destroyContext(this.errorContext.id);
13441
+ }
13442
+ }
13443
+ /**
13444
+ * Add an error
13445
+ */
13446
+ addError(error) {
13447
+ return this.errorStateService.addError(this.errorContext.id, error);
13448
+ }
13449
+ /**
13450
+ * Add error from exception
13451
+ */
13452
+ addErrorFromException(error, options) {
13453
+ return this.errorStateService.addFromException(this.errorContext.id, error, options);
13454
+ }
13455
+ /**
13456
+ * Dismiss an error
13457
+ */
13458
+ dismissError(errorId) {
13459
+ this.errorStateService.dismissError(this.errorContext.id, errorId);
13460
+ }
13461
+ /**
13462
+ * Clear all errors
13463
+ */
13464
+ clearErrors() {
13465
+ this.errorStateService.clearErrors(this.errorContext.id);
13466
+ }
13467
+ /**
13468
+ * Get all active errors
13469
+ */
13470
+ get activeErrors() {
13471
+ return this.errorContext?.errors().filter(e => !e.dismissed) || [];
13472
+ }
13473
+ /**
13474
+ * Check if there are any active errors
13475
+ */
13476
+ get hasErrors() {
13477
+ return this.errorContext?.hasErrors() || false;
13478
+ }
13479
+ /**
13480
+ * Check if there are any warnings
13481
+ */
13482
+ get hasWarnings() {
13483
+ return this.errorContext?.hasWarnings() || false;
13484
+ }
13485
+ /**
13486
+ * Get error count
13487
+ */
13488
+ get errorCount() {
13489
+ return this.errorContext?.errorCount() || 0;
13490
+ }
13491
+ }
13492
+
13493
+ /**
13494
+ * AMW Error Display Component
13495
+ *
13496
+ * Displays errors from an error context in a consistent, user-friendly manner.
13497
+ * Supports different display modes, severity icons, dismiss/retry actions.
13498
+ *
13499
+ * @example
13500
+ * ```html
13501
+ * <!-- Basic usage -->
13502
+ * <amw-error-display [context]="errorContext"></amw-error-display>
13503
+ *
13504
+ * <!-- With custom configuration -->
13505
+ * <amw-error-display
13506
+ * [context]="errorContext"
13507
+ * mode="inline"
13508
+ * [showDismiss]="true"
13509
+ * [showRetry]="true"
13510
+ * [maxVisible]="5">
13511
+ * </amw-error-display>
13512
+ * ```
13513
+ */
13514
+ class AmwErrorDisplayComponent {
13515
+ errorStateService = inject(AmwErrorStateService);
13516
+ /**
13517
+ * The error context to display errors from
13518
+ */
13519
+ context = input.required(...(ngDevMode ? [{ debugName: "context" }] : []));
13520
+ /**
13521
+ * Display mode
13522
+ * - 'banner': Full-width banner at top/bottom
13523
+ * - 'inline': Inline within content
13524
+ * - 'toast': Floating toast-style
13525
+ * - 'list': Simple list of errors
13526
+ */
13527
+ mode = input('inline', ...(ngDevMode ? [{ debugName: "mode" }] : []));
13528
+ /**
13529
+ * Position for banner/toast modes
13530
+ */
13531
+ position = input('top', ...(ngDevMode ? [{ debugName: "position" }] : []));
13532
+ /**
13533
+ * Whether to show dismiss buttons
13534
+ */
13535
+ showDismiss = input(true, ...(ngDevMode ? [{ debugName: "showDismiss" }] : []));
13536
+ /**
13537
+ * Whether to show retry buttons (for errors with retry actions)
13538
+ */
13539
+ showRetry = input(true, ...(ngDevMode ? [{ debugName: "showRetry" }] : []));
13540
+ /**
13541
+ * Maximum number of errors to show (-1 for unlimited)
13542
+ */
13543
+ maxVisible = input(-1, ...(ngDevMode ? [{ debugName: "maxVisible" }] : []));
13544
+ /**
13545
+ * Whether to show only active (non-dismissed) errors
13546
+ */
13547
+ activeOnly = input(true, ...(ngDevMode ? [{ debugName: "activeOnly" }] : []));
13548
+ /**
13549
+ * Filter by severity
13550
+ */
13551
+ severityFilter = input('all', ...(ngDevMode ? [{ debugName: "severityFilter" }] : []));
13552
+ /**
13553
+ * Emitted when an error is dismissed
13554
+ */
13555
+ errorDismissed = output();
13556
+ /**
13557
+ * Emitted when retry is clicked
13558
+ */
13559
+ errorRetried = output();
13560
+ /**
13561
+ * Get the resolved error context
13562
+ */
13563
+ resolvedContext = computed(() => {
13564
+ const ctx = this.context();
13565
+ if (typeof ctx === 'string') {
13566
+ return this.errorStateService.getContext(ctx);
13567
+ }
13568
+ return ctx;
13569
+ }, ...(ngDevMode ? [{ debugName: "resolvedContext" }] : []));
13570
+ /**
13571
+ * Get filtered errors to display
13572
+ */
13573
+ displayErrors = computed(() => {
13574
+ const ctx = this.resolvedContext();
13575
+ if (!ctx)
13576
+ return [];
13577
+ let errors = ctx.errors();
13578
+ // Filter active only
13579
+ if (this.activeOnly()) {
13580
+ errors = errors.filter(e => !e.dismissed);
13581
+ }
13582
+ // Filter by severity
13583
+ const severity = this.severityFilter();
13584
+ if (severity !== 'all') {
13585
+ errors = errors.filter(e => e.severity === severity);
13586
+ }
13587
+ // Limit visible
13588
+ const max = this.maxVisible();
13589
+ if (max > 0 && errors.length > max) {
13590
+ errors = errors.slice(-max);
13591
+ }
13592
+ return errors;
13593
+ }, ...(ngDevMode ? [{ debugName: "displayErrors" }] : []));
13594
+ /**
13595
+ * Whether there are any errors to display
13596
+ */
13597
+ hasErrors = computed(() => this.displayErrors().length > 0, ...(ngDevMode ? [{ debugName: "hasErrors" }] : []));
13598
+ /**
13599
+ * Get hidden error count
13600
+ */
13601
+ hiddenCount = computed(() => {
13602
+ const ctx = this.resolvedContext();
13603
+ if (!ctx)
13604
+ return 0;
13605
+ let totalErrors = ctx.errors();
13606
+ if (this.activeOnly()) {
13607
+ totalErrors = totalErrors.filter(e => !e.dismissed);
13608
+ }
13609
+ const max = this.maxVisible();
13610
+ if (max > 0 && totalErrors.length > max) {
13611
+ return totalErrors.length - max;
13612
+ }
13613
+ return 0;
13614
+ }, ...(ngDevMode ? [{ debugName: "hiddenCount" }] : []));
13615
+ /**
13616
+ * Get icon for severity
13617
+ */
13618
+ getIcon(severity) {
13619
+ const icons = {
13620
+ error: 'error',
13621
+ warning: 'warning',
13622
+ info: 'info'
13623
+ };
13624
+ return icons[severity];
13625
+ }
13626
+ /**
13627
+ * Dismiss an error
13628
+ */
13629
+ onDismiss(error) {
13630
+ const ctx = this.resolvedContext();
13631
+ if (ctx) {
13632
+ this.errorStateService.dismissError(ctx.id, error.id);
13633
+ this.errorDismissed.emit(error);
13634
+ }
13635
+ }
13636
+ /**
13637
+ * Retry an error's action
13638
+ */
13639
+ onRetry(error) {
13640
+ const ctx = this.resolvedContext();
13641
+ if (ctx) {
13642
+ this.errorStateService.retryError(ctx.id, error.id);
13643
+ this.errorRetried.emit(error);
13644
+ }
13645
+ }
13646
+ /**
13647
+ * Clear all errors
13648
+ */
13649
+ clearAll() {
13650
+ const ctx = this.resolvedContext();
13651
+ if (ctx) {
13652
+ this.errorStateService.clearErrors(ctx.id);
13653
+ }
13654
+ }
13655
+ /**
13656
+ * Track by function
13657
+ */
13658
+ trackByError(index, error) {
13659
+ return error.id;
13660
+ }
13661
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AmwErrorDisplayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
13662
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: AmwErrorDisplayComponent, isStandalone: true, selector: "amw-error-display", inputs: { context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: true, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, showDismiss: { classPropertyName: "showDismiss", publicName: "showDismiss", isSignal: true, isRequired: false, transformFunction: null }, showRetry: { classPropertyName: "showRetry", publicName: "showRetry", isSignal: true, isRequired: false, transformFunction: null }, maxVisible: { classPropertyName: "maxVisible", publicName: "maxVisible", isSignal: true, isRequired: false, transformFunction: null }, activeOnly: { classPropertyName: "activeOnly", publicName: "activeOnly", isSignal: true, isRequired: false, transformFunction: null }, severityFilter: { classPropertyName: "severityFilter", publicName: "severityFilter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { errorDismissed: "errorDismissed", errorRetried: "errorRetried" }, ngImport: i0, template: "@if (hasErrors()) {\n <div class=\"amw-error-display\"\n [class.amw-error-display--banner]=\"mode() === 'banner'\"\n [class.amw-error-display--inline]=\"mode() === 'inline'\"\n [class.amw-error-display--toast]=\"mode() === 'toast'\"\n [class.amw-error-display--list]=\"mode() === 'list'\"\n [class.amw-error-display--top]=\"position() === 'top'\"\n [class.amw-error-display--bottom]=\"position() === 'bottom'\">\n\n <div class=\"amw-error-display__container\">\n @for (error of displayErrors(); track trackByError($index, error)) {\n <div class=\"amw-error-display__item\"\n [class.amw-error-display__item--error]=\"error.severity === 'error'\"\n [class.amw-error-display__item--warning]=\"error.severity === 'warning'\"\n [class.amw-error-display__item--info]=\"error.severity === 'info'\"\n [class.amw-error-display__item--dismissed]=\"error.dismissed\">\n\n <div class=\"amw-error-display__icon\">\n <amw-icon [name]=\"getIcon(error.severity)\"></amw-icon>\n </div>\n\n <div class=\"amw-error-display__content\">\n <div class=\"amw-error-display__message\">{{ error.message }}</div>\n @if (error.source || error.code) {\n <div class=\"amw-error-display__meta\">\n @if (error.source) {\n <span class=\"amw-error-display__source\">{{ error.source }}</span>\n }\n @if (error.code) {\n <span class=\"amw-error-display__code\">[{{ error.code }}]</span>\n }\n </div>\n }\n </div>\n\n <div class=\"amw-error-display__actions\">\n @if (showRetry() && error.retryAction) {\n <amw-button\n appearance=\"text\"\n size=\"small\"\n icon=\"refresh\"\n (click)=\"onRetry(error)\"\n ariaLabel=\"Retry\">\n </amw-button>\n }\n @if (showDismiss() && error.dismissible) {\n <amw-button\n appearance=\"text\"\n size=\"small\"\n icon=\"close\"\n (click)=\"onDismiss(error)\"\n ariaLabel=\"Dismiss\">\n </amw-button>\n }\n </div>\n </div>\n }\n\n @if (hiddenCount() > 0) {\n <div class=\"amw-error-display__overflow\">\n +{{ hiddenCount() }} more error(s)\n </div>\n }\n\n @if (displayErrors().length > 1) {\n <div class=\"amw-error-display__footer\">\n <amw-button\n appearance=\"text\"\n size=\"small\"\n (click)=\"clearAll()\">\n Clear All\n </amw-button>\n </div>\n }\n </div>\n </div>\n}\n", styles: [".amw-error-display{font-family:var(--mdc-typography-body1-font-family, Roboto, sans-serif)}.amw-error-display--inline{margin:8px 0}.amw-error-display--banner{position:fixed;left:0;right:0;z-index:1000;padding:0 16px;box-shadow:0 2px 8px #00000026}.amw-error-display--banner.amw-error-display--top{top:0}.amw-error-display--banner.amw-error-display--bottom{bottom:0}.amw-error-display--toast{position:fixed;z-index:1000;max-width:400px;padding:8px}.amw-error-display--toast.amw-error-display--top{top:16px;right:16px}.amw-error-display--toast.amw-error-display--bottom{bottom:16px;right:16px}.amw-error-display--toast .amw-error-display__container{flex-direction:column;gap:8px}.amw-error-display--toast .amw-error-display__item{border-radius:8px;box-shadow:0 2px 8px #0003}.amw-error-display--list .amw-error-display__item{border-radius:0;border-bottom:1px solid var(--mdc-theme-outline-variant, #e0e0e0)}.amw-error-display--list .amw-error-display__item:last-child{border-bottom:none}.amw-error-display__container{display:flex;flex-direction:column;gap:4px}.amw-error-display__item{display:flex;align-items:flex-start;padding:12px 16px;border-radius:4px;animation:amw-error-slide-in .3s ease-out}.amw-error-display__item--error{background-color:var(--mdc-theme-error-container, #fdecea);color:#410002}.amw-error-display__item--error .amw-error-display__icon{color:#ba1a1a}.amw-error-display__item--warning{background-color:#fff3e0;color:#3d2800}.amw-error-display__item--warning .amw-error-display__icon{color:#9a5000}.amw-error-display__item--info{background-color:#e3f2fd;color:#002171}.amw-error-display__item--info .amw-error-display__icon{color:#002171}.amw-error-display__item--dismissed{opacity:.5;animation:amw-error-fade-out .3s ease-out}.amw-error-display__icon{flex-shrink:0;margin-right:12px;display:flex;align-items:center}.amw-error-display__icon amw-icon{font-size:20px;width:20px;height:20px}.amw-error-display__content{flex:1;min-width:0}.amw-error-display__message{font-size:14px;line-height:1.4;word-break:break-word}.amw-error-display__meta{display:flex;gap:8px;margin-top:4px;font-size:12px}.amw-error-display__source{font-weight:500}.amw-error-display__code{font-family:monospace}.amw-error-display__actions{flex-shrink:0;display:flex;gap:4px;margin-left:8px}.amw-error-display__actions amw-button{opacity:.7;transition:opacity .2s}.amw-error-display__actions amw-button:hover{opacity:1}.amw-error-display__overflow{padding:8px 16px;font-size:12px;color:var(--mdc-theme-on-surface-variant, #666);text-align:center;font-style:italic}.amw-error-display__footer{display:flex;justify-content:flex-end;padding:4px 8px}@keyframes amw-error-slide-in{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes amw-error-fade-out{0%{opacity:1}to{opacity:.5}}.dark-theme .amw-error-display__item--error{background-color:#b0002040;color:#ffb4ab}.dark-theme .amw-error-display__item--error .amw-error-display__icon{color:#ffb4ab}.dark-theme .amw-error-display__item--warning{background-color:#ff980033;color:#ffe0b2}.dark-theme .amw-error-display__item--warning .amw-error-display__icon{color:#ffe0b2}.dark-theme .amw-error-display__item--info{background-color:#2196f333;color:#bbdefb}.dark-theme .amw-error-display__item--info .amw-error-display__icon{color:#bbdefb}@media(prefers-reduced-motion:reduce){.amw-error-display__item{animation:none}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AmwIconComponent, selector: "amw-icon", inputs: ["name", "color", "size", "fontSet", "fontIcon", "inline", "iconClass", "ariaLabel"] }, { kind: "component", type: AmwButtonComponent, selector: "amw-button", inputs: ["type", "appearance", "fab", "icon", "iconPosition", "loading", "fullWidth", "autofocus", "text", "form", "formAction", "formMethod", "formTarget", "formEnctype", "formNoValidate", "formReset", "ripple", "disableRipple", "rippleColor", "rippleRadius", "rippleCentered", "rippleUnbounded", "spinnerSize", "spinnerColor"], outputs: ["buttonClick", "buttonFocus", "buttonBlur", "mouseenter", "mouseleave"] }], encapsulation: i0.ViewEncapsulation.None });
13663
+ }
13664
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: AmwErrorDisplayComponent, decorators: [{
13665
+ type: Component,
13666
+ args: [{ selector: 'amw-error-display', standalone: true, imports: [CommonModule, AmwIconComponent, AmwButtonComponent], encapsulation: ViewEncapsulation.None, template: "@if (hasErrors()) {\n <div class=\"amw-error-display\"\n [class.amw-error-display--banner]=\"mode() === 'banner'\"\n [class.amw-error-display--inline]=\"mode() === 'inline'\"\n [class.amw-error-display--toast]=\"mode() === 'toast'\"\n [class.amw-error-display--list]=\"mode() === 'list'\"\n [class.amw-error-display--top]=\"position() === 'top'\"\n [class.amw-error-display--bottom]=\"position() === 'bottom'\">\n\n <div class=\"amw-error-display__container\">\n @for (error of displayErrors(); track trackByError($index, error)) {\n <div class=\"amw-error-display__item\"\n [class.amw-error-display__item--error]=\"error.severity === 'error'\"\n [class.amw-error-display__item--warning]=\"error.severity === 'warning'\"\n [class.amw-error-display__item--info]=\"error.severity === 'info'\"\n [class.amw-error-display__item--dismissed]=\"error.dismissed\">\n\n <div class=\"amw-error-display__icon\">\n <amw-icon [name]=\"getIcon(error.severity)\"></amw-icon>\n </div>\n\n <div class=\"amw-error-display__content\">\n <div class=\"amw-error-display__message\">{{ error.message }}</div>\n @if (error.source || error.code) {\n <div class=\"amw-error-display__meta\">\n @if (error.source) {\n <span class=\"amw-error-display__source\">{{ error.source }}</span>\n }\n @if (error.code) {\n <span class=\"amw-error-display__code\">[{{ error.code }}]</span>\n }\n </div>\n }\n </div>\n\n <div class=\"amw-error-display__actions\">\n @if (showRetry() && error.retryAction) {\n <amw-button\n appearance=\"text\"\n size=\"small\"\n icon=\"refresh\"\n (click)=\"onRetry(error)\"\n ariaLabel=\"Retry\">\n </amw-button>\n }\n @if (showDismiss() && error.dismissible) {\n <amw-button\n appearance=\"text\"\n size=\"small\"\n icon=\"close\"\n (click)=\"onDismiss(error)\"\n ariaLabel=\"Dismiss\">\n </amw-button>\n }\n </div>\n </div>\n }\n\n @if (hiddenCount() > 0) {\n <div class=\"amw-error-display__overflow\">\n +{{ hiddenCount() }} more error(s)\n </div>\n }\n\n @if (displayErrors().length > 1) {\n <div class=\"amw-error-display__footer\">\n <amw-button\n appearance=\"text\"\n size=\"small\"\n (click)=\"clearAll()\">\n Clear All\n </amw-button>\n </div>\n }\n </div>\n </div>\n}\n", styles: [".amw-error-display{font-family:var(--mdc-typography-body1-font-family, Roboto, sans-serif)}.amw-error-display--inline{margin:8px 0}.amw-error-display--banner{position:fixed;left:0;right:0;z-index:1000;padding:0 16px;box-shadow:0 2px 8px #00000026}.amw-error-display--banner.amw-error-display--top{top:0}.amw-error-display--banner.amw-error-display--bottom{bottom:0}.amw-error-display--toast{position:fixed;z-index:1000;max-width:400px;padding:8px}.amw-error-display--toast.amw-error-display--top{top:16px;right:16px}.amw-error-display--toast.amw-error-display--bottom{bottom:16px;right:16px}.amw-error-display--toast .amw-error-display__container{flex-direction:column;gap:8px}.amw-error-display--toast .amw-error-display__item{border-radius:8px;box-shadow:0 2px 8px #0003}.amw-error-display--list .amw-error-display__item{border-radius:0;border-bottom:1px solid var(--mdc-theme-outline-variant, #e0e0e0)}.amw-error-display--list .amw-error-display__item:last-child{border-bottom:none}.amw-error-display__container{display:flex;flex-direction:column;gap:4px}.amw-error-display__item{display:flex;align-items:flex-start;padding:12px 16px;border-radius:4px;animation:amw-error-slide-in .3s ease-out}.amw-error-display__item--error{background-color:var(--mdc-theme-error-container, #fdecea);color:#410002}.amw-error-display__item--error .amw-error-display__icon{color:#ba1a1a}.amw-error-display__item--warning{background-color:#fff3e0;color:#3d2800}.amw-error-display__item--warning .amw-error-display__icon{color:#9a5000}.amw-error-display__item--info{background-color:#e3f2fd;color:#002171}.amw-error-display__item--info .amw-error-display__icon{color:#002171}.amw-error-display__item--dismissed{opacity:.5;animation:amw-error-fade-out .3s ease-out}.amw-error-display__icon{flex-shrink:0;margin-right:12px;display:flex;align-items:center}.amw-error-display__icon amw-icon{font-size:20px;width:20px;height:20px}.amw-error-display__content{flex:1;min-width:0}.amw-error-display__message{font-size:14px;line-height:1.4;word-break:break-word}.amw-error-display__meta{display:flex;gap:8px;margin-top:4px;font-size:12px}.amw-error-display__source{font-weight:500}.amw-error-display__code{font-family:monospace}.amw-error-display__actions{flex-shrink:0;display:flex;gap:4px;margin-left:8px}.amw-error-display__actions amw-button{opacity:.7;transition:opacity .2s}.amw-error-display__actions amw-button:hover{opacity:1}.amw-error-display__overflow{padding:8px 16px;font-size:12px;color:var(--mdc-theme-on-surface-variant, #666);text-align:center;font-style:italic}.amw-error-display__footer{display:flex;justify-content:flex-end;padding:4px 8px}@keyframes amw-error-slide-in{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes amw-error-fade-out{0%{opacity:1}to{opacity:.5}}.dark-theme .amw-error-display__item--error{background-color:#b0002040;color:#ffb4ab}.dark-theme .amw-error-display__item--error .amw-error-display__icon{color:#ffb4ab}.dark-theme .amw-error-display__item--warning{background-color:#ff980033;color:#ffe0b2}.dark-theme .amw-error-display__item--warning .amw-error-display__icon{color:#ffe0b2}.dark-theme .amw-error-display__item--info{background-color:#2196f333;color:#bbdefb}.dark-theme .amw-error-display__item--info .amw-error-display__icon{color:#bbdefb}@media(prefers-reduced-motion:reduce){.amw-error-display__item{animation:none}}\n"] }]
13667
+ }], propDecorators: { context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: true }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], showDismiss: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDismiss", required: false }] }], showRetry: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRetry", required: false }] }], maxVisible: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxVisible", required: false }] }], activeOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeOnly", required: false }] }], severityFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "severityFilter", required: false }] }], errorDismissed: [{ type: i0.Output, args: ["errorDismissed"] }], errorRetried: [{ type: i0.Output, args: ["errorRetried"] }] } });
13668
+
12180
13669
  // Calendar components
12181
13670
 
12182
13671
  /**
@@ -17685,5 +19174,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
17685
19174
  * Generated bundle index. Do not edit.
17686
19175
  */
17687
19176
 
17688
- export { AmwAccordionComponent, AmwAccordionPanelComponent, AmwAutoFocusDirective, AmwAutocompleteComponent, AmwBadgeDirective, AmwButtonComponent, AmwButtonToggleComponent, AmwButtonToggleGroupComponent, AmwCacheConfigService, AmwCacheSyncService, AmwCalendarBaseComponent, AmwCalendarFullComponent, AmwCalendarMiniComponent, AmwCalendarPickerComponent, AmwCardComponent, AmwCardService, AmwCheckboxComponent, AmwChipComponent, AmwChipInputComponent, AmwChipsComponent, AmwClickOutsideDirective, AmwColorPickerComponent, AmwCopyToClipboardDirective, AmwCurrencyPipe, AmwDashboardPageComponent, AmwDataTableComponent, AmwDatePipe, AmwDatepickerComponent, AmwDetailPageComponent, AmwDialogComponent, AmwDialogRef, AmwDialogService, AmwDividerComponent, AmwFileInputComponent, AmwFormPageComponent, AmwFormValidationComponent, AmwHttpCacheService, AmwIconButtonComponent, AmwIconComponent, AmwIndexedDbStorageService, AmwInputComponent, AmwListComponent, AmwListItemComponent, AmwListPageComponent, AmwLoadingService, AmwMasterDetailPageComponent, AmwMenuComponent, AmwMenuItemComponent, AmwMenuTriggerForDirective, AmwMessagingService, AmwNotificationService, AmwPaginatorComponent, AmwPopoverComponent, AmwProgressBarComponent, AmwProgressSpinnerComponent, AmwRadioComponent, AmwRadioGroupComponent, AmwRangeSliderComponent, AmwReportPageComponent, AmwSearchPageComponent, AmwSelectComponent, AmwSidenavComponent, AmwSliderComponent, AmwStepperComponent, AmwSwitchComponent, AmwTabComponent, AmwTabsComponent, AmwTextTransformPipe, AmwTextareaComponent, AmwThemeEditorComponent, AmwThemeManagerComponent, AmwThemePickerComponent, AmwThemeService, AmwTimepickerComponent, AmwToggleComponent, AmwToolbarComponent, AmwTooltipComponent, AmwTooltipDirective, AmwWorkflowPageComponent, BaseComponent, DefaultDashboardDataSource, DefaultFormPageDataSource, DefaultMasterDetailDataSource, DefaultReportPageDataSource, DefaultWorkflowPageDataSource, HttpCacheInterceptor, LIST_PAGE_DATA_SOURCE, WORKFLOW_PAGE_DATA_SOURCE, getAmwDialogTitle, httpCacheInterceptor };
19177
+ export { AmwAccordionComponent, AmwAccordionPanelComponent, AmwAutoFocusDirective, AmwAutocompleteComponent, AmwBadgeDirective, AmwButtonComponent, AmwButtonToggleComponent, AmwButtonToggleGroupComponent, AmwCacheConfigService, AmwCacheSyncService, AmwCalendarBaseComponent, AmwCalendarFullComponent, AmwCalendarMiniComponent, AmwCalendarPickerComponent, AmwCardComponent, AmwCardService, AmwCheckboxComponent, AmwChipComponent, AmwChipInputComponent, AmwChipsComponent, AmwClickOutsideDirective, AmwColorPickerComponent, AmwCopyToClipboardDirective, AmwCurrencyPipe, AmwDashboardPageComponent, AmwDataTableComponent, AmwDatePipe, AmwDatepickerComponent, AmwDetailPageComponent, AmwDialogComponent, AmwDialogRef, AmwDialogService, AmwDividerComponent, AmwErrorDisplayComponent, AmwErrorStateService, AmwFileInputComponent, AmwFormPageComponent, AmwFormValidationComponent, AmwFullScreenLoadingComponent, AmwFullScreenLoadingService, AmwHttpCacheService, AmwIconButtonComponent, AmwIconComponent, AmwIndexedDbStorageService, AmwInputComponent, AmwListComponent, AmwListItemComponent, AmwListPageComponent, AmwLoadingService, AmwMasterDetailPageComponent, AmwMenuComponent, AmwMenuItemComponent, AmwMenuTriggerForDirective, AmwMessagingService, AmwNotificationService, AmwPaginatorComponent, AmwPopoverComponent, AmwProgressBarComponent, AmwProgressSpinnerComponent, AmwRadioComponent, AmwRadioGroupComponent, AmwRangeSliderComponent, AmwReportPageComponent, AmwSearchPageComponent, AmwSelectComponent, AmwSidenavComponent, AmwSliderComponent, AmwStepperComponent, AmwSwitchComponent, AmwTabComponent, AmwTabsComponent, AmwTextTransformPipe, AmwTextareaComponent, AmwThemeEditorComponent, AmwThemeManagerComponent, AmwThemePickerComponent, AmwThemeService, AmwTimepickerComponent, AmwToggleComponent, AmwToolbarComponent, AmwTooltipComponent, AmwTooltipDirective, AmwValidationService, AmwValidationTooltipDirective, AmwWorkflowPageComponent, BaseComponent, DefaultDashboardDataSource, DefaultFormPageDataSource, DefaultMasterDetailDataSource, DefaultReportPageDataSource, DefaultWorkflowPageDataSource, ErrorStateMixin, HttpCacheInterceptor, LIST_PAGE_DATA_SOURCE, ValidationMixin, WORKFLOW_PAGE_DATA_SOURCE, getAmwDialogTitle, httpCacheInterceptor, loading };
17689
19178
  //# sourceMappingURL=angular-material-wrap.mjs.map