@vsn-ux/ngx-gaia 0.8.7 → 0.8.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,17 +1,17 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, makeEnvironmentProviders, inject, ElementRef, HostAttributeToken, input, numberAttribute, computed, ViewEncapsulation, Component, NgModule, Injectable, booleanAttribute, ChangeDetectionStrategy, output, contentChild, forwardRef, Injector, signal, linkedSignal, Directive, model, HostListener, TemplateRef, NgZone, HostBinding, Input, DOCUMENT, effect, DestroyRef, afterNextRender, Renderer2, afterEveryRender, contentChildren, viewChild } from '@angular/core';
2
+ import { InjectionToken, makeEnvironmentProviders, inject, ElementRef, HostAttributeToken, input, numberAttribute, computed, ViewEncapsulation, Component, NgModule, Injectable, booleanAttribute, ChangeDetectionStrategy, output, contentChild, Directive, linkedSignal, signal, Injector, DestroyRef, effect, isSignal, forwardRef, model, HostListener, viewChild, TemplateRef, contentChildren, NgZone, HostBinding, Input, DOCUMENT, afterNextRender, Renderer2, afterEveryRender } from '@angular/core';
3
3
  import * as i1 from 'lucide-angular';
4
- import { LucideAngularModule, X, CircleCheck, TriangleAlert, OctagonAlert, Info, Check, Minus, ChevronUp, ChevronDown } from 'lucide-angular';
5
- import { NG_VALUE_ACCESSOR, NgControl, NG_VALIDATORS, CheckboxRequiredValidator, RequiredValidator } from '@angular/forms';
4
+ import { LucideAngularModule, X, CircleCheck, TriangleAlert, OctagonAlert, Info, Check, Minus, ChevronUp, ChevronDown, CircleX } from 'lucide-angular';
5
+ import { NgForm, ControlContainer, NgControl, NG_VALUE_ACCESSOR, NG_VALIDATORS, CheckboxRequiredValidator, RequiredValidator } from '@angular/forms';
6
+ import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
7
+ import { NgTemplateOutlet } from '@angular/common';
6
8
  import * as i1$5 from '@angular/cdk/overlay';
7
9
  import { Overlay, createRepositionScrollStrategy, OverlayRef, CdkOverlayOrigin, OverlayModule } from '@angular/cdk/overlay';
8
10
  import { ComponentPortal } from '@angular/cdk/portal';
9
11
  import { Subject, takeUntil, map, merge, filter, Observable, isObservable } from 'rxjs';
10
12
  import { ESCAPE, hasModifierKey } from '@angular/cdk/keycodes';
11
- import { NgTemplateOutlet } from '@angular/common';
12
13
  import * as i1$1 from '@angular/cdk/menu';
13
14
  import { CdkMenu, CdkMenuItem, CdkMenuTrigger, MENU_SCROLL_STRATEGY } from '@angular/cdk/menu';
14
- import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
15
15
  import { Router, ResolveStart } from '@angular/router';
16
16
  import * as i1$2 from '@angular/cdk/a11y';
17
17
  import { CdkTrapFocus } from '@angular/cdk/a11y';
@@ -535,6 +535,118 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
535
535
  }]
536
536
  }] });
537
537
 
