valtech-components 2.0.383 → 2.0.385

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.
@@ -19,7 +19,7 @@ import 'prismjs/components/prism-markup';
19
19
  import 'prismjs/components/prism-typescript';
20
20
  import * as i1$2 from '@angular/forms';
21
21
  import { ReactiveFormsModule, FormsModule, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
22
- import { map as map$1 } from 'rxjs/operators';
22
+ import { map as map$1, distinctUntilChanged as distinctUntilChanged$1 } from 'rxjs/operators';
23
23
  import * as i1$3 from 'ng-otp-input';
24
24
  import { NgOtpInputComponent, NgOtpInputModule } from 'ng-otp-input';
25
25
  import 'prismjs/components/prism-bash';
@@ -5689,6 +5689,12 @@ class MultiSelectSimpleComponent {
5689
5689
  this.filteredOptions = computed(() => {
5690
5690
  const options = this.props?.options || [];
5691
5691
  const search = this.searchTerm().toLowerCase();
5692
+ // Debug
5693
+ console.log('[MultiSelectSimple] filteredOptions computed:', {
5694
+ optionsCount: options.length,
5695
+ searchTerm: search,
5696
+ options: options.slice(0, 3) // Primeras 3 opciones
5697
+ });
5692
5698
  if (!search) {
5693
5699
  return options;
5694
5700
  }
@@ -5705,7 +5711,7 @@ class MultiSelectSimpleComponent {
5705
5711
  });
5706
5712
  this.searchPlaceholder = '';
5707
5713
  // ControlValueAccessor
5708
- this.onChange = (value) => { };
5714
+ this.onChange = (_value) => { };
5709
5715
  this.onTouched = () => { };
5710
5716
  this.placeholder = this.langService.getText('_global', 'selectOptions', 'Seleccione opciones');
5711
5717
  this.searchPlaceholder = this.langService.getText('_global', 'search', 'Buscar');
@@ -5719,6 +5725,11 @@ class MultiSelectSimpleComponent {
5719
5725
  ngOnDestroy() {
5720
5726
  document.removeEventListener('click', this.handleClickOutside.bind(this));
5721
5727
  }
5728
+ ngOnChanges(changes) {
5729
+ if (changes['props'] && this.props) {
5730
+ this.syncSelectedValues();
5731
+ }
5732
+ }
5722
5733
  // ControlValueAccessor implementation
5723
5734
  writeValue(value) {
5724
5735
  const valueArray = this.parseValue(value);
@@ -5730,7 +5741,7 @@ class MultiSelectSimpleComponent {
5730
5741
  registerOnTouched(fn) {
5731
5742
  this.onTouched = fn;
5732
5743
  }
5733
- setDisabledState(isDisabled) {
5744
+ setDisabledState(_isDisabled) {
5734
5745
  // Handle disabled state if needed
5735
5746
  }
5736
5747
  // Component methods
@@ -5779,7 +5790,7 @@ class MultiSelectSimpleComponent {
5779
5790
  isSelected(option) {
5780
5791
  return this.selectedValues().includes(option[this.valueProperty]);
5781
5792
  }
5782
- trackByFn(index, option) {
5793
+ trackByFn(_index, option) {
5783
5794
  return option[this.valueProperty];
5784
5795
  }
5785
5796
  handleClickOutside(event) {
@@ -5830,7 +5841,7 @@ class MultiSelectSimpleComponent {
5830
5841
  useExisting: forwardRef(() => MultiSelectSimpleComponent),
5831
5842
  multi: true
5832
5843
  }
5833
- ], viewQueries: [{ propertyName: "dropdownRef", first: true, predicate: ["dropdown"], descendants: true }, { propertyName: "mainInputRef", first: true, predicate: ["mainInput"], descendants: true }], ngImport: i0, template: `
5844
+ ], viewQueries: [{ propertyName: "dropdownRef", first: true, predicate: ["dropdown"], descendants: true }, { propertyName: "mainInputRef", first: true, predicate: ["mainInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
5834
5845
  <div class="multi-select-container" (click)="toggleDropdown($event)">
5835
5846
  <!-- Main input display -->
5836
5847
  <ion-input
@@ -6748,376 +6759,285 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
6748
6759
  type: Input
6749
6760
  }] } });
6750
6761
 
6751
- /**
6752
- * val-select-search
6753
- *
6754
- * A searchable select/dropdown input with modal and filtering, integrated with Angular forms.
6755
- *
6756
- * @example
6757
- * <val-select-search [props]="{ control: myControl, label: 'Choose', options: [{ id: '1', name: 'Option 1' }] }"></val-select-search>
6758
- *
6759
- * @input props: InputMetadata - Configuration for the select input (form control, label, options, etc.)
6760
- */
6761
6762
  class SelectSearchComponent {
6762
6763
  constructor() {
6763
6764
  this.labelProperty = 'name';
6764
6765
  this.valueProperty = 'id';
6765
- this.multiple = false;
6766
+ this.placeholder = '';
6766
6767
  this.langService = inject(LangService);
6767
- this.icon = inject(IconService);
6768
- this.changeDetector = inject(ChangeDetectorRef);
6769
- this.searchTerm = '';
6770
- this.filteredItems = [];
6771
- this.selectedItems = [];
6772
- this.displayValue = '';
6773
- this.previousOptions = [];
6774
- this.isProcessingChanges = false;
6775
- this.label = this.langService.getText('_global', 'select', 'Seleccionar');
6768
+ // Signals for reactive state management
6769
+ this.isOpen = signal(false);
6770
+ this.searchTerm = signal('');
6771
+ this.selectedValue = signal(null);
6772
+ // Computed signals
6773
+ this.displayValue = computed(() => {
6774
+ const value = this.selectedValue();
6775
+ if (!value)
6776
+ return '';
6777
+ const option = this.getOptionByValue(value);
6778
+ return option ? option[this.labelProperty] : '';
6779
+ });
6780
+ this.filteredOptions = computed(() => {
6781
+ const options = this.props?.options || [];
6782
+ const search = this.searchTerm().toLowerCase();
6783
+ // Debug
6784
+ console.log('[SelectSearch] filteredOptions computed:', {
6785
+ optionsCount: options.length,
6786
+ searchTerm: search,
6787
+ options: options.slice(0, 3) // Primeras 3 opciones
6788
+ });
6789
+ if (!search) {
6790
+ return options;
6791
+ }
6792
+ return options.filter(option => {
6793
+ const label = option[this.labelProperty]
6794
+ ? replaceSpecialChars(String(option[this.labelProperty]).toLowerCase())
6795
+ : '';
6796
+ const value = option[this.valueProperty]
6797
+ ? replaceSpecialChars(String(option[this.valueProperty]).toLowerCase())
6798
+ : '';
6799
+ const searchTerm = replaceSpecialChars(search);
6800
+ return label.includes(searchTerm) || value.includes(searchTerm);
6801
+ });
6802
+ });
6776
6803
  this.placeholder = this.langService.getText('_global', 'selectOption', 'Seleccione una opción');
6804
+ // Close dropdown when clicking outside
6805
+ document.addEventListener('click', this.handleClickOutside.bind(this));
6777
6806
  }
6778
6807
  ngOnInit() {
6779
6808
  this.applyDefaultValue();
6780
- this.initializeItems();
6781
- this.syncControlValueWithSelectedItems();
6782
- this.updateDisplayValue();
6783
- this.subscribeToValueChanges();
6809
+ this.syncSelectedValue();
6784
6810
  }
6785
6811
  ngOnDestroy() {
6786
- // Limpiar suscripciones para evitar memory leaks
6787
- if (this.valueChangesSubscription) {
6788
- this.valueChangesSubscription.unsubscribe();
6789
- }
6812
+ document.removeEventListener('click', this.handleClickOutside.bind(this));
6790
6813
  }
6791
6814
  ngOnChanges(changes) {
6792
- // Evitar bucles infinitos
6793
- if (this.isProcessingChanges) {
6794
- return;
6795
- }
6796
- // Cuando cambia props o props.options
6797
- if (changes['props']) {
6798
- try {
6799
- this.isProcessingChanges = true;
6800
- // Desuscribirse del antiguo control si existe
6801
- if (this.valueChangesSubscription) {
6802
- this.valueChangesSubscription.unsubscribe();
6803
- }
6804
- if (this.props?.options) {
6805
- // Verificar si las opciones han cambiado realmente
6806
- const optionsChanged = !this.areOptionsEqual(this.previousOptions, this.props.options);
6807
- if (optionsChanged) {
6808
- this.previousOptions = [...this.props.options];
6809
- this.initializeItems();
6810
- }
6811
- }
6812
- // Sincronizar con el nuevo control si existe
6813
- this.syncControlValueWithSelectedItems();
6814
- this.updateDisplayValue();
6815
- // Suscribirse al nuevo control
6816
- this.subscribeToValueChanges();
6817
- }
6818
- finally {
6819
- this.isProcessingChanges = false;
6820
- }
6821
- }
6822
- }
6823
- ionViewWillEnter() {
6824
- if (this.isProcessingChanges) {
6825
- return;
6826
- }
6827
- try {
6828
- this.isProcessingChanges = true;
6829
- this.initializeItems();
6830
- this.syncControlValueWithSelectedItems();
6831
- this.updateDisplayValue();
6832
- this.subscribeToValueChanges();
6833
- }
6834
- finally {
6835
- this.isProcessingChanges = false;
6836
- }
6837
- }
6838
- // Suscribirse a cambios en el FormControl
6839
- subscribeToValueChanges() {
6840
- if (!this.props?.control)
6841
- return;
6842
- this.valueChangesSubscription = this.props.control.valueChanges.subscribe(value => {
6843
- if (this.isProcessingChanges)
6844
- return;
6845
- try {
6846
- this.isProcessingChanges = true;
6847
- this.syncControlValueWithSelectedItems();
6848
- this.updateDisplayValue();
6849
- }
6850
- finally {
6851
- this.isProcessingChanges = false;
6852
- }
6853
- });
6854
- }
6855
- // Compara si dos arrays de opciones son iguales
6856
- areOptionsEqual(prevOptions, newOptions) {
6857
- // PERF: Use reference equality first for fast path
6858
- if (prevOptions === newOptions)
6859
- return true;
6860
- if (!prevOptions || !newOptions)
6861
- return prevOptions === newOptions;
6862
- if (prevOptions.length !== newOptions.length)
6863
- return false;
6864
- // Only compare valueProperty for equality
6865
- for (let i = 0; i < prevOptions.length; i++) {
6866
- if (prevOptions[i][this.valueProperty] !== newOptions[i][this.valueProperty]) {
6867
- return false;
6868
- }
6869
- }
6870
- return true;
6871
- }
6872
- initializeItems() {
6873
- // PERF: Avoid unnecessary array copies
6874
- this.filteredItems = this.props?.options || [];
6875
- }
6876
- syncControlValueWithSelectedItems() {
6877
- if (!this.props?.control) {
6878
- this.selectedItems = [];
6879
- return;
6880
- }
6881
- const controlValue = this.props.control.value;
6882
- if (controlValue === null || controlValue === undefined) {
6883
- this.selectedItems = [];
6884
- return;
6885
- }
6886
- // PERF: Use a Map for faster lookup if options are large
6887
- if (this.props.options && this.props.options.length > 0) {
6888
- const map = new Map(this.props.options.map(opt => [opt[this.valueProperty], opt]));
6889
- const selectedOption = map.get(controlValue);
6890
- this.selectedItems = selectedOption ? [selectedOption] : [];
6815
+ if (changes['props'] && this.props) {
6816
+ this.syncSelectedValue();
6891
6817
  }
6892
- else {
6893
- this.selectedItems = [];
6894
- }
6895
- }
6896
- applyDefaultValue() {
6897
- applyDefaultValueToControl(this.props);
6898
6818
  }
6899
- onFilter(event) {
6900
- // If no search term, show all options
6901
- if (!event || event.trim() === '') {
6902
- this.filteredItems = this.props?.options ? [...this.props.options] : [];
6903
- this.changeDetector.detectChanges();
6904
- return;
6905
- }
6906
- // If no options, nothing to filter
6907
- if (!this.props?.options || this.props.options.length === 0) {
6908
- this.filteredItems = [];
6909
- this.changeDetector.detectChanges();
6910
- return;
6819
+ // Component methods
6820
+ toggleDropdown(event) {
6821
+ event.stopPropagation();
6822
+ this.isOpen.update(value => !value);
6823
+ if (this.isOpen()) {
6824
+ // Focus search bar when opening if available
6825
+ setTimeout(() => {
6826
+ const searchbar = this.dropdownRef?.nativeElement?.querySelector('ion-searchbar');
6827
+ if (searchbar) {
6828
+ searchbar.setFocus();
6829
+ }
6830
+ }, 100);
6911
6831
  }
6912
- // PERF: Avoid repeated replaceSpecialChars and toLowerCase for each option
6913
- const search = replaceSpecialChars(event.toLowerCase());
6914
- this.filteredItems = this.props.options.filter(element => {
6915
- // Only use labelProperty and valueProperty for filtering (faster)
6916
- const label = element[this.labelProperty]
6917
- ? replaceSpecialChars(String(element[this.labelProperty]).toLowerCase())
6918
- : '';
6919
- const value = element[this.valueProperty]
6920
- ? replaceSpecialChars(String(element[this.valueProperty]).toLowerCase())
6921
- : '';
6922
- return label.includes(search) || value.includes(search);
6923
- });
6924
- this.changeDetector.detectChanges();
6925
6832
  }
6926
- onFocus() {
6927
- console.log('onFocus');
6928
- }
6929
- onBlur() {
6930
- console.log('onBlur');
6833
+ onSearch(event) {
6834
+ this.searchTerm.set(event.detail.value || '');
6931
6835
  }
6932
- openModal() {
6933
- if (this.modal) {
6934
- this.modal.present();
6836
+ selectOption(option) {
6837
+ const value = option[this.valueProperty];
6838
+ this.selectedValue.set(value);
6839
+ this.isOpen.set(false);
6840
+ this.searchTerm.set('');
6841
+ // Update form control
6842
+ if (this.props?.control) {
6843
+ this.props.control.setValue(value);
6844
+ this.props.control.markAsDirty();
6845
+ this.props.control.markAsTouched();
6935
6846
  }
6936
6847
  }
6937
- preventDefaultBehavior(event) {
6938
- event.preventDefault();
6939
- event.stopPropagation();
6940
- this.openModal();
6848
+ isSelected(option) {
6849
+ return this.selectedValue() === option[this.valueProperty];
6941
6850
  }
6942
- cancelModal() {
6943
- // Reset filter and show all options when closing modal
6944
- this.searchTerm = '';
6945
- this.filteredItems = this.props?.options ? [...this.props.options] : [];
6946
- this.changeDetector.detectChanges();
6947
- if (this.modal) {
6948
- this.modal.dismiss();
6949
- }
6851
+ trackByFn(_index, option) {
6852
+ return option[this.valueProperty];
6950
6853
  }
6951
- selectItem(item) {
6952
- if (this.multiple) {
6953
- const index = this.selectedItems.findIndex(selectedItem => selectedItem[this.valueProperty] === item[this.valueProperty]);
6954
- if (index === -1) {
6955
- this.selectedItems.push(item);
6956
- }
6957
- else {
6958
- this.selectedItems.splice(index, 1);
6959
- }
6960
- }
6961
- else {
6962
- this.selectedItems = [item];
6963
- this.cancelModal();
6854
+ handleClickOutside(event) {
6855
+ if (this.isOpen() &&
6856
+ !this.mainInputRef?.nativeElement?.contains(event.target) &&
6857
+ !this.dropdownRef?.nativeElement?.contains(event.target)) {
6858
+ this.isOpen.set(false);
6859
+ this.searchTerm.set('');
6964
6860
  }
6965
- this.updateDisplayValue();
6966
- this.applyChanges();
6967
6861
  }
6968
- isItemSelected(item) {
6969
- return this.selectedItems.some(selectedItem => selectedItem[this.valueProperty] === item[this.valueProperty]);
6970
- }
6971
- updateDisplayValue() {
6972
- if (this.selectedItems.length === 0) {
6973
- this.displayValue = '';
6974
- return;
6975
- }
6976
- if (this.multiple) {
6977
- if (this.selectedItems.length === 1) {
6978
- this.displayValue = this.selectedItems[0][this.labelProperty];
6979
- }
6980
- else {
6981
- this.displayValue = `${this.selectedItems.length} elementos seleccionados`;
6982
- }
6983
- }
6984
- else {
6985
- this.displayValue = this.selectedItems[0][this.labelProperty];
6986
- }
6862
+ getOptionByValue(value) {
6863
+ return this.props?.options?.find(option => option[this.valueProperty] === value);
6987
6864
  }
6988
- applyChanges() {
6989
- if (!this.props?.control) {
6990
- return;
6991
- }
6992
- try {
6993
- this.isProcessingChanges = true;
6994
- if (this.selectedItems.length > 0) {
6995
- this.props.control.setValue(this.selectedItems[0][this.valueProperty]);
6996
- }
6997
- else {
6998
- this.props.control.setValue(null);
6999
- }
7000
- this.props.control.markAsDirty();
7001
- this.props.control.updateValueAndValidity();
7002
- }
7003
- finally {
7004
- this.isProcessingChanges = false;
6865
+ applyDefaultValue() {
6866
+ if (this.props) {
6867
+ applyDefaultValueToControl(this.props);
7005
6868
  }
7006
6869
  }
7007
- // Método público para reiniciar el componente
7008
- reset() {
7009
- this.selectedItems = [];
7010
- this.displayValue = '';
7011
- if (this.props?.control) {
7012
- this.props.control.setValue(null);
6870
+ syncSelectedValue() {
6871
+ if (this.props?.control?.value) {
6872
+ this.selectedValue.set(this.props.control.value);
7013
6873
  }
7014
- this.changeDetector.detectChanges();
7015
6874
  }
7016
6875
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectSearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7017
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: SelectSearchComponent, isStandalone: true, selector: "val-select-search", inputs: { label: "label", labelProperty: "labelProperty", valueProperty: "valueProperty", multiple: "multiple", placeholder: "placeholder", props: "props" }, viewQueries: [{ propertyName: "modal", first: true, predicate: ["modal"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
7018
- <ion-input
7019
- type="text"
7020
- [value]="displayValue"
7021
- [placeholder]="props?.placeholder || placeholder"
7022
- readonly
7023
- (mousedown)="preventDefaultBehavior($event)"
7024
- />
7025
-
7026
- <ion-input style="position: absolute;" [formControl]="props.control" type="hidden"></ion-input>
6876
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: SelectSearchComponent, isStandalone: true, selector: "val-select-search", inputs: { props: "props", labelProperty: "labelProperty", valueProperty: "valueProperty", placeholder: "placeholder" }, viewQueries: [{ propertyName: "dropdownRef", first: true, predicate: ["dropdown"], descendants: true }, { propertyName: "mainInputRef", first: true, predicate: ["mainInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
6877
+ <div class="select-container" (click)="toggleDropdown($event)">
6878
+ <!-- Main input display -->
6879
+ <ion-input
6880
+ #mainInput
6881
+ type="text"
6882
+ [value]="displayValue()"
6883
+ [placeholder]="props?.placeholder || placeholder"
6884
+ readonly
6885
+ class="main-input"
6886
+ [class.is-open]="isOpen()"
6887
+ />
6888
+
6889
+ <!-- Dropdown icon -->
6890
+ <ion-icon
6891
+ name="chevron-down-outline"
6892
+ class="dropdown-icon"
6893
+ [class.rotated]="isOpen()"
6894
+ ></ion-icon>
6895
+
6896
+ <!-- Hidden input for form control -->
6897
+ <ion-input
6898
+ style="position: absolute; opacity: 0; pointer-events: none;"
6899
+ [formControl]="props?.control"
6900
+ type="hidden"
6901
+ />
6902
+ </div>
7027
6903
 
7028
- <ion-modal
7029
- #modal
7030
- [initialBreakpoint]="1"
7031
- [breakpoints]="[0, 0.5, 0.75, 1]"
7032
- (didDismiss)="cancelModal()"
6904
+ <!-- Dropdown overlay -->
6905
+ <div
6906
+ class="dropdown-overlay"
6907
+ [class.visible]="isOpen()"
6908
+ #dropdown
7033
6909
  >
7034
- <ng-template>
7035
- <ion-header>
7036
- <ion-toolbar>
7037
- <ion-title>{{ label }}</ion-title>
7038
- <ion-buttons slot="end">
7039
- <ion-button (click)="cancelModal()">Cerrar</ion-button>
7040
- </ion-buttons>
7041
- </ion-toolbar>
7042
- <ion-toolbar>
7043
- <val-searchbar (filterEvent)="onFilter($event)" (focusEvent)="onFocus()" (blurEvent)="onBlur()" />
7044
- </ion-toolbar>
7045
- </ion-header>
7046
- <ion-content>
7047
- <ion-list>
7048
- <ion-item *ngFor="let item of filteredItems" button (click)="selectItem(item)" detail="false">
7049
- <ion-label>{{ item[labelProperty] }}</ion-label>
7050
- <ion-icon *ngIf="isItemSelected(item)" name="checkmark-outline" slot="end" color="primary"></ion-icon>
7051
- </ion-item>
7052
- <ion-item *ngIf="filteredItems.length === 0" lines="none">
7053
- <ion-label color="dark">No se encontraron resultados</ion-label>
7054
- </ion-item>
7055
- </ion-list>
7056
- </ion-content>
7057
- </ng-template>
7058
- </ion-modal>
7059
- `, isInline: true, styles: ["ion-header{padding:8px 8px 0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: IonicModule }, { kind: "component", type: i2.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i2.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i2.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2.IonInput, selector: "ion-input", inputs: ["autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "spellcheck", "step", "type", "value"] }, { kind: "component", type: i2.IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: i2.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2.IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: i2.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: i2.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: i2.IonModal, selector: "ion-modal" }, { kind: "directive", type: i2.TextValueAccessor, selector: "ion-input:not([type=number]),ion-textarea,ion-searchbar" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "component", type: SearchbarComponent, selector: "val-searchbar", inputs: ["disabled"], outputs: ["filterEvent", "focusEvent", "blurEvent"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] }); }
6910
+ <!-- Search bar -->
6911
+ <div class="search-container" *ngIf="props?.options && props.options.length > 5">
6912
+ <ion-searchbar
6913
+ #searchbar
6914
+ [placeholder]="'Buscar'"
6915
+ (ionInput)="onSearch($event)"
6916
+ [value]="searchTerm()"
6917
+ show-clear-button="focus"
6918
+ [debounce]="200"
6919
+ ></ion-searchbar>
6920
+ </div>
6921
+
6922
+ <!-- Options list -->
6923
+ <div class="options-container">
6924
+ <ion-list class="options-list">
6925
+ <ion-item
6926
+ *ngFor="let option of filteredOptions(); trackBy: trackByFn"
6927
+ button
6928
+ (click)="selectOption(option)"
6929
+ class="option-item"
6930
+ >
6931
+ <ion-label>{{ option[labelProperty] }}</ion-label>
6932
+ <ion-icon
6933
+ *ngIf="isSelected(option)"
6934
+ name="checkmark-outline"
6935
+ slot="end"
6936
+ color="primary"
6937
+ ></ion-icon>
6938
+ </ion-item>
6939
+
6940
+ <!-- No results message -->
6941
+ <ion-item *ngIf="filteredOptions().length === 0" class="no-results">
6942
+ <ion-label color="medium">
6943
+ {{ searchTerm() ? 'No se encontraron resultados' : 'No hay opciones disponibles' }}
6944
+ </ion-label>
6945
+ </ion-item>
6946
+ </ion-list>
6947
+ </div>
6948
+ </div>
6949
+ `, isInline: true, styles: [":host{display:block;position:relative;width:100%}.select-container{position:relative;display:flex;align-items:center;cursor:pointer}.select-container .main-input{flex:1;cursor:pointer}.select-container .main-input.is-open{--border-color: var(--ion-color-primary)}.select-container .dropdown-icon{position:absolute;right:12px;font-size:16px;color:var(--ion-color-medium);transition:transform .2s ease;pointer-events:none;z-index:2}.select-container .dropdown-icon.rotated{transform:rotate(180deg)}.dropdown-overlay{position:absolute;top:100%;left:0;right:0;background:var(--ion-background-color);border:1px solid var(--ion-color-light);border-radius:8px;box-shadow:0 4px 16px #0000001a;z-index:1000;max-height:300px;opacity:0;transform:translateY(-8px);pointer-events:none;transition:all .2s ease}.dropdown-overlay.visible{opacity:1;transform:translateY(4px);pointer-events:all}.search-container{padding:12px;border-bottom:1px solid var(--ion-color-light)}.search-container ion-searchbar{--background: var(--ion-color-light);--border-radius: 8px;--box-shadow: none;--padding-start: 12px;--padding-end: 12px;height:40px}.options-container{max-height:240px;overflow-y:auto}.options-container .options-list{padding:0}.options-container .option-item{--padding-start: 16px;--padding-end: 16px;--min-height: 48px;cursor:pointer}.options-container .option-item:hover{--background: var(--ion-color-light)}.options-container .option-item ion-label{font-size:16px;line-height:1.4}.options-container .option-item ion-icon{font-size:20px}.options-container .no-results{--padding-start: 16px;--padding-end: 16px;--min-height: 48px;text-align:center}.options-container .no-results ion-label{font-style:italic;font-size:14px}@media (max-width: 768px){.dropdown-overlay{max-height:250px}.options-container{max-height:200px}}@media (prefers-color-scheme: dark){.dropdown-overlay{box-shadow:0 4px 16px #0000004d}}.option-item:focus-within{--background: var(--ion-color-primary-tint);outline:2px solid var(--ion-color-primary);outline-offset:-2px}.option-item{transition:background-color .15s ease}.dropdown-icon{transition:transform .2s cubic-bezier(.4,0,.2,1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: IonicModule }, { kind: "component", type: i2.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2.IonInput, selector: "ion-input", inputs: ["autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "spellcheck", "step", "type", "value"] }, { kind: "component", type: i2.IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: i2.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2.IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: i2.IonSearchbar, selector: "ion-searchbar", inputs: ["animated", "autocapitalize", "autocomplete", "autocorrect", "cancelButtonIcon", "cancelButtonText", "clearIcon", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "maxlength", "minlength", "mode", "name", "placeholder", "searchIcon", "showCancelButton", "showClearButton", "spellcheck", "type", "value"] }, { kind: "directive", type: i2.TextValueAccessor, selector: "ion-input:not([type=number]),ion-textarea,ion-searchbar" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] }); }
7060
6950
  }
7061
6951
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectSearchComponent, decorators: [{
7062
6952
  type: Component,
7063
- args: [{ selector: 'val-select-search', standalone: true, imports: [CommonModule, IonicModule, FormsModule, SearchbarComponent, ReactiveFormsModule], template: `
7064
- <ion-input
7065
- type="text"
7066
- [value]="displayValue"
7067
- [placeholder]="props?.placeholder || placeholder"
7068
- readonly
7069
- (mousedown)="preventDefaultBehavior($event)"
7070
- />
7071
-
7072
- <ion-input style="position: absolute;" [formControl]="props.control" type="hidden"></ion-input>
6953
+ args: [{ selector: 'val-select-search', standalone: true, imports: [CommonModule, IonicModule, FormsModule, ReactiveFormsModule], template: `
6954
+ <div class="select-container" (click)="toggleDropdown($event)">
6955
+ <!-- Main input display -->
6956
+ <ion-input
6957
+ #mainInput
6958
+ type="text"
6959
+ [value]="displayValue()"
6960
+ [placeholder]="props?.placeholder || placeholder"
6961
+ readonly
6962
+ class="main-input"
6963
+ [class.is-open]="isOpen()"
6964
+ />
6965
+
6966
+ <!-- Dropdown icon -->
6967
+ <ion-icon
6968
+ name="chevron-down-outline"
6969
+ class="dropdown-icon"
6970
+ [class.rotated]="isOpen()"
6971
+ ></ion-icon>
6972
+
6973
+ <!-- Hidden input for form control -->
6974
+ <ion-input
6975
+ style="position: absolute; opacity: 0; pointer-events: none;"
6976
+ [formControl]="props?.control"
6977
+ type="hidden"
6978
+ />
6979
+ </div>
7073
6980
 
7074
- <ion-modal
7075
- #modal
7076
- [initialBreakpoint]="1"
7077
- [breakpoints]="[0, 0.5, 0.75, 1]"
7078
- (didDismiss)="cancelModal()"
6981
+ <!-- Dropdown overlay -->
6982
+ <div
6983
+ class="dropdown-overlay"
6984
+ [class.visible]="isOpen()"
6985
+ #dropdown
7079
6986
  >
7080
- <ng-template>
7081
- <ion-header>
7082
- <ion-toolbar>
7083
- <ion-title>{{ label }}</ion-title>
7084
- <ion-buttons slot="end">
7085
- <ion-button (click)="cancelModal()">Cerrar</ion-button>
7086
- </ion-buttons>
7087
- </ion-toolbar>
7088
- <ion-toolbar>
7089
- <val-searchbar (filterEvent)="onFilter($event)" (focusEvent)="onFocus()" (blurEvent)="onBlur()" />
7090
- </ion-toolbar>
7091
- </ion-header>
7092
- <ion-content>
7093
- <ion-list>
7094
- <ion-item *ngFor="let item of filteredItems" button (click)="selectItem(item)" detail="false">
7095
- <ion-label>{{ item[labelProperty] }}</ion-label>
7096
- <ion-icon *ngIf="isItemSelected(item)" name="checkmark-outline" slot="end" color="primary"></ion-icon>
7097
- </ion-item>
7098
- <ion-item *ngIf="filteredItems.length === 0" lines="none">
7099
- <ion-label color="dark">No se encontraron resultados</ion-label>
7100
- </ion-item>
7101
- </ion-list>
7102
- </ion-content>
7103
- </ng-template>
7104
- </ion-modal>
7105
- `, styles: ["ion-header{padding:8px 8px 0}\n"] }]
7106
- }], ctorParameters: () => [], propDecorators: { modal: [{
6987
+ <!-- Search bar -->
6988
+ <div class="search-container" *ngIf="props?.options && props.options.length > 5">
6989
+ <ion-searchbar
6990
+ #searchbar
6991
+ [placeholder]="'Buscar'"
6992
+ (ionInput)="onSearch($event)"
6993
+ [value]="searchTerm()"
6994
+ show-clear-button="focus"
6995
+ [debounce]="200"
6996
+ ></ion-searchbar>
6997
+ </div>
6998
+
6999
+ <!-- Options list -->
7000
+ <div class="options-container">
7001
+ <ion-list class="options-list">
7002
+ <ion-item
7003
+ *ngFor="let option of filteredOptions(); trackBy: trackByFn"
7004
+ button
7005
+ (click)="selectOption(option)"
7006
+ class="option-item"
7007
+ >
7008
+ <ion-label>{{ option[labelProperty] }}</ion-label>
7009
+ <ion-icon
7010
+ *ngIf="isSelected(option)"
7011
+ name="checkmark-outline"
7012
+ slot="end"
7013
+ color="primary"
7014
+ ></ion-icon>
7015
+ </ion-item>
7016
+
7017
+ <!-- No results message -->
7018
+ <ion-item *ngIf="filteredOptions().length === 0" class="no-results">
7019
+ <ion-label color="medium">
7020
+ {{ searchTerm() ? 'No se encontraron resultados' : 'No hay opciones disponibles' }}
7021
+ </ion-label>
7022
+ </ion-item>
7023
+ </ion-list>
7024
+ </div>
7025
+ </div>
7026
+ `, styles: [":host{display:block;position:relative;width:100%}.select-container{position:relative;display:flex;align-items:center;cursor:pointer}.select-container .main-input{flex:1;cursor:pointer}.select-container .main-input.is-open{--border-color: var(--ion-color-primary)}.select-container .dropdown-icon{position:absolute;right:12px;font-size:16px;color:var(--ion-color-medium);transition:transform .2s ease;pointer-events:none;z-index:2}.select-container .dropdown-icon.rotated{transform:rotate(180deg)}.dropdown-overlay{position:absolute;top:100%;left:0;right:0;background:var(--ion-background-color);border:1px solid var(--ion-color-light);border-radius:8px;box-shadow:0 4px 16px #0000001a;z-index:1000;max-height:300px;opacity:0;transform:translateY(-8px);pointer-events:none;transition:all .2s ease}.dropdown-overlay.visible{opacity:1;transform:translateY(4px);pointer-events:all}.search-container{padding:12px;border-bottom:1px solid var(--ion-color-light)}.search-container ion-searchbar{--background: var(--ion-color-light);--border-radius: 8px;--box-shadow: none;--padding-start: 12px;--padding-end: 12px;height:40px}.options-container{max-height:240px;overflow-y:auto}.options-container .options-list{padding:0}.options-container .option-item{--padding-start: 16px;--padding-end: 16px;--min-height: 48px;cursor:pointer}.options-container .option-item:hover{--background: var(--ion-color-light)}.options-container .option-item ion-label{font-size:16px;line-height:1.4}.options-container .option-item ion-icon{font-size:20px}.options-container .no-results{--padding-start: 16px;--padding-end: 16px;--min-height: 48px;text-align:center}.options-container .no-results ion-label{font-style:italic;font-size:14px}@media (max-width: 768px){.dropdown-overlay{max-height:250px}.options-container{max-height:200px}}@media (prefers-color-scheme: dark){.dropdown-overlay{box-shadow:0 4px 16px #0000004d}}.option-item:focus-within{--background: var(--ion-color-primary-tint);outline:2px solid var(--ion-color-primary);outline-offset:-2px}.option-item{transition:background-color .15s ease}.dropdown-icon{transition:transform .2s cubic-bezier(.4,0,.2,1)}\n"] }]
7027
+ }], ctorParameters: () => [], propDecorators: { dropdownRef: [{
7107
7028
  type: ViewChild,
7108
- args: ['modal']
7109
- }], label: [{
7029
+ args: ['dropdown']
7030
+ }], mainInputRef: [{
7031
+ type: ViewChild,
7032
+ args: ['mainInput']
7033
+ }], props: [{
7110
7034
  type: Input
7111
7035
  }], labelProperty: [{
7112
7036
  type: Input
7113
7037
  }], valueProperty: [{
7114
7038
  type: Input
7115
- }], multiple: [{
7116
- type: Input
7117
7039
  }], placeholder: [{
7118
7040
  type: Input
7119
- }], props: [{
7120
- type: Input
7121
7041
  }] } });
7122
7042
 
7123
7043
  /**
@@ -8287,6 +8207,7 @@ class FormComponent {
8287
8207
  this.onSelectChange = new EventEmitter();
8288
8208
  this.types = InputType;
8289
8209
  this.subscriptions = [];
8210
+ this.previousValues = new Map();
8290
8211
  }
8291
8212
  ngOnInit() {
8292
8213
  const formControls = {};
@@ -8317,8 +8238,15 @@ class FormComponent {
8317
8238
  }
8318
8239
  trackSelectChanges(fieldName) {
8319
8240
  const control = this.getControl(fieldName);
8320
- const subscription = control.valueChanges.subscribe(value => {
8321
- this.onSelectChange.emit({ field: fieldName, value });
8241
+ const subscription = control.valueChanges
8242
+ .pipe(distinctUntilChanged$1()) // Evitar valores duplicados
8243
+ .subscribe(value => {
8244
+ // Evitar loops - solo emitir si el valor realmente cambió
8245
+ const previousValue = this.previousValues.get(fieldName);
8246
+ if (previousValue !== value) {
8247
+ this.previousValues.set(fieldName, value);
8248
+ this.onSelectChange.emit({ field: fieldName, value });
8249
+ }
8322
8250
  });
8323
8251
  this.subscriptions.push(subscription);
8324
8252
  }
@@ -8333,6 +8261,14 @@ class FormComponent {
8333
8261
  if (!field.token) {
8334
8262
  field.token = `input-${field.type}-${field.name}`;
8335
8263
  }
8264
+ // Debug: verificar opciones para select fields
8265
+ if (field.type === this.types.SEARCH_SELECT || field.type === this.types.MULTI_SELECT || field.type === this.types.MULTI_SELECT_SIMPLE) {
8266
+ console.log(`[FormComponent] ${field.name} options:`, {
8267
+ type: field.type,
8268
+ optionsCount: field.options?.length || 0,
8269
+ options: field.options?.slice(0, 2) || []
8270
+ });
8271
+ }
8336
8272
  if (field.type === this.types.NUMBER_FROM_TO) {
8337
8273
  const fromControl = this.getControl(`${field.name}_from`);
8338
8274
  const toControl = this.getControl(`${field.name}_to`);
@@ -8470,7 +8406,7 @@ class FormComponent {
8470
8406
  ></val-button-group>
8471
8407
  </form>
8472
8408
  </div>
8473
- `, isInline: true, styles: [":root{--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}@media (prefers-color-scheme: dark){:root{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:.5rem 0}@media (min-width: 768px){.input{margin:.75rem 0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: TextInputComponent, selector: "val-text-input", inputs: ["props"] }, { kind: "component", type: CheckInputComponent, selector: "val-check-input" }, { kind: "component", type: ButtonGroupComponent, selector: "val-button-group", inputs: ["props"], outputs: ["onClick"] }, { kind: "component", type: DividerComponent, selector: "val-divider", inputs: ["props"] }, { kind: "component", type: HintComponent, selector: "val-hint", inputs: ["props"] }, { kind: "component", type: CommentInputComponent, selector: "val-comment-input", inputs: ["props"] }, { kind: "component", type: DateInputComponent, selector: "val-date-input", inputs: ["props"] }, { kind: "component", type: FileInputComponent, selector: "val-file-input", inputs: ["props"] }, { kind: "component", type: HourInputComponent, selector: "val-hour-input", inputs: ["props"] }, { kind: "component", type: EmailInputComponent, selector: "val-email-input", inputs: ["props"] }, { kind: "component", type: NumberInputComponent, selector: "val-number-input", inputs: ["props"] }, { kind: "component", type: NumberFromToComponent, selector: "val-number-from-to", inputs: ["props"] }, { kind: "component", type: RadioInputComponent, selector: "val-radio-input", inputs: ["props"] }, { kind: "component", type: PasswordInputComponent, selector: "val-password-input", inputs: ["props"] }, { kind: "component", type: PinInputComponent, selector: "val-pin-input", inputs: ["props"] }, { kind: "component", type: SelectSearchComponent, selector: "val-select-search", inputs: ["label", "labelProperty", "valueProperty", "multiple", "placeholder", "props"] }, { kind: "component", type: MultiSelectSearchComponent, selector: "val-multi-select-search", inputs: ["label", "labelProperty", "valueProperty", "placeholder", "props"] }, { kind: "component", type: MultiSelectSimpleComponent, selector: "val-multi-select-simple", inputs: ["props", "labelProperty", "valueProperty", "placeholder"] }, { kind: "component", type: SearchSelectorComponent, selector: "val-select-input", inputs: ["props"] }] }); }
8409
+ `, isInline: true, styles: [":root{--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}@media (prefers-color-scheme: dark){:root{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.section{margin-top:1rem}.input{margin:.5rem 0}@media (min-width: 768px){.input{margin:.75rem 0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: TextInputComponent, selector: "val-text-input", inputs: ["props"] }, { kind: "component", type: CheckInputComponent, selector: "val-check-input" }, { kind: "component", type: ButtonGroupComponent, selector: "val-button-group", inputs: ["props"], outputs: ["onClick"] }, { kind: "component", type: DividerComponent, selector: "val-divider", inputs: ["props"] }, { kind: "component", type: HintComponent, selector: "val-hint", inputs: ["props"] }, { kind: "component", type: CommentInputComponent, selector: "val-comment-input", inputs: ["props"] }, { kind: "component", type: DateInputComponent, selector: "val-date-input", inputs: ["props"] }, { kind: "component", type: FileInputComponent, selector: "val-file-input", inputs: ["props"] }, { kind: "component", type: HourInputComponent, selector: "val-hour-input", inputs: ["props"] }, { kind: "component", type: EmailInputComponent, selector: "val-email-input", inputs: ["props"] }, { kind: "component", type: NumberInputComponent, selector: "val-number-input", inputs: ["props"] }, { kind: "component", type: NumberFromToComponent, selector: "val-number-from-to", inputs: ["props"] }, { kind: "component", type: RadioInputComponent, selector: "val-radio-input", inputs: ["props"] }, { kind: "component", type: PasswordInputComponent, selector: "val-password-input", inputs: ["props"] }, { kind: "component", type: PinInputComponent, selector: "val-pin-input", inputs: ["props"] }, { kind: "component", type: SelectSearchComponent, selector: "val-select-search", inputs: ["props", "labelProperty", "valueProperty", "placeholder"] }, { kind: "component", type: MultiSelectSearchComponent, selector: "val-multi-select-search", inputs: ["label", "labelProperty", "valueProperty", "placeholder", "props"] }, { kind: "component", type: MultiSelectSimpleComponent, selector: "val-multi-select-simple", inputs: ["props", "labelProperty", "valueProperty", "placeholder"] }, { kind: "component", type: SearchSelectorComponent, selector: "val-select-input", inputs: ["props"] }] }); }
8474
8410
  }
8475
8411
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FormComponent, decorators: [{
8476
8412
  type: Component,