538
+ class GaFormControlErrorsDirective {
539
+ customErrorsInput = input.required({
540
+ alias: 'gaFormControlErrors',
541
+ });
542
+ customErrors = computed(() => {
543
+ // for better API ergonomics, we ignore errors with null and undefined values
544
+ // this lets to bind custom errors directly without nasty if checks
545
+ // e.g. [gaFormControlErrors]="{ required: isEmpty ? true : null, noMatch: form.getError('noMatch') }"
546
+ return Object.entries(this.customErrorsInput()).reduce((acc, [key, value]) => {
547
+ if (value !== null && value !== undefined) {
548
+ acc[key] = value;
549
+ }
550
+ return acc;
551
+ }, {});
552
+ });
553
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaFormControlErrorsDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
554
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.4", type: GaFormControlErrorsDirective, isStandalone: true, selector: "[gaFormControlErrors]", inputs: { customErrorsInput: { classPropertyName: "customErrorsInput", publicName: "gaFormControlErrors", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
555
+ }
556
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaFormControlErrorsDirective, decorators: [{
557
+ type: Directive,
558
+ args: [{
559
+ selector: '[gaFormControlErrors]',
560
+ }]
561
+ }] });
562
+
563
+ const GA_FORM_CONTROL_ADAPTER = new InjectionToken('ga-form-control-adapter');
564
+ function injectNgControlState({ implicitChildNgControl, explicitNgControl, explicitNgForm, } = {}) {
565
+ const gaFormControlAdapter = inject(GA_FORM_CONTROL_ADAPTER, {
566
+ optional: true,
567
+ });
568
+ let ngControlErrors;
569
+ let ngControlTouched;
570
+ let ngControlDisabled;
571
+ let ngControlName;
572
+ let ngFormSubmitted;
573
+ if (gaFormControlAdapter) {
574
+ ngControlErrors = linkedSignal(() => gaFormControlAdapter.ngControlErrors());
575
+ ngControlTouched = linkedSignal(() => gaFormControlAdapter.ngControlTouched());
576
+ ngControlDisabled = linkedSignal(() => gaFormControlAdapter.ngControlDisabled());
577
+ ngControlName = linkedSignal(() => gaFormControlAdapter.ngControlName());
578
+ ngFormSubmitted = linkedSignal(() => gaFormControlAdapter.ngFormSubmitted());
579
+ }
580
+ else {
581
+ ngControlErrors = signal(null);
582
+ ngControlTouched = signal(false);
583
+ ngControlDisabled = signal(false);
584
+ ngControlName = signal(null);
585
+ ngFormSubmitted = signal(false);
586
+ const injector = inject(Injector);
587
+ const destroyRef = inject(DestroyRef);
588
+ const implicitNgForm = inject(NgForm, { optional: true });
589
+ const implicitControlContainer = inject(ControlContainer, {
590
+ optional: true,
591
+ });
592
+ const ngForm = explicitNgForm ??
593
+ implicitNgForm ??
594
+ (implicitControlContainer?.formDirective instanceof NgForm
595
+ ? implicitControlContainer.formDirective
596
+ : null);
597
+ let ngControlSubscription = null;
598
+ effect(() => {
599
+ if (ngControlSubscription) {
600
+ ngControlSubscription.unsubscribe();
601
+ ngControlSubscription = null;
602
+ }
603
+ if (isSignal(explicitNgControl)) {
604
+ explicitNgControl = explicitNgControl();
605
+ }
606
+ const ngControl = explicitNgControl ??
607
+ implicitChildNgControl?.() ??
608
+ injector.get(NgControl, null, { self: true, optional: true });
609
+ if (ngControl?.control) {
610
+ const updateStatuses = () => {
611
+ ngControlErrors.set(ngControl.errors);
612
+ ngControlTouched.set(!!ngControl.touched);
613
+ ngControlDisabled.set(!!ngControl.disabled);
614
+ ngControlName.set(ngControl.name);
615
+ };
616
+ updateStatuses();
617
+ ngControlSubscription = ngControl.control.events
618
+ .pipe(takeUntilDestroyed(destroyRef))
619
+ .subscribe(() => updateStatuses());
620
+ }
621
+ });
622
+ if (ngForm) {
623
+ ngFormSubmitted.set(ngForm.submitted);
624
+ ngForm.ngSubmit
625
+ .pipe(takeUntilDestroyed(destroyRef))
626
+ .subscribe(() => ngFormSubmitted.set(ngForm.submitted));
627
+ }
628
+ }
629
+ const customErrorsDirective = inject(GaFormControlErrorsDirective, {
630
+ optional: true,
631
+ });
632
+ const inError = signal(false);
633
+ const errors = signal({});
634
+ effect(() => {
635
+ errors.set({
636
+ ...ngControlErrors(),
637
+ ...(customErrorsDirective?.customErrors() ?? {}),
638
+ });
639
+ const hasErrors = Object.keys(errors()).length > 0;
640
+ inError.set(hasErrors && (ngControlTouched() || ngFormSubmitted()));
641
+ });
642
+ return {
643
+ inError: inError.asReadonly(),
644
+ errors: errors.asReadonly(),
645
+ disabled: ngControlDisabled.asReadonly(),
646
+ name: ngControlName.asReadonly(),
647
+ };
648
+ }
649
+
538
650
  const CHECKBOX_CONTROL_VALUE_ACCESSOR = {
539
651
  provide: NG_VALUE_ACCESSOR,
540
652
  useExisting: forwardRef(() => GaCheckboxComponent),
@@ -547,7 +659,7 @@ class GaCheckboxComponent {
547
659
  /** @ignore */
548
660
  _uniqueId = `ga-checkbox-${++nextUniqueId$8}`;
549
661
  /** @ignore */
550
- injector = inject(Injector);
662
+ implicitNgControlState = injectNgControlState();
551
663
  /** @ignore */
552
664
  tabindex = inject(new HostAttributeToken('tabindex'), {
553
665
  optional: true,
@@ -557,16 +669,15 @@ class GaCheckboxComponent {
557
669
  _onTouched;
558
670
  /** @ignore */
559
671
  _onModelChanged;
560
- /** @ignore */
561
- _invalidNgModel = signal(false);
562
- _ngModelName = signal(null);
563
672
  /** The value attribute of the native input element */
564
673
  value = input(null);
565
- disabled = input(false, {
674
+ disabledInput = input(false, {
566
675
  transform: booleanAttribute,
676
+ alias: 'disabled',
567
677
  });
568
- checked = input(false, {
678
+ checkedInput = input(false, {
569
679
  transform: booleanAttribute,
680
+ alias: 'checked',
570
681
  });
571
682
  nameInput = input(null, { alias: 'name' });
572
683
  id = input(null);
@@ -583,29 +694,22 @@ class GaCheckboxComponent {
583
694
  alias: 'aria-errormessage',
584
695
  });
585
696
  required = input(false, { transform: booleanAttribute });
586
- disabledModel = linkedSignal(() => this.disabled());
587
- checkedModel = linkedSignal(() => this.checked());
697
+ disabled = linkedSignal(() => this.disabledInput());
698
+ checked = linkedSignal(() => this.checkedInput());
588
699
  change = output();
589
700
  indeterminateChange = output();
590
701
  /** @ignore */
591
702
  inputId = computed(() => (this.id() ? this.id() : this._uniqueId));
592
703
  /** @ignore */
593
704
  name = computed(() => {
594
- return this.nameInput() ?? this._ngModelName() ?? this._uniqueId;
705
+ return (this.nameInput() ?? this.implicitNgControlState.name() ?? this._uniqueId);
595
706
  });
596
707
  /** @ignore */
597
708
  invalid = computed(() => {
598
709
  return this.ariaInvalid()
599
710
  ? this.ariaInvalid() === 'true'
600
- : this._invalidNgModel();
711
+ : this.implicitNgControlState.inError();
601
712
  });
602
- ngDoCheck() {
603
- const ngControl = this.injector.get(NgControl, null, { self: true });
604
- if (ngControl) {
605
- this._invalidNgModel.set(!!ngControl.invalid);
606
- this._ngModelName.set(ngControl.name);
607
- }
608
- }
609
713
  /** @ignore */
610
714
  onInputChange(event) {
611
715
  // We always have to stop propagation on the change event.
@@ -615,7 +719,7 @@ class GaCheckboxComponent {
615
719
  if (this.disabled()) {
616
720
  return;
617
721
  }
618
- this.checkedModel.set(!this.checkedModel());
722
+ this.checked.set(!this.checked());
619
723
  this.updateModel();
620
724
  }
621
725
  /** @ignore */
@@ -632,19 +736,19 @@ class GaCheckboxComponent {
632
736
  }
633
737
  /** @ignore */
634
738
  writeValue(value) {
635
- this.checkedModel.set(!!value);
739
+ this.checked.set(!!value);
636
740
  }
637
741
  /** @ignore */
638
742
  setDisabledState(isDisabled) {
639
- this.disabledModel.set(isDisabled);
743
+ this.disabled.set(isDisabled);
640
744
  }
641
745
  /** @ignore */
642
746
  updateModel() {
643
- this._onModelChanged?.(this.checkedModel());
644
- this.change.emit(this.checkedModel());
747
+ this._onModelChanged?.(this.checked());
748
+ this.change.emit(this.checked());
645
749
  }
646
750
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaCheckboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
647
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.4", type: GaCheckboxComponent, isStandalone: true, selector: "ga-checkbox", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, nameInput: { classPropertyName: "nameInput", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedby: { classPropertyName: "ariaDescribedby", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, ariaInvalid: { classPropertyName: "ariaInvalid", publicName: "aria-invalid", isSignal: true, isRequired: false, transformFunction: null }, ariaErrormessage: { classPropertyName: "ariaErrormessage", publicName: "aria-errormessage", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { change: "change", indeterminateChange: "indeterminateChange" }, host: { properties: { "class.ga-checkbox--invalid": "invalid()", "attr.id": "null", "attr.tabindex": "null", "attr.aria-label": "null", "attr.aria-labelledby": "null", "attr.aria-describedby": "null", "attr.aria-invalid": "null", "attr.aria-errormessage": "null" }, classAttribute: "ga-checkbox" }, providers: [CHECKBOX_CONTROL_VALUE_ACCESSOR], ngImport: i0, template: "<input\n type=\"checkbox\"\n class=\"ga-checkbox__native\"\n [attr.id]=\"inputId()\"\n [name]=\"name()\"\n [checked]=\"checkedModel()\"\n [indeterminate]=\"indeterminate()\"\n [disabled]=\"disabledModel()\"\n [required]=\"required()\"\n [attr.value]=\"value()\"\n [attr.tabindex]=\"tabindex\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby()\"\n [attr.aria-describedby]=\"ariaDescribedby()\"\n [attr.aria-invalid]=\"ariaInvalid()\"\n [attr.aria-errormessage]=\"ariaErrormessage()\"\n (change)=\"onInputChange($event)\"\n (blur)=\"onBlur()\"\n/>\n<div class=\"ga-checkbox__marker\">\n <lucide-icon\n [img]=\"icons.Check\"\n class=\"ga-checkbox__marker__indicator-checked\"\n [size]=\"12\"\n [strokeWidth]=\"2\"\n [absoluteStrokeWidth]=\"true\"\n />\n <lucide-icon\n [img]=\"icons.Minus\"\n class=\"ga-checkbox__marker__indicator-indeterminate\"\n [size]=\"12\"\n [strokeWidth]=\"2\"\n [absoluteStrokeWidth]=\"true\"\n />\n</div>\n\n<label class=\"ga-checkbox__label\" [attr.for]=\"inputId()\"\n ><ng-content></ng-content\n></label>\n", dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
751
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.4", type: GaCheckboxComponent, isStandalone: true, selector: "ga-checkbox", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, checkedInput: { classPropertyName: "checkedInput", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, nameInput: { classPropertyName: "nameInput", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedby: { classPropertyName: "ariaDescribedby", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, ariaInvalid: { classPropertyName: "ariaInvalid", publicName: "aria-invalid", isSignal: true, isRequired: false, transformFunction: null }, ariaErrormessage: { classPropertyName: "ariaErrormessage", publicName: "aria-errormessage", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { change: "change", indeterminateChange: "indeterminateChange" }, host: { properties: { "class.ga-checkbox--invalid": "invalid()", "attr.id": "null", "attr.tabindex": "null", "attr.aria-label": "null", "attr.aria-labelledby": "null", "attr.aria-describedby": "null", "attr.aria-invalid": "null", "attr.aria-errormessage": "null" }, classAttribute: "ga-checkbox" }, providers: [CHECKBOX_CONTROL_VALUE_ACCESSOR], ngImport: i0, template: "<input\n type=\"checkbox\"\n class=\"ga-checkbox__native\"\n [attr.id]=\"inputId()\"\n [name]=\"name()\"\n [checked]=\"checked()\"\n [indeterminate]=\"indeterminate()\"\n [disabled]=\"disabled()\"\n [required]=\"required()\"\n [attr.value]=\"value()\"\n [attr.tabindex]=\"tabindex\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby()\"\n [attr.aria-describedby]=\"ariaDescribedby()\"\n [attr.aria-invalid]=\"ariaInvalid()\"\n [attr.aria-errormessage]=\"ariaErrormessage()\"\n (change)=\"onInputChange($event)\"\n (blur)=\"onBlur()\"\n/>\n<div class=\"ga-checkbox__marker\">\n <lucide-icon\n [img]=\"icons.Check\"\n class=\"ga-checkbox__marker__indicator-checked\"\n [size]=\"12\"\n [strokeWidth]=\"2\"\n [absoluteStrokeWidth]=\"true\"\n />\n <lucide-icon\n [img]=\"icons.Minus\"\n class=\"ga-checkbox__marker__indicator-indeterminate\"\n [size]=\"12\"\n [strokeWidth]=\"2\"\n [absoluteStrokeWidth]=\"true\"\n />\n</div>\n\n<label class=\"ga-checkbox__label\" [attr.for]=\"inputId()\"\n ><ng-content></ng-content\n></label>\n", dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
648
752
  }
649
753
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaCheckboxComponent, decorators: [{
650
754
  type: Component,
@@ -658,7 +762,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
658
762
  '[attr.aria-describedby]': 'null',
659
763
  '[attr.aria-invalid]': 'null',
660
764
  '[attr.aria-errormessage]': 'null',
661
- }, template: "<input\n type=\"checkbox\"\n class=\"ga-checkbox__native\"\n [attr.id]=\"inputId()\"\n [name]=\"name()\"\n [checked]=\"checkedModel()\"\n [indeterminate]=\"indeterminate()\"\n [disabled]=\"disabledModel()\"\n [required]=\"required()\"\n [attr.value]=\"value()\"\n [attr.tabindex]=\"tabindex\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby()\"\n [attr.aria-describedby]=\"ariaDescribedby()\"\n [attr.aria-invalid]=\"ariaInvalid()\"\n [attr.aria-errormessage]=\"ariaErrormessage()\"\n (change)=\"onInputChange($event)\"\n (blur)=\"onBlur()\"\n/>\n<div class=\"ga-checkbox__marker\">\n <lucide-icon\n [img]=\"icons.Check\"\n class=\"ga-checkbox__marker__indicator-checked\"\n [size]=\"12\"\n [strokeWidth]=\"2\"\n [absoluteStrokeWidth]=\"true\"\n />\n <lucide-icon\n [img]=\"icons.Minus\"\n class=\"ga-checkbox__marker__indicator-indeterminate\"\n [size]=\"12\"\n [strokeWidth]=\"2\"\n [absoluteStrokeWidth]=\"true\"\n />\n</div>\n\n<label class=\"ga-checkbox__label\" [attr.for]=\"inputId()\"\n ><ng-content></ng-content\n></label>\n" }]
765
+ }, template: "<input\n type=\"checkbox\"\n class=\"ga-checkbox__native\"\n [attr.id]=\"inputId()\"\n [name]=\"name()\"\n [checked]=\"checked()\"\n [indeterminate]=\"indeterminate()\"\n [disabled]=\"disabled()\"\n [required]=\"required()\"\n [attr.value]=\"value()\"\n [attr.tabindex]=\"tabindex\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby()\"\n [attr.aria-describedby]=\"ariaDescribedby()\"\n [attr.aria-invalid]=\"ariaInvalid()\"\n [attr.aria-errormessage]=\"ariaErrormessage()\"\n (change)=\"onInputChange($event)\"\n (blur)=\"onBlur()\"\n/>\n<div class=\"ga-checkbox__marker\">\n <lucide-icon\n [img]=\"icons.Check\"\n class=\"ga-checkbox__marker__indicator-checked\"\n [size]=\"12\"\n [strokeWidth]=\"2\"\n [absoluteStrokeWidth]=\"true\"\n />\n <lucide-icon\n [img]=\"icons.Minus\"\n class=\"ga-checkbox__marker__indicator-indeterminate\"\n [size]=\"12\"\n [strokeWidth]=\"2\"\n [absoluteStrokeWidth]=\"true\"\n />\n</div>\n\n<label class=\"ga-checkbox__label\" [attr.for]=\"inputId()\"\n ><ng-content></ng-content\n></label>\n" }]
662
766
  }] });
663
767
 
664
768
  const GA_CHECKBOX_REQUIRED_VALIDATOR = {
@@ -824,99 +928,72 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
824
928
  }]
825
929
  }] });
826
930
 
827
- class GaInputComponent {
828
- implicitNgControl = contentChild(NgControl);
829
- implicitInvalid = signal(false);
830
- invalidInput = input(null, { transform: booleanAttribute });
831
- invalid = computed(() => {
832
- return this.invalidInput() ?? this.implicitInvalid();
833
- });
834
- ngDoCheck() {
835
- // we can rely on computed because `ivalid` of NgControl is not a signal, yet
836
- const implicitNgControl = this.implicitNgControl();
837
- if (implicitNgControl) {
838
- this.implicitInvalid.set(!!implicitNgControl.invalid && !!implicitNgControl.dirty);
839
- }
840
- }
841
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
842
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.0.4", type: GaInputComponent, isStandalone: true, selector: "ga-input", inputs: { invalidInput: { classPropertyName: "invalidInput", publicName: "invalidInput", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.ga-input--invalid": "invalid()" }, classAttribute: "ga-input" }, queries: [{ propertyName: "implicitNgControl", first: true, predicate: NgControl, descendants: true, isSignal: true }], ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
843
- }
844
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaInputComponent, decorators: [{
845
- type: Component,
846
- args: [{
847
- selector: 'ga-input',
848
- template: `<ng-content />`,
849
- changeDetection: ChangeDetectionStrategy.OnPush,
850
- host: {
851
- class: 'ga-input',
852
- '[class.ga-input--invalid]': 'invalid()',
853
- },
854
- }]
855
- }] });
931
+ const GA_FORM_FIELD_ID = new InjectionToken('ga-form-field-id');
856
932
 
857
933
  const GA_FORM_CONTROL = new InjectionToken('ga-form-control');
858
934
  class GaFormControlDirective {
859
- _formControlId = input(undefined, {
935
+ formFieldId = inject(GA_FORM_FIELD_ID, { optional: true });
936
+ ngControlInput = input(undefined, {
860
937
  alias: 'gaFormControl',
861
938
  });
862
- _formControlDisabled = input(undefined, {
863
- alias: 'gaFormControlDisabled',
939
+ explicitNgControl = computed(() => {
940
+ const ngControl = this.ngControlInput();
941
+ if (ngControl instanceof NgControl) {
942
+ return ngControl;
943
+ }
944
+ return null;
945
+ });
946
+ ngControlState = injectNgControlState({
947
+ explicitNgControl: this.explicitNgControl,
948
+ });
949
+ inError = this.ngControlState.inError;
950
+ errors = this.ngControlState.errors;
951
+ ariaErrorMessageId = computed(() => {
952
+ if (!this.formFieldId || !this.inError()) {
953
+ return null;
954
+ }
955
+ return `${this.formFieldId}-callout`;
864
956
  });
865
957
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaFormControlDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
866
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.4", type: GaFormControlDirective, isStandalone: true, selector: "[gaFormControl]", inputs: { _formControlId: { classPropertyName: "_formControlId", publicName: "gaFormControl", isSignal: true, isRequired: false, transformFunction: null }, _formControlDisabled: { classPropertyName: "_formControlDisabled", publicName: "gaFormControlDisabled", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
867
- { provide: GA_FORM_CONTROL, useExisting: GaFormControlDirective },
868
- ], ngImport: i0 });
958
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.4", type: GaFormControlDirective, isStandalone: true, selector: "[gaFormControl]", inputs: { ngControlInput: { classPropertyName: "ngControlInput", publicName: "gaFormControl", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.aria-invalid": "inError() ? \"true\" : null", "attr.aria-errormessage": "ariaErrorMessageId()" } }, exportAs: ["gaFormControl"], ngImport: i0 });
869
959
  }
870
960
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaFormControlDirective, decorators: [{
871
961
  type: Directive,
872
962
  args: [{
963
+ exportAs: 'gaFormControl',
873
964
  selector: '[gaFormControl]',
874
- providers: [
875
- { provide: GA_FORM_CONTROL, useExisting: GaFormControlDirective },
876
- ],
965
+ host: {
966
+ '[attr.aria-invalid]': 'inError() ? "true" : null',
967
+ '[attr.aria-errormessage]': 'ariaErrorMessageId()',
968
+ },
877
969
  }]
878
970
  }] });
879
971
 
880
972
  let nextUniqueId$7 = 0;
881
973
  class GaInputDirective {
882
974
  uniqueId = `ga-input-${++nextUniqueId$7}`;
883
- implicitNgControl = inject(NgControl, {
884
- optional: true,
885
- self: true,
886
- });
887
975
  hasWrapper = inject(GaInputComponent, { optional: true });
888
- implicitInvalid = signal(false);
889
- implicitErrors = signal(null);
976
+ implicitNgControlState = injectNgControlState();
890
977
  invalidInput = input(null, {
891
978
  alias: 'invalid',
892
979
  transform: booleanAttribute,
893
980
  });
894
981
  idInput = input(undefined, { alias: 'id' });
895
- disabledInput = input(false, {
982
+ disabledInput = input(undefined, {
896
983
  alias: 'disabled',
897
984
  transform: booleanAttribute,
898
985
  });
899
986
  invalid = computed(() => {
900
- return this.invalidInput() ?? this.implicitInvalid();
987
+ return this.invalidInput() ?? this.implicitNgControlState.inError();
901
988
  });
902
989
  id = computed(() => {
903
990
  return this.idInput() ?? this.uniqueId;
904
991
  });
905
- disabled = linkedSignal(() => this.disabledInput());
906
- errors = this.implicitErrors.asReadonly();
992
+ disabled = computed(() => {
993
+ return this.disabledInput() ?? this.implicitNgControlState.disabled();
994
+ });
907
995
  _formControlId = this.id;
908
- _formControlDisabled = computed(() => this.disabled());
909
- ngDoCheck() {
910
- if (this.hasWrapper)
911
- return;
912
- // we can rely on computed because `ivalid` of NgControl is not a signal, yet
913
- const implicitNgControl = this.implicitNgControl;
914
- if (implicitNgControl) {
915
- this.implicitInvalid.set(!!implicitNgControl.invalid && !!implicitNgControl.dirty);
916
- this.implicitErrors.set(implicitNgControl.errors);
917
- this.disabled.set(!!implicitNgControl.disabled);
918
- }
919
- }
996
+ _formControlDisabled = this.disabled;
920
997
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaInputDirective, deps: [], target: i0.ɵɵFactoryTarget.Component });
921
998
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.4", type: GaInputDirective, isStandalone: true, selector: "[gaInput]", inputs: { invalidInput: { classPropertyName: "invalidInput", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, idInput: { classPropertyName: "idInput", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.id": "id()", "class.ga-input": "!hasWrapper", "class.ga-input--invalid": "!hasWrapper && invalid()" } }, providers: [{ provide: GA_FORM_CONTROL, useExisting: GaInputDirective }], ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
922
999
  }
@@ -936,6 +1013,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
936
1013
  }]
937
1014
  }] });
938
1015
 
1016
+ class GaInputComponent {
1017
+ gaInput = contentChild.required(GaInputDirective);
1018
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1019
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.0.4", type: GaInputComponent, isStandalone: true, selector: "ga-input", host: { properties: { "class.ga-input--invalid": "gaInput().invalid()" }, classAttribute: "ga-input" }, queries: [{ propertyName: "gaInput", first: true, predicate: GaInputDirective, descendants: true, isSignal: true }], ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
1020
+ }
1021
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaInputComponent, decorators: [{
1022
+ type: Component,
1023
+ args: [{
1024
+ selector: 'ga-input',
1025
+ template: `<ng-content />`,
1026
+ changeDetection: ChangeDetectionStrategy.OnPush,
1027
+ host: {
1028
+ class: 'ga-input',
1029
+ '[class.ga-input--invalid]': 'gaInput().invalid()',
1030
+ },
1031
+ }]
1032
+ }] });
1033
+
939
1034
  class GaInputModule {
940
1035
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaInputModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
941
1036
  static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.4", ngImport: i0, type: GaInputModule, imports: [GaInputComponent, GaInputDirective], exports: [GaInputComponent, GaInputDirective] });
@@ -949,19 +1044,110 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
949
1044
  }]
950
1045
  }] });
951
1046
 
1047
+ class GaFieldCalloutComponent {
1048
+ icons = { OctagonAlert };
1049
+ formField = inject(GaFormFieldComponent);
1050
+ id = this.formField.uniqueId + '-callout';
1051
+ shouldShowError = computed(() => {
1052
+ const formControl = this.formField.formControl();
1053
+ if (!formControl) {
1054
+ return false;
1055
+ }
1056
+ return formControl.inError() && this.overlappingErrors().length > 0;
1057
+ });
1058
+ overlappingErrors = computed(() => {
1059
+ const formControl = this.formField.formControl();
1060
+ if (!formControl) {
1061
+ return [];
1062
+ }
1063
+ const registeredErrors = this.formField
1064
+ .fieldErrors()
1065
+ .filter((err) => err.key());
1066
+ const controlErrorKeys = Object.keys(formControl.errors());
1067
+ return registeredErrors
1068
+ .filter((err) => controlErrorKeys.includes(err.key()))
1069
+ .map((err) => {
1070
+ const errorKey = err.key();
1071
+ return {
1072
+ key: errorKey,
1073
+ templateRef: err.templateRef,
1074
+ error: formControl.errors()[errorKey],
1075
+ };
1076
+ });
1077
+ });
1078
+ hasCallout = computed(() => !!this.formField.fieldInfo() || this.shouldShowError());
1079
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaFieldCalloutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1080
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: GaFieldCalloutComponent, isStandalone: true, selector: "ga-field-callout", host: { properties: { "attr.id": "id", "style.display": "hasCallout() ? null : \"none\"" }, classAttribute: "ga-form-field__info" }, ngImport: i0, template: "@if (shouldShowError()) {\n <ga-icon\n [icon]=\"icons.OctagonAlert\"\n class=\"ga-icon\"\n style=\"color: var(--ga-color-icon-error)\"\n size=\"16\"\n />\n <div>\n @for (error of overlappingErrors(); track error.key; let last = $last) {\n <span\n ><ng-container\n [ngTemplateOutlet]=\"error.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: error.error }\"\n />&nbsp;</span\n >\n }\n </div>\n} @else if (formField.fieldInfo()) {\n <ng-container [ngTemplateOutlet]=\"formField.fieldInfo()!.templateRef()\" />\n}\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: GaIconModule }, { kind: "component", type: GaIconComponent, selector: "ga-icon", inputs: ["icon", "size", "color", "strokeWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1081
+ }
1082
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaFieldCalloutComponent, decorators: [{
1083
+ type: Component,
1084
+ args: [{ selector: 'ga-field-callout', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgTemplateOutlet, GaIconModule], host: {
1085
+ class: 'ga-form-field__info',
1086
+ '[attr.id]': 'id',
1087
+ '[style.display]': 'hasCallout() ? null : "none"',
1088
+ }, template: "@if (shouldShowError()) {\n <ga-icon\n [icon]=\"icons.OctagonAlert\"\n class=\"ga-icon\"\n style=\"color: var(--ga-color-icon-error)\"\n size=\"16\"\n />\n <div>\n @for (error of overlappingErrors(); track error.key; let last = $last) {\n <span\n ><ng-container\n [ngTemplateOutlet]=\"error.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: error.error }\"\n />&nbsp;</span\n >\n }\n </div>\n} @else if (formField.fieldInfo()) {\n <ng-container [ngTemplateOutlet]=\"formField.fieldInfo()!.templateRef()\" />\n}\n" }]
1089
+ }] });
1090
+
1091
+ class GaFieldInfoComponent {
1092
+ templateRef = viewChild.required(TemplateRef);
1093
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaFieldInfoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1094
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.0.4", type: GaFieldInfoComponent, isStandalone: true, selector: "ga-info", host: { properties: { "style.display": "\"none\"" } }, viewQueries: [{ propertyName: "templateRef", first: true, predicate: TemplateRef, descendants: true, isSignal: true }], ngImport: i0, template: `<ng-template><ng-content /></ng-template>`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
1095
+ }
1096
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaFieldInfoComponent, decorators: [{
1097
+ type: Component,
1098
+ args: [{
1099
+ selector: 'ga-info',
1100
+ template: `<ng-template><ng-content /></ng-template>`,
1101
+ changeDetection: ChangeDetectionStrategy.OnPush,
1102
+ host: {
1103
+ '[style.display]': '"none"',
1104
+ },
1105
+ }]
1106
+ }] });
1107
+
1108
+ class GaFieldErrorDirective {
1109
+ templateRef = inject(TemplateRef, { self: true });
1110
+ key = input.required({ alias: 'gaError' });
1111
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaFieldErrorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1112
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.4", type: GaFieldErrorDirective, isStandalone: true, selector: "[gaError]", inputs: { key: { classPropertyName: "key", publicName: "gaError", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
1113
+ }
1114
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaFieldErrorDirective, decorators: [{
1115
+ type: Directive,
1116
+ args: [{
1117
+ selector: '[gaError]',
1118
+ }]
1119
+ }] });
1120
+
952
1121
  let nextUniqueId$6 = 0;
953
1122
  class GaFormFieldComponent {
954
- uniqueId = `ga-form-field-${++nextUniqueId$6}`;
1123
+ uniqueId = inject(GA_FORM_FIELD_ID);
955
1124
  disabled = input(undefined, { transform: booleanAttribute });
956
- formControl = contentChild(GA_FORM_CONTROL, { descendants: true });
1125
+ implicitFormControl = contentChild(GA_FORM_CONTROL, {
1126
+ descendants: true,
1127
+ });
1128
+ formControl = contentChild(GaFormControlDirective, {
1129
+ descendants: true,
1130
+ });
1131
+ fieldInfo = contentChild(GaFieldInfoComponent);
1132
+ fieldErrors = contentChildren(GaFieldErrorDirective);
957
1133
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaFormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
958
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.0.4", type: GaFormFieldComponent, isStandalone: true, selector: "ga-form-field", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "ga-form-field" }, queries: [{ propertyName: "formControl", first: true, predicate: GA_FORM_CONTROL, descendants: true, isSignal: true }], exportAs: ["gaFormField"], ngImport: i0, template: "<ng-content />\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
1134
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.0.4", type: GaFormFieldComponent, isStandalone: true, selector: "ga-form-field", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "ga-form-field" }, providers: [
1135
+ {
1136
+ provide: GA_FORM_FIELD_ID,
1137
+ useFactory: () => `ga-form-field-${++nextUniqueId$6}`,
1138
+ },
1139
+ ], queries: [{ propertyName: "implicitFormControl", first: true, predicate: GA_FORM_CONTROL, descendants: true, isSignal: true }, { propertyName: "formControl", first: true, predicate: GaFormControlDirective, descendants: true, isSignal: true }, { propertyName: "fieldInfo", first: true, predicate: GaFieldInfoComponent, descendants: true, isSignal: true }, { propertyName: "fieldErrors", predicate: GaFieldErrorDirective, isSignal: true }], exportAs: ["gaFormField"], ngImport: i0, template: "<ng-content select=\"ga-label\" />\n<ng-content />\n<ga-field-callout />\n", dependencies: [{ kind: "component", type: GaFieldCalloutComponent, selector: "ga-field-callout" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
959
1140
  }
960
1141
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaFormFieldComponent, decorators: [{
961
1142
  type: Component,
962
- args: [{ selector: 'ga-form-field', exportAs: 'gaFormField', changeDetection: ChangeDetectionStrategy.OnPush, host: {
1143
+ args: [{ selector: 'ga-form-field', exportAs: 'gaFormField', changeDetection: ChangeDetectionStrategy.OnPush, imports: [GaFieldCalloutComponent], host: {
963
1144
  class: 'ga-form-field',
964
- }, template: "<ng-content />\n" }]
1145
+ }, providers: [
1146
+ {
1147
+ provide: GA_FORM_FIELD_ID,
1148
+ useFactory: () => `ga-form-field-${++nextUniqueId$6}`,
1149
+ },
1150
+ ], template: "<ng-content select=\"ga-label\" />\n<ng-content />\n<ga-field-callout />\n" }]
965
1151
  }] });
966
1152
 
967
1153
  let nextUniqueId$5 = 0;
@@ -1361,11 +1547,11 @@ class GaFieldLabelComponent {
1361
1547
  definition = input(null);
1362
1548
  state = input();
1363
1549
  controlId = computed(() => {
1364
- return this.for() ?? this.formField.formControl()?._formControlId();
1550
+ return this.for() ?? this.formField.implicitFormControl()?._formControlId();
1365
1551
  });
1366
1552
  disabled = computed(() => {
1367
1553
  return (this.formField.disabled() ??
1368
- !!this.formField.formControl()?._formControlDisabled());
1554
+ !!this.formField.implicitFormControl()?._formControlDisabled());
1369
1555
  });
1370
1556
  controlElement = computed(() => {
1371
1557
  const control = this.document.querySelector(`#${this.controlId()}`);
@@ -1383,27 +1569,11 @@ class GaFieldLabelComponent {
1383
1569
  }
1384
1570
  }
1385
1571
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaFieldLabelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1386
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: GaFieldLabelComponent, isStandalone: true, selector: "ga-label", inputs: { for: { classPropertyName: "for", publicName: "for", isSignal: true, isRequired: false, transformFunction: null }, definition: { classPropertyName: "definition", publicName: "definition", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\n<label\n [attr.id]=\"uniqueId\"\n [attr.for]=\"controlId()\"\n class=\"ga-form-field__label\"\n [class.ga-form-field__label--defined]=\"!!definition()\"\n [class.ga-form-field__label--disabled]=\"\n !!formField.formControl()?._formControlDisabled()\n \"\n (click)=\"focusControl()\"\n [attr.tabindex]=\"definition() ? 0 : -1\"\n>\n <span\n class=\"ga-form-field__label-text\"\n [gaTooltip]=\"definition()\"\n gaTooltipPlacement=\"top-start\"\n ><ng-content\n /></span>\n @if (state()) {\n <span class=\"ga-form-field__label-state\">{{ state() }}</span>\n }\n</label>\n", dependencies: [{ kind: "ngmodule", type: GaTooltipModule }, { kind: "directive", type: GaTooltipDirective, selector: "[gaTooltip]", inputs: ["gaTooltip", "gaTooltipDisabled", "gaTooltipControlMode", "gaTooltipShowControlMode", "gaTooltipHideControlMode", "gaTooltipOffsetSize", "gaTooltipPlacement"], exportAs: ["gaTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1572
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: GaFieldLabelComponent, isStandalone: true, selector: "ga-label", inputs: { for: { classPropertyName: "for", publicName: "for", isSignal: true, isRequired: false, transformFunction: null }, definition: { classPropertyName: "definition", publicName: "definition", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\n<label\n [attr.id]=\"uniqueId\"\n [attr.for]=\"controlId()\"\n class=\"ga-form-field__label\"\n [class.ga-form-field__label--defined]=\"!!definition()\"\n [class.ga-form-field__label--disabled]=\"disabled()\"\n (click)=\"focusControl()\"\n [attr.tabindex]=\"definition() ? 0 : -1\"\n>\n <span\n class=\"ga-form-field__label-text\"\n [gaTooltip]=\"definition()\"\n gaTooltipPlacement=\"top-start\"\n ><ng-content\n /></span>\n @if (state()) {\n <span class=\"ga-form-field__label-state\">{{ state() }}</span>\n }\n</label>\n", dependencies: [{ kind: "ngmodule", type: GaTooltipModule }, { kind: "directive", type: GaTooltipDirective, selector: "[gaTooltip]", inputs: ["gaTooltip", "gaTooltipDisabled", "gaTooltipControlMode", "gaTooltipShowControlMode", "gaTooltipHideControlMode", "gaTooltipOffsetSize", "gaTooltipPlacement"], exportAs: ["gaTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1387
1573
  }
1388
1574
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaFieldLabelComponent, decorators: [{
1389
1575
  type: Component,
1390
- args: [{ selector: 'ga-label', imports: [GaTooltipModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\n<label\n [attr.id]=\"uniqueId\"\n [attr.for]=\"controlId()\"\n class=\"ga-form-field__label\"\n [class.ga-form-field__label--defined]=\"!!definition()\"\n [class.ga-form-field__label--disabled]=\"\n !!formField.formControl()?._formControlDisabled()\n \"\n (click)=\"focusControl()\"\n [attr.tabindex]=\"definition() ? 0 : -1\"\n>\n <span\n class=\"ga-form-field__label-text\"\n [gaTooltip]=\"definition()\"\n gaTooltipPlacement=\"top-start\"\n ><ng-content\n /></span>\n @if (state()) {\n <span class=\"ga-form-field__label-state\">{{ state() }}</span>\n }\n</label>\n" }]
1391
- }] });
1392
-
1393
- class GaFieldInfoComponent {
1394
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaFieldInfoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1395
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.4", type: GaFieldInfoComponent, isStandalone: true, selector: "ga-info", host: { classAttribute: "ga-form-field__info" }, ngImport: i0, template: `<ng-content />`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
1396
- }
1397
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaFieldInfoComponent, decorators: [{
1398
- type: Component,
1399
- args: [{
1400
- selector: 'ga-info',
1401
- template: `<ng-content />`,
1402
- changeDetection: ChangeDetectionStrategy.OnPush,
1403
- host: {
1404
- class: 'ga-form-field__info',
1405
- },
1406
- }]
1576
+ args: [{ selector: 'ga-label', imports: [GaTooltipModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\n<label\n [attr.id]=\"uniqueId\"\n [attr.for]=\"controlId()\"\n class=\"ga-form-field__label\"\n [class.ga-form-field__label--defined]=\"!!definition()\"\n [class.ga-form-field__label--disabled]=\"disabled()\"\n (click)=\"focusControl()\"\n [attr.tabindex]=\"definition() ? 0 : -1\"\n>\n <span\n class=\"ga-form-field__label-text\"\n [gaTooltip]=\"definition()\"\n gaTooltipPlacement=\"top-start\"\n ><ng-content\n /></span>\n @if (state()) {\n <span class=\"ga-form-field__label-state\">{{ state() }}</span>\n }\n</label>\n" }]
1407
1577
  }] });
1408
1578
 
1409
1579
  class GaLabelledByFormFieldDirective {
@@ -1437,11 +1607,15 @@ class GaFormFieldModule {
1437
1607
  static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.4", ngImport: i0, type: GaFormFieldModule, imports: [GaFormFieldComponent,
1438
1608
  GaFieldLabelComponent,
1439
1609
  GaFieldInfoComponent,
1610
+ GaFieldErrorDirective,
1611
+ GaFormControlErrorsDirective,
1440
1612
  GaFormControlDirective], exports: [GaFormFieldComponent,
1441
1613
  GaFieldLabelComponent,
1442
1614
  GaFieldInfoComponent,
1615
+ GaFieldErrorDirective,
1616
+ GaFormControlErrorsDirective,
1443
1617
  GaFormControlDirective] });
1444
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaFormFieldModule });
1618
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaFormFieldModule, imports: [GaFormFieldComponent] });
1445
1619
  }
1446
1620
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaFormFieldModule, decorators: [{
1447
1621
  type: NgModule,
@@ -1450,12 +1624,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
1450
1624
  GaFormFieldComponent,
1451
1625
  GaFieldLabelComponent,
1452
1626
  GaFieldInfoComponent,
1627
+ GaFieldErrorDirective,
1628
+ GaFormControlErrorsDirective,
1453
1629
  GaFormControlDirective,
1454
1630
  ],
1455
1631
  exports: [
1456
1632
  GaFormFieldComponent,
1457
1633
  GaFieldLabelComponent,
1458
1634
  GaFieldInfoComponent,
1635
+ GaFieldErrorDirective,
1636
+ GaFormControlErrorsDirective,
1459
1637
  GaFormControlDirective,
1460
1638
  ],
1461
1639
  }]
@@ -2285,6 +2463,7 @@ class GaRadioButtonComponent {
2285
2463
  tabindex = inject(new HostAttributeToken('tabindex'), {
2286
2464
  optional: true,
2287
2465
  });
2466
+ implicitNgControlState = injectNgControlState();
2288
2467
  _uniqueId = `ga-radio-button-${++nextUniqueId$3}`;
2289
2468
  /** The value attribute of the native input element */
2290
2469
  value = input(null);
@@ -2318,6 +2497,12 @@ class GaRadioButtonComponent {
2318
2497
  id = computed(() => this.inputId() ?? this._uniqueId);
2319
2498
  name = computed(() => this.radioGroup?.name() ?? this.inputName() ?? this._uniqueId);
2320
2499
  disabled = computed(() => this.radioGroup?.disabledModel() || this.inputDisabled());
2500
+ /** @ignore */
2501
+ invalid = computed(() => {
2502
+ return this.ariaInvalid()
2503
+ ? this.ariaInvalid() === 'true'
2504
+ : this.implicitNgControlState.inError();
2505
+ });
2321
2506
  checked = computed(() => this.radioGroup?.valueModel() === this.value() || this.inputChecked());
2322
2507
  onInputChange(event) {
2323
2508
  // We always have to stop propagation on the change event.
@@ -2334,13 +2519,13 @@ class GaRadioButtonComponent {
2334
2519
  this.radioGroup?.onBlur();
2335
2520
  }
2336
2521
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaRadioButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2337
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.4", type: GaRadioButtonComponent, isStandalone: true, selector: "ga-radio-button", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, inputName: { classPropertyName: "inputName", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, inputChecked: { classPropertyName: "inputChecked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, inputDisabled: { classPropertyName: "inputDisabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedby: { classPropertyName: "ariaDescribedby", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, ariaInvalid: { classPropertyName: "ariaInvalid", publicName: "aria-invalid", isSignal: true, isRequired: false, transformFunction: null }, ariaErrormessage: { classPropertyName: "ariaErrormessage", publicName: "aria-errormessage", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { change: "change" }, host: { properties: { "class.ga-radio-button--invalid": "ariaInvalid()", "attr.id": "null", "attr.tabindex": "null", "attr.aria-label": "null", "attr.aria-labelledby": "null", "attr.aria-describedby": "null" }, classAttribute: "ga-radio-button" }, ngImport: i0, template: "<input\n type=\"radio\"\n class=\"ga-radio-button__native\"\n [attr.id]=\"id()\"\n [name]=\"name()\"\n [checked]=\"checked()\"\n [disabled]=\"disabled()\"\n [attr.tabindex]=\"tabindex\"\n [attr.value]=\"value()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby()\"\n [attr.aria-describedby]=\"ariaDescribedby()\"\n [attr.aria-invalid]=\"ariaInvalid()\"\n [attr.aria-errormessage]=\"ariaErrormessage()\"\n (change)=\"onInputChange($event)\"\n (blur)=\"onBlur()\"\n/>\n\n<div class=\"ga-radio-button__marker\"></div>\n<label class=\"ga-radio-button__label\" [attr.for]=\"id()\"\n ><ng-content></ng-content\n></label>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
2522
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.4", type: GaRadioButtonComponent, isStandalone: true, selector: "ga-radio-button", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, inputName: { classPropertyName: "inputName", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, inputChecked: { classPropertyName: "inputChecked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, inputDisabled: { classPropertyName: "inputDisabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledby: { classPropertyName: "ariaLabelledby", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, ariaDescribedby: { classPropertyName: "ariaDescribedby", publicName: "aria-describedby", isSignal: true, isRequired: false, transformFunction: null }, ariaInvalid: { classPropertyName: "ariaInvalid", publicName: "aria-invalid", isSignal: true, isRequired: false, transformFunction: null }, ariaErrormessage: { classPropertyName: "ariaErrormessage", publicName: "aria-errormessage", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { change: "change" }, host: { properties: { "class.ga-radio-button--invalid": "invalid()", "attr.id": "null", "attr.tabindex": "null", "attr.aria-label": "null", "attr.aria-labelledby": "null", "attr.aria-describedby": "null" }, classAttribute: "ga-radio-button" }, ngImport: i0, template: "<input\n type=\"radio\"\n class=\"ga-radio-button__native\"\n [attr.id]=\"id()\"\n [name]=\"name()\"\n [checked]=\"checked()\"\n [disabled]=\"disabled()\"\n [attr.tabindex]=\"tabindex\"\n [attr.value]=\"value()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"ariaLabelledby()\"\n [attr.aria-describedby]=\"ariaDescribedby()\"\n [attr.aria-invalid]=\"ariaInvalid()\"\n [attr.aria-errormessage]=\"ariaErrormessage()\"\n (change)=\"onInputChange($event)\"\n (blur)=\"onBlur()\"\n/>\n\n<div class=\"ga-radio-button__marker\"></div>\n<label class=\"ga-radio-button__label\" [attr.for]=\"id()\"\n ><ng-content></ng-content\n></label>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
2338
2523
  }
2339
2524
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaRadioButtonComponent, decorators: [{
2340
2525
  type: Component,
2341
2526
  args: [{ selector: 'ga-radio-button', changeDetection: ChangeDetectionStrategy.OnPush, host: {
2342
2527
  class: 'ga-radio-button',
2343
- '[class.ga-radio-button--invalid]': 'ariaInvalid()',
2528
+ '[class.ga-radio-button--invalid]': 'invalid()',
2344
2529
  '[attr.id]': 'null',
2345
2530
  '[attr.tabindex]': 'null',
2346
2531
  '[attr.aria-label]': 'null',
@@ -2466,10 +2651,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
2466
2651
  }, template: "@if (selectComponent.multiple()) {\n @for (option of selectComponent.selectedOptions(); track option) {\n <div\n class=\"ga-tag\"\n [class.ga-tag--interactive-selected]=\"!selectComponent.disabled()\"\n [class.ga-tag--interactive-selected-disabled]=\"selectComponent.disabled()\"\n >\n <span class=\"ga-tag__label\">{{ option.cdkOption.getLabel() }}</span>\n @if (!selectComponent.disabled()) {\n <div class=\"ga-tag__separator\"></div>\n <ga-icon\n [icon]=\"icons.X\"\n size=\"16\"\n class=\"ga-tag__icon\"\n (click)=\"deselectOption(option); $event.stopPropagation()\"\n />\n }\n </div>\n }\n} @else {\n {{ singleViewValue() }}\n}\n" }]
2467
2652
  }] });
2468
2653
 
2654
+ function GA_SELECT_I18N_FACTORY() {
2655
+ return new GaSelectI18nDefault();
2656
+ }
2657
+ class GaSelectI18n {
2658
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaSelectI18n, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2659
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaSelectI18n, providedIn: 'root', useFactory: GA_SELECT_I18N_FACTORY });
2660
+ }
2661
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaSelectI18n, decorators: [{
2662
+ type: Injectable,
2663
+ args: [{
2664
+ providedIn: 'root',
2665
+ useFactory: GA_SELECT_I18N_FACTORY,
2666
+ }]
2667
+ }] });
2668
+ class GaSelectI18nDefault extends GaSelectI18n {
2669
+ /** A label for the clear button */
2670
+ clearLabel = 'Clear';
2671
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaSelectI18nDefault, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
2672
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaSelectI18nDefault });
2673
+ }
2674
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaSelectI18nDefault, decorators: [{
2675
+ type: Injectable
2676
+ }] });
2677
+ function provideGaSelectI18n(value) {
2678
+ return makeEnvironmentProviders([
2679
+ typeof value === 'function'
2680
+ ? { provide: GaSelectI18n, useFactory: value }
2681
+ : { provide: GaSelectI18n, useValue: value },
2682
+ ]);
2683
+ }
2684
+
2469
2685
  let nextUniqueId$2 = 0;
2470
2686
  class GaSelectComponent {
2471
2687
  _uniqueId = `ga-select-${++nextUniqueId$2}`;
2472
- focusedTriggerElement = null;
2688
+ icons = { CircleX };
2473
2689
  _onTouched;
2474
2690
  _onModelChanged;
2475
2691
  positions = [
@@ -2504,10 +2720,12 @@ class GaSelectComponent {
2504
2720
  ];
2505
2721
  injector = inject(Injector);
2506
2722
  elementRef = inject((ElementRef));
2723
+ i18n = inject(GaSelectI18n);
2507
2724
  overlayOrigin = inject(CdkOverlayOrigin);
2508
2725
  repositionScrollStrategy = createRepositionScrollStrategy(this.injector);
2509
- implicitInvalid = signal(false);
2726
+ implicitNgControlState = injectNgControlState();
2510
2727
  _isOpen = signal(false);
2728
+ shouldRecoverFocus = false;
2511
2729
  value = model(null);
2512
2730
  placeholder = input('');
2513
2731
  disabledInput = input(false, {
@@ -2521,6 +2739,8 @@ class GaSelectComponent {
2521
2739
  multiple = input(false, { transform: booleanAttribute });
2522
2740
  compareWith = input();
2523
2741
  searchable = input(false, { transform: booleanAttribute });
2742
+ clearable = input(false, { transform: booleanAttribute });
2743
+ clearableLabel = input();
2524
2744
  canSelectNullable = input(false, {
2525
2745
  transform: booleanAttribute,
2526
2746
  });
@@ -2554,10 +2774,17 @@ class GaSelectComponent {
2554
2774
  return activeOption?.cdkOption.id;
2555
2775
  });
2556
2776
  hasValue = computed(() => {
2557
- return this.gaOptions().some((option) => option.selected());
2777
+ if (!this.customSelectValue()) {
2778
+ // When no custom value component exists, we determine if there's a value
2779
+ // by checking selected options (which provide the display labels).
2780
+ return this.gaOptions().some((option) => option.selected());
2781
+ }
2782
+ // With a custom value component, we can check the value directly
2783
+ // which is useful for asynchronous selects, e.g. to display selected value without options
2784
+ return this.value() !== null || this.canSelectNullable();
2558
2785
  });
2559
2786
  invalid = computed(() => {
2560
- return this.invalidInput() ?? this.implicitInvalid();
2787
+ return this.invalidInput() ?? this.implicitNgControlState.inError();
2561
2788
  });
2562
2789
  _formControlId = computed(() => {
2563
2790
  // NOTE: The custom select cannot be connected to the label through `for` and `id` attributes,
@@ -2593,15 +2820,6 @@ class GaSelectComponent {
2593
2820
  this.autoClose();
2594
2821
  });
2595
2822
  }
2596
- ngDoCheck() {
2597
- const implicitNgControl = this.injector.get(NgControl, null, {
2598
- self: true,
2599
- });
2600
- // we can rely on computed because `ivalid` of NgControl is not a signal, yet
2601
- if (implicitNgControl) {
2602
- this.implicitInvalid.set(!!implicitNgControl.invalid && !!implicitNgControl.dirty);
2603
- }
2604
- }
2605
2823
  writeValue(value) {
2606
2824
  this.value.set(value);
2607
2825
  }
@@ -2637,6 +2855,7 @@ class GaSelectComponent {
2637
2855
  autoClose() {
2638
2856
  // close that was initiated by clicking the option
2639
2857
  if (!this.multiple()) {
2858
+ this.shouldRecoverFocus = true;
2640
2859
  this.close();
2641
2860
  }
2642
2861
  }
@@ -2665,6 +2884,19 @@ class GaSelectComponent {
2665
2884
  this.syncValue();
2666
2885
  }
2667
2886
  }
2887
+ onOverlayKeydown(event) {
2888
+ if (event.code === 'Escape') {
2889
+ this.shouldRecoverFocus = true;
2890
+ }
2891
+ }
2892
+ clearValue() {
2893
+ if (!this.clearable() || !this.searchable()) {
2894
+ return;
2895
+ }
2896
+ this.value.set(null);
2897
+ this._onModelChanged?.(null);
2898
+ this.autoClose();
2899
+ }
2668
2900
  onInputKeyDown(event) {
2669
2901
  switch (event.code) {
2670
2902
  case 'ArrowDown':
@@ -2686,11 +2918,17 @@ class GaSelectComponent {
2686
2918
  event.preventDefault();
2687
2919
  event.stopPropagation();
2688
2920
  break;
2921
+ case 'Backspace':
2922
+ if (this.textValue() === '') {
2923
+ this.clearValue();
2924
+ }
2925
+ event.stopPropagation();
2926
+ break;
2689
2927
  }
2690
2928
  }
2691
2929
  onOverlayAttach() {
2930
+ this.shouldRecoverFocus = false;
2692
2931
  this._isOpen.set(true);
2693
- this.focusedTriggerElement = document.activeElement;
2694
2932
  if (this.searchable()) {
2695
2933
  this.inputSearch().nativeElement.focus();
2696
2934
  }
@@ -2701,10 +2939,8 @@ class GaSelectComponent {
2701
2939
  }
2702
2940
  onOverlayDetach() {
2703
2941
  this._isOpen.set(false);
2704
- if (this.inputSearch()?.nativeElement !== this.focusedTriggerElement) {
2705
- this.focusedTriggerElement?.focus();
2706
- }
2707
- else if (this.searchable()) {
2942
+ if (this.inputSearch()?.nativeElement === document.activeElement ||
2943
+ this.shouldRecoverFocus) {
2708
2944
  this.elementRef.nativeElement.focus();
2709
2945
  }
2710
2946
  this.textValue.set('');
@@ -2744,7 +2980,7 @@ class GaSelectComponent {
2744
2980
  }
2745
2981
  }
2746
2982
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2747
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: GaSelectComponent, isStandalone: true, selector: "ga-select", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalidInput: { classPropertyName: "invalidInput", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, canSelectNullable: { classPropertyName: "canSelectNullable", publicName: "canSelectNullable", isSignal: true, isRequired: false, transformFunction: null }, textValue: { classPropertyName: "textValue", publicName: "textValue", isSignal: true, isRequired: false, transformFunction: null }, leftIcon: { classPropertyName: "leftIcon", publicName: "leftIcon", isSignal: true, isRequired: false, transformFunction: null }, idInput: { classPropertyName: "idInput", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", textValue: "textValueChange", opened: "opened", closed: "closed" }, host: { attributes: { "role": "combobox", "aria-haspopup": "listbox" }, listeners: { "click": "toggle()", "keydown.arrowdown": "open(); $event.preventDefault()", "keydown.space": "open(); $event.preventDefault()", "keydown.enter": "open(); $event.preventDefault()" }, properties: { "attr.id": "id()", "class.ga-select--multi": "multiple()", "class.ga-select--expanded": "isOpen()", "class.ga-select--disabled": "disabled()", "class.ga-select--invalid": "invalid()", "class.ga-select--empty": "!hasValue()", "attr.aria-expanded": "isOpen()", "attr.aria-controls": "cdkListbox().id", "attr.aria-invalid": "invalid()", "attr.aria-disabled": "disabled()", "attr.aria-owns": "searchable() ? cdkListbox().id : null", "attr.aria-activedescendant": "!searchable() ? activeDescendantId() : null", "attr.tabindex": "disabled() ? -1 : 0" }, classAttribute: "ga-select" }, providers: [
2983
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: GaSelectComponent, isStandalone: true, selector: "ga-select", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalidInput: { classPropertyName: "invalidInput", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, clearableLabel: { classPropertyName: "clearableLabel", publicName: "clearableLabel", isSignal: true, isRequired: false, transformFunction: null }, canSelectNullable: { classPropertyName: "canSelectNullable", publicName: "canSelectNullable", isSignal: true, isRequired: false, transformFunction: null }, textValue: { classPropertyName: "textValue", publicName: "textValue", isSignal: true, isRequired: false, transformFunction: null }, leftIcon: { classPropertyName: "leftIcon", publicName: "leftIcon", isSignal: true, isRequired: false, transformFunction: null }, idInput: { classPropertyName: "idInput", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", textValue: "textValueChange", opened: "opened", closed: "closed" }, host: { attributes: { "role": "combobox", "aria-haspopup": "listbox" }, listeners: { "click": "toggle()", "keydown.arrowdown": "open(); $event.preventDefault()", "keydown.space": "open(); $event.preventDefault()", "keydown.enter": "open(); $event.preventDefault()", "keydown.backspace": "clearValue(); $event.preventDefault()" }, properties: { "attr.id": "id()", "class.ga-select--multi": "multiple()", "class.ga-select--expanded": "isOpen()", "class.ga-select--disabled": "disabled()", "class.ga-select--invalid": "invalid()", "class.ga-select--empty": "!hasValue()", "attr.aria-expanded": "isOpen()", "attr.aria-controls": "cdkListbox().id", "attr.aria-invalid": "invalid()", "attr.aria-disabled": "disabled()", "attr.aria-owns": "searchable() ? cdkListbox().id : null", "attr.aria-activedescendant": "!searchable() ? activeDescendantId() : null", "attr.tabindex": "disabled() ? -1 : 0" }, classAttribute: "ga-select" }, providers: [
2748
2984
  {
2749
2985
  provide: NG_VALUE_ACCESSOR,
2750
2986
  useExisting: forwardRef(() => GaSelectComponent),
@@ -2754,7 +2990,7 @@ class GaSelectComponent {
2754
2990
  provide: GA_FORM_CONTROL,
2755
2991
  useExisting: forwardRef(() => GaSelectComponent),
2756
2992
  },
2757
- ], queries: [{ propertyName: "gaOptions", predicate: GaOptionComponent, descendants: true, read: GaOptionComponent, isSignal: true }, { propertyName: "cdkListbox", first: true, predicate: CdkListbox, descendants: true, isSignal: true }, { propertyName: "customSelectValue", first: true, predicate: GaSelectValueComponent, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "inputSearch", first: true, predicate: ["inputSearch"], descendants: true, isSignal: true }, { propertyName: "content", first: true, predicate: ["ngContent"], descendants: true, read: ElementRef, isSignal: true }], hostDirectives: [{ directive: i1$5.CdkOverlayOrigin }, { directive: GaLabelledByFormFieldDirective, inputs: ["aria-labelledby", "aria-labelledby"] }], ngImport: i0, template: "@if (leftIcon()) {\n <ga-icon [icon]=\"leftIcon()!\" />\n}\n\n<div class=\"ga-select__main-area\">\n @if (hasValue() && (!textValue() || multiple())) {\n @if (customSelectValue()) {\n <div class=\"ga-select__value\">\n <ng-content select=\"ga-select-value\" />\n </div>\n } @else {\n <ga-select-default-value />\n }\n } @else if (!searchable()) {\n <div class=\"ga-select__placeholder\">\n {{ placeholder() }}\n </div>\n }\n\n @if (searchable()) {\n <input\n #inputSearch\n type=\"text\"\n class=\"ga-select__input\"\n aria-autocomplete=\"list\"\n [value]=\"textValue()\"\n (input)=\"open(); textValue.set(inputSearch.value)\"\n (click)=\"open(); $event.stopPropagation()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"cdkListbox().id\"\n [attr.aria-activedescendant]=\"activeDescendantId()\"\n [placeholder]=\"hasValue() ? '' : placeholder()\"\n (keydown)=\"onInputKeyDown($event)\"\n tabindex=\"-1\"\n />\n }\n</div>\n\n<div class=\"ga-select__suffix\">\n <ga-icon [icon]=\"menuStatusIcon()\" class=\"ga-select__action-icon\" />\n</div>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayLockPosition\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayScrollStrategy]=\"repositionScrollStrategy\"\n (overlayOutsideClick)=\"close()\"\n (attach)=\"onOverlayAttach()\"\n (detach)=\"onOverlayDetach()\"\n>\n <ng-content select=\"ga-select-dropdown\" />\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: GaIconModule }, { kind: "component", type: GaIconComponent, selector: "ga-icon", inputs: ["icon", "size", "color", "strokeWidth"] }, { kind: "ngmodule", type: GaButtonModule }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$5.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "component", type: GaSelectDefaultValueComponent, selector: "ga-select-default-value" }] });
2993
+ ], queries: [{ propertyName: "gaOptions", predicate: GaOptionComponent, descendants: true, read: GaOptionComponent, isSignal: true }, { propertyName: "cdkListbox", first: true, predicate: CdkListbox, descendants: true, isSignal: true }, { propertyName: "customSelectValue", first: true, predicate: GaSelectValueComponent, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "inputSearch", first: true, predicate: ["inputSearch"], descendants: true, isSignal: true }, { propertyName: "content", first: true, predicate: ["ngContent"], descendants: true, read: ElementRef, isSignal: true }], hostDirectives: [{ directive: i1$5.CdkOverlayOrigin }, { directive: GaLabelledByFormFieldDirective, inputs: ["aria-labelledby", "aria-labelledby"] }], ngImport: i0, template: "@if (leftIcon()) {\n <ga-icon [icon]=\"leftIcon()!\" />\n}\n\n<div class=\"ga-select__main-area\">\n @if (hasValue() && (!textValue() || multiple())) {\n @if (customSelectValue()) {\n <div class=\"ga-select__value\">\n <ng-content select=\"ga-select-value\" />\n </div>\n } @else {\n <ga-select-default-value />\n }\n } @else if (!searchable()) {\n <div class=\"ga-select__placeholder\">\n {{ placeholder() }}\n </div>\n }\n\n @if (searchable()) {\n <input\n #inputSearch\n type=\"text\"\n class=\"ga-select__input\"\n aria-autocomplete=\"list\"\n [value]=\"textValue()\"\n (input)=\"open(); textValue.set(inputSearch.value)\"\n (click)=\"open(); $event.stopPropagation()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"cdkListbox().id\"\n [attr.aria-activedescendant]=\"activeDescendantId()\"\n [placeholder]=\"hasValue() ? '' : placeholder()\"\n (keydown)=\"onInputKeyDown($event)\"\n tabindex=\"-1\"\n />\n }\n</div>\n\n<div class=\"ga-select__suffix\">\n @if (clearable() && hasValue()) {\n <button\n type=\"button\"\n tabindex=\"-1\"\n (click)=\"clearValue(); $event.stopPropagation()\"\n [attr.aria-label]=\"clearableLabel() ?? i18n.clearLabel\"\n style=\"font-size: 0\"\n >\n <ga-icon [icon]=\"icons.CircleX\" size=\"16\" />\n </button>\n }\n\n <ga-icon [icon]=\"menuStatusIcon()\" class=\"ga-select__action-icon\" />\n</div>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayLockPosition\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayScrollStrategy]=\"repositionScrollStrategy\"\n (overlayOutsideClick)=\"close()\"\n (attach)=\"onOverlayAttach()\"\n (detach)=\"onOverlayDetach()\"\n (overlayKeydown)=\"onOverlayKeydown($event)\"\n>\n <ng-content select=\"ga-select-dropdown\" />\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: GaIconModule }, { kind: "component", type: GaIconComponent, selector: "ga-icon", inputs: ["icon", "size", "color", "strokeWidth"] }, { kind: "ngmodule", type: GaButtonModule }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$5.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "component", type: GaSelectDefaultValueComponent, selector: "ga-select-default-value" }] });
2758
2994
  }
2759
2995
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaSelectComponent, decorators: [{
2760
2996
  type: Component,
@@ -2800,7 +3036,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
2800
3036
  '(keydown.arrowdown)': 'open(); $event.preventDefault()',
2801
3037
  '(keydown.space)': 'open(); $event.preventDefault()',
2802
3038
  '(keydown.enter)': 'open(); $event.preventDefault()',
2803
- }, template: "@if (leftIcon()) {\n <ga-icon [icon]=\"leftIcon()!\" />\n}\n\n<div class=\"ga-select__main-area\">\n @if (hasValue() && (!textValue() || multiple())) {\n @if (customSelectValue()) {\n <div class=\"ga-select__value\">\n <ng-content select=\"ga-select-value\" />\n </div>\n } @else {\n <ga-select-default-value />\n }\n } @else if (!searchable()) {\n <div class=\"ga-select__placeholder\">\n {{ placeholder() }}\n </div>\n }\n\n @if (searchable()) {\n <input\n #inputSearch\n type=\"text\"\n class=\"ga-select__input\"\n aria-autocomplete=\"list\"\n [value]=\"textValue()\"\n (input)=\"open(); textValue.set(inputSearch.value)\"\n (click)=\"open(); $event.stopPropagation()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"cdkListbox().id\"\n [attr.aria-activedescendant]=\"activeDescendantId()\"\n [placeholder]=\"hasValue() ? '' : placeholder()\"\n (keydown)=\"onInputKeyDown($event)\"\n tabindex=\"-1\"\n />\n }\n</div>\n\n<div class=\"ga-select__suffix\">\n <ga-icon [icon]=\"menuStatusIcon()\" class=\"ga-select__action-icon\" />\n</div>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayLockPosition\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayScrollStrategy]=\"repositionScrollStrategy\"\n (overlayOutsideClick)=\"close()\"\n (attach)=\"onOverlayAttach()\"\n (detach)=\"onOverlayDetach()\"\n>\n <ng-content select=\"ga-select-dropdown\" />\n</ng-template>\n" }]
3039
+ '(keydown.backspace)': 'clearValue(); $event.preventDefault()',
3040
+ }, template: "@if (leftIcon()) {\n <ga-icon [icon]=\"leftIcon()!\" />\n}\n\n<div class=\"ga-select__main-area\">\n @if (hasValue() && (!textValue() || multiple())) {\n @if (customSelectValue()) {\n <div class=\"ga-select__value\">\n <ng-content select=\"ga-select-value\" />\n </div>\n } @else {\n <ga-select-default-value />\n }\n } @else if (!searchable()) {\n <div class=\"ga-select__placeholder\">\n {{ placeholder() }}\n </div>\n }\n\n @if (searchable()) {\n <input\n #inputSearch\n type=\"text\"\n class=\"ga-select__input\"\n aria-autocomplete=\"list\"\n [value]=\"textValue()\"\n (input)=\"open(); textValue.set(inputSearch.value)\"\n (click)=\"open(); $event.stopPropagation()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"cdkListbox().id\"\n [attr.aria-activedescendant]=\"activeDescendantId()\"\n [placeholder]=\"hasValue() ? '' : placeholder()\"\n (keydown)=\"onInputKeyDown($event)\"\n tabindex=\"-1\"\n />\n }\n</div>\n\n<div class=\"ga-select__suffix\">\n @if (clearable() && hasValue()) {\n <button\n type=\"button\"\n tabindex=\"-1\"\n (click)=\"clearValue(); $event.stopPropagation()\"\n [attr.aria-label]=\"clearableLabel() ?? i18n.clearLabel\"\n style=\"font-size: 0\"\n >\n <ga-icon [icon]=\"icons.CircleX\" size=\"16\" />\n </button>\n }\n\n <ga-icon [icon]=\"menuStatusIcon()\" class=\"ga-select__action-icon\" />\n</div>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayLockPosition\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayPositions]=\"positions\"\n [cdkConnectedOverlayScrollStrategy]=\"repositionScrollStrategy\"\n (overlayOutsideClick)=\"close()\"\n (attach)=\"onOverlayAttach()\"\n (detach)=\"onOverlayDetach()\"\n (overlayKeydown)=\"onOverlayKeydown($event)\"\n>\n <ng-content select=\"ga-select-dropdown\" />\n</ng-template>\n" }]
2804
3041
  }], ctorParameters: () => [] });
2805
3042
 
2806
3043
  class GaOptgroupComponent {
@@ -2940,8 +3177,9 @@ let nextUniqueId$1 = 0;
2940
3177
  class GaSwitchComponent {
2941
3178
  icons = { Check };
2942
3179
  /** @ignore */
3180
+ implicitNgControlState = injectNgControlState();
3181
+ /** @ignore */
2943
3182
  _uniqueId = `ga-switch-${++nextUniqueId$1}`;
2944
- injector = inject(Injector);
2945
3183
  /** @ignore */
2946
3184
  tabindex = input(0, {
2947
3185
  alias: 'tabindex',
@@ -2950,19 +3188,13 @@ class GaSwitchComponent {
2950
3188
  _onTouched;
2951
3189
  /** @ignore */
2952
3190
  _onModelChanged;
2953
- /** @ignore */
2954
- _invalidNgModel = signal(false);
2955
- _ngModelName = signal(null);
2956
3191
  checked = input(false, {
2957
3192
  transform: booleanAttribute,
2958
3193
  });
2959
3194
  disabled = input(false, {
2960
3195
  transform: booleanAttribute,
2961
3196
  });
2962
- ariaInvalid = input(false, {
2963
- transform: booleanAttribute,
2964
- alias: 'aria-invalid',
2965
- });
3197
+ ariaInvalid = input(null, { alias: 'aria-invalid' });
2966
3198
  label = input('');
2967
3199
  ariaLabel = input(null, { alias: 'aria-label' });
2968
3200
  ariaLabelledby = input(null, {
@@ -2983,23 +3215,14 @@ class GaSwitchComponent {
2983
3215
  inputId = computed(() => this.id() ?? this._uniqueId);
2984
3216
  /** @ignore */
2985
3217
  name = computed(() => {
2986
- return this.nameInput() ?? this._ngModelName() ?? this._uniqueId;
3218
+ return (this.nameInput() ?? this.implicitNgControlState.name() ?? this._uniqueId);
2987
3219
  });
2988
3220
  /** @ignore */
2989
3221
  invalidComputed = computed(() => {
2990
- return this.ariaInvalid() || this._invalidNgModel();
3222
+ return this.ariaInvalid()
3223
+ ? this.ariaInvalid() === 'true'
3224
+ : this.implicitNgControlState.inError();
2991
3225
  });
2992
- ngDoCheck() {
2993
- const implicitNgControl = this.injector.get(NgControl, null, {
2994
- self: true,
2995
- });
2996
- if (implicitNgControl) {
2997
- this._invalidNgModel.set(!!implicitNgControl.invalid && !!implicitNgControl.dirty);
2998
- if (implicitNgControl.name) {
2999
- this._ngModelName.set(implicitNgControl.name);
3000
- }
3001
- }
3002
- }
3003
3226
  /** @ignore */
3004
3227
  onInputChange(event) {
3005
3228
  const target = event.target;
@@ -3150,26 +3373,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
3150
3373
 
3151
3374
  let nextUniqueId = 0;
3152
3375
  class GaTextAreaDirective {
3376
+ implicitNgControlState = injectNgControlState();
3377
+ generatedUniqueId = `ga-text-area-${++nextUniqueId}`;
3153
3378
  id = input(undefined);
3154
- disabled = input(false, { transform: booleanAttribute });
3155
- invalid = input(undefined, { transform: booleanAttribute });
3156
- _formControlId = computed(() => this.uniqueId());
3157
- _formControlDisabled = computed(() => this.disabledModel());
3379
+ disabledInput = input(false, {
3380
+ alias: 'disabled',
3381
+ transform: booleanAttribute,
3382
+ });
3383
+ invalidInput = input(undefined, {
3384
+ alias: 'invalid',
3385
+ transform: booleanAttribute,
3386
+ });
3387
+ disabled = computed(() => this.disabledInput() ?? this.implicitNgControlState.disabled());
3388
+ invalid = computed(() => this.invalidInput() ?? this.implicitNgControlState.inError());
3158
3389
  uniqueId = computed(() => this.id() ?? this.generatedUniqueId);
3159
- invalidInput = computed(() => this.invalid() ?? this.implicitInvalid());
3160
- generatedUniqueId = `ga-text-area-${++nextUniqueId}`;
3161
- injector = inject(Injector);
3162
- implicitInvalid = signal(false);
3163
- disabledModel = linkedSignal(() => this.disabled());
3164
- ngDoCheck() {
3165
- const ngControl = this.injector.get(NgControl, null, { self: true });
3166
- if (ngControl) {
3167
- this.implicitInvalid.set(!!ngControl.invalid && !!ngControl.dirty);
3168
- this.disabledModel.set(!!ngControl.disabled);
3169
- }
3170
- }
3390
+ _formControlId = computed(() => this.uniqueId());
3391
+ _formControlDisabled = computed(() => this.disabled());
3171
3392
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaTextAreaDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
3172
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.4", type: GaTextAreaDirective, isStandalone: true, selector: "[gaTextArea]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.ga-text-area--invalid": "invalidInput()", "attr.id": "uniqueId()" }, classAttribute: "ga-text-area" }, ngImport: i0 });
3393
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.4", type: GaTextAreaDirective, isStandalone: true, selector: "[gaTextArea]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalidInput: { classPropertyName: "invalidInput", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.ga-text-area--invalid": "invalid()", "attr.id": "uniqueId()" }, classAttribute: "ga-text-area" }, ngImport: i0 });
3173
3394
  }
3174
3395
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GaTextAreaDirective, decorators: [{
3175
3396
  type: Directive,
@@ -3177,7 +3398,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
3177
3398
  selector: '[gaTextArea]',
3178
3399
  host: {
3179
3400
  class: 'ga-text-area',
3180
- '[class.ga-text-area--invalid]': 'invalidInput()',
3401
+ '[class.ga-text-area--invalid]': 'invalid()',
3181
3402
  '[attr.id]': 'uniqueId()',
3182
3403
  },
3183
3404
  }]
@@ -3204,5 +3425,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImpor
3204
3425
  * Generated bundle index. Do not edit.
3205
3426
  */
3206
3427
 
3207
- export { CHECKBOX_CONTROL_VALUE_ACCESSOR, DEFAULT_MODAL_OPTIONS, GA_ALERT_I18N_FACTORY, GA_BASE_FONT_SIZE, GA_BUTTON_I18N_FACTORY, GA_CHECKBOX_REQUIRED_VALIDATOR, GA_FORM_CONTROL, GA_ICON_DEFAULT_SIZE, GA_MODAL_DATA, GA_MODAL_I18N_FACTORY, GA_SELECT_REQUIRED_VALIDATOR, GA_TOOLTIP_DEFAULT_OFFSET, GaAlertComponent, GaAlertI18n, GaAlertI18nDefault, GaAlertModule, GaAlertTitleActionsComponent, GaAlertTitleComponent, GaBadgeComponent, GaBadgeModule, GaButtonDirective, GaButtonI18n, GaButtonI18nDefault, GaButtonModule, GaCardComponent, GaCardModule, GaCheckboxComponent, GaCheckboxModule, GaCheckboxRequiredValidator, GaFieldInfoComponent, GaFieldLabelComponent, GaFormControlDirective, GaFormFieldComponent, GaFormFieldModule, GaIconButtonDirective, GaIconComponent, GaIconModule, GaInputComponent, GaInputDirective, GaInputModule, GaLabelledByFormFieldDirective, GaLinkDirective, GaLinkModule, GaMenuComponent, GaMenuItemComponent, GaMenuModule, GaMenuSeparatorComponent, GaMenuTitleComponent, GaMenuTriggerDirective, GaMenuTriggerIconComponent, GaModalActionsComponent, GaModalCloseDirective, GaModalComponent, GaModalContentComponent, GaModalDescriptionComponent, GaModalDescriptionDirective, GaModalHeaderComponent, GaModalI18n, GaModalI18nDefault, GaModalLabelDirective, GaModalModule, GaModalOptions, GaModalRef, GaModalService, GaModalTitleDirective, GaOptgroupComponent, GaOptionComponent, GaRadioButtonComponent, GaRadioGroupComponent, GaRadioModule, GaSegmentedControlButtonDirective, GaSegmentedControlComponent, GaSegmentedControlIconButtonComponent, GaSegmentedControlModule, GaSegmentedControlTextButtonComponent, GaSelectComponent, GaSelectDropdownComponent, GaSelectDropdownSpinnerComponent, GaSelectModule, GaSelectRequiredValidator, GaSelectValueComponent, GaSpinnerComponent, GaSpinnerModule, GaSwitchComponent, GaSwitchModule, GaTextAreaDirective, GaTextAreaModule, GaTooltipComponent, GaTooltipDirective, GaTooltipModule, RADIO_CONTROL_VALUE_ACCESSOR, SWITCH_CONTROL_VALUE_ACCESSOR, provideGaAlertI18n, provideGaBaseFontSize, provideGaButtonI18n, provideGaModalI18n, provideGaModalOptions };
3428
+ export { CHECKBOX_CONTROL_VALUE_ACCESSOR, DEFAULT_MODAL_OPTIONS, GA_ALERT_I18N_FACTORY, GA_BASE_FONT_SIZE, GA_BUTTON_I18N_FACTORY, GA_CHECKBOX_REQUIRED_VALIDATOR, GA_FORM_CONTROL, GA_FORM_CONTROL_ADAPTER, GA_ICON_DEFAULT_SIZE, GA_MODAL_DATA, GA_MODAL_I18N_FACTORY, GA_SELECT_I18N_FACTORY, GA_SELECT_REQUIRED_VALIDATOR, GA_TOOLTIP_DEFAULT_OFFSET, GaAlertComponent, GaAlertI18n, GaAlertI18nDefault, GaAlertModule, GaAlertTitleActionsComponent, GaAlertTitleComponent, GaBadgeComponent, GaBadgeModule, GaButtonDirective, GaButtonI18n, GaButtonI18nDefault, GaButtonModule, GaCardComponent, GaCardModule, GaCheckboxComponent, GaCheckboxModule, GaCheckboxRequiredValidator, GaFieldErrorDirective, GaFieldInfoComponent, GaFieldLabelComponent, GaFormControlDirective, GaFormControlErrorsDirective, GaFormFieldComponent, GaFormFieldModule, GaIconButtonDirective, GaIconComponent, GaIconModule, GaInputComponent, GaInputDirective, GaInputModule, GaLabelledByFormFieldDirective, GaLinkDirective, GaLinkModule, GaMenuComponent, GaMenuItemComponent, GaMenuModule, GaMenuSeparatorComponent, GaMenuTitleComponent, GaMenuTriggerDirective, GaMenuTriggerIconComponent, GaModalActionsComponent, GaModalCloseDirective, GaModalComponent, GaModalContentComponent, GaModalDescriptionComponent, GaModalDescriptionDirective, GaModalHeaderComponent, GaModalI18n, GaModalI18nDefault, GaModalLabelDirective, GaModalModule, GaModalOptions, GaModalRef, GaModalService, GaModalTitleDirective, GaOptgroupComponent, GaOptionComponent, GaRadioButtonComponent, GaRadioGroupComponent, GaRadioModule, GaSegmentedControlButtonDirective, GaSegmentedControlComponent, GaSegmentedControlIconButtonComponent, GaSegmentedControlModule, GaSegmentedControlTextButtonComponent, GaSelectComponent, GaSelectDropdownComponent, GaSelectDropdownSpinnerComponent, GaSelectI18n, GaSelectI18nDefault, GaSelectModule, GaSelectRequiredValidator, GaSelectValueComponent, GaSpinnerComponent, GaSpinnerModule, GaSwitchComponent, GaSwitchModule, GaTextAreaDirective, GaTextAreaModule, GaTooltipComponent, GaTooltipDirective, GaTooltipModule, RADIO_CONTROL_VALUE_ACCESSOR, SWITCH_CONTROL_VALUE_ACCESSOR, injectNgControlState, provideGaAlertI18n, provideGaBaseFontSize, provideGaButtonI18n, provideGaModalI18n, provideGaModalOptions, provideGaSelectI18n };
3208
3429
  //# sourceMappingURL=vsn-ux-ngx-gaia.mjs.map