ln-20-lib-components 0.0.63 → 0.0.64

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.
@@ -0,0 +1,3748 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable, Component, model, input, computed, output, forwardRef, ChangeDetectionStrategy, effect, signal, ContentChildren, inject, ViewChild, Pipe, viewChild, ContentChild } from '@angular/core';
3
+ import { toObservable, takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
4
+ import * as i1 from '@angular/forms';
5
+ import { ReactiveFormsModule, NG_VALUE_ACCESSOR, FormsModule, NonNullableFormBuilder, FormGroup } from '@angular/forms';
6
+ import { switchMap, debounceTime, filter, map, distinctUntilChanged, Subject } from 'rxjs';
7
+ import * as i1$1 from '@angular/common';
8
+ import { NgClass, CommonModule } from '@angular/common';
9
+ import { CheckboxModule } from 'primeng/checkbox';
10
+ import * as i2 from 'primeng/datepicker';
11
+ import { DatePickerModule } from 'primeng/datepicker';
12
+ import { IftaLabelModule } from 'primeng/iftalabel';
13
+ import * as i6 from 'primeng/inputotp';
14
+ import { InputOtpModule } from 'primeng/inputotp';
15
+ import * as i3 from 'primeng/multiselect';
16
+ import { MultiSelectModule } from 'primeng/multiselect';
17
+ import * as i4 from 'primeng/select';
18
+ import { SelectModule } from 'primeng/select';
19
+ import * as i5 from 'primeng/togglebutton';
20
+ import { ToggleButtonModule } from 'primeng/togglebutton';
21
+ import * as i7 from 'primeng/toggleswitch';
22
+ import { ToggleSwitchModule } from 'primeng/toggleswitch';
23
+ import * as i10 from 'primeng/tooltip';
24
+ import { TooltipModule } from 'primeng/tooltip';
25
+ import * as i8 from 'primeng/inputnumber';
26
+ import { InputNumberModule } from 'primeng/inputnumber';
27
+ import * as i9 from 'primeng/textarea';
28
+ import { TextareaModule } from 'primeng/textarea';
29
+ import * as i2$1 from 'primeng/inputtext';
30
+ import { InputTextModule } from 'primeng/inputtext';
31
+ import { InputMaskModule } from 'primeng/inputmask';
32
+ import * as i9$1 from 'primeng/knob';
33
+ import { KnobModule } from 'primeng/knob';
34
+ import * as i11 from 'primeng/chip';
35
+ import { ChipModule } from 'primeng/chip';
36
+ import * as i4$1 from 'primeng/api';
37
+ import { PrimeTemplate, FilterService } from 'primeng/api';
38
+ import * as i1$2 from 'primeng/button';
39
+ import { ButtonModule } from 'primeng/button';
40
+ import jsPDF from 'jspdf';
41
+ import autoTable from 'jspdf-autotable';
42
+ import * as i2$2 from 'primeng/table';
43
+ import { TableModule } from 'primeng/table';
44
+ import * as XLSX from 'xlsx';
45
+ import * as i1$3 from 'primeng/badge';
46
+ import { BadgeModule } from 'primeng/badge';
47
+ import * as i1$4 from 'primeng/toolbar';
48
+ import { ToolbarModule } from 'primeng/toolbar';
49
+ import { DialogService, DynamicDialogRef, DynamicDialogConfig } from 'primeng/dynamicdialog';
50
+ import * as i1$5 from 'primeng/speeddial';
51
+ import { SpeedDialModule } from 'primeng/speeddial';
52
+
53
+ class LibComponentsService {
54
+ constructor() { }
55
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LibComponentsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
56
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LibComponentsService, providedIn: 'root' });
57
+ }
58
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LibComponentsService, decorators: [{
59
+ type: Injectable,
60
+ args: [{
61
+ providedIn: 'root'
62
+ }]
63
+ }], ctorParameters: () => [] });
64
+
65
+ class LibComponentsComponent {
66
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LibComponentsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
67
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: LibComponentsComponent, isStandalone: true, selector: "lib-lib-components", ngImport: i0, template: `
68
+ <p>
69
+ lib-components works!
70
+ </p>
71
+ `, isInline: true, styles: [""] });
72
+ }
73
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LibComponentsComponent, decorators: [{
74
+ type: Component,
75
+ args: [{ selector: 'lib-lib-components', imports: [], template: `
76
+ <p>
77
+ lib-components works!
78
+ </p>
79
+ ` }]
80
+ }] });
81
+
82
+ var ETypeInput;
83
+ (function (ETypeInput) {
84
+ ETypeInput["TEXT"] = "text";
85
+ ETypeInput["PASSWORD"] = "password";
86
+ ETypeInput["EMAIL"] = "email";
87
+ ETypeInput["EMAIL_PASSWORD"] = "email-password";
88
+ ETypeInput["NUMBER"] = "number";
89
+ ETypeInput["DATE"] = "date";
90
+ ETypeInput["TIME"] = "time";
91
+ ETypeInput["DATETIME_LOCAL"] = "datetime-local";
92
+ ETypeInput["SEARCH"] = "search";
93
+ ETypeInput["TEL"] = "tel";
94
+ ETypeInput["URL"] = "url";
95
+ ETypeInput["COLOR"] = "color";
96
+ ETypeInput["MONTH"] = "month";
97
+ ETypeInput["WEEK"] = "week";
98
+ ETypeInput["FILE"] = "file";
99
+ ETypeInput["CHECKBOX"] = "checkbox";
100
+ ETypeInput["RADIO"] = "radio";
101
+ ETypeInput["RANGE"] = "range";
102
+ ETypeInput["HIDDEN"] = "hidden";
103
+ ETypeInput["TEXTAREA"] = "textarea";
104
+ ETypeInput["SELECT"] = "select";
105
+ ETypeInput["MULTISELECT"] = "multiselect";
106
+ ETypeInput["AUTOCOMPLETE"] = "autocomplete";
107
+ ETypeInput["SWITCH"] = "switch";
108
+ ETypeInput["CALENDAR"] = "calendar";
109
+ ETypeInput["DROPDOWN"] = "dropdown";
110
+ ETypeInput["CHIPS"] = "chips";
111
+ ETypeInput["TOGGLE"] = "toggle";
112
+ ETypeInput["OTP"] = "otp";
113
+ ETypeInput["CURRENCY"] = "currency";
114
+ ETypeInput["KNOB"] = "knob";
115
+ ETypeInput["BADGE"] = "badge";
116
+ ETypeInput["DECIMAL"] = "decimal";
117
+ ETypeInput["IMAGE"] = "image";
118
+ ETypeInput["COMPONENT"] = "component";
119
+ ETypeInput["INPUT"] = "input";
120
+ })(ETypeInput || (ETypeInput = {}));
121
+
122
+ class DisabledContainerComponent {
123
+ disabled = model(false);
124
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: DisabledContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
125
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.17", type: DisabledContainerComponent, isStandalone: true, selector: "lib-disabled-container", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange" }, ngImport: i0, template: "<fieldset [disabled]=\"disabled()\" class=\"disabled-container\">\r\n <ng-content></ng-content>\r\n</fieldset>\r\n", styles: [".disabled-container{border:none;margin:0;padding:0;min-width:0}.disabled-container:disabled{opacity:.6;cursor:not-allowed}.disabled-container:disabled *{pointer-events:none}\n"] });
126
+ }
127
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: DisabledContainerComponent, decorators: [{
128
+ type: Component,
129
+ args: [{ selector: 'lib-disabled-container', imports: [], template: "<fieldset [disabled]=\"disabled()\" class=\"disabled-container\">\r\n <ng-content></ng-content>\r\n</fieldset>\r\n", styles: [".disabled-container{border:none;margin:0;padding:0;min-width:0}.disabled-container:disabled{opacity:.6;cursor:not-allowed}.disabled-container:disabled *{pointer-events:none}\n"] }]
130
+ }] });
131
+
132
+ class CustomInputComponent {
133
+ controlData = input.required();
134
+ controlUpperName = computed(() => this.controlData().controlName.toLocaleUpperCase());
135
+ showPassword = false;
136
+ output = output();
137
+ onChange = (_value) => { };
138
+ constructor() { }
139
+ control = computed(() => this.controlData().control);
140
+ controlValue = computed(() => this.control().value);
141
+ hasControlValue = computed(() => this.controlValue() !== null && this.controlValue() !== undefined);
142
+ writeValue(value) {
143
+ if (value !== this.controlData().control.value) {
144
+ this.controlData().control.setValue(value, { emitEvent: false });
145
+ }
146
+ }
147
+ get showLabel() {
148
+ return !this.controlData().hideLabel;
149
+ }
150
+ get inputTypesEnum() {
151
+ return ETypeInput;
152
+ }
153
+ onCheckboxChange(event, control) {
154
+ const input = event.target;
155
+ const isChecked = input.checked;
156
+ control.setValue(isChecked);
157
+ }
158
+ registerOnChange(fn) {
159
+ this.onChange = fn;
160
+ }
161
+ onBlur() {
162
+ this.controlData().onBlur?.();
163
+ }
164
+ onFocus() {
165
+ this.controlData().onFocus?.();
166
+ }
167
+ onTouched = () => { };
168
+ registerOnTouched(fn) {
169
+ this.onTouched = fn;
170
+ }
171
+ generateUniqueId(baseString) {
172
+ const timestamp = new Date().getTime();
173
+ const random = Math.random().toString(36).substring(2, 8);
174
+ return `${baseString}-${timestamp}-${random}`;
175
+ }
176
+ togglePasswordVisibility() {
177
+ this.showPassword = !this.showPassword;
178
+ }
179
+ onSelectChange() {
180
+ this.output.emit(this.controlData());
181
+ }
182
+ /**
183
+ * Sincroniza el valor del input visible con el input oculto de password
184
+ * para mantener ambos actualizados
185
+ */
186
+ syncPasswordAutofill(event) {
187
+ const visibleInput = event.target;
188
+ const currentComponent = visibleInput.closest('lib-custom-input');
189
+ if (!currentComponent)
190
+ return;
191
+ const hiddenInput = currentComponent.querySelector('input[type="password"][id^="password-autofill-hidden-"]');
192
+ if (hiddenInput && hiddenInput.value !== visibleInput.value) {
193
+ hiddenInput.value = visibleInput.value;
194
+ }
195
+ }
196
+ /**
197
+ * Maneja el autocompletado cuando el navegador llena el input oculto de password.
198
+ * Actualiza el input visible y el FormControl.
199
+ */
200
+ onPasswordAutofillHidden(event) {
201
+ const hiddenInput = event.target;
202
+ const passwordValue = hiddenInput.value;
203
+ if (!passwordValue)
204
+ return;
205
+ // Buscar el input visible de password en el mismo componente
206
+ const currentComponent = hiddenInput.closest('lib-custom-input');
207
+ if (!currentComponent)
208
+ return;
209
+ const visibleInput = currentComponent.querySelector('input[type="password"]:not([id^="password-autofill-hidden-"]), input[type="text"][class*="custom-password"]');
210
+ if (visibleInput && visibleInput.value !== passwordValue) {
211
+ // Actualizar el input visible
212
+ visibleInput.value = passwordValue;
213
+ // Actualizar el FormControl
214
+ this.controlData().control.setValue(passwordValue, { emitEvent: true });
215
+ // Disparar eventos para que Angular Forms lo detecte
216
+ visibleInput.dispatchEvent(new Event('input', { bubbles: true, cancelable: true }));
217
+ visibleInput.dispatchEvent(new Event('change', { bubbles: true, cancelable: true }));
218
+ }
219
+ }
220
+ /**
221
+ * Maneja el autocompletado del password cuando el navegador llena automáticamente
222
+ * el campo de password oculto en EMAIL_PASSWORD. Busca el siguiente campo de password
223
+ * en el formulario y actualiza su FormControl directamente.
224
+ */
225
+ onPasswordAutofill(event) {
226
+ const passwordInput = event.target;
227
+ const passwordValue = passwordInput.value;
228
+ if (!passwordValue)
229
+ return;
230
+ // Buscar el formulario padre
231
+ let parent = passwordInput.parentElement;
232
+ let formElement = null;
233
+ for (let i = 0; i < 6 && parent; i++) {
234
+ if (parent.tagName === 'FORM') {
235
+ formElement = parent;
236
+ break;
237
+ }
238
+ parent = parent.parentElement;
239
+ }
240
+ if (!formElement)
241
+ return;
242
+ // Buscar el componente lib-custom-input actual (EMAIL_PASSWORD)
243
+ const currentComponent = passwordInput.closest('lib-custom-input');
244
+ if (!currentComponent)
245
+ return;
246
+ // Buscar todos los componentes lib-custom-input en el formulario
247
+ const allCustomInputs = formElement.querySelectorAll('lib-custom-input');
248
+ const currentIndex = Array.from(allCustomInputs).indexOf(currentComponent);
249
+ // Buscar el siguiente componente después del actual que tenga un campo de password
250
+ for (let i = currentIndex + 1; i < allCustomInputs.length; i++) {
251
+ const nextComponent = allCustomInputs[i];
252
+ // Buscar el input de password dentro del componente siguiente
253
+ const passwordField = nextComponent.querySelector('input[type="password"]:not([id="password-autofill-helper"])');
254
+ if (passwordField) {
255
+ // Actualizar el valor directamente en el input
256
+ // y disparar eventos para que Angular Forms lo detecte
257
+ passwordField.value = passwordValue;
258
+ passwordField.dispatchEvent(new Event('input', { bubbles: true, cancelable: true }));
259
+ passwordField.dispatchEvent(new Event('change', { bubbles: true, cancelable: true }));
260
+ // Forzar la actualización después de un breve delay
261
+ // para asegurar que Angular Forms procese el cambio
262
+ setTimeout(() => {
263
+ if (passwordField.value !== passwordValue) {
264
+ passwordField.value = passwordValue;
265
+ passwordField.dispatchEvent(new Event('input', { bubbles: true }));
266
+ }
267
+ }, 50);
268
+ break;
269
+ }
270
+ }
271
+ }
272
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CustomInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
273
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: CustomInputComponent, isStandalone: true, selector: "lib-custom-input", inputs: { controlData: { classPropertyName: "controlData", publicName: "controlData", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { output: "output" }, providers: [{
274
+ provide: NG_VALUE_ACCESSOR,
275
+ useExisting: forwardRef(() => CustomInputComponent),
276
+ multi: true
277
+ }], ngImport: i0, template: "@let localControl = controlData().control;\r\n@let placeholder = controlData().label || controlUpperName();\r\n@let name = controlData().controlName;\r\n@let typeInput = controlData().typeInput;\r\n@let readonly = controlData().readonly || false;\r\n@let dateConfig = controlData().dateConfig;\r\n@let multiSelectConfig = controlData().multiSelectConfig;\r\n@let selectConfig = controlData().selectConfig;\r\n@let toggleConfig = controlData().toggleConfig;\r\n@let textareaConfig = controlData().textareaConfig;\r\n@let currencyConfig = controlData().currencyConfig;\r\n@let decimalConfig = controlData().decimalConfig;\r\n@let autoFocus = controlData().autoFocus ?? false;\r\n<div class=\"flex flex-col gap-1 \">\r\n <lib-disabled-container [disabled]=\"readonly\">\r\n\r\n <p style=\"font-size: 12px; letter-spacing: 0.5px;\" class=\"text-sm text-gray-600 dark:text-gray-300 truncate\"\r\n [pTooltip]=\"placeholder\" tooltipPosition=\"top\" [showDelay]=\"300\">\r\n {{ placeholder }}\r\n </p>\r\n @switch (typeInput) {\r\n @case (inputTypesEnum.EMAIL_PASSWORD) {\r\n <input [formControl]=\"localControl\" (blur)=\"onTouched()\" pInputText [id]=\"generateUniqueId(name)\" [name]=\"name\"\r\n type=\"email\" [readOnly]=\"readonly\" autocomplete=\"email\" autocorrect=\"on\" autocapitalize=\"on\"\r\n spellcheck=\"true\" [ngClass]=\"{\r\n 'border-red-500 focus:ring-red-500':\r\n localControl.invalid &&\r\n (localControl.dirty || localControl.touched),\r\n 'bg-gray-100 cursor-not-allowed': readonly,\r\n }\"\r\n class=\"custom-input h-12 w-full px-3 py-2 border border-gray-300 dark:border-transparent rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100\" />\r\n <input type=\"password\" name=\"password\" id=\"password-autofill-helper\" autocomplete=\"current-password\" tabindex=\"-1\"\r\n style=\"position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0;\"\r\n aria-hidden=\"true\"\r\n (input)=\"onPasswordAutofill($event)\" />\r\n }\r\n @case (inputTypesEnum.PASSWORD) {\r\n <!-- Input oculto siempre de tipo password para el autocompletado del navegador -->\r\n <input \r\n type=\"password\" \r\n name=\"password-autofill\"\r\n [id]=\"'password-autofill-hidden-' + generateUniqueId(name)\"\r\n autocomplete=\"current-password\" \r\n tabindex=\"-1\"\r\n style=\"position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0;\"\r\n aria-hidden=\"true\"\r\n [value]=\"localControl.value || ''\"\r\n (input)=\"onPasswordAutofillHidden($event)\" />\r\n <div class=\"relative\">\r\n <input [readOnly]=\"readonly || false\" [id]=\"generateUniqueId(name)\" [type]=\"showPassword ? 'text' : 'password'\"\r\n autocomplete=\"password\" autocorrect=\"on\" autocapitalize=\"on\" spellcheck=\"true\"\r\n class=\"custom-password w-full px-3 py-2 border border-gray-300 dark:border-transparent rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 transition-all duration-200\"\r\n aria-describedby=\"password-help\" [formControl]=\"localControl\" \r\n (input)=\"syncPasswordAutofill($event)\" />\r\n <button type=\"button\"\r\n class=\"custom-password-toggle absolute inset-y-0 right-0 flex items-center justify-center w-12 h-full text-gray-400 transition-colors duration-200 ease-in-out hover:text-gray-600 focus:outline-none focus:text-gray-600 active:text-gray-700 dark:text-gray-500 dark:hover:text-gray-300 dark:focus:text-gray-300\"\r\n (click)=\"togglePasswordVisibility()\" [attr.aria-label]=\"\r\n showPassword ? 'Ocultar contrase\u00F1a' : 'Mostrar contrase\u00F1a'\r\n \">\r\n <i class=\"fas text-lg transition-all duration-200 ease-in-out\" [ngClass]=\"{\r\n 'fa-solid fa-eye': !showPassword,\r\n 'fa-solid fa-eye-slash': showPassword,\r\n }\"></i>\r\n </button>\r\n </div>\r\n }\r\n @case (inputTypesEnum.EMAIL) {\r\n <input [formControl]=\"localControl\" (blur)=\"onTouched()\" pInputText [id]=\"generateUniqueId(name)\" [name]=\"name\"\r\n [type]=\"typeInput\" [readOnly]=\"readonly\" autocomplete=\"email\" autocorrect=\"on\" autocapitalize=\"on\" spellcheck=\"true\"\r\n [ngClass]=\"{\r\n 'border-red-500 focus:ring-red-500':\r\n localControl.invalid &&\r\n (localControl.dirty || localControl.touched),\r\n 'bg-gray-100 cursor-not-allowed': readonly,\r\n }\"\r\n class=\"custom-input h-12 w-full px-3 py-2 border border-gray-300 dark:border-transparent rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100\" />\r\n }\r\n @case (inputTypesEnum.CURRENCY) {\r\n <p-inputnumber [autofocus]=\"autoFocus ?? false\" [formControl]=\"localControl\" (onFocus)=\"onFocus()\" (onBlur)=\"onBlur()\" (blur)=\"onTouched()\" [id]=\"generateUniqueId(name)\" mode=\"currency\"\r\n [currency]=\"currencyConfig?.currency ?? 'USD'\" [locale]=\"currencyConfig?.locale ?? 'es-CO'\" [minFractionDigits]=\"currencyConfig?.minFractionDigits ?? 2\"\r\n [maxFractionDigits]=\"currencyConfig?.maxFractionDigits ?? 2\" [readonly]=\"readonly\" [disabled]=\"readonly\" />\r\n }\r\n @case (inputTypesEnum.DATE) {\r\n <lib-disabled-container [disabled]=\"readonly\">\r\n <p-datepicker [formControl]=\"localControl\" [selectionMode]=\"dateConfig?.selectionMode || 'single'\"\r\n [maxDate]=\"dateConfig?.maxDate || null\" [minDate]=\"dateConfig?.minDate || null\" dateFormat=\"dd/mm/yy\"\r\n class=\"custom-datepicker\" appendTo=\"body\" />\r\n </lib-disabled-container>\r\n }\r\n @case (inputTypesEnum.TOGGLE) {\r\n <div class=\"flex justify-center items-center p-4\">\r\n <p-togglebutton [formControl]=\"localControl\" [onLabel]=\"toggleConfig?.onLabel || 'Si'\"\r\n [offLabel]=\"toggleConfig?.offLabel || 'No'\" class=\"custom-toggle\" />\r\n </div>\r\n }\r\n @case (inputTypesEnum.MULTISELECT) {\r\n <p-multiselect [filter]=\"true\" [options]=\"multiSelectConfig?.options\" [formControl]=\"localControl\"\r\n [optionLabel]=\"multiSelectConfig?.optionLabel ?? 'name'\" placeholder=\"\" [maxSelectedLabels]=\"3\"\r\n class=\"custom-multiselect\" appendTo=\"body\" />\r\n }\r\n @case (inputTypesEnum.SELECT) {\r\n <p-select [filter]=\"true\" [options]=\"selectConfig?.options\" [formControl]=\"localControl\"\r\n [optionLabel]=\"selectConfig?.optionLabel ?? 'name'\" placeholder=\"\" class=\"custom-select\"\r\n (onChange)=\"onSelectChange()\" appendTo=\"body\" [disabled]=\"readonly\" [readonly]=\"readonly\" [styleClass]=\"\r\n (localControl.invalid && (localControl.dirty || localControl.touched) ? 'border-red-500 focus:ring-red-500 ' : '') +\r\n (readonly ? 'bg-gray-100 cursor-not-allowed' : '')\r\n \" />\r\n }\r\n \r\n @case (inputTypesEnum.CHECKBOX) {\r\n <div class=\"flex justify-center items-center p-4\">\r\n <input [id]=\"generateUniqueId(name)\" [readOnly]=\"readonly\" [type]=\"typeInput\" [checked]=\"localControl.value\"\r\n (change)=\"onCheckboxChange($event, localControl)\"\r\n class=\"custom-checkbox h-5 w-5 border-2 border-gray-300 dark:border-transparent rounded focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-700 transition-all duration-200\"\r\n [formControl]=\"localControl\" />\r\n </div>\r\n }\r\n @case (inputTypesEnum.OTP) {\r\n <div class=\"flex justify-center items-center p-4\">\r\n <p-inputotp [id]=\"generateUniqueId(name)\" (onBlur)=\"onTouched()\" [mask]=\"controlData().otpConfig?.mask ?? false\"\r\n [length]=\"controlData().otpConfig?.length ?? 6\" [integerOnly]=\"controlData().otpConfig?.integerOnly ?? false\"\r\n class=\"custom-otp border-2 border-gray-300 dark:border-transparent rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-700 transition-all duration-200\"\r\n [formControl]=\"localControl\" />\r\n </div>\r\n }\r\n @case (inputTypesEnum.SWITCH) {\r\n <div class=\"flex justify-center items-center p-4\">\r\n <p-toggleswitch [id]=\"generateUniqueId(name)\" [formControl]=\"localControl\" [readonly]=\"readonly\" [disabled]=\"readonly\"\r\n class=\"custom-switch border-2 border-gray-300 dark:border-transparent rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-700 transition-all duration-200\"\r\n (change)=\"onCheckboxChange($event, localControl)\">\r\n <ng-template #handle let-checked=\"checked\">\r\n <span class=\"text-xs bg-gray-100 dark:bg-gray-600 text-gray-800 dark:text-gray-200 rounded-full px-1\">\r\n @if (checked) {\r\n Si\r\n }\r\n @else {\r\n No\r\n }\r\n </span>\r\n </ng-template>\r\n </p-toggleswitch>\r\n </div>\r\n }\r\n @case (inputTypesEnum.DECIMAL) {\r\n <p-inputnumber [autofocus]=\"autoFocus ?? false\" [formControl]=\"localControl\" (onBlur)=\"onBlur()\" (blur)=\"onTouched()\" [id]=\"generateUniqueId(name)\" mode=\"decimal\"\r\n (onFocus)=\"onFocus()\"\r\n [locale]=\"'es-CO'\" [minFractionDigits]=\"decimalConfig?.minFractionDigits ?? 2\" [maxFractionDigits]=\"decimalConfig?.maxFractionDigits ?? 2\" [useGrouping]=\"decimalConfig?.useGrouping ?? true\" [readonly]=\"readonly\" [disabled]=\"readonly\" />\r\n }\r\n @case (inputTypesEnum.TEXTAREA) {\r\n <textarea pTextarea [formControl]=\"localControl\" [rows]=\"textareaConfig?.rows ?? 3\"\r\n [cols]=\"textareaConfig?.cols ?? 30\" [autoResize]=\"true\" [variant]=\"textareaConfig?.variant ?? 'outlined'\"\r\n (blur)=\"onTouched()\" [id]=\"generateUniqueId(name)\" [readonly]=\"readonly\" autocomplete=\"off\" autocorrect=\"off\"\r\n autocapitalize=\"off\" spellcheck=\"false\"\r\n class=\"custom-textarea w-full px-3 py-2 border border-gray-300 dark:border-transparent rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100\"></textarea>\r\n }\r\n @default {\r\n <input [formControl]=\"localControl\" (blur)=\"onTouched()\" pInputText [id]=\"generateUniqueId(name)\" [type]=\"typeInput\"\r\n [readOnly]=\"readonly\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" [ngClass]=\"{\r\n 'border-red-500 focus:ring-red-500':\r\n localControl.invalid &&\r\n (localControl.dirty || localControl.touched),\r\n 'bg-gray-100 cursor-not-allowed': readonly,\r\n }\"\r\n class=\"custom-input h-12 w-full px-3 py-2 border border-gray-300 dark:border-transparent rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100\" />\r\n }\r\n }\r\n </lib-disabled-container>\r\n\r\n</div>\r\n\r\n@if (localControl.invalid && !hasControlValue()) {\r\n<div class=\"custom-error mt-1 text-sm text-red-600 dark:text-red-400\">\r\n @if (localControl.errors?.[\"required\"]) {\r\n <span style=\"font-size: 0.675rem; font-style: italic; letter-spacing: 0.02em;\">{{\r\n 'El campo es requerido' }}</span>\r\n }\r\n @if (localControl.errors?.[\"min\"]) {\r\n <span style=\"font-size: 0.675rem; font-style: italic; letter-spacing: 0.02em;\">{{ 'El valor m\u00EDnimo es de ' +\r\n localControl.errors?.[\"min\"].min.toFixed(2) }}</span>\r\n }\r\n @if (localControl.errors?.[\"max\"]) {\r\n <span style=\"font-size: 0.675rem; font-style: italic; letter-spacing: 0.02em;\">{{ 'El valor m\u00E1ximo es de ' +\r\n localControl.errors?.[\"max\"].max.toFixed(2) }}</span>\r\n }\r\n @if (localControl.errors?.[\"minlength\"]) {\r\n <span style=\"font-size: 0.675rem; font-style: italic; letter-spacing: 0.02em;\">{{\r\n 'El largo m\u00EDnimo es de ' + localControl.errors?.[\"minlength\"].requiredLength\r\n }}</span>\r\n }\r\n @if (localControl.errors?.[\"maxlength\"]) {\r\n <span style=\"font-size: 0.675rem; font-style: italic; letter-spacing: 0.02em;\">{{\r\n 'El largo m\u00E1ximo es de ' + localControl.errors?.[\"maxlength\"].requiredLength\r\n }}</span>\r\n }\r\n @if (localControl.errors?.[\"email\"]) {\r\n <span style=\"font-size: 0.675rem; font-style: italic; letter-spacing: 0.02em;\">{{\r\n 'El correo electr\u00F3nico no es v\u00E1lido' }}</span>\r\n }\r\n @if (localControl.errors?.[\"pattern\"]) {\r\n <span style=\"font-size: 0.675rem; font-style: italic; letter-spacing: 0.02em;\">{{\r\n 'El formato no es v\u00E1lido' }}</span>\r\n }\r\n</div>\r\n}", styles: ["@charset \"UTF-8\";:host ::ng-deep p-datepicker>span>.p-inputtext{width:100%;border-radius:.5rem;outline:none;background-color:#f9fafb;height:44px;padding-right:2.5rem;color:#111827;transition:all .2s ease-in-out}:host ::ng-deep p-datepicker>.p-datepicker>.p-inputtext{background:transparent;color:#111827;height:44px;transition:all .2s ease-in-out}:host ::ng-deep .my-app-dark p-datepicker>.p-datepicker>.p-inputtext{background:transparent;background-color:#374151;color:#f3f4f6}:host ::ng-deep p-datepicker>span{width:100%;position:relative;display:inline-flex}:host ::ng-deep p-datepicker .p-datepicker-trigger{position:absolute!important;right:0!important;top:0!important;height:44px!important;width:2.5rem!important;background:transparent!important;border:none!important;box-shadow:none!important;color:#6b7280!important;display:flex!important;align-items:center!important;justify-content:center!important;z-index:1!important}:host ::ng-deep .my-app-dark p-datepicker .p-datepicker-trigger{color:#9ca3af!important}:host ::ng-deep p-datepicker .p-datepicker-trigger .p-button-icon{font-size:.875rem}:host ::ng-deep p-multiselect{border:1px solid #d1d5db;background:transparent;color:#111827;height:44px;width:100%;border-radius:.5rem;transition:all .2s ease-in-out}:host ::ng-deep .my-app-dark p-multiselect{background:transparent;color:#f3f4f6}:host ::ng-deep p-select{background:transparent;color:#111827;height:44px;width:100%;border-radius:.5rem;transition:all .2s ease-in-out}:host ::ng-deep .my-app-dark p-select{background:transparent;color:#f3f4f6}:host ::ng-deep p-select>.p-select-label{font-size:small;position:relative}:host ::ng-deep p-inputnumber{background:transparent;color:#111827;height:44px;width:100%;border:1px solid #d1d5db;border-radius:.5rem;transition:all .2s ease-in-out}:host ::ng-deep .my-app-dark p-inputnumber{background:transparent;color:#f3f4f6}:host-context(.my-app-dark) ::ng-deep .custom-datepicker>.p-inputwrapper>.p-inputtext{color:#f3f4f6;background-color:#374151}:host-context(.my-app-dark) ::ng-deep p-datepicker>span>.p-inputtext{background-color:#374151;color:#f3f4f6}:host-context(.my-app-dark) ::ng-deep .p-inputtext{background-color:#374151;color:#f3f4f6;border-color:transparent}:host-context(.my-app-dark) ::ng-deep .p-inputnumber-input{background-color:#374151;color:#f3f4f6;border-color:transparent}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: IftaLabelModule }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i2.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "style", "styleClass", "inputStyle", "inputId", "name", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "disabled", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "fluid", "icon", "appendTo", "readonlyInput", "shortYearCutoff", "monthNavigator", "yearNavigator", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "required", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "variant", "size", "minDate", "maxDate", "disabledDates", "disabledDays", "yearRange", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "locale", "view", "defaultDate"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i3.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "style", "styleClass", "panelStyle", "panelStyleClass", "inputId", "disabled", "fluid", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "variant", "appendTo", "dataKey", "name", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "size", "showClear", "autofocus", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "defaultLabel", "placeholder", "options", "filterValue", "itemSize", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i4.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "size", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: ToggleButtonModule }, { kind: "component", type: i5.ToggleButton, selector: "p-toggleButton, p-togglebutton, p-toggle-button", inputs: ["onLabel", "offLabel", "onIcon", "offIcon", "ariaLabel", "ariaLabelledBy", "disabled", "style", "styleClass", "inputId", "tabindex", "size", "iconPos", "autofocus", "allowEmpty"], outputs: ["onChange"] }, { kind: "ngmodule", type: InputOtpModule }, { kind: "component", type: i6.InputOtp, selector: "p-inputOtp, p-inputotp, p-input-otp", inputs: ["invalid", "disabled", "readonly", "variant", "tabindex", "length", "styleClass", "mask", "integerOnly", "autofocus", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: ToggleSwitchModule }, { kind: "component", type: i7.ToggleSwitch, selector: "p-toggleswitch, p-toggleSwitch, p-toggle-switch", inputs: ["style", "styleClass", "tabindex", "inputId", "name", "disabled", "readonly", "trueValue", "falseValue", "ariaLabel", "ariaLabelledBy", "autofocus"], outputs: ["onChange"] }, { kind: "ngmodule", type: InputNumberModule }, { kind: "component", type: i8.InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "style", "placeholder", "size", "maxlength", "tabindex", "title", "ariaLabelledBy", "ariaDescribedBy", "ariaLabel", "ariaRequired", "name", "required", "autocomplete", "min", "max", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "step", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "variant", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus", "disabled", "fluid"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "ngmodule", type: TextareaModule }, { kind: "directive", type: i9.Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["autoResize", "variant", "fluid", "pSize"], outputs: ["onResize"] }, { kind: "component", type: DisabledContainerComponent, selector: "lib-disabled-container", inputs: ["disabled"], outputs: ["disabledChange"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i10.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
278
+ }
279
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CustomInputComponent, decorators: [{
280
+ type: Component,
281
+ args: [{ selector: 'lib-custom-input', imports: [
282
+ ReactiveFormsModule,
283
+ IftaLabelModule,
284
+ NgClass,
285
+ DatePickerModule,
286
+ CheckboxModule,
287
+ MultiSelectModule,
288
+ SelectModule,
289
+ ToggleButtonModule,
290
+ InputOtpModule,
291
+ ToggleSwitchModule,
292
+ InputNumberModule,
293
+ TextareaModule,
294
+ DisabledContainerComponent,
295
+ TooltipModule,
296
+ ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [{
297
+ provide: NG_VALUE_ACCESSOR,
298
+ useExisting: forwardRef(() => CustomInputComponent),
299
+ multi: true
300
+ }], template: "@let localControl = controlData().control;\r\n@let placeholder = controlData().label || controlUpperName();\r\n@let name = controlData().controlName;\r\n@let typeInput = controlData().typeInput;\r\n@let readonly = controlData().readonly || false;\r\n@let dateConfig = controlData().dateConfig;\r\n@let multiSelectConfig = controlData().multiSelectConfig;\r\n@let selectConfig = controlData().selectConfig;\r\n@let toggleConfig = controlData().toggleConfig;\r\n@let textareaConfig = controlData().textareaConfig;\r\n@let currencyConfig = controlData().currencyConfig;\r\n@let decimalConfig = controlData().decimalConfig;\r\n@let autoFocus = controlData().autoFocus ?? false;\r\n<div class=\"flex flex-col gap-1 \">\r\n <lib-disabled-container [disabled]=\"readonly\">\r\n\r\n <p style=\"font-size: 12px; letter-spacing: 0.5px;\" class=\"text-sm text-gray-600 dark:text-gray-300 truncate\"\r\n [pTooltip]=\"placeholder\" tooltipPosition=\"top\" [showDelay]=\"300\">\r\n {{ placeholder }}\r\n </p>\r\n @switch (typeInput) {\r\n @case (inputTypesEnum.EMAIL_PASSWORD) {\r\n <input [formControl]=\"localControl\" (blur)=\"onTouched()\" pInputText [id]=\"generateUniqueId(name)\" [name]=\"name\"\r\n type=\"email\" [readOnly]=\"readonly\" autocomplete=\"email\" autocorrect=\"on\" autocapitalize=\"on\"\r\n spellcheck=\"true\" [ngClass]=\"{\r\n 'border-red-500 focus:ring-red-500':\r\n localControl.invalid &&\r\n (localControl.dirty || localControl.touched),\r\n 'bg-gray-100 cursor-not-allowed': readonly,\r\n }\"\r\n class=\"custom-input h-12 w-full px-3 py-2 border border-gray-300 dark:border-transparent rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100\" />\r\n <input type=\"password\" name=\"password\" id=\"password-autofill-helper\" autocomplete=\"current-password\" tabindex=\"-1\"\r\n style=\"position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0;\"\r\n aria-hidden=\"true\"\r\n (input)=\"onPasswordAutofill($event)\" />\r\n }\r\n @case (inputTypesEnum.PASSWORD) {\r\n <!-- Input oculto siempre de tipo password para el autocompletado del navegador -->\r\n <input \r\n type=\"password\" \r\n name=\"password-autofill\"\r\n [id]=\"'password-autofill-hidden-' + generateUniqueId(name)\"\r\n autocomplete=\"current-password\" \r\n tabindex=\"-1\"\r\n style=\"position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0;\"\r\n aria-hidden=\"true\"\r\n [value]=\"localControl.value || ''\"\r\n (input)=\"onPasswordAutofillHidden($event)\" />\r\n <div class=\"relative\">\r\n <input [readOnly]=\"readonly || false\" [id]=\"generateUniqueId(name)\" [type]=\"showPassword ? 'text' : 'password'\"\r\n autocomplete=\"password\" autocorrect=\"on\" autocapitalize=\"on\" spellcheck=\"true\"\r\n class=\"custom-password w-full px-3 py-2 border border-gray-300 dark:border-transparent rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 transition-all duration-200\"\r\n aria-describedby=\"password-help\" [formControl]=\"localControl\" \r\n (input)=\"syncPasswordAutofill($event)\" />\r\n <button type=\"button\"\r\n class=\"custom-password-toggle absolute inset-y-0 right-0 flex items-center justify-center w-12 h-full text-gray-400 transition-colors duration-200 ease-in-out hover:text-gray-600 focus:outline-none focus:text-gray-600 active:text-gray-700 dark:text-gray-500 dark:hover:text-gray-300 dark:focus:text-gray-300\"\r\n (click)=\"togglePasswordVisibility()\" [attr.aria-label]=\"\r\n showPassword ? 'Ocultar contrase\u00F1a' : 'Mostrar contrase\u00F1a'\r\n \">\r\n <i class=\"fas text-lg transition-all duration-200 ease-in-out\" [ngClass]=\"{\r\n 'fa-solid fa-eye': !showPassword,\r\n 'fa-solid fa-eye-slash': showPassword,\r\n }\"></i>\r\n </button>\r\n </div>\r\n }\r\n @case (inputTypesEnum.EMAIL) {\r\n <input [formControl]=\"localControl\" (blur)=\"onTouched()\" pInputText [id]=\"generateUniqueId(name)\" [name]=\"name\"\r\n [type]=\"typeInput\" [readOnly]=\"readonly\" autocomplete=\"email\" autocorrect=\"on\" autocapitalize=\"on\" spellcheck=\"true\"\r\n [ngClass]=\"{\r\n 'border-red-500 focus:ring-red-500':\r\n localControl.invalid &&\r\n (localControl.dirty || localControl.touched),\r\n 'bg-gray-100 cursor-not-allowed': readonly,\r\n }\"\r\n class=\"custom-input h-12 w-full px-3 py-2 border border-gray-300 dark:border-transparent rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100\" />\r\n }\r\n @case (inputTypesEnum.CURRENCY) {\r\n <p-inputnumber [autofocus]=\"autoFocus ?? false\" [formControl]=\"localControl\" (onFocus)=\"onFocus()\" (onBlur)=\"onBlur()\" (blur)=\"onTouched()\" [id]=\"generateUniqueId(name)\" mode=\"currency\"\r\n [currency]=\"currencyConfig?.currency ?? 'USD'\" [locale]=\"currencyConfig?.locale ?? 'es-CO'\" [minFractionDigits]=\"currencyConfig?.minFractionDigits ?? 2\"\r\n [maxFractionDigits]=\"currencyConfig?.maxFractionDigits ?? 2\" [readonly]=\"readonly\" [disabled]=\"readonly\" />\r\n }\r\n @case (inputTypesEnum.DATE) {\r\n <lib-disabled-container [disabled]=\"readonly\">\r\n <p-datepicker [formControl]=\"localControl\" [selectionMode]=\"dateConfig?.selectionMode || 'single'\"\r\n [maxDate]=\"dateConfig?.maxDate || null\" [minDate]=\"dateConfig?.minDate || null\" dateFormat=\"dd/mm/yy\"\r\n class=\"custom-datepicker\" appendTo=\"body\" />\r\n </lib-disabled-container>\r\n }\r\n @case (inputTypesEnum.TOGGLE) {\r\n <div class=\"flex justify-center items-center p-4\">\r\n <p-togglebutton [formControl]=\"localControl\" [onLabel]=\"toggleConfig?.onLabel || 'Si'\"\r\n [offLabel]=\"toggleConfig?.offLabel || 'No'\" class=\"custom-toggle\" />\r\n </div>\r\n }\r\n @case (inputTypesEnum.MULTISELECT) {\r\n <p-multiselect [filter]=\"true\" [options]=\"multiSelectConfig?.options\" [formControl]=\"localControl\"\r\n [optionLabel]=\"multiSelectConfig?.optionLabel ?? 'name'\" placeholder=\"\" [maxSelectedLabels]=\"3\"\r\n class=\"custom-multiselect\" appendTo=\"body\" />\r\n }\r\n @case (inputTypesEnum.SELECT) {\r\n <p-select [filter]=\"true\" [options]=\"selectConfig?.options\" [formControl]=\"localControl\"\r\n [optionLabel]=\"selectConfig?.optionLabel ?? 'name'\" placeholder=\"\" class=\"custom-select\"\r\n (onChange)=\"onSelectChange()\" appendTo=\"body\" [disabled]=\"readonly\" [readonly]=\"readonly\" [styleClass]=\"\r\n (localControl.invalid && (localControl.dirty || localControl.touched) ? 'border-red-500 focus:ring-red-500 ' : '') +\r\n (readonly ? 'bg-gray-100 cursor-not-allowed' : '')\r\n \" />\r\n }\r\n \r\n @case (inputTypesEnum.CHECKBOX) {\r\n <div class=\"flex justify-center items-center p-4\">\r\n <input [id]=\"generateUniqueId(name)\" [readOnly]=\"readonly\" [type]=\"typeInput\" [checked]=\"localControl.value\"\r\n (change)=\"onCheckboxChange($event, localControl)\"\r\n class=\"custom-checkbox h-5 w-5 border-2 border-gray-300 dark:border-transparent rounded focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-700 transition-all duration-200\"\r\n [formControl]=\"localControl\" />\r\n </div>\r\n }\r\n @case (inputTypesEnum.OTP) {\r\n <div class=\"flex justify-center items-center p-4\">\r\n <p-inputotp [id]=\"generateUniqueId(name)\" (onBlur)=\"onTouched()\" [mask]=\"controlData().otpConfig?.mask ?? false\"\r\n [length]=\"controlData().otpConfig?.length ?? 6\" [integerOnly]=\"controlData().otpConfig?.integerOnly ?? false\"\r\n class=\"custom-otp border-2 border-gray-300 dark:border-transparent rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-700 transition-all duration-200\"\r\n [formControl]=\"localControl\" />\r\n </div>\r\n }\r\n @case (inputTypesEnum.SWITCH) {\r\n <div class=\"flex justify-center items-center p-4\">\r\n <p-toggleswitch [id]=\"generateUniqueId(name)\" [formControl]=\"localControl\" [readonly]=\"readonly\" [disabled]=\"readonly\"\r\n class=\"custom-switch border-2 border-gray-300 dark:border-transparent rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-700 transition-all duration-200\"\r\n (change)=\"onCheckboxChange($event, localControl)\">\r\n <ng-template #handle let-checked=\"checked\">\r\n <span class=\"text-xs bg-gray-100 dark:bg-gray-600 text-gray-800 dark:text-gray-200 rounded-full px-1\">\r\n @if (checked) {\r\n Si\r\n }\r\n @else {\r\n No\r\n }\r\n </span>\r\n </ng-template>\r\n </p-toggleswitch>\r\n </div>\r\n }\r\n @case (inputTypesEnum.DECIMAL) {\r\n <p-inputnumber [autofocus]=\"autoFocus ?? false\" [formControl]=\"localControl\" (onBlur)=\"onBlur()\" (blur)=\"onTouched()\" [id]=\"generateUniqueId(name)\" mode=\"decimal\"\r\n (onFocus)=\"onFocus()\"\r\n [locale]=\"'es-CO'\" [minFractionDigits]=\"decimalConfig?.minFractionDigits ?? 2\" [maxFractionDigits]=\"decimalConfig?.maxFractionDigits ?? 2\" [useGrouping]=\"decimalConfig?.useGrouping ?? true\" [readonly]=\"readonly\" [disabled]=\"readonly\" />\r\n }\r\n @case (inputTypesEnum.TEXTAREA) {\r\n <textarea pTextarea [formControl]=\"localControl\" [rows]=\"textareaConfig?.rows ?? 3\"\r\n [cols]=\"textareaConfig?.cols ?? 30\" [autoResize]=\"true\" [variant]=\"textareaConfig?.variant ?? 'outlined'\"\r\n (blur)=\"onTouched()\" [id]=\"generateUniqueId(name)\" [readonly]=\"readonly\" autocomplete=\"off\" autocorrect=\"off\"\r\n autocapitalize=\"off\" spellcheck=\"false\"\r\n class=\"custom-textarea w-full px-3 py-2 border border-gray-300 dark:border-transparent rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100\"></textarea>\r\n }\r\n @default {\r\n <input [formControl]=\"localControl\" (blur)=\"onTouched()\" pInputText [id]=\"generateUniqueId(name)\" [type]=\"typeInput\"\r\n [readOnly]=\"readonly\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" [ngClass]=\"{\r\n 'border-red-500 focus:ring-red-500':\r\n localControl.invalid &&\r\n (localControl.dirty || localControl.touched),\r\n 'bg-gray-100 cursor-not-allowed': readonly,\r\n }\"\r\n class=\"custom-input h-12 w-full px-3 py-2 border border-gray-300 dark:border-transparent rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all duration-200 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100\" />\r\n }\r\n }\r\n </lib-disabled-container>\r\n\r\n</div>\r\n\r\n@if (localControl.invalid && !hasControlValue()) {\r\n<div class=\"custom-error mt-1 text-sm text-red-600 dark:text-red-400\">\r\n @if (localControl.errors?.[\"required\"]) {\r\n <span style=\"font-size: 0.675rem; font-style: italic; letter-spacing: 0.02em;\">{{\r\n 'El campo es requerido' }}</span>\r\n }\r\n @if (localControl.errors?.[\"min\"]) {\r\n <span style=\"font-size: 0.675rem; font-style: italic; letter-spacing: 0.02em;\">{{ 'El valor m\u00EDnimo es de ' +\r\n localControl.errors?.[\"min\"].min.toFixed(2) }}</span>\r\n }\r\n @if (localControl.errors?.[\"max\"]) {\r\n <span style=\"font-size: 0.675rem; font-style: italic; letter-spacing: 0.02em;\">{{ 'El valor m\u00E1ximo es de ' +\r\n localControl.errors?.[\"max\"].max.toFixed(2) }}</span>\r\n }\r\n @if (localControl.errors?.[\"minlength\"]) {\r\n <span style=\"font-size: 0.675rem; font-style: italic; letter-spacing: 0.02em;\">{{\r\n 'El largo m\u00EDnimo es de ' + localControl.errors?.[\"minlength\"].requiredLength\r\n }}</span>\r\n }\r\n @if (localControl.errors?.[\"maxlength\"]) {\r\n <span style=\"font-size: 0.675rem; font-style: italic; letter-spacing: 0.02em;\">{{\r\n 'El largo m\u00E1ximo es de ' + localControl.errors?.[\"maxlength\"].requiredLength\r\n }}</span>\r\n }\r\n @if (localControl.errors?.[\"email\"]) {\r\n <span style=\"font-size: 0.675rem; font-style: italic; letter-spacing: 0.02em;\">{{\r\n 'El correo electr\u00F3nico no es v\u00E1lido' }}</span>\r\n }\r\n @if (localControl.errors?.[\"pattern\"]) {\r\n <span style=\"font-size: 0.675rem; font-style: italic; letter-spacing: 0.02em;\">{{\r\n 'El formato no es v\u00E1lido' }}</span>\r\n }\r\n</div>\r\n}", styles: ["@charset \"UTF-8\";:host ::ng-deep p-datepicker>span>.p-inputtext{width:100%;border-radius:.5rem;outline:none;background-color:#f9fafb;height:44px;padding-right:2.5rem;color:#111827;transition:all .2s ease-in-out}:host ::ng-deep p-datepicker>.p-datepicker>.p-inputtext{background:transparent;color:#111827;height:44px;transition:all .2s ease-in-out}:host ::ng-deep .my-app-dark p-datepicker>.p-datepicker>.p-inputtext{background:transparent;background-color:#374151;color:#f3f4f6}:host ::ng-deep p-datepicker>span{width:100%;position:relative;display:inline-flex}:host ::ng-deep p-datepicker .p-datepicker-trigger{position:absolute!important;right:0!important;top:0!important;height:44px!important;width:2.5rem!important;background:transparent!important;border:none!important;box-shadow:none!important;color:#6b7280!important;display:flex!important;align-items:center!important;justify-content:center!important;z-index:1!important}:host ::ng-deep .my-app-dark p-datepicker .p-datepicker-trigger{color:#9ca3af!important}:host ::ng-deep p-datepicker .p-datepicker-trigger .p-button-icon{font-size:.875rem}:host ::ng-deep p-multiselect{border:1px solid #d1d5db;background:transparent;color:#111827;height:44px;width:100%;border-radius:.5rem;transition:all .2s ease-in-out}:host ::ng-deep .my-app-dark p-multiselect{background:transparent;color:#f3f4f6}:host ::ng-deep p-select{background:transparent;color:#111827;height:44px;width:100%;border-radius:.5rem;transition:all .2s ease-in-out}:host ::ng-deep .my-app-dark p-select{background:transparent;color:#f3f4f6}:host ::ng-deep p-select>.p-select-label{font-size:small;position:relative}:host ::ng-deep p-inputnumber{background:transparent;color:#111827;height:44px;width:100%;border:1px solid #d1d5db;border-radius:.5rem;transition:all .2s ease-in-out}:host ::ng-deep .my-app-dark p-inputnumber{background:transparent;color:#f3f4f6}:host-context(.my-app-dark) ::ng-deep .custom-datepicker>.p-inputwrapper>.p-inputtext{color:#f3f4f6;background-color:#374151}:host-context(.my-app-dark) ::ng-deep p-datepicker>span>.p-inputtext{background-color:#374151;color:#f3f4f6}:host-context(.my-app-dark) ::ng-deep .p-inputtext{background-color:#374151;color:#f3f4f6;border-color:transparent}:host-context(.my-app-dark) ::ng-deep .p-inputnumber-input{background-color:#374151;color:#f3f4f6;border-color:transparent}\n"] }]
301
+ }], ctorParameters: () => [] });
302
+
303
+ class FormChildComponent {
304
+ controlsData = input.required();
305
+ formGroup = input.required();
306
+ formSubmit = output();
307
+ constructor() {
308
+ }
309
+ submit() {
310
+ this.formSubmit.emit(this.formGroup());
311
+ }
312
+ onSelectChange(controlConfig) {
313
+ controlConfig.selectConfig?.change?.(controlConfig);
314
+ }
315
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormChildComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
316
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: FormChildComponent, isStandalone: true, selector: "lib-form-child", inputs: { controlsData: { classPropertyName: "controlsData", publicName: "controlsData", isSignal: true, isRequired: true, transformFunction: null }, formGroup: { classPropertyName: "formGroup", publicName: "formGroup", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { formSubmit: "formSubmit" }, ngImport: i0, template: "@let controls = controlsData();\r\n\r\n<form\r\n [formGroup]=\"formGroup()\"\r\n (submit)=\"submit()\"\r\n autocomplete=\"off\"\r\n class=\"grid grid-cols-12 gap-3\"\r\n>\r\n @for (controlData of controls; track controlData.controlName) {\r\n <div\r\n class=\"flex flex-col w-full\"\r\n [ngClass]=\"{\r\n 'col-span-1': !controlData.colSpan,\r\n 'col-span-2': controlData.colSpan === 2,\r\n 'col-span-3': controlData.colSpan === 3,\r\n 'col-span-4': controlData.colSpan === 4,\r\n 'col-span-5': controlData.colSpan === 5,\r\n 'col-span-6': controlData.colSpan === 6,\r\n 'col-span-7': controlData.colSpan === 7,\r\n 'col-span-8': controlData.colSpan === 8,\r\n 'col-span-9': controlData.colSpan === 9,\r\n 'col-span-10': controlData.colSpan === 10,\r\n 'col-span-11': controlData.colSpan === 11,\r\n 'col-span-12': controlData.colSpan === 12,\r\n }\"\r\n >\r\n <lib-custom-input\r\n [id]=\"controlData.controlName\"\r\n [controlData]=\"controlData\"\r\n [formControlName]=\"controlData.controlName\"\r\n class=\"w-full\"\r\n (output)=\"onSelectChange($event)\"\r\n >\r\n </lib-custom-input>\r\n </div>\r\n }\r\n</form>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: CustomInputComponent, selector: "lib-custom-input", inputs: ["controlData"], outputs: ["output"] }] });
317
+ }
318
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormChildComponent, decorators: [{
319
+ type: Component,
320
+ args: [{ selector: 'lib-form-child', imports: [
321
+ ReactiveFormsModule,
322
+ CommonModule,
323
+ CustomInputComponent
324
+ ], template: "@let controls = controlsData();\r\n\r\n<form\r\n [formGroup]=\"formGroup()\"\r\n (submit)=\"submit()\"\r\n autocomplete=\"off\"\r\n class=\"grid grid-cols-12 gap-3\"\r\n>\r\n @for (controlData of controls; track controlData.controlName) {\r\n <div\r\n class=\"flex flex-col w-full\"\r\n [ngClass]=\"{\r\n 'col-span-1': !controlData.colSpan,\r\n 'col-span-2': controlData.colSpan === 2,\r\n 'col-span-3': controlData.colSpan === 3,\r\n 'col-span-4': controlData.colSpan === 4,\r\n 'col-span-5': controlData.colSpan === 5,\r\n 'col-span-6': controlData.colSpan === 6,\r\n 'col-span-7': controlData.colSpan === 7,\r\n 'col-span-8': controlData.colSpan === 8,\r\n 'col-span-9': controlData.colSpan === 9,\r\n 'col-span-10': controlData.colSpan === 10,\r\n 'col-span-11': controlData.colSpan === 11,\r\n 'col-span-12': controlData.colSpan === 12,\r\n }\"\r\n >\r\n <lib-custom-input\r\n [id]=\"controlData.controlName\"\r\n [controlData]=\"controlData\"\r\n [formControlName]=\"controlData.controlName\"\r\n class=\"w-full\"\r\n (output)=\"onSelectChange($event)\"\r\n >\r\n </lib-custom-input>\r\n </div>\r\n }\r\n</form>\r\n" }]
325
+ }], ctorParameters: () => [] });
326
+
327
+ class HttpMessageComponent {
328
+ httpMessage = model();
329
+ clearMessage() {
330
+ this.httpMessage.set(undefined);
331
+ }
332
+ get isError() {
333
+ const message = this.httpMessage();
334
+ return message?.type === 'error';
335
+ }
336
+ get isSuccess() {
337
+ const message = this.httpMessage();
338
+ return message?.type === 'success';
339
+ }
340
+ get isWarning() {
341
+ const message = this.httpMessage();
342
+ return message?.type === 'warning';
343
+ }
344
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: HttpMessageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
345
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: HttpMessageComponent, isStandalone: true, selector: "lib-http-message", inputs: { httpMessage: { classPropertyName: "httpMessage", publicName: "httpMessage", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { httpMessage: "httpMessageChange" }, ngImport: i0, template: "@if (httpMessage()) {\r\n @if (isError) {\r\n <div class=\"group relative mt-3 p-3 rounded-lg bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 transition-all duration-200 hover:shadow-md\">\r\n <div class=\"flex items-start gap-2\">\r\n <svg class=\"w-5 h-5 text-red-500 dark:text-red-400 flex-shrink-0 mt-0.5\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\r\n <path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z\" clip-rule=\"evenodd\" />\r\n </svg>\r\n <p class=\"flex-1 text-red-700 dark:text-red-300 text-sm font-medium leading-relaxed\">\r\n {{ httpMessage()?.message }}\r\n </p>\r\n <button\r\n type=\"button\"\r\n (click)=\"clearMessage()\"\r\n class=\"opacity-0 group-hover:opacity-100 transition-opacity duration-200 text-red-500 dark:text-red-400 hover:text-red-700 dark:hover:text-red-200 p-1 rounded hover:bg-red-100 dark:hover:bg-red-800/30\"\r\n aria-label=\"Cerrar mensaje de error\"\r\n >\r\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n @if (isSuccess) {\r\n <div class=\"group relative mt-3 p-3 rounded-lg bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 transition-all duration-200 hover:shadow-md\">\r\n <div class=\"flex items-start gap-2\">\r\n <svg class=\"w-5 h-5 text-green-500 dark:text-green-400 flex-shrink-0 mt-0.5\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\r\n <path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\" clip-rule=\"evenodd\" />\r\n </svg>\r\n <p class=\"flex-1 text-green-700 dark:text-green-300 text-sm font-medium leading-relaxed\">\r\n {{ httpMessage()?.message }}\r\n </p>\r\n <button\r\n type=\"button\"\r\n (click)=\"clearMessage()\"\r\n class=\"opacity-0 group-hover:opacity-100 transition-opacity duration-200 text-green-500 dark:text-green-400 hover:text-green-700 dark:hover:text-green-200 p-1 rounded hover:bg-green-100 dark:hover:bg-green-800/30\"\r\n aria-label=\"Cerrar mensaje de \u00E9xito\"\r\n >\r\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n @if (isWarning) {\r\n <div class=\"group relative mt-3 p-3 rounded-lg bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 transition-all duration-200 hover:shadow-md\">\r\n <div class=\"flex items-start gap-2\">\r\n <svg class=\"w-5 h-5 text-amber-500 dark:text-amber-400 flex-shrink-0 mt-0.5\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\r\n <path fill-rule=\"evenodd\" d=\"M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z\" clip-rule=\"evenodd\" />\r\n </svg>\r\n <p class=\"flex-1 text-amber-700 dark:text-amber-300 text-sm font-medium leading-relaxed\">\r\n {{ httpMessage()?.message }}\r\n </p>\r\n <button\r\n type=\"button\"\r\n (click)=\"clearMessage()\"\r\n class=\"opacity-0 group-hover:opacity-100 transition-opacity duration-200 text-amber-500 dark:text-amber-400 hover:text-amber-700 dark:hover:text-amber-200 p-1 rounded hover:bg-amber-100 dark:hover:bg-amber-800/30\"\r\n aria-label=\"Cerrar mensaje de advertencia\"\r\n >\r\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n}\r\n", styles: [""], changeDetection: i0.ChangeDetectionStrategy.OnPush });
346
+ }
347
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: HttpMessageComponent, decorators: [{
348
+ type: Component,
349
+ args: [{ selector: 'lib-http-message', imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (httpMessage()) {\r\n @if (isError) {\r\n <div class=\"group relative mt-3 p-3 rounded-lg bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 transition-all duration-200 hover:shadow-md\">\r\n <div class=\"flex items-start gap-2\">\r\n <svg class=\"w-5 h-5 text-red-500 dark:text-red-400 flex-shrink-0 mt-0.5\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\r\n <path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z\" clip-rule=\"evenodd\" />\r\n </svg>\r\n <p class=\"flex-1 text-red-700 dark:text-red-300 text-sm font-medium leading-relaxed\">\r\n {{ httpMessage()?.message }}\r\n </p>\r\n <button\r\n type=\"button\"\r\n (click)=\"clearMessage()\"\r\n class=\"opacity-0 group-hover:opacity-100 transition-opacity duration-200 text-red-500 dark:text-red-400 hover:text-red-700 dark:hover:text-red-200 p-1 rounded hover:bg-red-100 dark:hover:bg-red-800/30\"\r\n aria-label=\"Cerrar mensaje de error\"\r\n >\r\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n @if (isSuccess) {\r\n <div class=\"group relative mt-3 p-3 rounded-lg bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 transition-all duration-200 hover:shadow-md\">\r\n <div class=\"flex items-start gap-2\">\r\n <svg class=\"w-5 h-5 text-green-500 dark:text-green-400 flex-shrink-0 mt-0.5\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\r\n <path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\" clip-rule=\"evenodd\" />\r\n </svg>\r\n <p class=\"flex-1 text-green-700 dark:text-green-300 text-sm font-medium leading-relaxed\">\r\n {{ httpMessage()?.message }}\r\n </p>\r\n <button\r\n type=\"button\"\r\n (click)=\"clearMessage()\"\r\n class=\"opacity-0 group-hover:opacity-100 transition-opacity duration-200 text-green-500 dark:text-green-400 hover:text-green-700 dark:hover:text-green-200 p-1 rounded hover:bg-green-100 dark:hover:bg-green-800/30\"\r\n aria-label=\"Cerrar mensaje de \u00E9xito\"\r\n >\r\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n @if (isWarning) {\r\n <div class=\"group relative mt-3 p-3 rounded-lg bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 transition-all duration-200 hover:shadow-md\">\r\n <div class=\"flex items-start gap-2\">\r\n <svg class=\"w-5 h-5 text-amber-500 dark:text-amber-400 flex-shrink-0 mt-0.5\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\r\n <path fill-rule=\"evenodd\" d=\"M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z\" clip-rule=\"evenodd\" />\r\n </svg>\r\n <p class=\"flex-1 text-amber-700 dark:text-amber-300 text-sm font-medium leading-relaxed\">\r\n {{ httpMessage()?.message }}\r\n </p>\r\n <button\r\n type=\"button\"\r\n (click)=\"clearMessage()\"\r\n class=\"opacity-0 group-hover:opacity-100 transition-opacity duration-200 text-amber-500 dark:text-amber-400 hover:text-amber-700 dark:hover:text-amber-200 p-1 rounded hover:bg-amber-100 dark:hover:bg-amber-800/30\"\r\n aria-label=\"Cerrar mensaje de advertencia\"\r\n >\r\n <svg class=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n}\r\n" }]
350
+ }] });
351
+
352
+ class FormComponent {
353
+ formGroup = model.required();
354
+ controls = input.required();
355
+ formConfig = input();
356
+ httpMessage = model();
357
+ formSubmit = output();
358
+ formChanges = output();
359
+ formChangesDebounced = output();
360
+ constructor() {
361
+ effect(() => {
362
+ const controls = this.controls();
363
+ const controlsNames = this.controls().map((controlConfig) => controlConfig.controlName);
364
+ const controlsToDelete = Object.keys(this.formGroup().controls).filter(control => !controlsNames.includes(control));
365
+ controls.forEach((controlData) => {
366
+ this.formGroup.update((formGroup) => {
367
+ if (formGroup.contains(controlData.controlName)) {
368
+ formGroup.setControl(controlData.controlName, controlData.control);
369
+ }
370
+ else {
371
+ formGroup.addControl(controlData.controlName, controlData.control);
372
+ }
373
+ controlsToDelete.forEach(controlName => {
374
+ formGroup.removeControl(controlName);
375
+ });
376
+ return formGroup;
377
+ });
378
+ });
379
+ });
380
+ effect(() => {
381
+ const controlsDataTypeSelect = this.controls().filter((controlData) => controlData.typeInput === ETypeInput.SELECT);
382
+ controlsDataTypeSelect.forEach((controlData) => {
383
+ const control = this.formGroup().get(controlData.controlName);
384
+ const controlValue = control?.value;
385
+ if (controlValue) {
386
+ const options = controlData.selectConfig?.options ?? [];
387
+ const optionSelected = options.find((option) => {
388
+ return option.code === controlValue.code;
389
+ });
390
+ if (optionSelected) {
391
+ control?.setValue(optionSelected);
392
+ }
393
+ }
394
+ });
395
+ });
396
+ effect(() => {
397
+ this.formGroup().valueChanges.subscribe(() => {
398
+ this.formChanges.emit(this.formGroup());
399
+ });
400
+ });
401
+ const fg$ = toObservable(this.formGroup);
402
+ fg$.pipe(switchMap((fg) => fg.valueChanges.pipe(debounceTime(650), filter(() => this.anyInteracted(fg)), map(() => fg))), takeUntilDestroyed())
403
+ .subscribe(() => this.formChangesDebounced.emit(this.formGroup()));
404
+ }
405
+ anyInteracted(formGroup) {
406
+ return Object.values(formGroup.controls).some(control => control.touched || control.dirty);
407
+ }
408
+ submit(formGroup) {
409
+ this.formSubmit.emit(formGroup);
410
+ }
411
+ clearHttpMessage() {
412
+ this.httpMessage.set(undefined);
413
+ }
414
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
415
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: FormComponent, isStandalone: true, selector: "lib-form", inputs: { formGroup: { classPropertyName: "formGroup", publicName: "formGroup", isSignal: true, isRequired: true, transformFunction: null }, controls: { classPropertyName: "controls", publicName: "controls", isSignal: true, isRequired: true, transformFunction: null }, formConfig: { classPropertyName: "formConfig", publicName: "formConfig", isSignal: true, isRequired: false, transformFunction: null }, httpMessage: { classPropertyName: "httpMessage", publicName: "httpMessage", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { formGroup: "formGroupChange", httpMessage: "httpMessageChange", formSubmit: "formSubmit", formChanges: "formChanges", formChangesDebounced: "formChangesDebounced" }, ngImport: i0, template: "<div class=\"w-full p-2 rounded-lg\" [style.backgroundColor]=\"formConfig()?.backgroundColor || 'transparent'\">\r\n <lib-form-child [controlsData]=\"controls()\" [formGroup]=\"formGroup()\" (formSubmit)=\"submit($event)\">\r\n </lib-form-child>\r\n @if (httpMessage()) {\r\n <lib-http-message [(httpMessage)]=\"httpMessage\"></lib-http-message>\r\n }\r\n</div>", styles: [""], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: FormChildComponent, selector: "lib-form-child", inputs: ["controlsData", "formGroup"], outputs: ["formSubmit"] }, { kind: "component", type: HttpMessageComponent, selector: "lib-http-message", inputs: ["httpMessage"], outputs: ["httpMessageChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
416
+ }
417
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormComponent, decorators: [{
418
+ type: Component,
419
+ args: [{ selector: 'lib-form', imports: [
420
+ ReactiveFormsModule,
421
+ FormChildComponent,
422
+ HttpMessageComponent
423
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"w-full p-2 rounded-lg\" [style.backgroundColor]=\"formConfig()?.backgroundColor || 'transparent'\">\r\n <lib-form-child [controlsData]=\"controls()\" [formGroup]=\"formGroup()\" (formSubmit)=\"submit($event)\">\r\n </lib-form-child>\r\n @if (httpMessage()) {\r\n <lib-http-message [(httpMessage)]=\"httpMessage\"></lib-http-message>\r\n }\r\n</div>" }]
424
+ }], ctorParameters: () => [] });
425
+
426
+ /**
427
+ * Utilidades para manejar errores de API según la interfaz IApiError
428
+ */
429
+ class ApiErrorUtil {
430
+ /**
431
+ * Procesa errores de API y extrae el mensaje según la interfaz IApiError
432
+ * @param error - El error HTTP recibido
433
+ * @param fallbackMessage - Mensaje por defecto si no se puede extraer el mensaje del error
434
+ * @returns El mensaje de error procesado
435
+ */
436
+ static handleApiError(error, fallbackMessage) {
437
+ const apiError = error.error;
438
+ const errorMessage = Array.isArray(apiError?.message)
439
+ ? apiError.message.join(', ')
440
+ : apiError?.message ?? fallbackMessage;
441
+ return errorMessage;
442
+ }
443
+ /**
444
+ * Procesa errores de API con información detallada de campos
445
+ * y muestra tanto el mensaje general como los errores específicos de campo
446
+ * @param error - El error HTTP recibido
447
+ * @param fallbackMessage - Mensaje por defecto si no se puede extraer el mensaje del error
448
+ * @returns El mensaje de error procesado con información de campos si está disponible
449
+ */
450
+ static handleApiErrorWithFields(error, fallbackMessage) {
451
+ const apiError = error.error;
452
+ let errorMessage = Array.isArray(apiError?.message)
453
+ ? apiError.message.join(', ')
454
+ : apiError?.message ?? fallbackMessage;
455
+ // Si hay errores de campo específicos, los agregamos al mensaje
456
+ if (apiError?.errors && apiError.errors.length > 0) {
457
+ const fieldErrors = apiError.errors
458
+ .map(fieldError => `${fieldError.field}: ${fieldError.message}`)
459
+ .join(', ');
460
+ errorMessage = `${errorMessage}. Errores de campos: ${fieldErrors}`;
461
+ }
462
+ return errorMessage;
463
+ }
464
+ /**
465
+ * Obtiene solo los errores de campo específicos
466
+ * @param error - El error HTTP recibido
467
+ * @returns Array de errores de campo o array vacío si no hay errores
468
+ */
469
+ static getFieldErrors(error) {
470
+ const apiError = error.error;
471
+ return apiError?.errors ?? [];
472
+ }
473
+ /**
474
+ * Verifica si el error tiene errores de campo específicos
475
+ * @param error - El error HTTP recibido
476
+ * @returns true si hay errores de campo, false en caso contrario
477
+ */
478
+ static hasFieldErrors(error) {
479
+ const apiError = error.error;
480
+ return apiError?.errors && apiError.errors.length > 0;
481
+ }
482
+ /**
483
+ * Obtiene el código de error específico
484
+ * @param error - El error HTTP recibido
485
+ * @returns El código de error o undefined si no está disponible
486
+ */
487
+ static getErrorCode(error) {
488
+ const apiError = error.error;
489
+ return apiError?.errorCode;
490
+ }
491
+ /**
492
+ * Obtiene el timestamp del error
493
+ * @param error - El error HTTP recibido
494
+ * @returns El timestamp del error o undefined si no está disponible
495
+ */
496
+ static getErrorTimestamp(error) {
497
+ const apiError = error.error;
498
+ return apiError?.timestamp;
499
+ }
500
+ }
501
+
502
+ class CookieUtil {
503
+ /**
504
+ * Obtiene el valor de una cookie por su nombre
505
+ * @param name - Nombre de la cookie
506
+ * @returns El valor de la cookie o null si no existe
507
+ */
508
+ static getCookie(name) {
509
+ if (typeof document === 'undefined') {
510
+ return null;
511
+ }
512
+ const nameEQ = name + '=';
513
+ const ca = document.cookie.split(';');
514
+ for (let i = 0; i < ca.length; i++) {
515
+ let c = ca[i];
516
+ while (c.charAt(0) === ' ') {
517
+ c = c.substring(1, c.length);
518
+ }
519
+ if (c.indexOf(nameEQ) === 0) {
520
+ return c.substring(nameEQ.length, c.length);
521
+ }
522
+ }
523
+ return null;
524
+ }
525
+ /**
526
+ * Establece una cookie
527
+ * @param name - Nombre de la cookie
528
+ * @param value - Valor de la cookie
529
+ * @param days - Días hasta que expire (por defecto 365)
530
+ * @param path - Ruta de la cookie (por defecto '/')
531
+ */
532
+ static setCookie(name, value, days = 365, path = '/') {
533
+ if (typeof document === 'undefined') {
534
+ return;
535
+ }
536
+ let expires = '';
537
+ if (days) {
538
+ const date = new Date();
539
+ date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
540
+ expires = '; expires=' + date.toUTCString();
541
+ }
542
+ document.cookie = name + '=' + (value || '') + expires + '; path=' + path;
543
+ }
544
+ /**
545
+ * Elimina una cookie
546
+ * @param name - Nombre de la cookie a eliminar
547
+ * @param path - Ruta de la cookie (por defecto '/')
548
+ */
549
+ static eraseCookie(name, path = '/') {
550
+ if (typeof document === 'undefined') {
551
+ return;
552
+ }
553
+ document.cookie = name + '=; Path=' + path + '; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
554
+ }
555
+ /**
556
+ * Obtiene un valor booleano desde una cookie
557
+ * @param name - Nombre de la cookie
558
+ * @param defaultValue - Valor por defecto si la cookie no existe
559
+ * @returns El valor booleano
560
+ */
561
+ static getBooleanCookie(name, defaultValue = false) {
562
+ const value = this.getCookie(name);
563
+ if (value === null) {
564
+ return defaultValue;
565
+ }
566
+ return value === 'true';
567
+ }
568
+ /**
569
+ * Establece un valor booleano en una cookie
570
+ * @param name - Nombre de la cookie
571
+ * @param value - Valor booleano
572
+ * @param days - Días hasta que expire (por defecto 365)
573
+ * @param path - Ruta de la cookie (por defecto '/')
574
+ */
575
+ static setBooleanCookie(name, value, days = 365, path = '/') {
576
+ this.setCookie(name, value.toString(), days, path);
577
+ }
578
+ }
579
+
580
+ const formatCurrency = (amount, currency) => {
581
+ return new Intl.NumberFormat('es-CO', {
582
+ style: 'currency',
583
+ currency: currency || 'COP'
584
+ }).format(amount);
585
+ };
586
+
587
+ const isSameDay = (date1, date2) => {
588
+ const date1Copy = new Date(date1.setHours(0, 0, 0, 0));
589
+ const date2Copy = new Date(date2.setHours(0, 0, 0, 0));
590
+ return date1Copy.getTime() === date2Copy.getTime();
591
+ };
592
+ const formatDateDMA = (date) => {
593
+ return new Date(date).toLocaleDateString('es-CO', {
594
+ year: 'numeric',
595
+ month: '2-digit',
596
+ day: '2-digit'
597
+ });
598
+ };
599
+ // Crea una funcion que tambien muestre la hora
600
+ const formatDateDMAWithTime = (date) => {
601
+ return new Date(date).toLocaleDateString('es-CO', {
602
+ year: 'numeric',
603
+ month: '2-digit',
604
+ day: '2-digit',
605
+ hour: '2-digit',
606
+ minute: '2-digit'
607
+ });
608
+ };
609
+
610
+ /**
611
+ * Enum con los tipos de archivos más relevantes para la aplicación
612
+ */
613
+ var EFileType;
614
+ (function (EFileType) {
615
+ // Documentos
616
+ EFileType["PDF"] = "application/pdf";
617
+ EFileType["DOC"] = "application/msword";
618
+ EFileType["DOCX"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
619
+ EFileType["XLS"] = "application/vnd.ms-excel";
620
+ EFileType["XLSX"] = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
621
+ EFileType["PPT"] = "application/vnd.ms-powerpoint";
622
+ EFileType["PPTX"] = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
623
+ EFileType["TXT"] = "text/plain";
624
+ EFileType["RTF"] = "application/rtf";
625
+ // Imágenes
626
+ EFileType["JPG"] = "image/jpeg";
627
+ EFileType["PNG"] = "image/png";
628
+ EFileType["GIF"] = "image/gif";
629
+ EFileType["BMP"] = "image/bmp";
630
+ EFileType["SVG"] = "image/svg+xml";
631
+ EFileType["WEBP"] = "image/webp";
632
+ // Archivos comprimidos
633
+ EFileType["ZIP"] = "application/zip";
634
+ EFileType["RAR"] = "application/vnd.rar";
635
+ EFileType["TAR"] = "application/x-tar";
636
+ EFileType["GZ"] = "application/gzip";
637
+ // Archivos de datos
638
+ EFileType["CSV"] = "text/csv";
639
+ EFileType["JSON"] = "application/json";
640
+ EFileType["XML"] = "application/xml";
641
+ // Archivos de audio
642
+ EFileType["MP3"] = "audio/mpeg";
643
+ EFileType["WAV"] = "audio/wav";
644
+ EFileType["OGG"] = "audio/ogg";
645
+ // Archivos de video
646
+ EFileType["MP4"] = "video/mp4";
647
+ EFileType["AVI"] = "video/x-msvideo";
648
+ EFileType["MOV"] = "video/quicktime";
649
+ EFileType["WMV"] = "video/x-ms-wmv";
650
+ // Todos los tipos de imagen
651
+ EFileType["ALL_IMAGES"] = "image/*";
652
+ // Todos los tipos de documento
653
+ EFileType["ALL_DOCUMENTS"] = "application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation,text/plain,application/rtf";
654
+ // Todos los tipos de archivo
655
+ EFileType["ALL_FILES"] = "*/*";
656
+ })(EFileType || (EFileType = {}));
657
+ /**
658
+ * Método mejorado para abrir el selector de archivos
659
+ * @param options - Opciones para configurar el input de archivo
660
+ */
661
+ const triggerFileInput = (options = {}) => {
662
+ const { accept = EFileType.ALL_FILES, multiple = false, onFileSelected } = options;
663
+ const input = document.createElement('input');
664
+ input.type = 'file';
665
+ input.accept = accept;
666
+ input.multiple = multiple;
667
+ input.style.display = 'none';
668
+ input.onchange = (event) => {
669
+ const target = event.target;
670
+ const files = target.files;
671
+ if (files && files.length > 0 && onFileSelected) {
672
+ if (multiple) {
673
+ // Si es múltiple, llamar al callback con todos los archivos
674
+ Array.from(files).forEach(file => {
675
+ onFileSelected(file);
676
+ });
677
+ }
678
+ else {
679
+ // Si es único, llamar al callback con el primer archivo
680
+ const file = files[0];
681
+ onFileSelected(file);
682
+ }
683
+ }
684
+ document.body.removeChild(input);
685
+ };
686
+ document.body.appendChild(input);
687
+ input.click();
688
+ };
689
+ /**
690
+ * Función para capturar una foto usando la cámara
691
+ */
692
+ const capturePhotoFromCamera = async (options = {}) => {
693
+ const { quality = 0.9, facingMode = 'environment', onPhotoTaken, onError } = options;
694
+ try {
695
+ if (!navigator.mediaDevices?.getUserMedia) {
696
+ throw new Error('Cámara no soportada en este navegador');
697
+ }
698
+ const stream = await navigator.mediaDevices.getUserMedia({
699
+ video: { facingMode }
700
+ });
701
+ const video = document.createElement('video');
702
+ const canvas = document.createElement('canvas');
703
+ const context = canvas.getContext('2d');
704
+ // Crear modal
705
+ const modal = document.createElement('div');
706
+ modal.style.cssText = `
707
+ position: fixed; top: 0; left: 0; width: 100%; height: 100%;
708
+ background: rgba(0,0,0,0.9); display: flex; flex-direction: column;
709
+ align-items: center; justify-content: center; z-index: 10000;
710
+ `;
711
+ video.style.cssText = 'width: 80%; max-width: 500px; border-radius: 8px;';
712
+ video.srcObject = stream;
713
+ video.autoplay = true;
714
+ video.playsInline = true;
715
+ const buttonsDiv = document.createElement('div');
716
+ buttonsDiv.style.cssText = 'display: flex; gap: 20px; margin-top: 20px;';
717
+ const captureBtn = document.createElement('button');
718
+ captureBtn.textContent = 'Tomar Foto';
719
+ captureBtn.style.cssText = `
720
+ padding: 12px 24px; background: #007bff; color: white;
721
+ border: none; border-radius: 6px; cursor: pointer; font-size: 16px;
722
+ `;
723
+ const cancelBtn = document.createElement('button');
724
+ cancelBtn.textContent = 'Cancelar';
725
+ cancelBtn.style.cssText = `
726
+ padding: 12px 24px; background: #6c757d; color: white;
727
+ border: none; border-radius: 6px; cursor: pointer; font-size: 16px;
728
+ `;
729
+ const cleanup = () => {
730
+ stream.getTracks().forEach(track => track.stop());
731
+ modal.remove();
732
+ };
733
+ captureBtn.onclick = () => {
734
+ canvas.width = video.videoWidth;
735
+ canvas.height = video.videoHeight;
736
+ context.drawImage(video, 0, 0);
737
+ canvas.toBlob((blob) => {
738
+ if (blob && onPhotoTaken) {
739
+ const file = new File([blob], `photo-${Date.now()}.jpg`, { type: 'image/jpeg' });
740
+ onPhotoTaken(file);
741
+ }
742
+ cleanup();
743
+ }, 'image/jpeg', quality);
744
+ };
745
+ cancelBtn.onclick = cleanup;
746
+ document.addEventListener('keydown', (e) => {
747
+ if (e.key === 'Escape')
748
+ cleanup();
749
+ });
750
+ buttonsDiv.append(captureBtn, cancelBtn);
751
+ modal.append(video, buttonsDiv);
752
+ document.body.appendChild(modal);
753
+ }
754
+ catch (error) {
755
+ if (onError)
756
+ onError(error);
757
+ }
758
+ };
759
+ var EFileIcons;
760
+ (function (EFileIcons) {
761
+ EFileIcons["FILE"] = "file";
762
+ EFileIcons["IMAGE"] = "image";
763
+ EFileIcons["VIDEO"] = "video";
764
+ EFileIcons["FOLDER"] = "folder";
765
+ EFileIcons["EXCEL"] = "excel";
766
+ EFileIcons["SIGNATURE"] = "signature";
767
+ EFileIcons["CONTRACT"] = "contract";
768
+ EFileIcons["FINGERPRINT"] = "fingerprint";
769
+ EFileIcons["ID_CARD"] = "id_card";
770
+ EFileIcons["FILE_BOX"] = "file_box";
771
+ EFileIcons["SECURE_BUILDING"] = "secure_building";
772
+ EFileIcons["POLICE"] = "police";
773
+ })(EFileIcons || (EFileIcons = {}));
774
+ const DocumentIcon = {
775
+ [EFileIcons.FILE]: 'fa-solid fa-file-lines',
776
+ [EFileIcons.IMAGE]: 'fa-solid fa-file-image',
777
+ [EFileIcons.VIDEO]: 'fa-solid fa-file-video',
778
+ [EFileIcons.FOLDER]: 'fa-solid fa-folder',
779
+ [EFileIcons.EXCEL]: 'fa-solid fa-file-excel',
780
+ [EFileIcons.SIGNATURE]: 'fa-solid fa-signature',
781
+ [EFileIcons.CONTRACT]: 'fa-solid fa-file-contract',
782
+ [EFileIcons.FINGERPRINT]: 'fa-solid fa-fingerprint',
783
+ [EFileIcons.ID_CARD]: 'fa-solid fa-id-card',
784
+ [EFileIcons.SECURE_BUILDING]: 'fa-solid fa-building-shield',
785
+ [EFileIcons.POLICE]: 'fa-solid fa-hand-middle-finger',
786
+ [EFileIcons.FILE_BOX]: 'fa-solid fa-box-archive'
787
+ };
788
+ const downloadFile = (blob, fileName) => {
789
+ const url = window.URL.createObjectURL(blob);
790
+ const link = document.createElement('a');
791
+ link.href = url;
792
+ link.download = fileName;
793
+ document.body.appendChild(link);
794
+ link.click();
795
+ document.body.removeChild(link);
796
+ window.URL.revokeObjectURL(url);
797
+ };
798
+
799
+ //sin uuid, codigo propio
800
+ const generateId = () => {
801
+ return Date.now().toString(36) + Math.random().toString(36).substring(2, 15);
802
+ };
803
+
804
+ const formatNumber = (number) => {
805
+ return new Intl.NumberFormat('es-CO', {
806
+ minimumFractionDigits: 2,
807
+ maximumFractionDigits: 2
808
+ }).format(number);
809
+ };
810
+ const fixedNumber = (number) => {
811
+ return Number(number.toFixed(2));
812
+ };
813
+
814
+ const hasValues = (obj) => {
815
+ return Object.values(obj).some(value => value !== null && value !== undefined);
816
+ };
817
+ /**
818
+ * Elimina las propiedades de un objeto que tengan valores null o undefined.
819
+ * Retorna un nuevo objeto sin mutar el original.
820
+ * @param obj - Objeto del cual se eliminarán las propiedades null/undefined
821
+ * @returns Nuevo objeto sin las propiedades con valores null o undefined
822
+ */
823
+ const removeNullUndefined = (obj) => {
824
+ const result = {};
825
+ Object.keys(obj).forEach(key => {
826
+ const value = obj[key];
827
+ if (value !== null && value !== undefined) {
828
+ result[key] = value;
829
+ }
830
+ });
831
+ return result;
832
+ };
833
+ /**
834
+ * Realiza un upsert en un array de strings. Si el string ya existe, no hace nada.
835
+ * Si no existe, lo agrega al array.
836
+ * @param targetArray - Array de strings donde se realizará el upsert
837
+ * @param value - String o array de strings a insertar
838
+ * @returns Array actualizado con los nuevos valores
839
+ */
840
+ const upsertArrayStrings = (targetArray, value) => {
841
+ // Crear una copia del array original para evitar mutaciones
842
+ const result = [...targetArray];
843
+ // Convertir el valor a array para procesamiento uniforme
844
+ const valuesToInsert = Array.isArray(value) ? value : [value];
845
+ // Procesar cada valor
846
+ valuesToInsert.forEach(stringValue => {
847
+ // Solo agregar si no existe en el array
848
+ if (!result.includes(stringValue)) {
849
+ result.push(stringValue);
850
+ }
851
+ });
852
+ return result;
853
+ };
854
+ const sameArray = (arr1, arr2) => {
855
+ if (arr1.length !== arr2.length)
856
+ return false;
857
+ const sorted1 = Array.from(arr1).sort();
858
+ const sorted2 = Array.from(arr2).sort();
859
+ return sorted1.every((item, index) => item === sorted2[index]);
860
+ };
861
+ const getOptionByCode = (options, code) => {
862
+ if (!code)
863
+ return undefined;
864
+ return options.find((item) => item.code === code);
865
+ };
866
+ const createEnumeratedList = (items) => {
867
+ if (items.length === 0) {
868
+ return '';
869
+ }
870
+ if (items.length === 1) {
871
+ return `1. ${items[0]}`;
872
+ }
873
+ return items
874
+ .map((item, index) => `${index + 1}. ${item}`)
875
+ .join('\n');
876
+ };
877
+
878
+ class PrimeNgUtil {
879
+ static isPrimeNgSelection(value) {
880
+ return typeof value === 'object' && value !== null && 'name' in value && 'code' in value;
881
+ }
882
+ }
883
+
884
+ class InlineInputComponent {
885
+ config = input({ typeInput: ETypeInput.TEXT });
886
+ value = model(null);
887
+ outputValue = output();
888
+ outputBlur = output();
889
+ outputDebounced = output();
890
+ // Capturar templates proyectados desde el componente padre
891
+ templates;
892
+ // Para el manejo de chips
893
+ chips = [];
894
+ currentInput = '';
895
+ showDuplicateMessage = false;
896
+ duplicateChips = [];
897
+ duplicateMessageTimer = null;
898
+ constructor() {
899
+ effect(() => {
900
+ this.outputValue.emit(this.value());
901
+ });
902
+ const value$ = toObservable(this.value);
903
+ value$
904
+ .pipe(debounceTime(300), // <- adjust ms here
905
+ distinctUntilChanged(), // avoid repeats for same value
906
+ takeUntilDestroyed() // auto-cleanup on destroy
907
+ )
908
+ .subscribe(v => this.outputDebounced.emit(v));
909
+ effect(() => {
910
+ this.valueSelect.update((_prev) => {
911
+ const options = this.config()?.selectConfig?.options;
912
+ const currentValue = this.value();
913
+ if (this.isSelection(currentValue))
914
+ return currentValue;
915
+ if (currentValue === null || currentValue === undefined)
916
+ return undefined;
917
+ return options?.find(option => option.code === currentValue);
918
+ });
919
+ });
920
+ }
921
+ ngOnInit() {
922
+ }
923
+ onChange = () => { };
924
+ onTouched = () => { };
925
+ writeValue(value) {
926
+ this.value.set(value);
927
+ // Si es tipo CHIPS, inicializar los chips desde el valor
928
+ if (this.type === ETypeInput.CHIPS && typeof value === 'string') {
929
+ this.chips = value ? value.split(' ').filter(chip => chip.trim() !== '') : [];
930
+ }
931
+ }
932
+ registerOnChange(fn) {
933
+ this.onChange = fn;
934
+ }
935
+ registerOnTouched(fn) {
936
+ this.onTouched = fn;
937
+ }
938
+ onChangeValue(value) {
939
+ let nextValue = value;
940
+ if (this.type === ETypeInput.MULTISELECT && Array.isArray(value)) {
941
+ nextValue = value.filter((item) => item != null && this.isSelection(item));
942
+ }
943
+ this.value.set(nextValue);
944
+ this.onChange(nextValue);
945
+ }
946
+ onBlur() {
947
+ this.onTouched();
948
+ this.outputBlur.emit(this.value());
949
+ }
950
+ /**
951
+ * Maneja eventos de teclado para prevenir la navegación de PrimeNG Table
952
+ * cuando se usan las flechas izquierda/derecha dentro del input
953
+ */
954
+ onKeyDown(event) {
955
+ // Verificar si son teclas de flecha izquierda o derecha
956
+ if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
957
+ // Detener la propagación del evento hacia el table
958
+ event.stopPropagation();
959
+ }
960
+ }
961
+ isSelection(value) {
962
+ return PrimeNgUtil.isPrimeNgSelection(value);
963
+ }
964
+ /**
965
+ * Normaliza el valor del multiselect: PrimeNG ColumnFilter devuelve string[] (name/code)
966
+ * pero p-multiselect espera IPrimeNgSelection[] cuando las options son objetos.
967
+ */
968
+ multiSelectValue = computed(() => {
969
+ return this.normalizeMultiSelectValue(this.value());
970
+ });
971
+ normalizeMultiSelectValue(value) {
972
+ if (value == null) {
973
+ return [];
974
+ }
975
+ if (!Array.isArray(value)) {
976
+ return [];
977
+ }
978
+ const options = this.config()?.multiSelectConfig?.options ?? [];
979
+ return value
980
+ .filter((item) => item != null && item !== '')
981
+ .map((item) => {
982
+ if (this.isSelection(item)) {
983
+ return item;
984
+ }
985
+ if (typeof item === 'string') {
986
+ return options.find((option) => option.code === item || option.name === item);
987
+ }
988
+ return undefined;
989
+ })
990
+ .filter((item) => !!item);
991
+ }
992
+ valueSelect = signal(undefined);
993
+ setValueSelect(value) {
994
+ this.valueSelect.set(value);
995
+ }
996
+ get type() {
997
+ return this.config()?.typeInput ?? ETypeInput.TEXT;
998
+ }
999
+ get ETypeInput() {
1000
+ return ETypeInput;
1001
+ }
1002
+ get duplicatesText() {
1003
+ return this.duplicateChips.join(', ');
1004
+ }
1005
+ get currency() {
1006
+ return this.config()?.currencyConfig?.currency ?? 'COP';
1007
+ }
1008
+ get locale() {
1009
+ return this.config()?.currencyConfig?.locale ?? 'es-CO';
1010
+ }
1011
+ get minFractionDigits() {
1012
+ return this.config()?.currencyConfig?.minFractionDigits ?? 2;
1013
+ }
1014
+ get maxFractionDigits() {
1015
+ return this.config()?.currencyConfig?.maxFractionDigits ?? 2;
1016
+ }
1017
+ knobValueInput = computed(() => {
1018
+ let response = this.value();
1019
+ const knobConfig = this.config()?.knobConfig ?? { min: 0, max: 100, step: 1 };
1020
+ response = parseInt(this.value()) ?? 0;
1021
+ if (response < (knobConfig?.min ?? 0)) {
1022
+ response = knobConfig.min ?? 0;
1023
+ }
1024
+ if (response > (knobConfig?.max ?? 100)) {
1025
+ response = knobConfig.max ?? 100;
1026
+ }
1027
+ return response;
1028
+ });
1029
+ knobValueTemplate = computed(() => {
1030
+ return this.config()?.knobConfig?.valueTemplate ?? '';
1031
+ });
1032
+ // Métodos para manejo de chips
1033
+ onChipInputChange(event) {
1034
+ const target = event.target;
1035
+ this.currentInput = target.value;
1036
+ }
1037
+ onChipKeydown(event) {
1038
+ if (event.key === ' ' || event.key === 'Enter') {
1039
+ event.preventDefault();
1040
+ this.addChip();
1041
+ }
1042
+ else if (event.key === 'Backspace' && this.currentInput === '' && this.chips.length > 0) {
1043
+ // Si no hay texto y hay chips, eliminar el último chip
1044
+ this.removeChip(this.chips.length - 1);
1045
+ }
1046
+ // No interceptar las flechas aquí ya que se maneja en onKeyDown
1047
+ }
1048
+ onChipPaste(event) {
1049
+ event.preventDefault();
1050
+ const pastedText = event.clipboardData?.getData('text') || '';
1051
+ this.processPastedText(pastedText);
1052
+ }
1053
+ addChip() {
1054
+ const trimmedValue = this.currentInput.trim();
1055
+ if (trimmedValue) {
1056
+ if (this.chips.includes(trimmedValue)) {
1057
+ // Mostrar mensaje de duplicado con el chip específico
1058
+ this.duplicateChips = [trimmedValue];
1059
+ this.showDuplicateAlert();
1060
+ }
1061
+ else {
1062
+ this.chips.push(trimmedValue);
1063
+ this.currentInput = '';
1064
+ this.updateChipsValue();
1065
+ this.hideDuplicateAlert();
1066
+ }
1067
+ }
1068
+ }
1069
+ removeChip(index) {
1070
+ this.chips.splice(index, 1);
1071
+ this.updateChipsValue();
1072
+ }
1073
+ updateChipsValue() {
1074
+ const chipsValue = this.chips.join(' ');
1075
+ this.value.set(chipsValue);
1076
+ this.onChange(chipsValue);
1077
+ }
1078
+ showDuplicateAlert() {
1079
+ this.showDuplicateMessage = true;
1080
+ // Limpiar timer anterior si existe
1081
+ if (this.duplicateMessageTimer) {
1082
+ clearTimeout(this.duplicateMessageTimer);
1083
+ }
1084
+ // Ocultar mensaje después de 3 segundos
1085
+ this.duplicateMessageTimer = setTimeout(() => {
1086
+ this.hideDuplicateAlert();
1087
+ }, 3000);
1088
+ }
1089
+ hideDuplicateAlert() {
1090
+ this.showDuplicateMessage = false;
1091
+ this.duplicateChips = [];
1092
+ if (this.duplicateMessageTimer) {
1093
+ clearTimeout(this.duplicateMessageTimer);
1094
+ this.duplicateMessageTimer = null;
1095
+ }
1096
+ }
1097
+ processPastedText(text) {
1098
+ // Dividir el texto por espacios y filtrar elementos vacíos
1099
+ const newChips = text
1100
+ .split(/\s+/) // Dividir por uno o más espacios
1101
+ .map(chip => chip.trim()) // Limpiar espacios en cada elemento
1102
+ .filter(chip => chip !== ''); // Filtrar elementos vacíos
1103
+ const foundDuplicates = [];
1104
+ let addedChips = 0;
1105
+ // Agregar cada chip nuevo y recopilar duplicados
1106
+ newChips.forEach(chipText => {
1107
+ if (!this.chips.includes(chipText)) {
1108
+ this.chips.push(chipText);
1109
+ addedChips++;
1110
+ }
1111
+ else {
1112
+ // Solo agregar a duplicados si no está ya en la lista
1113
+ if (!foundDuplicates.includes(chipText)) {
1114
+ foundDuplicates.push(chipText);
1115
+ }
1116
+ }
1117
+ });
1118
+ // Limpiar el input actual
1119
+ this.currentInput = '';
1120
+ // Actualizar el valor si se agregaron chips
1121
+ if (addedChips > 0) {
1122
+ this.updateChipsValue();
1123
+ }
1124
+ // Mostrar alerta si hubo duplicados
1125
+ if (foundDuplicates.length > 0) {
1126
+ this.duplicateChips = foundDuplicates;
1127
+ this.showDuplicateAlert();
1128
+ }
1129
+ else {
1130
+ this.hideDuplicateAlert();
1131
+ }
1132
+ }
1133
+ /**
1134
+ * Método público para establecer chips desde un array externo
1135
+ * @param chipsArray Array de strings que representan las chips
1136
+ */
1137
+ setChipsFromArray(chipsArray) {
1138
+ if (!Array.isArray(chipsArray)) {
1139
+ console.warn('setChipsFromArray: El parámetro debe ser un array de strings');
1140
+ return;
1141
+ }
1142
+ // Filtrar elementos válidos (strings no vacíos)
1143
+ const validChips = chipsArray
1144
+ .filter(chip => typeof chip === 'string' && chip.trim() !== '')
1145
+ .map(chip => chip.trim());
1146
+ // Actualizar el array de chips
1147
+ this.chips = [...validChips];
1148
+ // Limpiar el input actual
1149
+ this.currentInput = '';
1150
+ // Actualizar el valor del componente
1151
+ this.updateChipsValue();
1152
+ // Ocultar cualquier mensaje de duplicado
1153
+ this.hideDuplicateAlert();
1154
+ }
1155
+ /**
1156
+ * Método público para obtener las chips actuales como array
1157
+ * @returns Array de strings con las chips actuales
1158
+ */
1159
+ getChipsAsArray() {
1160
+ return [...this.chips];
1161
+ }
1162
+ /**
1163
+ * Método público para limpiar todas las chips
1164
+ */
1165
+ clearAllChips() {
1166
+ this.chips = [];
1167
+ this.currentInput = '';
1168
+ this.updateChipsValue();
1169
+ this.hideDuplicateAlert();
1170
+ }
1171
+ /**
1172
+ * Método público para agregar múltiples chips desde un array
1173
+ * Evita duplicados y muestra mensajes de alerta si es necesario
1174
+ * @param chipsArray Array de strings a agregar
1175
+ */
1176
+ addChipsFromArray(chipsArray) {
1177
+ if (!Array.isArray(chipsArray)) {
1178
+ console.warn('addChipsFromArray: El parámetro debe ser un array de strings');
1179
+ return;
1180
+ }
1181
+ // Filtrar elementos válidos
1182
+ const validChips = chipsArray
1183
+ .filter(chip => typeof chip === 'string' && chip.trim() !== '')
1184
+ .map(chip => chip.trim());
1185
+ const foundDuplicates = [];
1186
+ let addedChips = 0;
1187
+ // Agregar cada chip nuevo y recopilar duplicados
1188
+ validChips.forEach(chipText => {
1189
+ if (!this.chips.includes(chipText)) {
1190
+ this.chips.push(chipText);
1191
+ addedChips++;
1192
+ }
1193
+ else {
1194
+ // Solo agregar a duplicados si no está ya en la lista
1195
+ if (!foundDuplicates.includes(chipText)) {
1196
+ foundDuplicates.push(chipText);
1197
+ }
1198
+ }
1199
+ });
1200
+ // Actualizar el valor si se agregaron chips
1201
+ if (addedChips > 0) {
1202
+ this.updateChipsValue();
1203
+ }
1204
+ // Mostrar alerta si hubo duplicados
1205
+ if (foundDuplicates.length > 0) {
1206
+ this.duplicateChips = foundDuplicates;
1207
+ this.showDuplicateAlert();
1208
+ }
1209
+ else {
1210
+ this.hideDuplicateAlert();
1211
+ }
1212
+ }
1213
+ // Limpiar timer al destruir el componente
1214
+ ngOnDestroy() {
1215
+ if (this.duplicateMessageTimer) {
1216
+ clearTimeout(this.duplicateMessageTimer);
1217
+ }
1218
+ }
1219
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: InlineInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1220
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: InlineInputComponent, isStandalone: true, selector: "lib-inline-input", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", outputValue: "outputValue", outputBlur: "outputBlur", outputDebounced: "outputDebounced" }, providers: [
1221
+ {
1222
+ provide: NG_VALUE_ACCESSOR,
1223
+ useExisting: forwardRef(() => InlineInputComponent),
1224
+ multi: true
1225
+ }
1226
+ ], queries: [{ propertyName: "templates", predicate: PrimeTemplate }], ngImport: i0, template: "@let valueInput = value();\n@let isDisabled = config().isDisabled ?? false;\n@let knobConfig = config().knobConfig;\n@let textareaConfig = config().textareaConfig;\n@let dateConfig = config().dateConfig;\n\n@switch (type) {\n@case (ETypeInput.CURRENCY) {\n<p-inputnumber [ngModel]=\"valueInput\" (ngModelChange)=\"onChangeValue($event)\" (onBlur)=\"onBlur()\"\n (keydown)=\"onKeyDown($event)\" mode=\"currency\" [currency]=\"currency\" [locale]=\"locale\"\n [minFractionDigits]=\"minFractionDigits\" [maxFractionDigits]=\"maxFractionDigits\" class=\"w-full\"\n [disabled]=\"isDisabled\" />\n}\n@case (ETypeInput.DECIMAL) {\n<p-inputnumber [ngModel]=\"valueInput\" (ngModelChange)=\"onChangeValue($event)\" (onBlur)=\"onBlur()\"\n (keydown)=\"onKeyDown($event)\" mode=\"decimal\" [locale]=\"locale\" [minFractionDigits]=\"2\" [maxFractionDigits]=\"2\"\n [useGrouping]=\"true\" class=\"w-full\" [disabled]=\"isDisabled\" />\n}\n@case (ETypeInput.DATE) {\n<p-datepicker [ngModel]=\"valueInput\" appendTo=\"body\" (ngModelChange)=\"onChangeValue($event)\" (onBlur)=\"onBlur()\"\n (keydown)=\"onKeyDown($event)\" class=\"w-full\" [disabled]=\"isDisabled\" [maxDate]=\"dateConfig?.maxDate || null\"\n [minDate]=\"dateConfig?.minDate || null\" [selectionMode]=\"dateConfig?.selectionMode || 'single'\" dateFormat=\"dd/mm/yy\" />\n}\n@case (ETypeInput.DATETIME_LOCAL) {\n<p-datepicker [ngModel]=\"valueInput\" appendTo=\"body\" (ngModelChange)=\"onChangeValue($event)\" (onBlur)=\"onBlur()\"\n (keydown)=\"onKeyDown($event)\" class=\"w-full\" [showTime]=\"true\" [hourFormat]=\"'24'\" [disabled]=\"isDisabled\"\n [maxDate]=\"dateConfig?.maxDate || null\" [minDate]=\"dateConfig?.minDate || null\" [selectionMode]=\"dateConfig?.selectionMode || 'single'\"\n dateFormat=\"dd/mm/yy\" />\n}\n@case (ETypeInput.SELECT) {\n<p-select [options]=\"config().selectConfig?.options ?? []\" [optionLabel]=\"config().selectConfig?.optionLabel ?? 'name'\"\n [(ngModel)]=\"valueSelect\" (ngModelChange)=\"onChangeValue($event)\" (onBlur)=\"onBlur()\" (keydown)=\"onKeyDown($event)\"\n appendTo=\"body\" class=\"w-full inline-input-select\" [disabled]=\"config().isDisabled ?? false\" >\n @for (template of templates; track $index) {\n <ng-template [pTemplate]=\"template.getType()\" let-item>\n <ng-container *ngTemplateOutlet=\"template.template; context: { $implicit: item }\"></ng-container>\n </ng-template>\n }\n</p-select>\n}\n@case (ETypeInput.MULTISELECT) {\n<p-multiselect [options]=\"config().multiSelectConfig?.options ?? []\"\n [optionLabel]=\"config().multiSelectConfig?.optionLabel ?? 'name'\" [ngModel]=\"multiSelectValue()\"\n (ngModelChange)=\"onChangeValue($event)\" (onBlur)=\"onBlur()\" (keydown)=\"onKeyDown($event)\" [filter]=\"true\"\n appendTo=\"body\" class=\"w-full\" [disabled]=\"isDisabled\" />\n}\n@case (ETypeInput.OTP) {\n<p-inputotp class=\"w-full\" [mask]=\"config().otpConfig?.mask ?? false\" [length]=\"config().otpConfig?.length ?? 6\"\n [integerOnly]=\"config().otpConfig?.integerOnly ?? false\" [ngModel]=\"valueInput\"\n (ngModelChange)=\"onChangeValue($event)\" (onBlur)=\"onBlur()\" (keydown)=\"onKeyDown($event)\" [disabled]=\"isDisabled\" />\n}\n@case (ETypeInput.KNOB) {\n<p-knob [ngModel]=\"knobValueInput()\" (ngModelChange)=\"onChangeValue($event)\" class=\"w-full\" [min]=\"knobConfig?.min ?? 0\"\n [max]=\"knobConfig?.max ?? 100\" [step]=\"knobConfig?.step ?? 1\" [disabled]=\"isDisabled\" [readonly]=\"true\"\n [valueTemplate]=\"knobValueTemplate()\" [size]=\"knobConfig?.size ?? 100\" />\n}\n@case (ETypeInput.TEXTAREA) {\n<textarea class=\"w-full h-full p-2 border border-gray-300 rounded-md\" pTextarea [rows]=\"textareaConfig?.rows ?? 3\"\n [cols]=\"textareaConfig?.cols ?? 30\" [autoResize]=\"true\" [variant]=\"textareaConfig?.variant ?? 'outlined'\"\n [disabled]=\"isDisabled\" [ngModel]=\"valueInput\" (ngModelChange)=\"onChangeValue($event)\" (blur)=\"onBlur()\"\n (keydown)=\"onKeyDown($event)\"></textarea>\n}\n@case (ETypeInput.CHIPS) {\n<div class=\"chips-input-wrapper\">\n <div\n class=\"chips-container w-full p-2 border border-gray-300 rounded-md min-h-[40px] flex flex-wrap items-center gap-2\"\n [class.border-red-500]=\"showDuplicateMessage\">\n @for (chip of chips; track $index) {\n <p-chip [label]=\"chip\" [removable]=\"!isDisabled\" (onRemove)=\"removeChip($index)\" class=\"chip-item\" />\n }\n <input type=\"text\" class=\"chip-input flex-1 border-0 outline-0 bg-transparent min-w-[100px]\" [value]=\"currentInput\"\n (input)=\"onChipInputChange($event)\" (keydown)=\"onChipKeydown($event); onKeyDown($event)\"\n (paste)=\"onChipPaste($event)\" [disabled]=\"isDisabled\"\n placeholder=\"Escribe o pega elementos separados por espacios...\" />\n </div>\n @if (showDuplicateMessage) {\n <div class=\"duplicate-message text-red-500 text-sm mt-1 flex items-center gap-1\">\n <i class=\"pi pi-exclamation-triangle text-red-500\"></i>\n <span>\n @if (duplicateChips.length === 1) {\n El elemento \"<strong>{{ duplicatesText }}</strong>\" ya existe en la lista\n } @else {\n Los elementos \"<strong>{{ duplicatesText }}</strong>\" ya existen en la lista\n }\n </span>\n </div>\n }\n</div>\n}\n@case (ETypeInput.SWITCH) {\n<div class=\"flex justify-center items-center p-2\">\n <p-toggleswitch [ngModel]=\"valueInput\" (ngModelChange)=\"onChangeValue($event)\" (onBlur)=\"onBlur()\"\n class=\"w-full\" [disabled]=\"isDisabled\" />\n</div>\n}\n@default {\n<input pInputText class=\"w-full h-full p-2 border border-gray-300 rounded-md\" [type]=\"type\"\n [readOnly]=\"config().readonly ?? false\" [ngModel]=\"valueInput\" (ngModelChange)=\"onChangeValue($event)\"\n (blur)=\"onBlur()\" (keydown)=\"onKeyDown($event)\" [disabled]=\"isDisabled\" />\n}\n}", styles: [":host{width:100%;height:100%}.chips-input-wrapper{width:100%}.chips-input-wrapper .chips-container{cursor:text;transition:border-color .2s ease,box-shadow .2s ease}.chips-input-wrapper .chips-container:focus-within{border-color:#007ad9;box-shadow:0 0 0 1px #007ad9}.chips-input-wrapper .chips-container.border-red-500{border-color:#ef4444!important;box-shadow:0 0 0 1px #ef4444!important}.chips-input-wrapper .chips-container .chip-item{margin:0}.chips-input-wrapper .chips-container .chip-input:focus{outline:none}.chips-input-wrapper .chips-container .chip-input::placeholder{color:#6b7280;font-style:italic}.chips-input-wrapper .duplicate-message{animation:slideDown .3s ease-out}.chips-input-wrapper .duplicate-message i{font-size:14px}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}::ng-deep p-select.inline-input-select{border:1px solid #d1d5db!important;background:transparent;color:#111827;height:44px;width:100%;border-radius:.5rem;transition:all .2s ease-in-out;display:flex;align-items:center;justify-content:space-between}::ng-deep p-select.inline-input-select .p-select-label{border:none}::ng-deep p-select.inline-input-select .p-select-trigger{border:none}::ng-deep .my-app-dark p-select.inline-input-select{border:1px solid transparent!important;background:transparent;color:#f3f4f6}::ng-deep .my-app-dark p-inputnumber .p-inputnumber-input{background-color:#374151;color:#f3f4f6;border-color:transparent}::ng-deep .my-app-dark p-datepicker .p-inputtext{background-color:#374151;color:#f3f4f6}::ng-deep .my-app-dark p-multiselect .p-multiselect-label{background-color:#374151;color:#f3f4f6}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i2$1.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i2.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "style", "styleClass", "inputStyle", "inputId", "name", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "disabled", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "fluid", "icon", "appendTo", "readonlyInput", "shortYearCutoff", "monthNavigator", "yearNavigator", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "required", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "variant", "size", "minDate", "maxDate", "disabledDates", "disabledDays", "yearRange", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "locale", "view", "defaultDate"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "directive", type: i4$1.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i4.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "size", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i3.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "style", "styleClass", "panelStyle", "panelStyleClass", "inputId", "disabled", "fluid", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "variant", "appendTo", "dataKey", "name", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "size", "showClear", "autofocus", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "defaultLabel", "placeholder", "options", "filterValue", "itemSize", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: InputMaskModule }, { kind: "ngmodule", type: InputNumberModule }, { kind: "component", type: i8.InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "style", "placeholder", "size", "maxlength", "tabindex", "title", "ariaLabelledBy", "ariaDescribedBy", "ariaLabel", "ariaRequired", "name", "required", "autocomplete", "min", "max", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "step", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "variant", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus", "disabled", "fluid"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "ngmodule", type: InputOtpModule }, { kind: "component", type: i6.InputOtp, selector: "p-inputOtp, p-inputotp, p-input-otp", inputs: ["invalid", "disabled", "readonly", "variant", "tabindex", "length", "styleClass", "mask", "integerOnly", "autofocus", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: KnobModule }, { kind: "component", type: i9$1.Knob, selector: "p-knob", inputs: ["styleClass", "style", "ariaLabel", "ariaLabelledBy", "tabindex", "valueColor", "rangeColor", "textColor", "valueTemplate", "name", "size", "step", "min", "max", "strokeWidth", "disabled", "showValue", "readonly"], outputs: ["onChange"] }, { kind: "ngmodule", type: TextareaModule }, { kind: "directive", type: i9.Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["autoResize", "variant", "fluid", "pSize"], outputs: ["onResize"] }, { kind: "ngmodule", type: ChipModule }, { kind: "component", type: i11.Chip, selector: "p-chip", inputs: ["label", "icon", "image", "alt", "style", "styleClass", "removable", "removeIcon", "chipProps"], outputs: ["onRemove", "onImageError"] }, { kind: "ngmodule", type: ToggleSwitchModule }, { kind: "component", type: i7.ToggleSwitch, selector: "p-toggleswitch, p-toggleSwitch, p-toggle-switch", inputs: ["style", "styleClass", "tabindex", "inputId", "name", "disabled", "readonly", "trueValue", "falseValue", "ariaLabel", "ariaLabelledBy", "autofocus"], outputs: ["onChange"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1227
+ }
1228
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: InlineInputComponent, decorators: [{
1229
+ type: Component,
1230
+ args: [{ selector: 'lib-inline-input', standalone: true, imports: [
1231
+ FormsModule,
1232
+ InputTextModule,
1233
+ DatePickerModule,
1234
+ SelectModule,
1235
+ MultiSelectModule,
1236
+ InputMaskModule,
1237
+ InputNumberModule,
1238
+ InputOtpModule,
1239
+ KnobModule,
1240
+ TextareaModule,
1241
+ ChipModule,
1242
+ ToggleSwitchModule,
1243
+ CommonModule
1244
+ ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
1245
+ {
1246
+ provide: NG_VALUE_ACCESSOR,
1247
+ useExisting: forwardRef(() => InlineInputComponent),
1248
+ multi: true
1249
+ }
1250
+ ], template: "@let valueInput = value();\n@let isDisabled = config().isDisabled ?? false;\n@let knobConfig = config().knobConfig;\n@let textareaConfig = config().textareaConfig;\n@let dateConfig = config().dateConfig;\n\n@switch (type) {\n@case (ETypeInput.CURRENCY) {\n<p-inputnumber [ngModel]=\"valueInput\" (ngModelChange)=\"onChangeValue($event)\" (onBlur)=\"onBlur()\"\n (keydown)=\"onKeyDown($event)\" mode=\"currency\" [currency]=\"currency\" [locale]=\"locale\"\n [minFractionDigits]=\"minFractionDigits\" [maxFractionDigits]=\"maxFractionDigits\" class=\"w-full\"\n [disabled]=\"isDisabled\" />\n}\n@case (ETypeInput.DECIMAL) {\n<p-inputnumber [ngModel]=\"valueInput\" (ngModelChange)=\"onChangeValue($event)\" (onBlur)=\"onBlur()\"\n (keydown)=\"onKeyDown($event)\" mode=\"decimal\" [locale]=\"locale\" [minFractionDigits]=\"2\" [maxFractionDigits]=\"2\"\n [useGrouping]=\"true\" class=\"w-full\" [disabled]=\"isDisabled\" />\n}\n@case (ETypeInput.DATE) {\n<p-datepicker [ngModel]=\"valueInput\" appendTo=\"body\" (ngModelChange)=\"onChangeValue($event)\" (onBlur)=\"onBlur()\"\n (keydown)=\"onKeyDown($event)\" class=\"w-full\" [disabled]=\"isDisabled\" [maxDate]=\"dateConfig?.maxDate || null\"\n [minDate]=\"dateConfig?.minDate || null\" [selectionMode]=\"dateConfig?.selectionMode || 'single'\" dateFormat=\"dd/mm/yy\" />\n}\n@case (ETypeInput.DATETIME_LOCAL) {\n<p-datepicker [ngModel]=\"valueInput\" appendTo=\"body\" (ngModelChange)=\"onChangeValue($event)\" (onBlur)=\"onBlur()\"\n (keydown)=\"onKeyDown($event)\" class=\"w-full\" [showTime]=\"true\" [hourFormat]=\"'24'\" [disabled]=\"isDisabled\"\n [maxDate]=\"dateConfig?.maxDate || null\" [minDate]=\"dateConfig?.minDate || null\" [selectionMode]=\"dateConfig?.selectionMode || 'single'\"\n dateFormat=\"dd/mm/yy\" />\n}\n@case (ETypeInput.SELECT) {\n<p-select [options]=\"config().selectConfig?.options ?? []\" [optionLabel]=\"config().selectConfig?.optionLabel ?? 'name'\"\n [(ngModel)]=\"valueSelect\" (ngModelChange)=\"onChangeValue($event)\" (onBlur)=\"onBlur()\" (keydown)=\"onKeyDown($event)\"\n appendTo=\"body\" class=\"w-full inline-input-select\" [disabled]=\"config().isDisabled ?? false\" >\n @for (template of templates; track $index) {\n <ng-template [pTemplate]=\"template.getType()\" let-item>\n <ng-container *ngTemplateOutlet=\"template.template; context: { $implicit: item }\"></ng-container>\n </ng-template>\n }\n</p-select>\n}\n@case (ETypeInput.MULTISELECT) {\n<p-multiselect [options]=\"config().multiSelectConfig?.options ?? []\"\n [optionLabel]=\"config().multiSelectConfig?.optionLabel ?? 'name'\" [ngModel]=\"multiSelectValue()\"\n (ngModelChange)=\"onChangeValue($event)\" (onBlur)=\"onBlur()\" (keydown)=\"onKeyDown($event)\" [filter]=\"true\"\n appendTo=\"body\" class=\"w-full\" [disabled]=\"isDisabled\" />\n}\n@case (ETypeInput.OTP) {\n<p-inputotp class=\"w-full\" [mask]=\"config().otpConfig?.mask ?? false\" [length]=\"config().otpConfig?.length ?? 6\"\n [integerOnly]=\"config().otpConfig?.integerOnly ?? false\" [ngModel]=\"valueInput\"\n (ngModelChange)=\"onChangeValue($event)\" (onBlur)=\"onBlur()\" (keydown)=\"onKeyDown($event)\" [disabled]=\"isDisabled\" />\n}\n@case (ETypeInput.KNOB) {\n<p-knob [ngModel]=\"knobValueInput()\" (ngModelChange)=\"onChangeValue($event)\" class=\"w-full\" [min]=\"knobConfig?.min ?? 0\"\n [max]=\"knobConfig?.max ?? 100\" [step]=\"knobConfig?.step ?? 1\" [disabled]=\"isDisabled\" [readonly]=\"true\"\n [valueTemplate]=\"knobValueTemplate()\" [size]=\"knobConfig?.size ?? 100\" />\n}\n@case (ETypeInput.TEXTAREA) {\n<textarea class=\"w-full h-full p-2 border border-gray-300 rounded-md\" pTextarea [rows]=\"textareaConfig?.rows ?? 3\"\n [cols]=\"textareaConfig?.cols ?? 30\" [autoResize]=\"true\" [variant]=\"textareaConfig?.variant ?? 'outlined'\"\n [disabled]=\"isDisabled\" [ngModel]=\"valueInput\" (ngModelChange)=\"onChangeValue($event)\" (blur)=\"onBlur()\"\n (keydown)=\"onKeyDown($event)\"></textarea>\n}\n@case (ETypeInput.CHIPS) {\n<div class=\"chips-input-wrapper\">\n <div\n class=\"chips-container w-full p-2 border border-gray-300 rounded-md min-h-[40px] flex flex-wrap items-center gap-2\"\n [class.border-red-500]=\"showDuplicateMessage\">\n @for (chip of chips; track $index) {\n <p-chip [label]=\"chip\" [removable]=\"!isDisabled\" (onRemove)=\"removeChip($index)\" class=\"chip-item\" />\n }\n <input type=\"text\" class=\"chip-input flex-1 border-0 outline-0 bg-transparent min-w-[100px]\" [value]=\"currentInput\"\n (input)=\"onChipInputChange($event)\" (keydown)=\"onChipKeydown($event); onKeyDown($event)\"\n (paste)=\"onChipPaste($event)\" [disabled]=\"isDisabled\"\n placeholder=\"Escribe o pega elementos separados por espacios...\" />\n </div>\n @if (showDuplicateMessage) {\n <div class=\"duplicate-message text-red-500 text-sm mt-1 flex items-center gap-1\">\n <i class=\"pi pi-exclamation-triangle text-red-500\"></i>\n <span>\n @if (duplicateChips.length === 1) {\n El elemento \"<strong>{{ duplicatesText }}</strong>\" ya existe en la lista\n } @else {\n Los elementos \"<strong>{{ duplicatesText }}</strong>\" ya existen en la lista\n }\n </span>\n </div>\n }\n</div>\n}\n@case (ETypeInput.SWITCH) {\n<div class=\"flex justify-center items-center p-2\">\n <p-toggleswitch [ngModel]=\"valueInput\" (ngModelChange)=\"onChangeValue($event)\" (onBlur)=\"onBlur()\"\n class=\"w-full\" [disabled]=\"isDisabled\" />\n</div>\n}\n@default {\n<input pInputText class=\"w-full h-full p-2 border border-gray-300 rounded-md\" [type]=\"type\"\n [readOnly]=\"config().readonly ?? false\" [ngModel]=\"valueInput\" (ngModelChange)=\"onChangeValue($event)\"\n (blur)=\"onBlur()\" (keydown)=\"onKeyDown($event)\" [disabled]=\"isDisabled\" />\n}\n}", styles: [":host{width:100%;height:100%}.chips-input-wrapper{width:100%}.chips-input-wrapper .chips-container{cursor:text;transition:border-color .2s ease,box-shadow .2s ease}.chips-input-wrapper .chips-container:focus-within{border-color:#007ad9;box-shadow:0 0 0 1px #007ad9}.chips-input-wrapper .chips-container.border-red-500{border-color:#ef4444!important;box-shadow:0 0 0 1px #ef4444!important}.chips-input-wrapper .chips-container .chip-item{margin:0}.chips-input-wrapper .chips-container .chip-input:focus{outline:none}.chips-input-wrapper .chips-container .chip-input::placeholder{color:#6b7280;font-style:italic}.chips-input-wrapper .duplicate-message{animation:slideDown .3s ease-out}.chips-input-wrapper .duplicate-message i{font-size:14px}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}::ng-deep p-select.inline-input-select{border:1px solid #d1d5db!important;background:transparent;color:#111827;height:44px;width:100%;border-radius:.5rem;transition:all .2s ease-in-out;display:flex;align-items:center;justify-content:space-between}::ng-deep p-select.inline-input-select .p-select-label{border:none}::ng-deep p-select.inline-input-select .p-select-trigger{border:none}::ng-deep .my-app-dark p-select.inline-input-select{border:1px solid transparent!important;background:transparent;color:#f3f4f6}::ng-deep .my-app-dark p-inputnumber .p-inputnumber-input{background-color:#374151;color:#f3f4f6;border-color:transparent}::ng-deep .my-app-dark p-datepicker .p-inputtext{background-color:#374151;color:#f3f4f6}::ng-deep .my-app-dark p-multiselect .p-multiselect-label{background-color:#374151;color:#f3f4f6}\n"] }]
1251
+ }], ctorParameters: () => [], propDecorators: { templates: [{
1252
+ type: ContentChildren,
1253
+ args: [PrimeTemplate]
1254
+ }] } });
1255
+
1256
+ class AminatedContainerComponent {
1257
+ isLoading = true;
1258
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AminatedContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1259
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: AminatedContainerComponent, isStandalone: true, selector: "lib-aminated-container", ngImport: i0, template: "<div class=\"fade-in-container\">\r\n <ng-content></ng-content>\r\n</div>\r\n", styles: ["@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.fade-in-container{animation:fadeIn .8s ease-out forwards;opacity:0;transform:translateY(10px)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
1260
+ }
1261
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AminatedContainerComponent, decorators: [{
1262
+ type: Component,
1263
+ args: [{ selector: 'lib-aminated-container', imports: [CommonModule], template: "<div class=\"fade-in-container\">\r\n <ng-content></ng-content>\r\n</div>\r\n", styles: ["@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.fade-in-container{animation:fadeIn .8s ease-out forwards;opacity:0;transform:translateY(10px)}\n"] }]
1264
+ }] });
1265
+
1266
+ class SpeedDialService {
1267
+ panelOffset = 10;
1268
+ mainButtonHost;
1269
+ activeAnchor;
1270
+ _isMenuOpen = signal(false);
1271
+ _panelTop = signal('0px');
1272
+ _panelLeft = signal('0px');
1273
+ constructor() { }
1274
+ _speedDialConfig = signal({});
1275
+ speedDialConfig = this._speedDialConfig.asReadonly();
1276
+ isMenuOpen = this._isMenuOpen.asReadonly();
1277
+ panelTop = this._panelTop.asReadonly();
1278
+ panelLeft = this._panelLeft.asReadonly();
1279
+ setSpeedDialConfig(config) {
1280
+ this._speedDialConfig.set(config);
1281
+ if (this.isMenuOpen())
1282
+ this.updatePanelPosition();
1283
+ }
1284
+ setMainButtonHost(host) {
1285
+ this.mainButtonHost = host;
1286
+ if (this.isMenuOpen())
1287
+ this.updatePanelPosition();
1288
+ }
1289
+ buttons = computed(() => {
1290
+ return this.speedDialConfig().buttons;
1291
+ });
1292
+ overlayButtons = computed(() => {
1293
+ return this.buttons().map((button) => {
1294
+ return {
1295
+ ...button,
1296
+ onClick: (data) => {
1297
+ this.closeMenu();
1298
+ button.onClick?.(data);
1299
+ }
1300
+ };
1301
+ });
1302
+ });
1303
+ mainButton = computed(() => {
1304
+ const rawMainButton = this.speedDialConfig().mainButton;
1305
+ return {
1306
+ ...rawMainButton,
1307
+ icon: this.isMenuOpen() ? 'fa-solid fa-xmark' : rawMainButton.icon,
1308
+ severity: this.isMenuOpen() ? 'danger' : rawMainButton.severity,
1309
+ onClick: (data) => {
1310
+ rawMainButton.onClick?.(data);
1311
+ }
1312
+ };
1313
+ });
1314
+ direction = computed(() => {
1315
+ return this.speedDialConfig().direction;
1316
+ });
1317
+ toggleMenu(anchor) {
1318
+ const nextState = !this.isMenuOpen();
1319
+ this._isMenuOpen.set(nextState);
1320
+ this.activeAnchor = anchor ?? this.mainButtonHost;
1321
+ if (!nextState)
1322
+ return;
1323
+ this.updatePanelPosition();
1324
+ window.addEventListener('resize', this.handleViewportChange);
1325
+ window.addEventListener('scroll', this.handleViewportChange, true);
1326
+ }
1327
+ closeMenu() {
1328
+ if (!this.isMenuOpen())
1329
+ return;
1330
+ this._isMenuOpen.set(false);
1331
+ this.activeAnchor = undefined;
1332
+ window.removeEventListener('resize', this.handleViewportChange);
1333
+ window.removeEventListener('scroll', this.handleViewportChange, true);
1334
+ }
1335
+ destroy() {
1336
+ this.closeMenu();
1337
+ this.mainButtonHost = undefined;
1338
+ }
1339
+ handleViewportChange = () => {
1340
+ if (!this.isMenuOpen())
1341
+ return;
1342
+ this.updatePanelPosition();
1343
+ };
1344
+ updatePanelPosition() {
1345
+ const anchor = this.activeAnchor ?? this.mainButtonHost;
1346
+ if (!anchor)
1347
+ return;
1348
+ const rect = anchor.getBoundingClientRect();
1349
+ const fixedContainingBlock = this.getFixedContainingBlock(anchor);
1350
+ const containingBlockRect = fixedContainingBlock?.getBoundingClientRect();
1351
+ const offsetTop = containingBlockRect?.top ?? 0;
1352
+ const offsetLeft = containingBlockRect?.left ?? 0;
1353
+ switch (this.direction()) {
1354
+ case 'top':
1355
+ this._panelTop.set(`${rect.top - offsetTop - this.panelOffset}px`);
1356
+ this._panelLeft.set(`${rect.left - offsetLeft}px`);
1357
+ break;
1358
+ case 'bottom':
1359
+ this._panelTop.set(`${rect.bottom - offsetTop + this.panelOffset}px`);
1360
+ this._panelLeft.set(`${rect.left - offsetLeft}px`);
1361
+ break;
1362
+ case 'left':
1363
+ this._panelTop.set(`${rect.top - offsetTop}px`);
1364
+ this._panelLeft.set(`${rect.left - offsetLeft - this.panelOffset}px`);
1365
+ break;
1366
+ case 'right':
1367
+ this._panelTop.set(`${rect.top - offsetTop}px`);
1368
+ this._panelLeft.set(`${rect.right - offsetLeft + this.panelOffset}px`);
1369
+ break;
1370
+ }
1371
+ }
1372
+ /**
1373
+ * Detecta el ancestro que actúa como containing block para elementos fixed.
1374
+ * Si existe (por transform/filter/contain/etc), el panel debe posicionarse
1375
+ * relativo a ese contenedor y no al viewport.
1376
+ */
1377
+ getFixedContainingBlock(element) {
1378
+ let current = element.parentElement;
1379
+ while (current) {
1380
+ const styles = window.getComputedStyle(current);
1381
+ const hasTransformContext = styles.transform !== 'none' ||
1382
+ styles.perspective !== 'none' ||
1383
+ styles.filter !== 'none' ||
1384
+ (styles.backdropFilter && styles.backdropFilter !== 'none') ||
1385
+ styles.contain.includes('paint') ||
1386
+ styles.contain.includes('layout') ||
1387
+ styles.willChange.includes('transform') ||
1388
+ styles.willChange.includes('filter') ||
1389
+ styles.willChange.includes('perspective');
1390
+ if (hasTransformContext) {
1391
+ return current;
1392
+ }
1393
+ current = current.parentElement;
1394
+ }
1395
+ return null;
1396
+ }
1397
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SpeedDialService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1398
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SpeedDialService, providedIn: 'root' });
1399
+ }
1400
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SpeedDialService, decorators: [{
1401
+ type: Injectable,
1402
+ args: [{
1403
+ providedIn: 'root'
1404
+ }]
1405
+ }], ctorParameters: () => [] });
1406
+
1407
+ class AppButtonNgService {
1408
+ buttonConfig = signal({});
1409
+ constructor() {
1410
+ // Effect para manejar automáticamente la rotación de mensajes
1411
+ effect(() => {
1412
+ const config = this.buttonConfig();
1413
+ if (config.loading && config.loadingMessages && config.loadingMessages.length > 1) {
1414
+ this.startMessageRotation();
1415
+ }
1416
+ else {
1417
+ this.stopMessageRotation();
1418
+ }
1419
+ });
1420
+ }
1421
+ setButtonConfig(buttonConfig) {
1422
+ this.buttonConfig.set(buttonConfig);
1423
+ }
1424
+ // Computed público para acceder al label dinámico
1425
+ label = computed(() => {
1426
+ const config = this.buttonConfig();
1427
+ // Si está cargando y tiene mensajes de carga, rotar entre ellos
1428
+ if (config.loading && config.loadingMessages && config.loadingMessages.length > 0) {
1429
+ const messages = config.loadingMessages;
1430
+ const index = this.messageIndex() % messages.length; // Wrap around
1431
+ return messages[index];
1432
+ }
1433
+ // Si no está cargando, retornar el label normal
1434
+ return config.label ? config.label : '';
1435
+ });
1436
+ //#region Loading Messages
1437
+ messageIndex = signal(0);
1438
+ intervalId;
1439
+ startMessageRotation() {
1440
+ if (this.intervalId)
1441
+ return;
1442
+ this.intervalId = setInterval(() => {
1443
+ this.messageIndex.update(index => index + 1);
1444
+ }, 6000);
1445
+ }
1446
+ stopMessageRotation() {
1447
+ if (this.intervalId) {
1448
+ clearInterval(this.intervalId);
1449
+ this.intervalId = undefined;
1450
+ this.messageIndex.set(0);
1451
+ }
1452
+ }
1453
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AppButtonNgService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1454
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AppButtonNgService, providedIn: 'root' });
1455
+ }
1456
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AppButtonNgService, decorators: [{
1457
+ type: Injectable,
1458
+ args: [{
1459
+ providedIn: 'root'
1460
+ }]
1461
+ }], ctorParameters: () => [] });
1462
+
1463
+ class ButtonNgComponent {
1464
+ appButtonNgService = inject(AppButtonNgService);
1465
+ buttonConfig = model.required();
1466
+ onClick = output();
1467
+ constructor() {
1468
+ effect(() => {
1469
+ this.appButtonNgService.setButtonConfig(this.buttonConfig());
1470
+ });
1471
+ }
1472
+ get label() {
1473
+ return this.appButtonNgService.label();
1474
+ }
1475
+ onClickButton() {
1476
+ if (this.buttonConfig().onClick) {
1477
+ return;
1478
+ }
1479
+ this.onClick.emit();
1480
+ }
1481
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: ButtonNgComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1482
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: ButtonNgComponent, isStandalone: true, selector: "lib-button-ng", inputs: { buttonConfig: { classPropertyName: "buttonConfig", publicName: "buttonConfig", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { buttonConfig: "buttonConfigChange", onClick: "onClick" }, providers: [AppButtonNgService], ngImport: i0, template: "@let config = buttonConfig(); @let tooltipConfig = buttonConfig().tooltipConfig;\r\n@if (!config.hideButton) {\r\n <div\r\n [ngClass]=\"{\r\n 'full-width-button': config.fullWidth,\r\n 'full-height-button': config.fullHeight,\r\n 'cursor-pointer': this.onClick\r\n }\"\r\n [class]=\"config.class ?? ''\"\r\n >\r\n <p-button\r\n [label]=\"config.hasTemplate ? undefined : label\"\r\n [icon]=\"config.hasTemplate ? undefined : config.icon\"\r\n [severity]=\"config.hasTemplate ? 'secondary' : config.severity\"\r\n [loading]=\"config.loading || false\"\r\n [disabled]=\"config.disabled || false\"\r\n [rounded]=\"config.rounded || false\"\r\n [raised]=\"config.raised || false\"\r\n [variant]=\"config.hasTemplate ? 'text' : config.variant\"\r\n [badge]=\"config.badge\"\r\n (onClick)=\"config?.onClick?.() ?? onClickButton()\"\r\n [size]=\"config?.size\"\r\n pTooltip=\"{{ tooltipConfig?.pTooltip }}\"\r\n [tooltipPosition]=\"tooltipConfig?.tooltipPosition ?? 'top'\"\r\n [iconPos]=\"config?.iconPos ?? 'left'\"\r\n [ngClass]=\"{\r\n 'cursor-pointer': (config.onClick || config.hasStaticClick) && !config.disabled,\r\n 'cursor-auto': !((config.onClick || config.hasStaticClick) && !config.disabled),\r\n 'no-hover-template': config.hasTemplate\r\n }\"\r\n [outlined]=\"config.outlined || false\"\r\n [text]=\"config.text || false\"\r\n >\r\n @if (config.hasTemplate) {\r\n <ng-content></ng-content>\r\n }\r\n </p-button>\r\n </div>\r\n}\r\n", styles: [".full-width-button ::ng-deep p-button button{width:100%}.full-height-button ::ng-deep p-button button{height:100%}::ng-deep .cursor-auto button{cursor:auto!important}::ng-deep .cursor-pointer button{cursor:pointer!important}::ng-deep .no-hover-template button{background:transparent!important;border:none!important;box-shadow:none!important;padding:0!important}::ng-deep .no-hover-template button:hover,::ng-deep .no-hover-template button:focus,::ng-deep .no-hover-template button:active{background:transparent!important;border:none!important;box-shadow:none!important}\n"], dependencies: [{ kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i10.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
1483
+ }
1484
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: ButtonNgComponent, decorators: [{
1485
+ type: Component,
1486
+ args: [{ selector: 'lib-button-ng', imports: [
1487
+ ButtonModule,
1488
+ TooltipModule,
1489
+ CommonModule
1490
+ ], providers: [AppButtonNgService], template: "@let config = buttonConfig(); @let tooltipConfig = buttonConfig().tooltipConfig;\r\n@if (!config.hideButton) {\r\n <div\r\n [ngClass]=\"{\r\n 'full-width-button': config.fullWidth,\r\n 'full-height-button': config.fullHeight,\r\n 'cursor-pointer': this.onClick\r\n }\"\r\n [class]=\"config.class ?? ''\"\r\n >\r\n <p-button\r\n [label]=\"config.hasTemplate ? undefined : label\"\r\n [icon]=\"config.hasTemplate ? undefined : config.icon\"\r\n [severity]=\"config.hasTemplate ? 'secondary' : config.severity\"\r\n [loading]=\"config.loading || false\"\r\n [disabled]=\"config.disabled || false\"\r\n [rounded]=\"config.rounded || false\"\r\n [raised]=\"config.raised || false\"\r\n [variant]=\"config.hasTemplate ? 'text' : config.variant\"\r\n [badge]=\"config.badge\"\r\n (onClick)=\"config?.onClick?.() ?? onClickButton()\"\r\n [size]=\"config?.size\"\r\n pTooltip=\"{{ tooltipConfig?.pTooltip }}\"\r\n [tooltipPosition]=\"tooltipConfig?.tooltipPosition ?? 'top'\"\r\n [iconPos]=\"config?.iconPos ?? 'left'\"\r\n [ngClass]=\"{\r\n 'cursor-pointer': (config.onClick || config.hasStaticClick) && !config.disabled,\r\n 'cursor-auto': !((config.onClick || config.hasStaticClick) && !config.disabled),\r\n 'no-hover-template': config.hasTemplate\r\n }\"\r\n [outlined]=\"config.outlined || false\"\r\n [text]=\"config.text || false\"\r\n >\r\n @if (config.hasTemplate) {\r\n <ng-content></ng-content>\r\n }\r\n </p-button>\r\n </div>\r\n}\r\n", styles: [".full-width-button ::ng-deep p-button button{width:100%}.full-height-button ::ng-deep p-button button{height:100%}::ng-deep .cursor-auto button{cursor:auto!important}::ng-deep .cursor-pointer button{cursor:pointer!important}::ng-deep .no-hover-template button{background:transparent!important;border:none!important;box-shadow:none!important;padding:0!important}::ng-deep .no-hover-template button:hover,::ng-deep .no-hover-template button:focus,::ng-deep .no-hover-template button:active{background:transparent!important;border:none!important;box-shadow:none!important}\n"] }]
1491
+ }], ctorParameters: () => [] });
1492
+
1493
+ class SpeedDialComponent {
1494
+ mainButtonContainer;
1495
+ speedDialConfig = input.required();
1496
+ speedDialService = inject(SpeedDialService);
1497
+ constructor() {
1498
+ effect(() => {
1499
+ this.speedDialService.setSpeedDialConfig(this.speedDialConfig());
1500
+ });
1501
+ }
1502
+ get buttons() {
1503
+ return this.speedDialService.buttons();
1504
+ }
1505
+ get overlayButtons() {
1506
+ return this.speedDialService.overlayButtons();
1507
+ }
1508
+ get mainButton() {
1509
+ return this.speedDialService.mainButton();
1510
+ }
1511
+ get isMenuOpen() {
1512
+ return this.speedDialService.isMenuOpen();
1513
+ }
1514
+ get panelTop() {
1515
+ return this.speedDialService.panelTop();
1516
+ }
1517
+ get panelLeft() {
1518
+ return this.speedDialService.panelLeft();
1519
+ }
1520
+ get direction() {
1521
+ return this.speedDialService.direction();
1522
+ }
1523
+ ngAfterViewInit() {
1524
+ const hostElement = this.mainButtonContainer?.nativeElement;
1525
+ if (!hostElement)
1526
+ return;
1527
+ this.speedDialService.setMainButtonHost(hostElement);
1528
+ }
1529
+ ngOnDestroy() {
1530
+ this.speedDialService.destroy();
1531
+ }
1532
+ closeMenu() {
1533
+ this.speedDialService.closeMenu();
1534
+ }
1535
+ onMainButtonClick(event) {
1536
+ const target = event.target;
1537
+ const anchor = target?.closest('button,[role="button"]');
1538
+ this.speedDialService.toggleMenu(anchor ?? this.mainButtonContainer?.nativeElement);
1539
+ }
1540
+ stopPropagation(event) {
1541
+ event.stopPropagation();
1542
+ }
1543
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SpeedDialComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1544
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SpeedDialComponent, isStandalone: true, selector: "lib-speed-dial", inputs: { speedDialConfig: { classPropertyName: "speedDialConfig", publicName: "speedDialConfig", isSignal: true, isRequired: true, transformFunction: null } }, providers: [SpeedDialService], viewQueries: [{ propertyName: "mainButtonContainer", first: true, predicate: ["mainButtonContainer"], descendants: true }], ngImport: i0, template: "<div\r\n #mainButtonContainer\r\n class=\"speed-dial-main-button\"\r\n [class.speed-dial-main-button--open]=\"isMenuOpen\"\r\n (click)=\"onMainButtonClick($event)\"\r\n>\r\n <lib-button-ng [buttonConfig]=\"mainButton\"></lib-button-ng>\r\n</div>\r\n\r\n@if (isMenuOpen) {\r\n <div class=\"speed-dial-overlay\" (click)=\"closeMenu()\">\r\n <div\r\n class=\"speed-dial-panel bg-gray-100 dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-lg\"\r\n [style.top]=\"panelTop\"\r\n [style.left]=\"panelLeft\"\r\n (click)=\"stopPropagation($event)\"\r\n [ngClass]=\"{\r\n 'speed-dial-panel--top': direction === 'top',\r\n 'speed-dial-panel--bottom': direction === 'bottom',\r\n 'speed-dial-panel--left': direction === 'left',\r\n 'speed-dial-panel--right': direction === 'right'\r\n }\"\r\n >\r\n @for (button of overlayButtons; track $index) {\r\n <lib-button-ng [buttonConfig]=\"button\"></lib-button-ng>\r\n }\r\n </div>\r\n </div>\r\n}\r\n", styles: [".speed-dial-main-button{display:inline-flex}.speed-dial-main-button--open{position:relative;z-index:2147483647}.speed-dial-overlay{position:fixed;inset:0;z-index:2147483645}.speed-dial-panel{position:fixed;z-index:2147483646;display:flex;gap:.5rem;overflow:auto;padding:.75rem;border-radius:.75rem;background:#fff;box-shadow:0 10px 30px #0f172a40}.speed-dial-panel--top{flex-direction:column;max-width:22rem;max-height:30rem;transform:translateY(-100%)}.speed-dial-panel--bottom{flex-direction:column;max-width:22rem;max-height:30rem}.speed-dial-panel--left{flex-direction:row;max-width:40rem;max-height:8rem;transform:translate(-100%)}.speed-dial-panel--right{flex-direction:row;max-width:40rem;max-height:8rem}:host-context(.dark) .speed-dial-panel{background:#111827}\n"], dependencies: [{ kind: "component", type: ButtonNgComponent, selector: "lib-button-ng", inputs: ["buttonConfig"], outputs: ["buttonConfigChange", "onClick"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
1545
+ }
1546
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SpeedDialComponent, decorators: [{
1547
+ type: Component,
1548
+ args: [{ selector: 'lib-speed-dial', imports: [ButtonNgComponent, CommonModule], providers: [SpeedDialService], template: "<div\r\n #mainButtonContainer\r\n class=\"speed-dial-main-button\"\r\n [class.speed-dial-main-button--open]=\"isMenuOpen\"\r\n (click)=\"onMainButtonClick($event)\"\r\n>\r\n <lib-button-ng [buttonConfig]=\"mainButton\"></lib-button-ng>\r\n</div>\r\n\r\n@if (isMenuOpen) {\r\n <div class=\"speed-dial-overlay\" (click)=\"closeMenu()\">\r\n <div\r\n class=\"speed-dial-panel bg-gray-100 dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-lg\"\r\n [style.top]=\"panelTop\"\r\n [style.left]=\"panelLeft\"\r\n (click)=\"stopPropagation($event)\"\r\n [ngClass]=\"{\r\n 'speed-dial-panel--top': direction === 'top',\r\n 'speed-dial-panel--bottom': direction === 'bottom',\r\n 'speed-dial-panel--left': direction === 'left',\r\n 'speed-dial-panel--right': direction === 'right'\r\n }\"\r\n >\r\n @for (button of overlayButtons; track $index) {\r\n <lib-button-ng [buttonConfig]=\"button\"></lib-button-ng>\r\n }\r\n </div>\r\n </div>\r\n}\r\n", styles: [".speed-dial-main-button{display:inline-flex}.speed-dial-main-button--open{position:relative;z-index:2147483647}.speed-dial-overlay{position:fixed;inset:0;z-index:2147483645}.speed-dial-panel{position:fixed;z-index:2147483646;display:flex;gap:.5rem;overflow:auto;padding:.75rem;border-radius:.75rem;background:#fff;box-shadow:0 10px 30px #0f172a40}.speed-dial-panel--top{flex-direction:column;max-width:22rem;max-height:30rem;transform:translateY(-100%)}.speed-dial-panel--bottom{flex-direction:column;max-width:22rem;max-height:30rem}.speed-dial-panel--left{flex-direction:row;max-width:40rem;max-height:8rem;transform:translate(-100%)}.speed-dial-panel--right{flex-direction:row;max-width:40rem;max-height:8rem}:host-context(.dark) .speed-dial-panel{background:#111827}\n"] }]
1549
+ }], ctorParameters: () => [], propDecorators: { mainButtonContainer: [{
1550
+ type: ViewChild,
1551
+ args: ['mainButtonContainer']
1552
+ }] } });
1553
+
1554
+ class KeyToDisplayNamePipe {
1555
+ transform(key, keysNames) {
1556
+ return keysNames?.[key] ?? key;
1557
+ }
1558
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: KeyToDisplayNamePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
1559
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.17", ngImport: i0, type: KeyToDisplayNamePipe, isStandalone: true, name: "keyToDisplayName" });
1560
+ }
1561
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: KeyToDisplayNamePipe, decorators: [{
1562
+ type: Pipe,
1563
+ args: [{
1564
+ name: 'keyToDisplayName'
1565
+ }]
1566
+ }] });
1567
+
1568
+ class BadgeNgComponent {
1569
+ config = model.required();
1570
+ get value() {
1571
+ return this.config().value;
1572
+ }
1573
+ get severity() {
1574
+ return this.config().severity;
1575
+ }
1576
+ get badgeSize() {
1577
+ return this.config().badgeSize ?? 'small';
1578
+ }
1579
+ get fullWidth() {
1580
+ return this.config().fullWidth ?? true;
1581
+ }
1582
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: BadgeNgComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1583
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.17", type: BadgeNgComponent, isStandalone: true, selector: "lib-badge-ng", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { config: "configChange" }, ngImport: i0, template: "<p-badge\r\n [style]=\"{\r\n textAlign: 'center',\r\n width: fullWidth ? '100%' : 'auto'\r\n }\"\r\n [value]=\"value\"\r\n [severity]=\"severity\"\r\n [badgeSize]=\"badgeSize\"\r\n/>\r\n", dependencies: [{ kind: "ngmodule", type: BadgeModule }, { kind: "component", type: i1$3.Badge, selector: "p-badge", inputs: ["styleClass", "style", "badgeSize", "size", "severity", "value", "badgeDisabled"] }] });
1584
+ }
1585
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: BadgeNgComponent, decorators: [{
1586
+ type: Component,
1587
+ args: [{ selector: 'lib-badge-ng', imports: [BadgeModule], template: "<p-badge\r\n [style]=\"{\r\n textAlign: 'center',\r\n width: fullWidth ? '100%' : 'auto'\r\n }\"\r\n [value]=\"value\"\r\n [severity]=\"severity\"\r\n [badgeSize]=\"badgeSize\"\r\n/>\r\n" }]
1588
+ }] });
1589
+
1590
+ class ToolbarNgComponent {
1591
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: ToolbarNgComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1592
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: ToolbarNgComponent, isStandalone: true, selector: "lib-toolbar-ng", ngImport: i0, template: "<p-toolbar class=\"border-0 bg-transparent\">\r\n <ng-template pTemplate=\"start\">\r\n <ng-content select=\"[toolbarStart]\"></ng-content>\r\n </ng-template>\r\n\r\n <ng-template pTemplate=\"center\">\r\n <ng-content select=\"[toolbarCenter]\"></ng-content>\r\n </ng-template>\r\n\r\n <ng-template pTemplate=\"end\">\r\n <ng-content select=\"[toolbarEnd]\"></ng-content>\r\n </ng-template>\r\n</p-toolbar>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: ToolbarModule }, { kind: "component", type: i1$4.Toolbar, selector: "p-toolbar", inputs: ["style", "styleClass", "ariaLabelledBy"] }, { kind: "directive", type: i4$1.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }] });
1593
+ }
1594
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: ToolbarNgComponent, decorators: [{
1595
+ type: Component,
1596
+ args: [{ selector: 'lib-toolbar-ng', imports: [
1597
+ ToolbarModule
1598
+ ], template: "<p-toolbar class=\"border-0 bg-transparent\">\r\n <ng-template pTemplate=\"start\">\r\n <ng-content select=\"[toolbarStart]\"></ng-content>\r\n </ng-template>\r\n\r\n <ng-template pTemplate=\"center\">\r\n <ng-content select=\"[toolbarCenter]\"></ng-content>\r\n </ng-template>\r\n\r\n <ng-template pTemplate=\"end\">\r\n <ng-content select=\"[toolbarEnd]\"></ng-content>\r\n </ng-template>\r\n</p-toolbar>\r\n" }]
1599
+ }] });
1600
+
1601
+ // services/dialog.service.ts
1602
+ class CustomDialogService {
1603
+ dialogRef;
1604
+ dialogService = inject(DialogService);
1605
+ constructor() { }
1606
+ open(component, options = {}) {
1607
+ const defaultConfig = {
1608
+ closable: true,
1609
+ header: options.header || '',
1610
+ width: options.width || '50%',
1611
+ height: options.height || 'auto',
1612
+ closeOnEscape: options.closeOnEscape ?? true,
1613
+ baseZIndex: options.baseZIndex || 10000,
1614
+ maximizable: options.maximizable ?? true,
1615
+ data: options.data || {},
1616
+ style: {
1617
+ borderRadius: '8px',
1618
+ ...options.style
1619
+ },
1620
+ modal: true
1621
+ };
1622
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
1623
+ this.dialogRef = this.dialogService.open(component, defaultConfig);
1624
+ return this.dialogRef;
1625
+ }
1626
+ close(result) {
1627
+ if (this.dialogRef) {
1628
+ this.dialogRef.close(result);
1629
+ }
1630
+ }
1631
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CustomDialogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1632
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CustomDialogService, providedIn: 'root' });
1633
+ }
1634
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: CustomDialogService, decorators: [{
1635
+ type: Injectable,
1636
+ args: [{
1637
+ providedIn: 'root'
1638
+ }]
1639
+ }], ctorParameters: () => [] });
1640
+
1641
+ class BaseDialogComponent {
1642
+ destroy$ = new Subject();
1643
+ data;
1644
+ ref = inject(DynamicDialogRef);
1645
+ config = inject(DynamicDialogConfig);
1646
+ constructor() {
1647
+ this.data = this.config.data;
1648
+ }
1649
+ ngOnDestroy() {
1650
+ this.destroy$.next();
1651
+ this.destroy$.complete();
1652
+ }
1653
+ close(result) {
1654
+ this.ref.close(result);
1655
+ }
1656
+ dismiss() {
1657
+ this.ref.close({ success: false });
1658
+ }
1659
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: BaseDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1660
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: BaseDialogComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: '', isInline: true });
1661
+ }
1662
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: BaseDialogComponent, decorators: [{
1663
+ type: Component,
1664
+ args: [{
1665
+ standalone: true,
1666
+ template: ''
1667
+ }]
1668
+ }], ctorParameters: () => [] });
1669
+
1670
+ const pickListConstant = (e, element) => {
1671
+ if (e.id === element?.id) {
1672
+ e.isSelected = !e.isSelected;
1673
+ if (e.isSelected) {
1674
+ delete e.buttonConfig.variant;
1675
+ delete e.buttonConfig.raised;
1676
+ }
1677
+ else {
1678
+ e.buttonConfig.variant = 'outlined';
1679
+ e.buttonConfig.raised = true;
1680
+ }
1681
+ }
1682
+ };
1683
+
1684
+ class ContainerElementsComponent {
1685
+ cols = input(3);
1686
+ elements = model([]);
1687
+ severityButton = input('contrast');
1688
+ outputElements = output();
1689
+ constructor() {
1690
+ }
1691
+ ngOnInit() {
1692
+ this.elements.update((elements) => {
1693
+ elements.forEach((e) => {
1694
+ // Si e.isSelected es true, se elimina el variant y raised
1695
+ if (e.isSelected) {
1696
+ delete e.buttonConfig.variant;
1697
+ delete e.buttonConfig.raised;
1698
+ }
1699
+ else {
1700
+ e.buttonConfig.variant = 'outlined';
1701
+ e.buttonConfig.raised = true;
1702
+ }
1703
+ e.buttonConfig = {
1704
+ ...e.buttonConfig,
1705
+ fullWidth: true,
1706
+ fullHeight: true,
1707
+ hasStaticClick: true,
1708
+ severity: this.severityButton()
1709
+ };
1710
+ });
1711
+ return [...elements];
1712
+ });
1713
+ }
1714
+ containerClass = computed(() => 'w-[45%] flex flex-col shadow-md bg-white dark:bg-gray-800 rounded-xl h-full overflow-y-auto');
1715
+ titleClass = computed(() => 'text-lg font-bold self-center text-center');
1716
+ containerElementsClass = computed(() => `grid grid-cols-${this.cols() ?? 3} gap-2 p-2`);
1717
+ getButtonConfig(buttonConfig) {
1718
+ return { ...buttonConfig, fullWidth: true, severity: this.severityButton(), hasStaticClick: true };
1719
+ }
1720
+ onButtonClick(element) {
1721
+ this.elements.update((elements) => {
1722
+ elements.forEach((e) => {
1723
+ pickListConstant(e, element);
1724
+ });
1725
+ return [...elements];
1726
+ });
1727
+ this.outputElements.emit([...this.elements()]);
1728
+ }
1729
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: ContainerElementsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1730
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: ContainerElementsComponent, isStandalone: true, selector: "lib-container-elements", inputs: { cols: { classPropertyName: "cols", publicName: "cols", isSignal: true, isRequired: false, transformFunction: null }, elements: { classPropertyName: "elements", publicName: "elements", isSignal: true, isRequired: false, transformFunction: null }, severityButton: { classPropertyName: "severityButton", publicName: "severityButton", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { elements: "elementsChange", outputElements: "outputElements" }, ngImport: i0, template: "<div class=\"h-full w-full\" [class]=\"containerClass()\">\r\n <div class=\"dynamic-grid\" [style.--grid-cols]=\"cols()\">\r\n @for (element of elements(); track element.id) {\r\n <div class=\"grid-item\">\r\n @if (element.buttonConfig) {\r\n <lib-button-ng [(buttonConfig)]=\"element.buttonConfig\" (onClick)=\"onButtonClick(element)\"></lib-button-ng>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</div>", styles: [".dynamic-grid{display:grid;gap:.5rem;padding:.5rem;grid-template-columns:repeat(var(--grid-cols, 3),1fr)}.grid-item{border-radius:.375rem;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a}\n"], dependencies: [{ kind: "component", type: ButtonNgComponent, selector: "lib-button-ng", inputs: ["buttonConfig"], outputs: ["buttonConfigChange", "onClick"] }, { kind: "ngmodule", type: CommonModule }] });
1731
+ }
1732
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: ContainerElementsComponent, decorators: [{
1733
+ type: Component,
1734
+ args: [{ selector: 'lib-container-elements', imports: [ButtonNgComponent, CommonModule], template: "<div class=\"h-full w-full\" [class]=\"containerClass()\">\r\n <div class=\"dynamic-grid\" [style.--grid-cols]=\"cols()\">\r\n @for (element of elements(); track element.id) {\r\n <div class=\"grid-item\">\r\n @if (element.buttonConfig) {\r\n <lib-button-ng [(buttonConfig)]=\"element.buttonConfig\" (onClick)=\"onButtonClick(element)\"></lib-button-ng>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</div>", styles: [".dynamic-grid{display:grid;gap:.5rem;padding:.5rem;grid-template-columns:repeat(var(--grid-cols, 3),1fr)}.grid-item{border-radius:.375rem;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a}\n"] }]
1735
+ }], ctorParameters: () => [] });
1736
+
1737
+ class PickListComponent {
1738
+ constructor() {
1739
+ }
1740
+ ngOnInit() { }
1741
+ sourceElements = model([]);
1742
+ hasAnySourceElementSelected = computed(() => this.sourceElements().some(element => element.isSelected));
1743
+ targetElements = model([]);
1744
+ hasAnyTargetElementSelected = computed(() => this.targetElements().some(element => element.isSelected));
1745
+ config = input();
1746
+ outputElements = output();
1747
+ sourceSeverityButton = computed(() => this.config()?.sourceSeverityButton ?? 'secondary');
1748
+ targetSeverityButton = computed(() => this.config()?.targetSeverityButton ?? 'contrast');
1749
+ controlButtons = computed(() => [
1750
+ {
1751
+ label: '',
1752
+ icon: 'pi pi-angle-double-right',
1753
+ severity: this.sourceSeverityButton(),
1754
+ disabled: this.sourceElements().length === 0,
1755
+ tooltipConfig: {
1756
+ pTooltip: this.sourceElements().length === 0 ? 'No hay elementos' : 'Mover todos hacia la derecha',
1757
+ tooltipPosition: 'top'
1758
+ },
1759
+ onClick: () => {
1760
+ this.moveAllSourceToTarget();
1761
+ }
1762
+ },
1763
+ {
1764
+ label: '',
1765
+ icon: 'pi pi-angle-right',
1766
+ severity: this.sourceSeverityButton(),
1767
+ disabled: !this.hasAnySourceElementSelected(),
1768
+ tooltipConfig: {
1769
+ pTooltip: !this.hasAnySourceElementSelected() ? 'No hay elementos seleccionados' : 'Mover los elementos seleccionados hacia la derecha',
1770
+ tooltipPosition: 'top'
1771
+ },
1772
+ onClick: () => {
1773
+ this.moveSelectedSourceToTarget();
1774
+ }
1775
+ },
1776
+ {
1777
+ label: '',
1778
+ icon: 'pi pi-angle-double-left',
1779
+ severity: this.targetSeverityButton(),
1780
+ disabled: this.targetElements().length === 0,
1781
+ tooltipConfig: {
1782
+ pTooltip: this.targetElements().length === 0 ? 'No hay elementos' : 'Mover todos hacia la izquierda',
1783
+ tooltipPosition: 'top'
1784
+ },
1785
+ onClick: () => {
1786
+ this.moveAllTargetToSource();
1787
+ }
1788
+ },
1789
+ {
1790
+ label: '',
1791
+ icon: 'pi pi-angle-left',
1792
+ severity: this.targetSeverityButton(),
1793
+ disabled: !this.hasAnyTargetElementSelected(),
1794
+ tooltipConfig: {
1795
+ pTooltip: !this.hasAnyTargetElementSelected() ? 'No hay elementos seleccionados' : 'Mover los elementos seleccionados hacia la izquierda',
1796
+ tooltipPosition: 'top'
1797
+ },
1798
+ onClick: () => {
1799
+ this.moveSelectedTargetToSource();
1800
+ }
1801
+ }
1802
+ ]);
1803
+ /**
1804
+ * Mueve todos los elementos del sourceElements al targetElements,
1805
+ * convirtiendo su severidad para que coincida con targetSeverityButton
1806
+ */
1807
+ moveAllSourceToTarget() {
1808
+ const sourceElementsCopy = [...this.sourceElements()];
1809
+ if (sourceElementsCopy.length === 0) {
1810
+ return;
1811
+ }
1812
+ // Convertir los elementos para usar targetSeverityButton
1813
+ const convertedElements = sourceElementsCopy.map(element => {
1814
+ const convertedElement = {
1815
+ ...element,
1816
+ isSelected: false, // Limpiar selección
1817
+ buttonConfig: {
1818
+ ...element.buttonConfig,
1819
+ severity: this.targetSeverityButton(),
1820
+ variant: 'outlined',
1821
+ raised: true
1822
+ }
1823
+ };
1824
+ return convertedElement;
1825
+ });
1826
+ // Agregar elementos convertidos al target
1827
+ this.targetElements.update(currentTarget => [
1828
+ ...currentTarget,
1829
+ ...convertedElements
1830
+ ]);
1831
+ // Limpiar sourceElements
1832
+ this.sourceElements.set([]);
1833
+ this.handleOutputElements();
1834
+ }
1835
+ /**
1836
+ * Mueve todos los elementos del targetElements al sourceElements,
1837
+ * convirtiendo su severidad para que coincida con sourceSeverityButton
1838
+ */
1839
+ moveAllTargetToSource() {
1840
+ const targetElementsCopy = [...this.targetElements()];
1841
+ if (targetElementsCopy.length === 0) {
1842
+ return;
1843
+ }
1844
+ // Convertir los elementos para usar sourceSeverityButton
1845
+ const convertedElements = targetElementsCopy.map(element => {
1846
+ const convertedElement = {
1847
+ ...element,
1848
+ isSelected: false, // Limpiar selección
1849
+ buttonConfig: {
1850
+ ...element.buttonConfig,
1851
+ severity: this.sourceSeverityButton(),
1852
+ variant: 'outlined',
1853
+ raised: true
1854
+ }
1855
+ };
1856
+ return convertedElement;
1857
+ });
1858
+ // Agregar elementos convertidos al source
1859
+ this.sourceElements.update(currentSource => [
1860
+ ...currentSource,
1861
+ ...convertedElements
1862
+ ]);
1863
+ // Limpiar targetElements
1864
+ this.targetElements.set([]);
1865
+ this.handleOutputElements();
1866
+ }
1867
+ /**
1868
+ * Mueve los elementos seleccionados del sourceElements al targetElements,
1869
+ * ubicándolos en la primera posición y convirtiendo su severidad
1870
+ */
1871
+ moveSelectedSourceToTarget() {
1872
+ const selectedElements = this.sourceElements().filter(element => element.isSelected);
1873
+ const remainingElements = this.sourceElements().filter(element => !element.isSelected);
1874
+ if (selectedElements.length === 0) {
1875
+ return;
1876
+ }
1877
+ // Convertir los elementos seleccionados para usar targetSeverityButton
1878
+ const convertedElements = selectedElements.map(element => {
1879
+ const convertedElement = {
1880
+ ...element,
1881
+ isSelected: false, // Limpiar selección
1882
+ buttonConfig: {
1883
+ ...element.buttonConfig,
1884
+ severity: this.targetSeverityButton(),
1885
+ variant: 'outlined',
1886
+ raised: true
1887
+ }
1888
+ };
1889
+ return convertedElement;
1890
+ });
1891
+ // Agregar elementos convertidos al inicio de targetElements
1892
+ this.targetElements.update(currentTarget => [
1893
+ ...convertedElements,
1894
+ ...currentTarget
1895
+ ]);
1896
+ // Actualizar sourceElements sin los elementos seleccionados
1897
+ this.sourceElements.set(remainingElements);
1898
+ this.handleOutputElements();
1899
+ }
1900
+ /**
1901
+ * Mueve los elementos seleccionados del targetElements al sourceElements,
1902
+ * ubicándolos en la primera posición y convirtiendo su severidad
1903
+ */
1904
+ moveSelectedTargetToSource() {
1905
+ const selectedElements = this.targetElements().filter(element => element.isSelected);
1906
+ const remainingElements = this.targetElements().filter(element => !element.isSelected);
1907
+ if (selectedElements.length === 0) {
1908
+ return;
1909
+ }
1910
+ // Convertir los elementos seleccionados para usar sourceSeverityButton
1911
+ const convertedElements = selectedElements.map(element => {
1912
+ const convertedElement = {
1913
+ ...element,
1914
+ isSelected: false, // Limpiar selección
1915
+ buttonConfig: {
1916
+ ...element.buttonConfig,
1917
+ severity: this.sourceSeverityButton(),
1918
+ variant: 'outlined',
1919
+ raised: true
1920
+ }
1921
+ };
1922
+ return convertedElement;
1923
+ });
1924
+ // Agregar elementos convertidos al inicio de sourceElements
1925
+ this.sourceElements.update(currentSource => [
1926
+ ...convertedElements,
1927
+ ...currentSource
1928
+ ]);
1929
+ // Actualizar targetElements sin los elementos seleccionados
1930
+ this.targetElements.set(remainingElements);
1931
+ this.handleOutputElements();
1932
+ }
1933
+ handleOutputElements() {
1934
+ this.outputElements.emit({ sourceElements: this.sourceElements(), targetElements: this.targetElements() });
1935
+ }
1936
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: PickListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1937
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: PickListComponent, isStandalone: true, selector: "lib-pick-list", inputs: { sourceElements: { classPropertyName: "sourceElements", publicName: "sourceElements", isSignal: true, isRequired: false, transformFunction: null }, targetElements: { classPropertyName: "targetElements", publicName: "targetElements", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sourceElements: "sourceElementsChange", targetElements: "targetElementsChange", outputElements: "outputElements" }, ngImport: i0, template: "@let cols = config()?.cols ?? 3;\r\n@let sourceSeverityButton = config()?.sourceSeverityButton ?? 'secondary';\r\n@let targetSeverityButton = config()?.targetSeverityButton ?? 'contrast';\r\n<div class=\"flex gap-4 h-80 w-full bg-gray-100 dark:bg-gray-800 rounded-xl p-3\">\r\n <lib-container-elements id=\"source-container\" [cols]=\"cols\" class=\"w-full h-full\" [(elements)]=\"sourceElements\"\r\n #sourceContainer [severityButton]=\"sourceSeverityButton\"\r\n (outputElements)=\"handleOutputElements()\"></lib-container-elements>\r\n\r\n <div class=\"w-[10%] flex flex-col items-center justify-center gap-6 rounded-xl bg-gray-200 dark:bg-gray-800\">\r\n @for (button of controlButtons(); track $index) {\r\n <lib-button-ng [buttonConfig]=\"button\"></lib-button-ng>\r\n }\r\n </div>\r\n\r\n <lib-container-elements id=\"target-container\" [cols]=\"cols\" class=\"w-full h-full\" [(elements)]=\"targetElements\"\r\n #targetContainer [severityButton]=\"targetSeverityButton\"\r\n (outputElements)=\"handleOutputElements()\"></lib-container-elements>\r\n\r\n</div>", styles: [""], dependencies: [{ kind: "component", type: ButtonNgComponent, selector: "lib-button-ng", inputs: ["buttonConfig"], outputs: ["buttonConfigChange", "onClick"] }, { kind: "component", type: ContainerElementsComponent, selector: "lib-container-elements", inputs: ["cols", "elements", "severityButton"], outputs: ["elementsChange", "outputElements"] }] });
1938
+ }
1939
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: PickListComponent, decorators: [{
1940
+ type: Component,
1941
+ args: [{ selector: 'lib-pick-list', imports: [ButtonNgComponent, ContainerElementsComponent], template: "@let cols = config()?.cols ?? 3;\r\n@let sourceSeverityButton = config()?.sourceSeverityButton ?? 'secondary';\r\n@let targetSeverityButton = config()?.targetSeverityButton ?? 'contrast';\r\n<div class=\"flex gap-4 h-80 w-full bg-gray-100 dark:bg-gray-800 rounded-xl p-3\">\r\n <lib-container-elements id=\"source-container\" [cols]=\"cols\" class=\"w-full h-full\" [(elements)]=\"sourceElements\"\r\n #sourceContainer [severityButton]=\"sourceSeverityButton\"\r\n (outputElements)=\"handleOutputElements()\"></lib-container-elements>\r\n\r\n <div class=\"w-[10%] flex flex-col items-center justify-center gap-6 rounded-xl bg-gray-200 dark:bg-gray-800\">\r\n @for (button of controlButtons(); track $index) {\r\n <lib-button-ng [buttonConfig]=\"button\"></lib-button-ng>\r\n }\r\n </div>\r\n\r\n <lib-container-elements id=\"target-container\" [cols]=\"cols\" class=\"w-full h-full\" [(elements)]=\"targetElements\"\r\n #targetContainer [severityButton]=\"targetSeverityButton\"\r\n (outputElements)=\"handleOutputElements()\"></lib-container-elements>\r\n\r\n</div>" }]
1942
+ }], ctorParameters: () => [] });
1943
+
1944
+ class AdvancedFilterService {
1945
+ constructor() {
1946
+ // Effect para actualizar isSelected basado en los chips
1947
+ effect(() => {
1948
+ const chips = [...this.searchChips()];
1949
+ this.updateElementSelection(chips);
1950
+ });
1951
+ }
1952
+ configInlineInput = computed(() => ({
1953
+ typeInput: ETypeInput.CHIPS
1954
+ }));
1955
+ _searchChips = signal([]);
1956
+ searchChips = this._searchChips.asReadonly();
1957
+ setSearchChips(searchChips) {
1958
+ this._searchChips.set(searchChips);
1959
+ }
1960
+ setStringToArrayChips(searchValue) {
1961
+ this._searchChips.set(searchValue.split(' ').filter(chip => chip.trim() !== ''));
1962
+ }
1963
+ _sourceElements = signal([]);
1964
+ sourceElements = this._sourceElements.asReadonly();
1965
+ setSourceElements(sourceElements) {
1966
+ this._sourceElements.set(sourceElements);
1967
+ }
1968
+ configPickList = computed(() => ({
1969
+ cols: 3,
1970
+ sourceSeverityButton: 'contrast',
1971
+ targetSeverityButton: 'success'
1972
+ }));
1973
+ /**
1974
+ * Actualiza la selección de elementos basándose en los chips del input
1975
+ * @param chips Array de strings que representan los chips actuales
1976
+ */
1977
+ updateElementSelection(chips) {
1978
+ this._sourceElements.update(currentElements => {
1979
+ return currentElements.map((element) => {
1980
+ // Verificar si el label del elemento está en el array de chips
1981
+ const shouldBeSelected = chips.includes(element.buttonConfig?.label || '');
1982
+ if (shouldBeSelected) {
1983
+ delete element.buttonConfig.variant;
1984
+ delete element.buttonConfig.raised;
1985
+ }
1986
+ else {
1987
+ element.buttonConfig.variant = 'outlined';
1988
+ element.buttonConfig.raised = true;
1989
+ }
1990
+ return {
1991
+ ...element,
1992
+ isSelected: shouldBeSelected
1993
+ };
1994
+ });
1995
+ });
1996
+ }
1997
+ outputElements(event) {
1998
+ const { sourceElements } = event;
1999
+ this.setSourceElements(sourceElements);
2000
+ this.validateAndSyncChipsWithElements(sourceElements);
2001
+ }
2002
+ /**
2003
+ * Valida y sincroniza los chips con los elementos de sourceElements
2004
+ * @param sourceElements Array de elementos fuente
2005
+ */
2006
+ validateAndSyncChipsWithElements(sourceElements) {
2007
+ const currentChips = this._searchChips();
2008
+ if (sourceElements.length === 0) {
2009
+ this.setSearchChips([]);
2010
+ return;
2011
+ }
2012
+ const validChips = [];
2013
+ // Iterar sobre cada chip actual
2014
+ currentChips.forEach(chip => {
2015
+ // Buscar el elemento correspondiente en sourceElements
2016
+ const element = sourceElements.find(el => el.buttonConfig?.label === chip);
2017
+ if (element) {
2018
+ // Si la chip existe en sourceElements
2019
+ if (element.isSelected === false) {
2020
+ // Si la chip está en isSelected false, NO la incluimos en validChips (la eliminamos)
2021
+ return;
2022
+ }
2023
+ else {
2024
+ // Si la chip está seleccionada, la mantenemos
2025
+ validChips.push(chip);
2026
+ }
2027
+ }
2028
+ else {
2029
+ // Si la chip no está en sourceElements, NO la incluimos en validChips (la eliminamos)
2030
+ return;
2031
+ }
2032
+ });
2033
+ // Verificar si hay elementos seleccionados que no tienen chip correspondiente
2034
+ sourceElements.forEach(element => {
2035
+ if (element.isSelected && element.buttonConfig?.label) {
2036
+ const chipExists = currentChips.includes(element.buttonConfig.label);
2037
+ if (!chipExists) {
2038
+ // Si el elemento está seleccionado pero no tiene chip, agregamos la chip
2039
+ validChips.push(element.buttonConfig.label);
2040
+ }
2041
+ }
2042
+ });
2043
+ // Actualizar los chips solo si hay cambios
2044
+ if (JSON.stringify(validChips.sort()) !== JSON.stringify(currentChips.sort())) {
2045
+ this._searchChips.set(validChips);
2046
+ }
2047
+ }
2048
+ /**
2049
+ * Método público para establecer chips desde un array externo
2050
+ * Útil para gestionar las chips programáticamente
2051
+ * @param chipsArray Array de strings que representan las chips
2052
+ */
2053
+ setChipsFromArray(chipsArray) {
2054
+ if (!Array.isArray(chipsArray)) {
2055
+ console.warn('setChipsFromArray: El parámetro debe ser un array de strings');
2056
+ return;
2057
+ }
2058
+ // Filtrar elementos válidos (strings no vacíos)
2059
+ const validChips = chipsArray
2060
+ .filter(chip => typeof chip === 'string' && chip.trim() !== '')
2061
+ .map(chip => chip.trim());
2062
+ // Actualizar las chips
2063
+ this._searchChips.set(validChips);
2064
+ }
2065
+ /**
2066
+ * Método público para limpiar todas las chips
2067
+ */
2068
+ clearAllChips() {
2069
+ this._searchChips.set([]);
2070
+ }
2071
+ /**
2072
+ * Método público para agregar chips desde un array
2073
+ * Evita duplicados
2074
+ * @param chipsArray Array de strings a agregar
2075
+ */
2076
+ addChipsFromArray(chipsArray) {
2077
+ if (!Array.isArray(chipsArray)) {
2078
+ console.warn('addChipsFromArray: El parámetro debe ser un array de strings');
2079
+ return;
2080
+ }
2081
+ const currentChips = this._searchChips();
2082
+ // Filtrar elementos válidos y únicos
2083
+ const validChips = chipsArray
2084
+ .filter(chip => typeof chip === 'string' && chip.trim() !== '')
2085
+ .map(chip => chip.trim())
2086
+ .filter(chip => !currentChips.includes(chip));
2087
+ // Agregar las nuevas chips
2088
+ if (validChips.length > 0) {
2089
+ this._searchChips.set([...currentChips, ...validChips]);
2090
+ }
2091
+ }
2092
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AdvancedFilterService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2093
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AdvancedFilterService, providedIn: 'root' });
2094
+ }
2095
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AdvancedFilterService, decorators: [{
2096
+ type: Injectable,
2097
+ args: [{
2098
+ providedIn: 'root'
2099
+ }]
2100
+ }], ctorParameters: () => [] });
2101
+
2102
+ class AdvancedFilterComponent {
2103
+ advancedFilterService = inject(AdvancedFilterService);
2104
+ sourceElements = model([]);
2105
+ targetElements = model([]);
2106
+ // Referencia al componente de inline input para gestionar las chips
2107
+ inlineInputComponent = viewChild('inlineInputRef');
2108
+ constructor() {
2109
+ // Sincronizar el service con el model del componente
2110
+ effect(() => {
2111
+ this.sourceElements.set(this.advancedFilterService.sourceElements());
2112
+ });
2113
+ // Efecto para sincronizar chips con el inline input
2114
+ effect(() => {
2115
+ const chips = this.advancedFilterService.searchChips();
2116
+ const inlineInput = this.inlineInputComponent();
2117
+ if (inlineInput && Array.isArray(chips)) {
2118
+ // Usar el nuevo método para establecer las chips
2119
+ inlineInput.setChipsFromArray(chips);
2120
+ }
2121
+ });
2122
+ }
2123
+ ngOnInit() {
2124
+ this.initializeChipsWhitSourceElementsSelected();
2125
+ this.advancedFilterService.setSourceElements(this.sourceElements());
2126
+ }
2127
+ initializeChipsWhitSourceElementsSelected() {
2128
+ this.advancedFilterService.setSearchChips(this.sourceElements()
2129
+ .filter((element) => element.isSelected)
2130
+ .map((element) => element.buttonConfig?.label?.toString() ?? ''));
2131
+ }
2132
+ get configInlineInput() {
2133
+ return this.advancedFilterService.configInlineInput();
2134
+ }
2135
+ valueChangeInlineInput(value) {
2136
+ this.advancedFilterService.setStringToArrayChips(value);
2137
+ }
2138
+ get configPickList() {
2139
+ return this.advancedFilterService.configPickList();
2140
+ }
2141
+ outputElements(event) {
2142
+ this.advancedFilterService.outputElements(event);
2143
+ }
2144
+ /**
2145
+ * Método público para establecer chips desde un array externo
2146
+ * @param chipsArray Array de strings que representan las chips
2147
+ */
2148
+ setChipsFromArray(chipsArray) {
2149
+ this.advancedFilterService.setChipsFromArray(chipsArray);
2150
+ }
2151
+ /**
2152
+ * Método público para limpiar todas las chips
2153
+ */
2154
+ clearAllChips() {
2155
+ this.advancedFilterService.clearAllChips();
2156
+ }
2157
+ /**
2158
+ * Método público para agregar chips desde un array
2159
+ * @param chipsArray Array de strings a agregar
2160
+ */
2161
+ addChipsFromArray(chipsArray) {
2162
+ this.advancedFilterService.addChipsFromArray(chipsArray);
2163
+ }
2164
+ /**
2165
+ * Método público para obtener las chips actuales como array
2166
+ * @returns Array de strings con las chips actuales
2167
+ */
2168
+ getChipsAsArray() {
2169
+ return this.advancedFilterService.searchChips();
2170
+ }
2171
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AdvancedFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2172
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.2.17", type: AdvancedFilterComponent, isStandalone: true, selector: "lib-advanced-filter", inputs: { sourceElements: { classPropertyName: "sourceElements", publicName: "sourceElements", isSignal: true, isRequired: false, transformFunction: null }, targetElements: { classPropertyName: "targetElements", publicName: "targetElements", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sourceElements: "sourceElementsChange", targetElements: "targetElementsChange" }, providers: [AdvancedFilterService], viewQueries: [{ propertyName: "inlineInputComponent", first: true, predicate: ["inlineInputRef"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"flex flex-col gap-4\">\r\n <lib-inline-input #inlineInputRef [config]=\"configInlineInput\" (valueChange)=\"valueChangeInlineInput($event)\">\r\n </lib-inline-input>\r\n <lib-pick-list [(sourceElements)]=\"sourceElements\" [(targetElements)]=\"targetElements\"\r\n (outputElements)=\"outputElements($event)\" [config]=\"configPickList\"></lib-pick-list>\r\n</div>", styles: [""], dependencies: [{ kind: "component", type: InlineInputComponent, selector: "lib-inline-input", inputs: ["config", "value"], outputs: ["valueChange", "outputValue", "outputBlur", "outputDebounced"] }, { kind: "component", type: PickListComponent, selector: "lib-pick-list", inputs: ["sourceElements", "targetElements", "config"], outputs: ["sourceElementsChange", "targetElementsChange", "outputElements"] }] });
2173
+ }
2174
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: AdvancedFilterComponent, decorators: [{
2175
+ type: Component,
2176
+ args: [{ selector: 'lib-advanced-filter', imports: [InlineInputComponent, PickListComponent], providers: [AdvancedFilterService], template: "<div class=\"flex flex-col gap-4\">\r\n <lib-inline-input #inlineInputRef [config]=\"configInlineInput\" (valueChange)=\"valueChangeInlineInput($event)\">\r\n </lib-inline-input>\r\n <lib-pick-list [(sourceElements)]=\"sourceElements\" [(targetElements)]=\"targetElements\"\r\n (outputElements)=\"outputElements($event)\" [config]=\"configPickList\"></lib-pick-list>\r\n</div>" }]
2177
+ }], ctorParameters: () => [] });
2178
+
2179
+ class ModalAdvancedFilterComponent extends BaseDialogComponent {
2180
+ constructor() {
2181
+ super();
2182
+ }
2183
+ sourceElements = signal([]);
2184
+ targetElements = signal([]);
2185
+ ngOnInit() {
2186
+ if (this.data) {
2187
+ this.sourceElements.set(this.data.sourceElements ?? []);
2188
+ this.targetElements.set(this.data.targetElements ?? []);
2189
+ }
2190
+ }
2191
+ applyFiltersButton = computed(() => {
2192
+ return {
2193
+ label: 'Aplicar Filtros',
2194
+ severity: 'info',
2195
+ onClick: () => {
2196
+ this.close({ success: true, data: { sourceElements: this.sourceElements(), targetElements: this.targetElements() } });
2197
+ },
2198
+ disabled: this.targetElements().length === 0
2199
+ };
2200
+ });
2201
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: ModalAdvancedFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2202
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: ModalAdvancedFilterComponent, isStandalone: true, selector: "lib-modal-advanced-filter", usesInheritance: true, ngImport: i0, template: "<div class=\"flex flex-col gap-4\">\r\n <lib-advanced-filter [(sourceElements)]=\"sourceElements\" [(targetElements)]=\"targetElements\"></lib-advanced-filter>\r\n <div class=\"flex justify-end\">\r\n <lib-button-ng [buttonConfig]=\"applyFiltersButton()\"></lib-button-ng>\r\n </div>\r\n</div>", styles: [""], dependencies: [{ kind: "component", type: AdvancedFilterComponent, selector: "lib-advanced-filter", inputs: ["sourceElements", "targetElements"], outputs: ["sourceElementsChange", "targetElementsChange"] }, { kind: "component", type: ButtonNgComponent, selector: "lib-button-ng", inputs: ["buttonConfig"], outputs: ["buttonConfigChange", "onClick"] }] });
2203
+ }
2204
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: ModalAdvancedFilterComponent, decorators: [{
2205
+ type: Component,
2206
+ args: [{ selector: 'lib-modal-advanced-filter', imports: [AdvancedFilterComponent, ButtonNgComponent], template: "<div class=\"flex flex-col gap-4\">\r\n <lib-advanced-filter [(sourceElements)]=\"sourceElements\" [(targetElements)]=\"targetElements\"></lib-advanced-filter>\r\n <div class=\"flex justify-end\">\r\n <lib-button-ng [buttonConfig]=\"applyFiltersButton()\"></lib-button-ng>\r\n </div>\r\n</div>" }]
2207
+ }], ctorParameters: () => [] });
2208
+
2209
+ class TableNgEditService {
2210
+ editConfig = signal(undefined);
2211
+ keysNames = signal({});
2212
+ constructor() { }
2213
+ setEditConfig(editConfig) {
2214
+ this.editConfig.set(editConfig);
2215
+ }
2216
+ setKeysNames(keysNames) {
2217
+ this.keysNames.set(keysNames);
2218
+ }
2219
+ fb = inject(NonNullableFormBuilder);
2220
+ controls = computed(() => {
2221
+ const formValues = this.searchFormGroup().value;
2222
+ const controls = [
2223
+ {
2224
+ controlName: 'search',
2225
+ control: this.fb.control(formValues.search, { validators: [] }),
2226
+ typeInput: ETypeInput.TEXT,
2227
+ colSpan: 12,
2228
+ label: '-'
2229
+ }
2230
+ ];
2231
+ return controls;
2232
+ });
2233
+ searchFormGroup = signal(new FormGroup({}));
2234
+ _cellTableNgData = signal(undefined);
2235
+ cellTableNgData = this._cellTableNgData.asReadonly();
2236
+ setCellTableNgData(cellTableNgData) {
2237
+ this._cellTableNgData.set(cellTableNgData);
2238
+ }
2239
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TableNgEditService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2240
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TableNgEditService, providedIn: 'root' });
2241
+ }
2242
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TableNgEditService, decorators: [{
2243
+ type: Injectable,
2244
+ args: [{
2245
+ providedIn: 'root'
2246
+ }]
2247
+ }], ctorParameters: () => [] });
2248
+
2249
+ class TableNgGeneralService {
2250
+ constructor() { }
2251
+ MOCK_EMPTY_DATE = new Date(1900, 0, 1);
2252
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TableNgGeneralService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2253
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TableNgGeneralService, providedIn: 'root' });
2254
+ }
2255
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TableNgGeneralService, decorators: [{
2256
+ type: Injectable,
2257
+ args: [{
2258
+ providedIn: 'root'
2259
+ }]
2260
+ }], ctorParameters: () => [] });
2261
+
2262
+ class TableNgService {
2263
+ tableNgGeneralService = inject(TableNgGeneralService);
2264
+ filterService = inject(FilterService);
2265
+ dialogService = inject(CustomDialogService);
2266
+ initialValue;
2267
+ constructor() {
2268
+ this.filterService.register('globalCustomFilter', (rowData, filter) => {
2269
+ if (!filter || filter.trim() === '')
2270
+ return true;
2271
+ const searchTerm = filter.toLowerCase();
2272
+ // Si es string
2273
+ if (typeof rowData === 'string') {
2274
+ return rowData.toLowerCase().includes(searchTerm);
2275
+ }
2276
+ // Si es array de botones
2277
+ if (Array.isArray(rowData)) {
2278
+ return rowData.some((button) => {
2279
+ const label = button.label || '';
2280
+ return label.toLowerCase().includes(searchTerm);
2281
+ });
2282
+ }
2283
+ return false;
2284
+ });
2285
+ /**
2286
+ * Filtro para arrays de strings que verifica si el valor contiene alguno de los strings del filtro.
2287
+ * Uso: dt.filter(['valor1', 'valor2'], 'nombreColumna', 'arrayStringFilter')
2288
+ * @param rowData - Puede ser un string o array de strings
2289
+ * @param filter - Array de strings para filtrar
2290
+ * @returns true si encuentra coincidencias parciales (case-insensitive)
2291
+ */
2292
+ this.filterService.register('arrayStringFilter', (rowData, filter) => {
2293
+ // Si no hay filtro o el filtro está vacío, mostrar todos los elementos
2294
+ if (!filter || !Array.isArray(filter) || filter.length === 0)
2295
+ return true;
2296
+ // Si rowData es null, undefined o vacío, no mostrar el elemento
2297
+ if (rowData == null || rowData === '')
2298
+ return false;
2299
+ // Si rowData es un string
2300
+ if (typeof rowData === 'string') {
2301
+ return filter.some(filterValue => rowData.toLowerCase().includes(filterValue.toLowerCase()));
2302
+ }
2303
+ // Si rowData es un array de strings
2304
+ if (Array.isArray(rowData)) {
2305
+ return rowData.some(dataValue => filter.some(filterValue => typeof dataValue === 'string' &&
2306
+ dataValue.toLowerCase().includes(filterValue.toLowerCase())));
2307
+ }
2308
+ // Para otros tipos de datos, convertir a string si es posible
2309
+ const stringValue = String(rowData);
2310
+ if (stringValue && stringValue !== 'undefined' && stringValue !== 'null') {
2311
+ return filter.some(filterValue => stringValue.toLowerCase().includes(filterValue.toLowerCase()));
2312
+ }
2313
+ return false;
2314
+ });
2315
+ /**
2316
+ * Filtro exacto para arrays de strings que verifica coincidencias exactas.
2317
+ * Uso: dt.filter(['valor1', 'valor2'], 'nombreColumna', 'arrayStringExactFilter')
2318
+ * @param rowData - Puede ser un string o array de strings
2319
+ * @param filter - Array de strings para filtrar
2320
+ * @returns true si encuentra coincidencias exactas (case-sensitive)
2321
+ */
2322
+ this.filterService.register('arrayStringExactFilter', (rowData, filter) => {
2323
+ if (!filter || !Array.isArray(filter) || filter.length === 0)
2324
+ return true;
2325
+ // Si rowData es null, undefined o vacío, no mostrar el elemento
2326
+ if (rowData == null || rowData === '')
2327
+ return false;
2328
+ // Si rowData es un string
2329
+ if (typeof rowData === 'string') {
2330
+ return filter.includes(rowData);
2331
+ }
2332
+ // Si rowData es un array de strings
2333
+ if (Array.isArray(rowData)) {
2334
+ return rowData.some(dataValue => filter.includes(dataValue));
2335
+ }
2336
+ // Para otros tipos de datos, convertir a string si es posible
2337
+ const stringValue = String(rowData);
2338
+ if (stringValue && stringValue !== 'undefined' && stringValue !== 'null') {
2339
+ return filter.includes(stringValue);
2340
+ }
2341
+ return false;
2342
+ });
2343
+ this.filterService.register('customIn', (rowData, filter) => {
2344
+ if (!filter || !Array.isArray(filter) || filter.length === 0)
2345
+ return true;
2346
+ // Si rowData es null, undefined o vacío, no mostrar el elemento
2347
+ if (rowData == null || rowData === '')
2348
+ return false;
2349
+ if (typeof rowData === 'string') {
2350
+ return filter.includes(rowData);
2351
+ }
2352
+ // Para otros tipos de datos, convertir a string si es posible
2353
+ const stringValue = String(rowData);
2354
+ if (stringValue && stringValue !== 'undefined' && stringValue !== 'null') {
2355
+ return filter.includes(stringValue);
2356
+ }
2357
+ return false;
2358
+ });
2359
+ }
2360
+ get MOCK_EMPTY_DATE() {
2361
+ return this.tableNgGeneralService.MOCK_EMPTY_DATE;
2362
+ }
2363
+ setInitialValue(data) {
2364
+ this.initialValue = data;
2365
+ }
2366
+ //#region SORT
2367
+ customSort(event) {
2368
+ let field = undefined;
2369
+ let order = undefined;
2370
+ switch (event.mode) {
2371
+ case 'single':
2372
+ field = event.field;
2373
+ order = event.order;
2374
+ break;
2375
+ case 'multiple': {
2376
+ const multiSortMeta = event.multiSortMeta ?? [];
2377
+ const sortMeta = multiSortMeta[0];
2378
+ field = sortMeta?.field ?? undefined;
2379
+ order = sortMeta?.order ?? undefined;
2380
+ break;
2381
+ }
2382
+ default:
2383
+ break;
2384
+ }
2385
+ if (!field || order === undefined)
2386
+ return;
2387
+ const data = event.data ?? [];
2388
+ if (order === 0) {
2389
+ // Sin sorting - restaurar orden original
2390
+ data.splice(0, data.length, ...this.initialValue);
2391
+ }
2392
+ else {
2393
+ // Aplicar sorting
2394
+ data.sort((a, b) => {
2395
+ const valueA = this.getFieldValue(a, field);
2396
+ const valueB = this.getFieldValue(b, field);
2397
+ const result = this.compareValues(valueA, valueB);
2398
+ return order * result; // 1 para ASC, -1 para DESC
2399
+ });
2400
+ }
2401
+ }
2402
+ getFieldValue(item, field) {
2403
+ const rawValue = item.rowData[field];
2404
+ // Si es un array (probablemente IButtonConfig[])
2405
+ if (Array.isArray(rawValue) && rawValue.length > 0) {
2406
+ // Verificar si tenemos configuración de sorting para este campo
2407
+ const buttonKeyToSort = item.sortConfig?.buttonKeyToSort?.[field];
2408
+ if (buttonKeyToSort) {
2409
+ // Usar la primera configuración de botón del array
2410
+ const firstButton = rawValue[0];
2411
+ return firstButton[buttonKeyToSort];
2412
+ }
2413
+ // Si no hay configuración, intentar usar 'label' por defecto
2414
+ const firstButton = rawValue[0];
2415
+ return firstButton.label || '';
2416
+ }
2417
+ // Si es un string o cualquier otro tipo
2418
+ return rawValue;
2419
+ }
2420
+ compareValues(a, b) {
2421
+ // Manejar valores null/undefined
2422
+ if (a == null && b == null)
2423
+ return 0;
2424
+ if (a == null)
2425
+ return -1;
2426
+ if (b == null)
2427
+ return 1;
2428
+ // Si ambos son strings, usar localeCompare para mejor sorting
2429
+ if (typeof a === 'string' && typeof b === 'string') {
2430
+ return a.toLowerCase().localeCompare(b.toLowerCase());
2431
+ }
2432
+ // Si ambos son números
2433
+ if (typeof a === 'number' && typeof b === 'number') {
2434
+ return a - b;
2435
+ }
2436
+ // Si ambos son booleanos
2437
+ if (typeof a === 'boolean' && typeof b === 'boolean') {
2438
+ return a === b ? 0 : a ? 1 : -1;
2439
+ }
2440
+ // Si son fechas
2441
+ if (a instanceof Date && b instanceof Date) {
2442
+ return a.getTime() - b.getTime();
2443
+ }
2444
+ // Para otros tipos, convertir a string y comparar
2445
+ const strA = String(a).toLowerCase();
2446
+ const strB = String(b).toLowerCase();
2447
+ return strA.localeCompare(strB);
2448
+ }
2449
+ //#endregion
2450
+ //#region Global Filter
2451
+ fb = inject(NonNullableFormBuilder);
2452
+ controls = computed(() => {
2453
+ const formValues = this.searchFormGroup().value;
2454
+ const controls = [
2455
+ {
2456
+ controlName: 'search',
2457
+ control: this.fb.control(formValues.search, { validators: [] }),
2458
+ typeInput: ETypeInput.TEXT,
2459
+ colSpan: 12,
2460
+ label: 'Buscar'
2461
+ }
2462
+ ];
2463
+ return controls;
2464
+ });
2465
+ searchFormGroup = signal(new FormGroup({}));
2466
+ values = toSignal(this.searchFormGroup().valueChanges);
2467
+ submitGlobalSearch(formGroup, dt) {
2468
+ const search = formGroup.value.search ?? '';
2469
+ dt.filterGlobal(search, 'globalCustomFilter');
2470
+ }
2471
+ clearSearchInput() {
2472
+ this.searchFormGroup().get('search')?.setValue('');
2473
+ }
2474
+ //#endregion
2475
+ //#region Selection
2476
+ async openModalManagementSelectedItems(selectedItems, config) {
2477
+ const { SelectedItemsManagementComponent } = await import('./ln-20-lib-components-selected-items-management.component-CQe3kn_e.mjs');
2478
+ let configSelectedItems = config;
2479
+ if (config) {
2480
+ configSelectedItems = structuredClone(config);
2481
+ delete configSelectedItems.lazyLoadingConfig;
2482
+ const selectionTableConfig = {
2483
+ ...(configSelectedItems.selectionTableConfig ?? {}),
2484
+ showManagementConfig: false
2485
+ };
2486
+ const globalFilterConfig = {
2487
+ ...(configSelectedItems.globalFilterConfig ?? {}),
2488
+ advancedIdentifierFiltersConfig: {
2489
+ isEnabled: false
2490
+ }
2491
+ };
2492
+ configSelectedItems.globalFilterConfig = globalFilterConfig;
2493
+ configSelectedItems.selectionTableConfig = selectionTableConfig;
2494
+ }
2495
+ const ref = this.dialogService?.open(SelectedItemsManagementComponent, {
2496
+ header: 'Gestionar Seleccionados',
2497
+ data: {
2498
+ selectedItems: selectedItems(),
2499
+ config: configSelectedItems
2500
+ },
2501
+ width: '90%',
2502
+ height: '90%',
2503
+ styleClass: 'overflow-hidden'
2504
+ });
2505
+ ref.onClose.subscribe((selectedReturnItems) => {
2506
+ if (selectedReturnItems) {
2507
+ selectedItems.set(selectedReturnItems);
2508
+ }
2509
+ });
2510
+ }
2511
+ //#endregion
2512
+ //#region Custom Filter
2513
+ //#endregion
2514
+ excelButton = computed(() => {
2515
+ return {
2516
+ label: '',
2517
+ icon: 'fa-solid fa-file-excel',
2518
+ variant: 'text',
2519
+ severity: 'success',
2520
+ raised: true,
2521
+ size: 'large',
2522
+ tooltipConfig: {
2523
+ pTooltip: this.config()?.labelsConfig?.exportExcelTooltip ?? 'Exportar a Excel',
2524
+ tooltipPosition: 'top'
2525
+ }
2526
+ };
2527
+ });
2528
+ pdfButton = computed(() => {
2529
+ return {
2530
+ label: '',
2531
+ icon: 'fa-solid fa-file-pdf',
2532
+ variant: 'text',
2533
+ severity: 'danger',
2534
+ raised: true,
2535
+ size: 'large',
2536
+ tooltipConfig: {
2537
+ pTooltip: this.config()?.labelsConfig?.exportPdfTooltip ?? 'Exportar a PDF',
2538
+ tooltipPosition: 'top'
2539
+ }
2540
+ };
2541
+ });
2542
+ refreshButton = computed(() => {
2543
+ return {
2544
+ label: '',
2545
+ icon: 'fa-solid fa-refresh',
2546
+ variant: 'text',
2547
+ severity: 'info',
2548
+ raised: true,
2549
+ size: 'large',
2550
+ onClick: () => {
2551
+ this.refreshTable();
2552
+ },
2553
+ tooltipConfig: {
2554
+ pTooltip: this.config()?.labelsConfig?.refreshTooltip ?? 'Refrescar',
2555
+ tooltipPosition: 'top'
2556
+ },
2557
+ loading: this.isLoadingRefreshButton(),
2558
+ disabled: this.isLoadingRefreshButton(),
2559
+ };
2560
+ });
2561
+ refreshTable() {
2562
+ if (this.refreshConfig()) {
2563
+ this.refreshConfig()?.callback();
2564
+ }
2565
+ }
2566
+ _config = signal(undefined);
2567
+ config = this._config.asReadonly();
2568
+ setConfig(value) {
2569
+ this._config.set(value);
2570
+ }
2571
+ refreshConfig = computed(() => {
2572
+ return this.config()?.refreshConfig;
2573
+ });
2574
+ enableRefreshButton = computed(() => {
2575
+ return this.refreshConfig()?.isEnabled ?? false;
2576
+ });
2577
+ isLoadingRefreshButton = computed(() => {
2578
+ return this.refreshConfig()?.isLoading ?? false;
2579
+ });
2580
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TableNgService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2581
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TableNgService, providedIn: 'root' });
2582
+ }
2583
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TableNgService, decorators: [{
2584
+ type: Injectable,
2585
+ args: [{
2586
+ providedIn: 'root'
2587
+ }]
2588
+ }], ctorParameters: () => [] });
2589
+
2590
+ /* eslint-disable @typescript-eslint/no-unsafe-argument */
2591
+ class TableNgComponent {
2592
+ tableNgService = inject(TableNgService);
2593
+ tableNgEditService = inject(TableNgEditService);
2594
+ dialogService = inject(CustomDialogService);
2595
+ data = model.required();
2596
+ totalRows = computed(() => this.data().length);
2597
+ // Loading state management
2598
+ loadingTimeout = null;
2599
+ isLoading = model(false);
2600
+ timeoutExpired = signal(false);
2601
+ config = model();
2602
+ editConfig = model();
2603
+ footerConfig = model();
2604
+ toolbarButtons = model([]);
2605
+ toolbarSpeedDialButtons = model([]);
2606
+ sourceElements = model([]);
2607
+ targetElements = model([]);
2608
+ httpMessage = model();
2609
+ lazyLoading = output();
2610
+ outputChangeData = output();
2611
+ outputHandleEditInitButton = output();
2612
+ outputAddRow = output();
2613
+ outputDeleteRow = output();
2614
+ outputRowInlineChange = output();
2615
+ outputRowDataChange = output();
2616
+ outputEditData = output();
2617
+ outputIsEditing = output();
2618
+ outputCheckAll = output();
2619
+ resetData() {
2620
+ this.data.set([]);
2621
+ }
2622
+ advancedFiltersPerformed = [];
2623
+ advancedFiltersValues = signal({});
2624
+ dt;
2625
+ fb = inject(NonNullableFormBuilder);
2626
+ /**
2627
+ * Config del control booleano en el header por columna.
2628
+ * Si todas las celdas checkeables (INPUT + CHECKBOX|SWITCH) de esa columna son readonly,
2629
+ * el control del header también debe ser readonly.
2630
+ */
2631
+ inlineConfigCheckHeader(columnKey, typeInput) {
2632
+ return {
2633
+ typeInput,
2634
+ readonly: this.isColumnBulkReadonly(columnKey)
2635
+ };
2636
+ }
2637
+ /**
2638
+ * True si hay al menos una celda checkeable en la columna y todas son readonly.
2639
+ */
2640
+ isColumnBulkReadonly(columnKey) {
2641
+ const rows = this.data().filter((row) => this.isInputCheckboxOrSwitchCell(row, columnKey));
2642
+ if (rows.length === 0)
2643
+ return false;
2644
+ return rows.every((row) => row.rowDataInput?.[columnKey]?.readonly === true);
2645
+ }
2646
+ inlineConfigCheckHeaderCheckAll = {
2647
+ typeInput: ETypeInput.SWITCH
2648
+ };
2649
+ /**
2650
+ * Celda editable como `INPUT` cuyo control es CHECKBOX o SWITCH (según `rowDataInput`).
2651
+ */
2652
+ isInputCheckboxOrSwitchCell(item, columnKey) {
2653
+ if (item.typeCell?.[columnKey] !== ETypeInput.INPUT)
2654
+ return false;
2655
+ const t = item.rowDataInput?.[columnKey]?.typeInput;
2656
+ return t === ETypeInput.CHECKBOX || t === ETypeInput.SWITCH;
2657
+ }
2658
+ /**
2659
+ * Estado del check "todos" del toolbar: true solo si hay al menos una celda
2660
+ * INPUT + (CHECKBOX | SWITCH) y todas esas celdas (todas las columnas y filas) son truthy.
2661
+ */
2662
+ checkAllHeaderReflectValue() {
2663
+ const columnKeys = this.config()?.keys ?? [];
2664
+ let hasAnyCheckable = false;
2665
+ for (const row of this.data()) {
2666
+ for (const key of columnKeys) {
2667
+ if (this.isInputCheckboxOrSwitchCell(row, key)) {
2668
+ hasAnyCheckable = true;
2669
+ if (!row.rowData?.[key]) {
2670
+ return false;
2671
+ }
2672
+ }
2673
+ }
2674
+ }
2675
+ return hasAnyCheckable;
2676
+ }
2677
+ /**
2678
+ * Toolbar: pone `value` en todas las celdas que cumplan INPUT + (CHECKBOX | SWITCH), en todas las columnas de `config.keys`.
2679
+ */
2680
+ checkAll(value) {
2681
+ const columnKeys = this.config()?.keys ?? [];
2682
+ this.data.update((rows) => rows.map((row) => {
2683
+ let nextRowData = { ...row.rowData };
2684
+ let changed = false;
2685
+ for (const key of columnKeys) {
2686
+ if (this.isInputCheckboxOrSwitchCell(row, key)) {
2687
+ nextRowData = { ...nextRowData, [key]: value };
2688
+ changed = true;
2689
+ }
2690
+ }
2691
+ if (!changed)
2692
+ return row;
2693
+ return { ...row, rowData: nextRowData };
2694
+ }));
2695
+ this.outputChangeData.emit([...this.data()]);
2696
+ this.outputCheckAll.emit(value);
2697
+ }
2698
+ //#region Labels Configuration
2699
+ /** Get pagination report template with default English value */
2700
+ getCustomPageReport() {
2701
+ return this.config()?.labelsConfig?.customPageReport ?? 'Showing {first} to {last} of {totalRecords} entries';
2702
+ }
2703
+ /** Get selected items label with default English value */
2704
+ getSelectedItemsLabel() {
2705
+ return this.config()?.labelsConfig?.selectedItemsLabel ?? 'You have selected';
2706
+ }
2707
+ /** Get records label with default English value */
2708
+ getRecordsLabel() {
2709
+ return this.config()?.labelsConfig?.recordsLabel ?? 'records';
2710
+ }
2711
+ /** Get loading message with default English value */
2712
+ getLoadingMessage() {
2713
+ return this.config()?.labelsConfig?.loadingMessage ?? 'Loading...';
2714
+ }
2715
+ /** Get no data message with default English value */
2716
+ getNoDataMessage() {
2717
+ return this.config()?.labelsConfig?.noDataMessage ?? 'No information available';
2718
+ }
2719
+ //#endregion
2720
+ constructor() {
2721
+ this.tableNgEditService.setEditConfig(this.editConfig());
2722
+ this.tableNgEditService.setKeysNames(this.config()?.keysNames ?? {});
2723
+ // Si hay configuración de errores y estamos en modo edición por celda,
2724
+ // mostramos las validaciones de inmediato.
2725
+ effect(() => {
2726
+ const editConfig = this.editConfig();
2727
+ const rowErrorConfig = editConfig?.rowEditConfig?.rowErrorConfig;
2728
+ if (editConfig?.isEnabled && editConfig?.type === 'cell' && (rowErrorConfig?.isEnabled ?? false)) {
2729
+ this.setEnableErrors(true);
2730
+ }
2731
+ });
2732
+ // Effect para sincronizar el config con el servicio cuando cambie
2733
+ effect(() => {
2734
+ const configValue = this.config();
2735
+ if (configValue) {
2736
+ this.tableNgService.setConfig(configValue);
2737
+ }
2738
+ });
2739
+ effect(() => {
2740
+ this.outputChangeData.emit([...this.data()]);
2741
+ });
2742
+ // Effect para gestionar el loading basado en el estado de data
2743
+ effect(() => {
2744
+ const currentData = this.data();
2745
+ // Limpiar el timeout anterior si existe
2746
+ if (this.loadingTimeout) {
2747
+ clearTimeout(this.loadingTimeout);
2748
+ this.loadingTimeout = null;
2749
+ }
2750
+ if (currentData.length === 0) {
2751
+ // Si data está vacío, activar loading
2752
+ this.isLoading.set(true);
2753
+ this.loadingTimeout = setTimeout(() => {
2754
+ if (this.data().length === 0) {
2755
+ this.isLoading.set(false);
2756
+ this.timeoutExpired.set(true);
2757
+ }
2758
+ }, 0);
2759
+ }
2760
+ else {
2761
+ // Si hay data, desactivar loading y resetear timeout
2762
+ this.isLoading.set(false);
2763
+ this.timeoutExpired.set(false);
2764
+ }
2765
+ });
2766
+ }
2767
+ ngOnInit() {
2768
+ this.tableNgService.setInitialValue([...this.data()]);
2769
+ const cellTableNgData = this.editConfig()?.cellEditConfig?.defaultTableNgData;
2770
+ if (cellTableNgData) {
2771
+ this.tableNgEditService.setCellTableNgData(cellTableNgData);
2772
+ }
2773
+ }
2774
+ ngOnDestroy() {
2775
+ // Limpiar el timeout al destruir el componente
2776
+ if (this.loadingTimeout) {
2777
+ clearTimeout(this.loadingTimeout);
2778
+ this.loadingTimeout = null;
2779
+ }
2780
+ }
2781
+ get hideToolbar() { return this.config()?.hideToolbar ?? false; }
2782
+ /**
2783
+ * Calcula el número total de columnas para el colspan del mensaje vacío
2784
+ */
2785
+ totalColumns = computed(() => {
2786
+ const selectedColumns = this.config()?.selectedColumns ?? [];
2787
+ const baseColumns = selectedColumns.length > 0 ? selectedColumns.length : this.keys().length;
2788
+ const selectionColumn = this.config()?.selectionTableConfig?.isEnabled ? 1 : 0;
2789
+ const expansionColumn = this.config()?.rowExpansionConfig?.isEnabled ? 1 : 0;
2790
+ const editColumn = (this.editConfig()?.type === 'row' || this.editConfig()?.type === 'cell') && this.editConfig()?.isEnabled ? 1 : 0;
2791
+ return baseColumns + selectionColumn + expansionColumn + editColumn;
2792
+ });
2793
+ isPrimeNgSelection(value) {
2794
+ return PrimeNgUtil.isPrimeNgSelection(value);
2795
+ }
2796
+ hasErrorValues(object) {
2797
+ return Object.keys(object).length > 0;
2798
+ }
2799
+ rowFieldsValue = signal({});
2800
+ rowFieldsHasValue = computed(() => {
2801
+ return Object.keys(this.rowFieldsValue()).reduce((acc, key) => {
2802
+ acc[key] = !!this.rowFieldsValue()[key];
2803
+ return acc;
2804
+ }, {});
2805
+ });
2806
+ inlineChange(value, key) {
2807
+ this.rowFieldsValue.update((prev) => {
2808
+ return { ...prev, [key]: value };
2809
+ });
2810
+ this.outputRowInlineChange.emit({ ...this.rowFieldsValue() });
2811
+ }
2812
+ trackById(index, item) {
2813
+ return item.id;
2814
+ }
2815
+ frozenHandle(value) {
2816
+ return value ? value : false;
2817
+ }
2818
+ isDate(value) {
2819
+ return value instanceof Date;
2820
+ }
2821
+ onFilter(event) {
2822
+ const filters = event.filters;
2823
+ if (!filters)
2824
+ return;
2825
+ const global = filters['global'];
2826
+ if (!global?.['value']) {
2827
+ this.handleAdvancedFiltersPerformed(filters);
2828
+ }
2829
+ }
2830
+ resetRowDatas() {
2831
+ this.data.update((data) => {
2832
+ return data.map((item) => {
2833
+ return {
2834
+ ...item,
2835
+ rowData: {}
2836
+ };
2837
+ });
2838
+ });
2839
+ }
2840
+ get ETypeInput() {
2841
+ return ETypeInput;
2842
+ }
2843
+ /**
2844
+ * Refleja en el header si todas las filas tienen `true` en esa columna (solo lectura visual).
2845
+ * Si hay mezcla o todo es false, devuelve false.
2846
+ */
2847
+ booleanColumnHeaderReflectValue(columnKey) {
2848
+ const rows = this.data().filter((row) => this.isInputCheckboxOrSwitchCell(row, columnKey));
2849
+ if (rows.length === 0)
2850
+ return false;
2851
+ return rows.every((row) => !!row.rowData?.[columnKey]);
2852
+ }
2853
+ /**
2854
+ * Asigna el mismo booleano solo a filas cuya celda en esa columna sea INPUT + (CHECKBOX | SWITCH).
2855
+ */
2856
+ applyBulkBooleanToColumn(value, columnKey) {
2857
+ this.data.update((rows) => rows.map((row) => {
2858
+ if (!this.isInputCheckboxOrSwitchCell(row, columnKey))
2859
+ return row;
2860
+ return {
2861
+ ...row,
2862
+ rowData: {
2863
+ ...row.rowData,
2864
+ [columnKey]: value
2865
+ }
2866
+ };
2867
+ }));
2868
+ }
2869
+ handleCheckValue() {
2870
+ this.outputChangeData.emit([...this.data()]);
2871
+ }
2872
+ handleAdvancedFiltersPerformed(filters) {
2873
+ if (!filters)
2874
+ return;
2875
+ const entriesFilters = Object.entries(filters);
2876
+ const keysColumn = this.config()?.keys ?? [];
2877
+ entriesFilters.forEach(([key, value]) => {
2878
+ const valueArray = value;
2879
+ const hasValue = !!valueArray[0]?.value;
2880
+ const keyColumn = key.split('.')[1];
2881
+ if (keysColumn.includes(keyColumn)) {
2882
+ const index = this.advancedFiltersPerformed.indexOf(keyColumn);
2883
+ if (hasValue && index === -1) {
2884
+ // Agregar si no existe
2885
+ this.advancedFiltersPerformed.push(keyColumn);
2886
+ }
2887
+ else if (!hasValue && index !== -1) {
2888
+ // Quitar si ya no tiene valor
2889
+ this.advancedFiltersPerformed.splice(index, 1);
2890
+ }
2891
+ }
2892
+ });
2893
+ }
2894
+ numberOfRecords = computed(() => {
2895
+ return this.data().length ?? 0;
2896
+ });
2897
+ hasRecords = computed(() => {
2898
+ return this.numberOfRecords() > 0;
2899
+ });
2900
+ /**
2901
+ * Computed que valida si al menos una fila tiene datos válidos en rowData.
2902
+ * Retorna true si al menos una fila tiene un valor que no sea '', null o undefined.
2903
+ * Retorna false si todas las filas tienen valores vacíos, null o undefined.
2904
+ */
2905
+ hasValidRowData = computed(() => {
2906
+ const data = this.data();
2907
+ return data.some(item => {
2908
+ if (!item?.rowData || typeof item.rowData !== 'object') {
2909
+ return false;
2910
+ }
2911
+ const values = Object.values(item.rowData);
2912
+ // Verificar si al menos un valor es válido (no vacío, null o undefined)
2913
+ return values.some(value => {
2914
+ if (value === null || value === undefined || value === '') {
2915
+ return false;
2916
+ }
2917
+ // Si es string, verificar que no esté vacío después de trim
2918
+ if (typeof value === 'string') {
2919
+ return value.trim() !== '';
2920
+ }
2921
+ // Para otros tipos (números, fechas, booleanos, etc.)
2922
+ return true;
2923
+ });
2924
+ });
2925
+ });
2926
+ keys = computed(() => {
2927
+ return this.config()?.keys ?? [];
2928
+ });
2929
+ onRowClick(item) {
2930
+ item.onClick();
2931
+ }
2932
+ //#region Scroll Config
2933
+ scrollHeight = computed(() => {
2934
+ const scrollHeightInitial = this.config()?.scrollConfig?.scrollHeight ?? '58vh';
2935
+ let res = scrollHeightInitial;
2936
+ if (this.showBottomToolbar()) {
2937
+ const { number: size, unit } = this.parseValue(scrollHeightInitial);
2938
+ res = `${size - 7.6}${unit}`;
2939
+ }
2940
+ return res;
2941
+ });
2942
+ parseValue(str) {
2943
+ const match = str.match(/^(-?\d+\.?\d*)(.*)$/);
2944
+ if (match) {
2945
+ return {
2946
+ number: parseFloat(match[1]),
2947
+ unit: match[2]
2948
+ };
2949
+ }
2950
+ return { number: 0, unit: '' };
2951
+ }
2952
+ //#endregion
2953
+ //#region Paginator Config
2954
+ paginatorStyleClass = computed(() => {
2955
+ if (this.showBottomToolbar()) {
2956
+ return 'p-datatable-paginator p-datatable-paginator-bottom sticky bottom-18 z-10';
2957
+ }
2958
+ return 'p-datatable-paginator p-datatable-paginator-bottom sticky bottom-2 z-10';
2959
+ });
2960
+ //#endregion
2961
+ //#region toolbar config
2962
+ showBottomToolbar = computed(() => {
2963
+ return this.showManagementSelectionConfig();
2964
+ });
2965
+ //#endregion
2966
+ //#region Clear Filters
2967
+ clearFilters() {
2968
+ this.tableNgService.clearSearchInput();
2969
+ this.advancedFiltersPerformed = [];
2970
+ this.advancedFiltersValues.set({});
2971
+ this.dt.clear();
2972
+ this.targetElements.set([]);
2973
+ this.handleTableValueToSourceElements();
2974
+ this.selectedItems.set([]);
2975
+ }
2976
+ get filteredValue() {
2977
+ return !!this.dt?.filteredValue && this.dt.filteredValue.length > 0;
2978
+ }
2979
+ clearFiltersButton = computed(() => {
2980
+ return {
2981
+ icon: 'fa-solid fa-filter-circle-xmark',
2982
+ rounded: true,
2983
+ raised: true,
2984
+ severity: 'contrast',
2985
+ tooltipConfig: {
2986
+ pTooltip: 'Limpiar filtros'
2987
+ },
2988
+ onClick: () => {
2989
+ this.clearFilters();
2990
+ }
2991
+ };
2992
+ });
2993
+ //#endregion
2994
+ //#region Global Filter
2995
+ get controlsGlobalFilter() {
2996
+ return this.tableNgService.controls();
2997
+ }
2998
+ get searchFormGroupGlobalFilter() {
2999
+ return this.tableNgService.searchFormGroup();
3000
+ }
3001
+ submitGlobalSearch(formGroup) {
3002
+ this.dt.globalFilterFields = this.config()?.globalFilterConfig?.globalFilterFields ?? [];
3003
+ this.tableNgService.submitGlobalSearch(formGroup, this.dt);
3004
+ }
3005
+ //#endregion
3006
+ //#region SORT
3007
+ customSort(event) {
3008
+ this.tableNgService.customSort(event);
3009
+ }
3010
+ //#endregion
3011
+ //#region Selection
3012
+ selectedItems = model([]);
3013
+ totalItemsSelected = computed(() => this.selectedItems().length);
3014
+ showManagementSelectionConfig = computed(() => this.totalItemsSelected() > 0 && (this.config()?.selectionTableConfig?.showManagementConfig ?? false));
3015
+ buttonTotalItemsSelected = computed(() => {
3016
+ return {
3017
+ label: this.totalItemsSelected().toLocaleString(),
3018
+ variant: 'text',
3019
+ rounded: true
3020
+ };
3021
+ });
3022
+ showSelectedItemsManagementButton = computed(() => {
3023
+ return {
3024
+ icon: 'fa-solid fa-eye',
3025
+ rounded: true,
3026
+ variant: 'text',
3027
+ severity: 'secondary',
3028
+ onClick: () => {
3029
+ this.openModalManagementSelectedItems();
3030
+ }
3031
+ };
3032
+ });
3033
+ openModalManagementSelectedItems() {
3034
+ this.tableNgService.openModalManagementSelectedItems(this.selectedItems, this.config())
3035
+ .then(() => { })
3036
+ .catch(() => { });
3037
+ }
3038
+ //#endregion
3039
+ //#region Custom Filter
3040
+ isCustomColumnFilterEnabled(filterConfig) {
3041
+ return filterConfig?.customColumnFilterConfig?.isEnabled ?? false;
3042
+ }
3043
+ inlineFormChanges(inlineValue, filter, typeInput, key) {
3044
+ const lazyLoadingConfig = this.config()?.lazyLoadingConfig;
3045
+ if (typeInput === ETypeInput.MULTISELECT) {
3046
+ const options = Array.isArray(inlineValue)
3047
+ ? inlineValue.filter((item) => PrimeNgUtil.isPrimeNgSelection(item))
3048
+ : [];
3049
+ const arrayValue = options.length > 0
3050
+ ? options.map((data) => lazyLoadingConfig?.isEnabled ? data.code : data.name)
3051
+ : undefined;
3052
+ if (Array.isArray(arrayValue) && arrayValue.length === 0) {
3053
+ if (key) {
3054
+ this.advancedFiltersValues.update((prev) => {
3055
+ const { [key]: _value, ...rest } = prev;
3056
+ return { ...rest };
3057
+ });
3058
+ }
3059
+ filter(null);
3060
+ return;
3061
+ }
3062
+ if (options.length > 0) {
3063
+ if (key) {
3064
+ this.advancedFiltersValues.update((prev) => ({ ...prev, [key]: options }));
3065
+ }
3066
+ filter(arrayValue);
3067
+ }
3068
+ return;
3069
+ }
3070
+ let filterValue = inlineValue;
3071
+ if (typeInput === ETypeInput.SELECT &&
3072
+ inlineValue &&
3073
+ typeof inlineValue === 'object' &&
3074
+ 'code' in inlineValue) {
3075
+ filterValue = inlineValue.code;
3076
+ }
3077
+ const isEmpty = filterValue === '' || filterValue === null || filterValue === undefined;
3078
+ if (key) {
3079
+ if (isEmpty) {
3080
+ this.advancedFiltersValues.update((prev) => {
3081
+ const { [key]: _value, ...rest } = prev;
3082
+ return { ...rest };
3083
+ });
3084
+ }
3085
+ else {
3086
+ this.advancedFiltersValues.update((prev) => ({ ...prev, [key]: filterValue }));
3087
+ }
3088
+ }
3089
+ filter(isEmpty ? null : filterValue);
3090
+ }
3091
+ formChanges(formValue, filter, key) {
3092
+ if (Array.isArray(formValue['multiSelect'])) {
3093
+ this.advancedFiltersValues.update((prev) => {
3094
+ return { ...prev, [key]: formValue };
3095
+ });
3096
+ }
3097
+ if (!Array.isArray(formValue['multiSelect']) && this.advancedFiltersValues()?.[key]) {
3098
+ this.advancedFiltersValues.update((prev) => {
3099
+ const { [key]: _value, ...rest } = prev;
3100
+ return { ...rest };
3101
+ });
3102
+ }
3103
+ const arrayValue = Array.isArray(formValue['multiSelect'])
3104
+ ? formValue['multiSelect'].map((data) => data.code)
3105
+ : [];
3106
+ if (arrayValue.length > 0) {
3107
+ filter(arrayValue);
3108
+ }
3109
+ }
3110
+ rowDataKey(key) {
3111
+ return `rowData.${key}`;
3112
+ }
3113
+ //#endregion
3114
+ //#region Lazy Loading
3115
+ onLazyLoad(event) {
3116
+ const filters = event.filters ?? {};
3117
+ const filtersWithValue = this.getFiltersWithValue(filters);
3118
+ const metaPagination = {};
3119
+ if (event.first) {
3120
+ metaPagination.skip = event.first;
3121
+ }
3122
+ if (event.rows) {
3123
+ metaPagination.limit = event.rows;
3124
+ }
3125
+ if (event.sortOrder) {
3126
+ metaPagination.sortOrder = event.sortOrder === 1 ? 'ASC' : 'DESC';
3127
+ }
3128
+ if (event.sortField) {
3129
+ metaPagination.sortBy = event.sortField;
3130
+ }
3131
+ const lazyLoadResponse = {
3132
+ filters: filtersWithValue,
3133
+ metaPagination
3134
+ };
3135
+ this.lazyLoading.emit(lazyLoadResponse);
3136
+ }
3137
+ getFiltersWithValue(filters) {
3138
+ const result = {};
3139
+ Object.entries(filters).forEach(([key, filter]) => {
3140
+ const keyColumn = key.split('.')[1];
3141
+ if (!filter)
3142
+ return;
3143
+ if (Array.isArray(filter)) {
3144
+ // Si es un array, filtrar solo los elementos que tienen value
3145
+ const filtersWithValue = filter.filter(f => f.value !== undefined && f.value !== null && f.value !== '');
3146
+ if (filtersWithValue.length > 0) {
3147
+ result[keyColumn] = filtersWithValue;
3148
+ }
3149
+ }
3150
+ else {
3151
+ // Si es un objeto único, verificar si tiene value
3152
+ if (filter.value !== undefined && filter.value !== null && filter.value !== '') {
3153
+ result[keyColumn] = filter;
3154
+ }
3155
+ }
3156
+ });
3157
+ return result;
3158
+ }
3159
+ //#endregion
3160
+ //#region Edit
3161
+ onCellValueChange() {
3162
+ this.updateDataWithTableValue();
3163
+ }
3164
+ onRowDataChange(_data) {
3165
+ }
3166
+ onEditData() {
3167
+ this.updateDataWithTableValue();
3168
+ this.outputEditData.emit([...this.data()]);
3169
+ }
3170
+ get controlsEdit() {
3171
+ return this.tableNgEditService.controls();
3172
+ }
3173
+ get searchFormGroupEdit() {
3174
+ return this.tableNgEditService.searchFormGroup();
3175
+ }
3176
+ customControlConfig(key, value) {
3177
+ return {
3178
+ controlName: key,
3179
+ control: this.fb.control(value),
3180
+ typeInput: ETypeInput.TEXT
3181
+ };
3182
+ }
3183
+ cellFormGroup = this.fb.group({});
3184
+ //#region Row
3185
+ addRowButton = computed(() => {
3186
+ const editConfig = this.editConfig();
3187
+ const isDisabled = editConfig?.type === 'cell'
3188
+ ? (editConfig?.cellEditConfig?.isDisabledAddButton ?? false)
3189
+ : (editConfig?.rowEditConfig?.isDisabledAddButton ?? false) || this.hasRowInEdit;
3190
+ const button = {
3191
+ icon: 'fa-solid fa-plus',
3192
+ rounded: true,
3193
+ severity: 'success',
3194
+ tooltipConfig: {
3195
+ pTooltip: isDisabled ? 'No hay datos para agregar' : 'Agregar registro',
3196
+ tooltipPosition: 'top'
3197
+ },
3198
+ onClick: () => {
3199
+ this.addRow();
3200
+ },
3201
+ disabled: isDisabled
3202
+ };
3203
+ return button;
3204
+ });
3205
+ addRow() {
3206
+ const editConfig = this.editConfig();
3207
+ const templateRow = this.tableNgEditService.cellTableNgData();
3208
+ // Si es modo cell y hay defaultTableNgData configurado, agregar la fila directamente
3209
+ if (editConfig?.type === 'cell' && templateRow) {
3210
+ const id = `${(this.totalRows() + 1).toString()}-${generateId()}`;
3211
+ const rowDataId = `${id}-${generateId()}`;
3212
+ // templateRow es siempre la misma referencia (defaultTableNgData): hay que clonar para que
3213
+ // cada fila nueva sea independiente y no comparta el mismo objeto con las demás.
3214
+ const newRow = {
3215
+ ...templateRow,
3216
+ id,
3217
+ rowData: { ...structuredClone(templateRow.rowData), id: rowDataId }
3218
+ };
3219
+ this.data.update(currentData => [...currentData, newRow]);
3220
+ this.outputChangeData.emit(this.data());
3221
+ return;
3222
+ }
3223
+ // Comportamiento original para modo row o cuando no hay defaultTableNgData
3224
+ this.outputAddRow.emit(this.data());
3225
+ this.setEditingRowId(null);
3226
+ }
3227
+ defaultTableNgData = computed(() => {
3228
+ const editConfig = this.editConfig();
3229
+ let defaultData;
3230
+ // Usar la configuración apropiada según el tipo de edición
3231
+ if (editConfig?.type === 'cell' && editConfig?.cellEditConfig?.defaultTableNgData) {
3232
+ defaultData = editConfig.cellEditConfig.defaultTableNgData;
3233
+ }
3234
+ else if (editConfig?.type === 'row' && editConfig?.rowEditConfig?.defaultTableNgData) {
3235
+ defaultData = editConfig.rowEditConfig.defaultTableNgData;
3236
+ }
3237
+ const res = { ...defaultData };
3238
+ return {
3239
+ ...res,
3240
+ id: generateId()
3241
+ };
3242
+ });
3243
+ clonedRowData = null;
3244
+ editingRowId = signal(null);
3245
+ /**
3246
+ * Verifica si una fila específica está siendo editada
3247
+ */
3248
+ isRowEditing(id) {
3249
+ return this.editingRowId() === id;
3250
+ }
3251
+ /**
3252
+ * Verifica si hay alguna fila siendo editada actualmente
3253
+ */
3254
+ get hasRowInEdit() {
3255
+ return this.editingRowId() !== null;
3256
+ }
3257
+ onRowEditInit(data) {
3258
+ // Verificar si ya hay una fila en edición
3259
+ this.clonedRowData = structuredClone(data.rowData);
3260
+ this.setEditingRowId(data.id);
3261
+ this.outputHandleEditInitButton.emit(data);
3262
+ }
3263
+ setEditingRowId(id) {
3264
+ this.editingRowId.set(id);
3265
+ this.outputIsEditing.emit(true);
3266
+ }
3267
+ onRowEditSave(_data) {
3268
+ this.clonedRowData = null;
3269
+ this.editingRowId.set(null);
3270
+ this.updateDataWithTableValue();
3271
+ this.setEnableErrors(false);
3272
+ this.outputIsEditing.emit(false);
3273
+ this.outputRowDataChange.emit(_data);
3274
+ }
3275
+ onRowEditCancel(data, index) {
3276
+ if (this.clonedRowData && this.editingRowId() === data.id) {
3277
+ const items = [...this.data()];
3278
+ items[index] = { ...items[index], rowData: this.clonedRowData };
3279
+ this.data.set(items);
3280
+ }
3281
+ this.clonedRowData = null;
3282
+ this.setEditingRowId(null);
3283
+ this.setEnableErrors(false);
3284
+ this.outputIsEditing.emit(false);
3285
+ }
3286
+ updateDataWithTableValue() {
3287
+ const tableValue = (this.dt.value ?? []);
3288
+ this.data.set([...tableValue]);
3289
+ }
3290
+ editInitButton = computed(() => {
3291
+ return {
3292
+ icon: 'fa-solid fa-pencil',
3293
+ rounded: true,
3294
+ variant: 'text',
3295
+ severity: 'secondary'
3296
+ };
3297
+ });
3298
+ getEditInitButton(productId) {
3299
+ return {
3300
+ ...this.editInitButton(),
3301
+ disabled: this.hasRowInEdit && !this.isRowEditing(productId)
3302
+ };
3303
+ }
3304
+ editSaveButton = computed(() => {
3305
+ return {
3306
+ icon: 'fa-solid fa-check',
3307
+ rounded: true,
3308
+ variant: 'text',
3309
+ severity: 'secondary'
3310
+ };
3311
+ });
3312
+ editSaveButtonWithErrors = computed(() => {
3313
+ return {
3314
+ icon: 'fa-solid fa-check',
3315
+ rounded: true,
3316
+ variant: 'text',
3317
+ severity: 'secondary'
3318
+ };
3319
+ });
3320
+ enableErrors = false;
3321
+ setEnableErrors(value) {
3322
+ this.enableErrors = value;
3323
+ }
3324
+ onEditSaveWithErrors() {
3325
+ this.setEnableErrors(true);
3326
+ }
3327
+ editCancelButton = computed(() => {
3328
+ return {
3329
+ icon: 'fa-solid fa-times',
3330
+ rounded: true,
3331
+ variant: 'text',
3332
+ severity: 'secondary'
3333
+ };
3334
+ });
3335
+ deleteRowButton = computed(() => {
3336
+ return {
3337
+ icon: 'fa-solid fa-trash',
3338
+ rounded: true,
3339
+ variant: 'text',
3340
+ severity: 'danger'
3341
+ };
3342
+ });
3343
+ getDeleteRowButton() {
3344
+ return {
3345
+ ...this.deleteRowButton(),
3346
+ disabled: this.hasRowInEdit
3347
+ };
3348
+ }
3349
+ removeRowFromData(data) {
3350
+ const { id } = data;
3351
+ const items = [...this.data()];
3352
+ items.splice(items.findIndex(item => item.id === id), 1);
3353
+ this.data.set(items);
3354
+ this.outputDeleteRow.emit(data);
3355
+ }
3356
+ deleteRow(data) {
3357
+ this.removeRowFromData(data);
3358
+ this.outputEditData.emit(this.data());
3359
+ }
3360
+ //#endregion Row
3361
+ get footerRows() {
3362
+ return this.footerConfig()?.footerRows || [];
3363
+ }
3364
+ applyPipe(value, pipeConfig) {
3365
+ if (!pipeConfig || !pipeConfig.pipe) {
3366
+ return value?.toString() || '';
3367
+ }
3368
+ switch (pipeConfig.pipe) {
3369
+ case 'currency': {
3370
+ const currencyCode = pipeConfig.args?.[0] || 'COP';
3371
+ return new Intl.NumberFormat('es-CO', {
3372
+ style: 'currency',
3373
+ currency: currencyCode
3374
+ }).format(value);
3375
+ }
3376
+ case 'number': {
3377
+ const digits = pipeConfig.args?.[0] || '1.2-2';
3378
+ const [minInteger, fractional] = digits.split('.');
3379
+ const [minFractional, maxFractional] = fractional ? fractional.split('-') : ['0', '0'];
3380
+ return new Intl.NumberFormat('es-CO', {
3381
+ minimumIntegerDigits: parseInt(minInteger),
3382
+ minimumFractionDigits: parseInt(minFractional),
3383
+ maximumFractionDigits: parseInt(maxFractional || minFractional)
3384
+ }).format(value);
3385
+ }
3386
+ case 'date': {
3387
+ if (value instanceof Date) {
3388
+ return value.toLocaleDateString('es-CO');
3389
+ }
3390
+ return value?.toString() || '';
3391
+ }
3392
+ default:
3393
+ return value?.toString() || '';
3394
+ }
3395
+ }
3396
+ // #endregion
3397
+ //#region Row Expansion
3398
+ rowExpansionButton(isRowExpanded) {
3399
+ return computed(() => {
3400
+ return {
3401
+ icon: isRowExpanded ? 'fa-solid fa-chevron-down' : 'fa-solid fa-chevron-right',
3402
+ rounded: true,
3403
+ variant: 'text',
3404
+ severity: 'contrast'
3405
+ };
3406
+ });
3407
+ }
3408
+ //#endregion
3409
+ itemTemplateInput = input(null);
3410
+ itemTemplate;
3411
+ get currentItemTemplate() {
3412
+ return this.itemTemplateInput() || this.itemTemplate || null;
3413
+ }
3414
+ isThatItemInTheProductSelection(field) {
3415
+ const selectedColumns = this.config()?.selectedColumns ?? [];
3416
+ if (!selectedColumns.length) {
3417
+ return true;
3418
+ }
3419
+ return selectedColumns.some((column) => column.field === field);
3420
+ }
3421
+ //#region Advanced Identifier Filters
3422
+ advancedIdentifierFiltersButton = computed(() => {
3423
+ return {
3424
+ icon: 'pi pi-filter',
3425
+ rounded: true,
3426
+ severity: 'warn',
3427
+ raised: true,
3428
+ tooltipConfig: {
3429
+ pTooltip: this.data().length === 0 ? 'No hay datos para filtrar' : 'Filtros avanzados',
3430
+ tooltipPosition: 'top'
3431
+ },
3432
+ onClick: () => {
3433
+ this.openAdvancedIdentifierFilters();
3434
+ },
3435
+ disabled: this.data().length === 0
3436
+ };
3437
+ });
3438
+ openAdvancedIdentifierFilters() {
3439
+ if (this.sourceElements().length === 0) {
3440
+ this.handleTableValueToSourceElements();
3441
+ }
3442
+ this.handleSelectedItemsToSourceElements();
3443
+ if (this.data().length === 0) {
3444
+ return;
3445
+ }
3446
+ const ref = this.dialogService.open(ModalAdvancedFilterComponent, {
3447
+ header: 'Filtros Avanzados',
3448
+ width: '70%',
3449
+ height: '70%',
3450
+ styleClass: 'overflow-hidden',
3451
+ data: {
3452
+ sourceElements: this.sourceElements(),
3453
+ targetElements: this.targetElements()
3454
+ }
3455
+ });
3456
+ ref.onClose.subscribe((result) => {
3457
+ const { sourceElements, targetElements } = result?.data ?? {};
3458
+ if (!result?.success) {
3459
+ return;
3460
+ }
3461
+ if (result?.data?.targetElements?.length === 0) {
3462
+ return;
3463
+ }
3464
+ if (sourceElements.length === 0) {
3465
+ return;
3466
+ }
3467
+ this.sourceElements.set(sourceElements ?? []);
3468
+ this.targetElements.set(targetElements ?? []);
3469
+ this.identifiersSelected.set((this.targetElements() ?? []).filter((element) => element.buttonConfig?.label).map((element) => element.buttonConfig?.label) ?? []);
3470
+ this.dt.filter(this.identifiersSelected(), 'rowData.identifier', 'arrayStringFilter');
3471
+ });
3472
+ }
3473
+ handleTableValueToSourceElements() {
3474
+ const value = this.data();
3475
+ if (!value.some((item) => item.rowData?.['identifier'])) {
3476
+ return;
3477
+ }
3478
+ const sourceElements = value.map((item) => ({
3479
+ id: item.id,
3480
+ buttonConfig: {
3481
+ label: item.rowData?.['identifier'],
3482
+ fullWidth: true,
3483
+ fullHeight: true
3484
+ },
3485
+ isSelected: false
3486
+ }));
3487
+ this.sourceElements.set(sourceElements);
3488
+ }
3489
+ handleSelectedItemsToSourceElements() {
3490
+ const selectedItems = this.selectedItems();
3491
+ if (!selectedItems.some((item) => item.rowData?.['identifier'])) {
3492
+ return;
3493
+ }
3494
+ const identifiers = selectedItems.map((item) => item.rowData?.['identifier']);
3495
+ const sourceElements = this.sourceElements().map((item) => ({
3496
+ ...item,
3497
+ isSelected: identifiers.includes(item.buttonConfig?.label)
3498
+ }));
3499
+ this.sourceElements.set(sourceElements);
3500
+ }
3501
+ identifiersSelected = signal([]);
3502
+ //#endregion
3503
+ get excelButton() {
3504
+ return this.tableNgService.excelButton();
3505
+ }
3506
+ get pdfButton() {
3507
+ return this.tableNgService.pdfButton();
3508
+ }
3509
+ lazyLoadingConfig = computed(() => {
3510
+ return this.config()?.lazyLoadingConfig ?? undefined;
3511
+ });
3512
+ isEnabledLazyLoading = computed(() => {
3513
+ return this.lazyLoadingConfig()?.isEnabled ?? false;
3514
+ });
3515
+ prepareDataForExport(dataToExport) {
3516
+ const keys = this.config()?.keys ?? [];
3517
+ const keysNames = this.config()?.keysNames ?? {};
3518
+ return dataToExport.map((item) => {
3519
+ const row = {};
3520
+ const rowData = item.rowData;
3521
+ keys.forEach((key) => {
3522
+ const keyName = keysNames[key] ?? key;
3523
+ if (rowData[key]) {
3524
+ let value = rowData[key];
3525
+ switch (typeof value) {
3526
+ case 'number':
3527
+ value = formatNumber(value);
3528
+ break;
3529
+ default:
3530
+ break;
3531
+ }
3532
+ row[keyName] = value;
3533
+ }
3534
+ });
3535
+ return row;
3536
+ });
3537
+ }
3538
+ exportCSV(data) {
3539
+ // Create a new workbook
3540
+ const workbook = XLSX.utils.book_new();
3541
+ const worksheet = XLSX.utils.json_to_sheet(data);
3542
+ // Get title from config or use default
3543
+ const name = this.config()?.excelConfig?.name ?? 'Report';
3544
+ const fileName = name || 'table-export';
3545
+ // Excel sheet names cannot exceed 31 characters
3546
+ const sheetName = name.substring(0, 31);
3547
+ // Add the worksheet to the workbook
3548
+ XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
3549
+ // Generate Excel file and trigger download
3550
+ XLSX.writeFile(workbook, `${fileName}.xlsx`);
3551
+ }
3552
+ exportData(dt, endpoint) {
3553
+ if (this.isEnabledLazyLoading()) {
3554
+ const filters = dt.filters ?? {};
3555
+ const filterQuery = {};
3556
+ Object.entries(filters).forEach(([key, value]) => {
3557
+ const keyName = key.split('.')[1];
3558
+ const valueFilter = value[0]?.value;
3559
+ filterQuery[keyName] = valueFilter;
3560
+ });
3561
+ this.lazyLoadingConfig()?.excelLazyLoadingConfig?.callback(removeNullUndefined(filterQuery))
3562
+ .subscribe((response) => {
3563
+ const data = this.prepareDataForExport(response);
3564
+ if (endpoint === 'excel') {
3565
+ this.exportCSV(data);
3566
+ }
3567
+ else {
3568
+ this.exportPDF(data);
3569
+ }
3570
+ });
3571
+ }
3572
+ else {
3573
+ const value = dt.value ?? this.data();
3574
+ const filteredValue = dt.filteredValue ?? [];
3575
+ let dataToExport = [];
3576
+ if (filteredValue.length > 0) {
3577
+ dataToExport = filteredValue;
3578
+ }
3579
+ else {
3580
+ dataToExport = value;
3581
+ }
3582
+ const data = this.prepareDataForExport(dataToExport);
3583
+ if (endpoint === 'excel') {
3584
+ this.exportCSV(data);
3585
+ }
3586
+ else {
3587
+ this.exportPDF(data);
3588
+ }
3589
+ }
3590
+ }
3591
+ exportPDF(data) {
3592
+ // Get title from config or use default
3593
+ const name = this.config()?.pdfConfig?.name ?? this.config()?.excelConfig?.name ?? 'Report';
3594
+ const fileName = name || 'table-export';
3595
+ // Get keys and column names
3596
+ const keys = this.config()?.keys ?? [];
3597
+ const keysNames = this.config()?.keysNames ?? {};
3598
+ // Prepare headers
3599
+ const headers = keys.map((key) => keysNames[key] ?? key);
3600
+ // Prepare rows data
3601
+ const rows = data.map((row) => {
3602
+ return keys.map((key) => {
3603
+ const keyName = keysNames[key] ?? key;
3604
+ return row[keyName] ?? '';
3605
+ });
3606
+ });
3607
+ // Create PDF document
3608
+ const doc = new jsPDF({
3609
+ orientation: 'landscape',
3610
+ unit: 'mm',
3611
+ format: 'a4'
3612
+ });
3613
+ // Add title
3614
+ doc.setFontSize(16);
3615
+ doc.text(name, 14, 15);
3616
+ // Add table
3617
+ autoTable(doc, {
3618
+ head: [headers],
3619
+ body: rows,
3620
+ startY: 20,
3621
+ styles: {
3622
+ fontSize: 8,
3623
+ cellPadding: 2
3624
+ },
3625
+ headStyles: {
3626
+ fillColor: [66, 139, 202],
3627
+ textColor: 255,
3628
+ fontStyle: 'bold'
3629
+ },
3630
+ alternateRowStyles: {
3631
+ fillColor: [245, 245, 245]
3632
+ },
3633
+ margin: { top: 20 }
3634
+ });
3635
+ // Save PDF
3636
+ doc.save(`${fileName}.pdf`);
3637
+ }
3638
+ enableExcelButton = computed(() => {
3639
+ return this.config()?.excelConfig?.isEnabled ?? false;
3640
+ });
3641
+ enablePdfButton = computed(() => {
3642
+ return this.config()?.pdfConfig?.isEnabled ?? false;
3643
+ });
3644
+ get enableRefreshButton() {
3645
+ return this.tableNgService.enableRefreshButton();
3646
+ }
3647
+ get refreshButton() {
3648
+ return this.tableNgService.refreshButton();
3649
+ }
3650
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TableNgComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3651
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: TableNgComponent, isStandalone: true, selector: "lib-table-ng", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, isLoading: { classPropertyName: "isLoading", publicName: "isLoading", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, editConfig: { classPropertyName: "editConfig", publicName: "editConfig", isSignal: true, isRequired: false, transformFunction: null }, footerConfig: { classPropertyName: "footerConfig", publicName: "footerConfig", isSignal: true, isRequired: false, transformFunction: null }, toolbarButtons: { classPropertyName: "toolbarButtons", publicName: "toolbarButtons", isSignal: true, isRequired: false, transformFunction: null }, toolbarSpeedDialButtons: { classPropertyName: "toolbarSpeedDialButtons", publicName: "toolbarSpeedDialButtons", isSignal: true, isRequired: false, transformFunction: null }, sourceElements: { classPropertyName: "sourceElements", publicName: "sourceElements", isSignal: true, isRequired: false, transformFunction: null }, targetElements: { classPropertyName: "targetElements", publicName: "targetElements", isSignal: true, isRequired: false, transformFunction: null }, httpMessage: { classPropertyName: "httpMessage", publicName: "httpMessage", isSignal: true, isRequired: false, transformFunction: null }, selectedItems: { classPropertyName: "selectedItems", publicName: "selectedItems", isSignal: true, isRequired: false, transformFunction: null }, itemTemplateInput: { classPropertyName: "itemTemplateInput", publicName: "itemTemplateInput", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { data: "dataChange", isLoading: "isLoadingChange", config: "configChange", editConfig: "editConfigChange", footerConfig: "footerConfigChange", toolbarButtons: "toolbarButtonsChange", toolbarSpeedDialButtons: "toolbarSpeedDialButtonsChange", sourceElements: "sourceElementsChange", targetElements: "targetElementsChange", httpMessage: "httpMessageChange", lazyLoading: "lazyLoading", outputChangeData: "outputChangeData", outputHandleEditInitButton: "outputHandleEditInitButton", outputAddRow: "outputAddRow", outputDeleteRow: "outputDeleteRow", outputRowInlineChange: "outputRowInlineChange", outputRowDataChange: "outputRowDataChange", outputEditData: "outputEditData", outputIsEditing: "outputIsEditing", outputCheckAll: "outputCheckAll", selectedItems: "selectedItemsChange" }, providers: [TableNgService, TableNgEditService], queries: [{ propertyName: "itemTemplate", first: true, predicate: ["item"], descendants: true, static: true }], viewQueries: [{ propertyName: "dt", first: true, predicate: ["dt"], descendants: true }], ngImport: i0, template: "@let paginationConfig = config()?.paginationConfig;\r\n@let globalFilterConfig = config()?.globalFilterConfig;\r\n@let selectionTableConfig = config()?.selectionTableConfig;\r\n@let filterConfigByKey = config()?.filterConfigByKey;\r\n@let frozenColumnConfigByKey = config()?.frozenColumnConfigByKey;\r\n@let scrollConfig = config()?.scrollConfig;\r\n@let lazyLoadingConfig = config()?.lazyLoadingConfig;\r\n@let keysNames = config()?.keysNames;\r\n@let columnConfig = config()?.columnConfig;\r\n@let editEnabled = editConfig()?.isEnabled ?? false;\r\n@let editType = editConfig()?.type ?? 'cell';\r\n@let inlineControls = editConfig()?.inlineControls;\r\n@let rowErrorConfig = editConfig()?.rowEditConfig?.rowErrorConfig;\r\n@let footerRows = footerConfig()?.footerRows;\r\n@let footerEnabled = footerConfig()?.isEnabled ?? false;\r\n@let titleConfig = config()?.titleConfig;\r\n@let selectedColumns = config()?.selectedColumns;\r\n@let rowExpansionConfig = config()?.rowExpansionConfig;\r\n@let advancedIdentifierFiltersConfig = config()?.globalFilterConfig?.advancedIdentifierFiltersConfig;\r\n@let inputConfig = config()?.inputConfig;\r\n@let hasCheckRows = config()?.hasCheckRows ?? false;\r\n<div class=\"p-datatable-wrapper\">\r\n @if (titleConfig?.isEnabled && titleConfig?.title) {\r\n <div class=\"table-title-container\">\r\n <h2 class=\"table-title\">{{ titleConfig!.title }}</h2>\r\n </div>\r\n }\r\n @if (!hideToolbar || (filteredValue || advancedFiltersPerformed.length > 0)) {\r\n <lib-toolbar-ng class=\"p-toolbar-header sticky top-0 z-30 dark:bg-gray-800\">\r\n <div class=\"flex gap-2\" toolbarStart>\r\n @if (globalFilterConfig?.isEnabled && !lazyLoadingConfig?.isEnabled) {\r\n <lib-form [controls]=\"controlsGlobalFilter\" [(formGroup)]=\"searchFormGroupGlobalFilter\"\r\n (formSubmit)=\"submitGlobalSearch($event)\"></lib-form>\r\n }\r\n @if (advancedIdentifierFiltersConfig?.isEnabled) {\r\n <lib-button-ng class=\"animate__animated animate__fadeIn\"\r\n [buttonConfig]=\"advancedIdentifierFiltersButton()\"></lib-button-ng>\r\n }\r\n @if (filteredValue || advancedFiltersPerformed.length > 0) {\r\n <lib-button-ng class=\"animate__animated animate__fadeIn\" [buttonConfig]=\"clearFiltersButton()\"></lib-button-ng>\r\n }\r\n @if (hasCheckRows) {\r\n <div class=\"inline-flex\" (click)=\"$event.stopPropagation()\">\r\n <lib-inline-input\r\n [ngModel]=\"checkAllHeaderReflectValue()\"\r\n (ngModelChange)=\"checkAll($event)\"\r\n [config]=\"inlineConfigCheckHeaderCheckAll\">\r\n </lib-inline-input>\r\n </div>\r\n }\r\n </div>\r\n <div class=\"flex gap-2\" toolbarEnd>\r\n @if (toolbarSpeedDialButtons().length > 0) {\r\n @for (speedDial of toolbarSpeedDialButtons(); track $index) {\r\n <lib-speed-dial [speedDialConfig]=\"speedDial\"></lib-speed-dial>\r\n }\r\n }\r\n @if (toolbarButtons().length > 0) {\r\n @for (button of toolbarButtons(); track $index) {\r\n <lib-button-ng [buttonConfig]=\"button\"></lib-button-ng>\r\n }\r\n }\r\n @if ((editType === 'row' || editType === 'cell') && editEnabled) {\r\n <lib-button-ng [buttonConfig]=\"addRowButton()\"></lib-button-ng>\r\n }\r\n @if (enableExcelButton()) {\r\n <lib-button-ng [buttonConfig]=\"excelButton\" (onClick)=\"exportData(dt,'excel')\"></lib-button-ng>\r\n }\r\n @if (enablePdfButton()) {\r\n <lib-button-ng [buttonConfig]=\"pdfButton\" (onClick)=\"exportData(dt,'pdf')\"></lib-button-ng>\r\n }\r\n @if (enableRefreshButton) {\r\n <lib-button-ng [buttonConfig]=\"refreshButton\"></lib-button-ng>\r\n }\r\n </div>\r\n </lib-toolbar-ng>\r\n }\r\n <p-table #dt styleClass=\"p-datatable-sm\" tableStyleClass=\"table table-xs\" [value]=\"data()\" [lazy]=\"lazyLoadingConfig?.isEnabled ?? false\"\r\n [editMode]=\"editType\" [totalRecords]=\"\r\n lazyLoadingConfig?.isEnabled\r\n ? lazyLoadingConfig!.totalRecords\r\n : data().length\r\n \" [customSort]=\"true\" [paginator]=\"paginationConfig?.paginator ?? true\" [showCurrentPageReport]=\"true\"\r\n [rows]=\"paginationConfig?.rows ?? 5\" [rowsPerPageOptions]=\"paginationConfig?.rowsPerPageOptions ?? [5, 10, 20]\"\r\n [paginatorStyleClass]=\"paginatorStyleClass()\" [resizableColumns]=\"true\" [rowTrackBy]=\"trackById\"\r\n [columns]=\"selectedColumns\" [scrollable]=\"scrollConfig?.isEnabled ?? false\"\r\n [scrollHeight]=\"scrollConfig?.isEnabled ? scrollHeight() : undefined\" (onLazyLoad)=\"onLazyLoad($event)\"\r\n (sortFunction)=\"customSort($event)\" (onFilter)=\"onFilter($event)\" [(selection)]=\"selectedItems\"\r\n [currentPageReportTemplate]=\"getCustomPageReport()\" selectionPageOnly=\"true\" dataKey=\"id\" class=\"w-full\">\r\n <ng-template #header let-columns>\r\n <tr>\r\n @if (rowExpansionConfig?.isEnabled) {\r\n <th alignFrozen=\"left\" pFrozenColumn style=\"width: 2rem\" class=\"p-datatable-header-cell p-frozen-column\">\r\n\r\n </th>\r\n }\r\n @if (selectionTableConfig?.isEnabled) {\r\n <th alignFrozen=\"left\" pFrozenColumn style=\"width: 2rem\" class=\"p-datatable-header-cell p-frozen-column\">\r\n <p-tableHeaderCheckbox />\r\n </th>\r\n }\r\n\r\n @if (selectedColumns) {\r\n @for (column of columns; track $index) {\r\n <th pResizableColumn [id]=\"column.field\" alignFrozen=\"right\" pFrozenColumn\r\n [frozen]=\"frozenHandle(frozenColumnConfigByKey?.[column.field])\" [pSortableColumn]=\"column.field\"\r\n class=\"p-datatable-header-cell\" [style.width.%]=\"columnConfig?.sizeByKey?.[column.field] ?? null\" [ngClass]=\"{\r\n 'p-frozen-column': frozenHandle(\r\n frozenColumnConfigByKey?.[column.field]\r\n ),\r\n }\">\r\n <div class=\"flex gap-2 justify-center items-center py-0 px-0\">\r\n {{ column.field | keyToDisplayName: keysNames }}\r\n @if (inputConfig?.[column.field]?.isEnabled) {\r\n @let columnInputConfig = inputConfig![column.field]!;\r\n @if (columnInputConfig.type === ETypeInput.SWITCH || columnInputConfig.type === ETypeInput.CHECKBOX) {\r\n <div class=\"inline-flex\" (click)=\"$event.stopPropagation()\">\r\n <lib-inline-input\r\n [ngModel]=\"booleanColumnHeaderReflectValue(column.field)\"\r\n (ngModelChange)=\"applyBulkBooleanToColumn($event, column.field)\"\r\n [config]=\"inlineConfigCheckHeader(column.field, columnInputConfig.type)\">\r\n </lib-inline-input>\r\n </div>\r\n }\r\n }\r\n @if(!editEnabled){\r\n <p-sortIcon [field]=\"column.field\" />\r\n }\r\n @if (filterConfigByKey?.[column.field]?.isEnabled) {\r\n @let columnFilterConfig = filterConfigByKey![column.field]!;\r\n <p-columnFilter [field]=\"`rowData.${column.field}`\" display=\"menu\" [ngClass]=\"{\r\n 'bg-green-200 rounded-full p-1 shadow-sm text-green-500 transition-all duration-300 ease-in-out':\r\n advancedFiltersPerformed.includes(column.field),\r\n }\" [type]=\"columnFilterConfig.primeNgColumnFilterConfig?.type ?? 'text'\"\r\n [matchMode]=\"columnFilterConfig.primeNgColumnFilterConfig?.matchMode\"\r\n [showMatchModes]=\"columnFilterConfig.primeNgColumnFilterConfig?.showMatchModes ?? false\"\r\n [showOperator]=\"columnFilterConfig.primeNgColumnFilterConfig?.showOperator ?? false\"\r\n [showAddButton]=\"columnFilterConfig.primeNgColumnFilterConfig?.showAddButton ?? false\"\r\n [showApplyButton]=\"columnFilterConfig.primeNgColumnFilterConfig?.showApplyButton ?? false\"\r\n [showClearButton]=\"columnFilterConfig.primeNgColumnFilterConfig?.showClearButton ?? false\">\r\n @if (isCustomColumnFilterEnabled(columnFilterConfig)) {\r\n <ng-template pTemplate=\"filter\" let-value let-filter=\"filterCallback\">\r\n <div style=\"min-width: 20rem\">\r\n <lib-inline-input\r\n [ngModel]=\"value\"\r\n (outputValue)=\"inlineFormChanges($event, filter, columnFilterConfig.customColumnFilterConfig?.inlineControlConfig?.typeInput, column.field)\"\r\n [config]=\"columnFilterConfig.customColumnFilterConfig?.inlineControlConfig ?? {typeInput: ETypeInput.TEXT}\">\r\n </lib-inline-input>\r\n </div>\r\n </ng-template>\r\n }\r\n </p-columnFilter>\r\n }\r\n </div>\r\n </th>\r\n }\r\n }@else {\r\n @for (key of keys(); track $index) {\r\n <th [id]=\"key\" pResizableColumn alignFrozen=\"right\" pFrozenColumn\r\n [frozen]=\"frozenHandle(frozenColumnConfigByKey?.[key])\" [pSortableColumn]=\"key\"\r\n class=\"p-datatable-header-cell\" [style.width.%]=\"columnConfig?.sizeByKey?.[key] ?? null\" [ngClass]=\"{\r\n 'p-frozen-column': frozenHandle(frozenColumnConfigByKey?.[key]),\r\n }\">\r\n \r\n <div class=\"flex gap-2 justify-center items-center py-0 px-0\">\r\n {{ key | keyToDisplayName: keysNames }}\r\n @if (inputConfig?.[key]?.isEnabled) {\r\n @let keyInputConfig = inputConfig![key]!;\r\n @if (keyInputConfig.type === ETypeInput.SWITCH || keyInputConfig.type === ETypeInput.CHECKBOX) {\r\n <div class=\"inline-flex\" (click)=\"$event.stopPropagation()\">\r\n <lib-inline-input\r\n [ngModel]=\"booleanColumnHeaderReflectValue(key)\"\r\n (ngModelChange)=\"applyBulkBooleanToColumn($event, key)\"\r\n [config]=\"inlineConfigCheckHeader(key, keyInputConfig.type)\">\r\n </lib-inline-input>\r\n </div>\r\n }\r\n }\r\n @if(!editEnabled){\r\n <p-sortIcon [field]=\"key\" />\r\n }\r\n @if (filterConfigByKey?.[key]?.isEnabled) {\r\n @let columnFilterConfig = filterConfigByKey![key]!;\r\n <p-columnFilter [field]=\"`rowData.${key}`\" display=\"menu\" [ngClass]=\"{\r\n 'bg-green-200 rounded-full p-1 shadow-sm text-green-500 transition-all duration-300 ease-in-out':\r\n advancedFiltersPerformed.includes(key),\r\n }\" [type]=\"columnFilterConfig.primeNgColumnFilterConfig?.type ?? 'text'\"\r\n [matchMode]=\"columnFilterConfig.primeNgColumnFilterConfig?.matchMode\"\r\n [showMatchModes]=\"columnFilterConfig.primeNgColumnFilterConfig?.showMatchModes ?? false\"\r\n [showOperator]=\"columnFilterConfig.primeNgColumnFilterConfig?.showOperator ?? false\"\r\n [showAddButton]=\"columnFilterConfig.primeNgColumnFilterConfig?.showAddButton ?? false\"\r\n [showApplyButton]=\"columnFilterConfig.primeNgColumnFilterConfig?.showApplyButton ?? false\"\r\n [showClearButton]=\"columnFilterConfig.primeNgColumnFilterConfig?.showClearButton ?? false\">\r\n @if (isCustomColumnFilterEnabled(columnFilterConfig)) {\r\n <ng-template pTemplate=\"filter\" let-value let-filter=\"filterCallback\">\r\n <div style=\"min-width: 20rem\">\r\n <lib-inline-input\r\n [ngModel]=\"value\"\r\n (outputValue)=\"inlineFormChanges($event, filter, columnFilterConfig.customColumnFilterConfig?.inlineControlConfig?.typeInput, key)\"\r\n [config]=\"columnFilterConfig.customColumnFilterConfig?.inlineControlConfig ?? {typeInput: ETypeInput.TEXT}\">\r\n </lib-inline-input>\r\n </div>\r\n </ng-template>\r\n }\r\n </p-columnFilter>\r\n }\r\n </div>\r\n </th>\r\n }\r\n }\r\n\r\n @if (editType === 'cell' && editEnabled) {\r\n <th class=\"p-datatable-header-cell\" style=\"width: 100px\">\r\n </th>\r\n }\r\n @if (editType === 'row' && editEnabled) {\r\n <th class=\"p-datatable-header-cell\" style=\"width: 100px\">\r\n </th>\r\n }\r\n\r\n </tr>\r\n </ng-template>\r\n\r\n <ng-template #emptymessage>\r\n <tr>\r\n <td [attr.colspan]=\"totalColumns()\">\r\n @if (isLoading()) {\r\n <!-- Loading state -->\r\n <div class=\"p-8 text-center\">\r\n <div class=\"flex flex-col items-center justify-center gap-4\">\r\n <i class=\"pi pi-spin pi-spinner text-4xl text-blue-500\"></i>\r\n <p class=\"text-gray-600 text-lg\">{{ getLoadingMessage() }}</p>\r\n </div>\r\n </div>\r\n } @else if (timeoutExpired()) {\r\n <!-- No data available -->\r\n <div class=\"p-8 text-center text-gray-500\">\r\n <div class=\"flex flex-col items-center justify-center gap-3\">\r\n <i class=\"pi pi-info-circle text-4xl text-gray-400\"></i>\r\n <p class=\"text-lg\">{{ getNoDataMessage() }}</p>\r\n </div>\r\n </div>\r\n }\r\n </td>\r\n </tr>\r\n </ng-template>\r\n\r\n @if (hasRecords()) {\r\n @if (editEnabled) {\r\n @switch (editType) {\r\n @case ('cell') {\r\n <ng-template #body let-item let-editing=\"editing\">\r\n <tr class=\"p-datatable-row p-selectable-row\">\r\n @if (selectedColumns) {\r\n @for (column of selectedColumns; track $index){\r\n <td [pEditableColumn]=\"column.field\" pEditableColumnField=\"rowData.{{column.field}}\">\r\n <p-cellEditor>\r\n <ng-template #input>\r\n <lib-inline-input [(ngModel)]=\"item.rowData[column.field]\" (outputDebounced)=\"onEditData()\"\r\n [config]=\"inlineControls?.[column.field] ?? {typeInput: ETypeInput.TEXT}\">\r\n </lib-inline-input>\r\n </ng-template>\r\n <ng-template #output>\r\n @if (inlineControls?.[column.field]?.typeInput === ETypeInput.NUMBER) {\r\n <div class=\"text-right\">\r\n {{\r\n item.rowData[column.field]\r\n | number: (\r\n inlineControls?.[column.field]?.numberConfig?.minFractionDigits === 0 &&\r\n inlineControls?.[column.field]?.numberConfig?.maxFractionDigits === 0\r\n ? '1.0-0'\r\n : '1.2-2'\r\n )\r\n }}\r\n\r\n </div>\r\n } @else if(inlineControls?.[column.field]?.typeInput === ETypeInput.CURRENCY) {\r\n <div class=\"text-right\">\r\n {{ item.rowData[column.field] | currency: item?.currencyTypeCellConfig?.[column.field]?.currency ??\r\n 'USD' }}\r\n </div>\r\n } @else if(inlineControls?.[column.field]?.typeInput === ETypeInput.DATE) {\r\n <div class=\"text-left\">\r\n {{ item.rowData[column.field] | date: \"dd/MM/yyyy\" }}\r\n </div>\r\n } @else if(inlineControls?.[column.field]?.typeInput === ETypeInput.DATETIME_LOCAL) {\r\n <div class=\"text-left\">\r\n {{ item.rowData[column.field] | date: \"dd/MM/yyyy HH:mm\" }}\r\n </div>\r\n }@else if(inlineControls?.[column.field]?.typeInput === ETypeInput.SELECT) {\r\n <div class=\"text-left\">\r\n {{ item.rowData[column.field]?.name ?? item.rowData[column.field]?.value ?? '' }}\r\n </div>\r\n }\r\n @else if(inlineControls?.[column.field]?.typeInput === ETypeInput.SWITCH) {\r\n <div class=\"text-center\">\r\n @if (item.rowData[column.field]) {\r\n <i class=\"fa-solid fa-check text-green-500\"></i>\r\n } @else {\r\n <i class=\"fa-solid fa-times text-red-500\"></i>\r\n }\r\n </div>\r\n } @else {\r\n @if (item.rowData[column.field]?.name) {\r\n {{ item.rowData[column.field]?.name }}\r\n } @else {\r\n {{ item.rowData[column.field] }}\r\n }\r\n }\r\n\r\n </ng-template>\r\n </p-cellEditor>\r\n\r\n @if (rowErrorConfig; as errorConfig) {\r\n @if (errorConfig.isEnabled && enableErrors && errorConfig.fieldErrors[item.id]?.[column.field]; as columnFieldError) {\r\n <span class=\"text-red-500 italic text-xs\">\r\n {{ columnFieldError.message }}\r\n </span>\r\n }\r\n }\r\n </td>\r\n }\r\n } @else {\r\n @for (key of keys(); track $index){\r\n <td [pEditableColumn]=\"key\" pEditableColumnField=\"rowData.{{key}}\">\r\n <p-cellEditor>\r\n <ng-template #input>\r\n <lib-inline-input [(ngModel)]=\"item.rowData[key]\" (outputDebounced)=\"onEditData()\"\r\n [config]=\"inlineControls?.[key] ?? {typeInput: ETypeInput.TEXT}\">\r\n </lib-inline-input>\r\n </ng-template>\r\n <ng-template #output>\r\n @if (inlineControls?.[key]?.typeInput === ETypeInput.NUMBER) {\r\n <div class=\"text-right\">\r\n {{\r\n item.rowData[key]\r\n | number: (\r\n inlineControls?.[key]?.numberConfig?.minFractionDigits === 0 &&\r\n inlineControls?.[key]?.numberConfig?.maxFractionDigits === 0\r\n ? '1.0-0'\r\n : '1.2-2'\r\n )\r\n }}\r\n </div>\r\n } @else if(inlineControls?.[key]?.typeInput === ETypeInput.CURRENCY) {\r\n <div class=\"text-right\">\r\n {{ item.rowData[key] | currency: item?.currencyTypeCellConfig?.[key]?.currency ?? 'USD' }}\r\n </div>\r\n } @else if(inlineControls?.[key]?.typeInput === ETypeInput.DATE) {\r\n <div class=\"text-left\">\r\n {{ item.rowData[key] | date: \"dd/MM/yyyy\" }}\r\n </div>\r\n } @else if(inlineControls?.[key]?.typeInput === ETypeInput.DATETIME_LOCAL) {\r\n <div class=\"text-left\">\r\n {{ item.rowData[key] | date: \"dd/MM/yyyy HH:mm\" }}\r\n </div>\r\n } @else if(inlineControls?.[key]?.typeInput === ETypeInput.SELECT) {\r\n <div class=\"text-left\">\r\n {{ item.rowData[key]?.name ?? item.rowData[key]?.value ?? '' }}\r\n </div>\r\n } @else if (inlineControls?.[key]?.typeInput === ETypeInput.SWITCH) {\r\n <div class=\"text-center\">\r\n @if (item.rowData[key]) {\r\n <i class=\"fa-solid fa-check text-green-500\"></i>\r\n } @else {\r\n <i class=\"fa-solid fa-times text-red-500\"></i>\r\n }\r\n </div>\r\n } @else {\r\n @if (item.rowData[key]?.name) {\r\n {{ item.rowData[key]?.name }}\r\n } @else {\r\n {{ item.rowData[key] }}\r\n }\r\n }\r\n </ng-template>\r\n </p-cellEditor>\r\n\r\n @if (rowErrorConfig; as errorConfig) {\r\n @if (errorConfig.isEnabled && enableErrors && errorConfig.fieldErrors[item.id]?.[key]; as keyFieldError) {\r\n <span class=\"text-red-500 italic text-xs\">\r\n {{ keyFieldError.message }}\r\n </span>\r\n }\r\n }\r\n </td>\r\n }\r\n }\r\n @if (editType === 'cell' && editEnabled) {\r\n <td class=\"px-2 py-1 text-center\">\r\n <div class=\"flex justify-center items-center gap-2\">\r\n <lib-button-ng [buttonConfig]=\"getDeleteRowButton()\" (onClick)=\"deleteRow(item)\"></lib-button-ng>\r\n </div>\r\n </td>\r\n }\r\n </tr>\r\n </ng-template>\r\n }\r\n @case ('row') {\r\n <ng-template #body let-item let-editing=\"editing\" let-ri=\"rowIndex\">\r\n <tr [pEditableRow]=\"item\" class=\"cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 border-b\">\r\n @if (selectedColumns) {\r\n @for (column of selectedColumns; track $index){\r\n <td>\r\n <div class=\"flex flex-col gap-2\">\r\n <p-cellEditor>\r\n <ng-template #input>\r\n <lib-inline-input [(ngModel)]=\"item.rowData[column.field]\"\r\n (outputValue)=\"inlineChange($event, column.field)\" (outputDebounced)=\"onEditData()\"\r\n [config]=\"inlineControls?.[column.field] ?? {typeInput: ETypeInput.TEXT}\">\r\n </lib-inline-input>\r\n\r\n </ng-template>\r\n <ng-template #output>\r\n\r\n @if (inlineControls?.[column.field]?.typeInput === ETypeInput.NUMBER) {\r\n <div class=\"text-right\">\r\n {{ item.rowData[column.field] | number: '1.2-2' }}\r\n\r\n </div>\r\n } @else if(inlineControls?.[column.field]?.typeInput === ETypeInput.CURRENCY) {\r\n <div class=\"text-right\">\r\n {{ item.rowData[column.field] | currency: item?.currencyTypeCellConfig?.[column.field]?.currency ??\r\n 'USD' }}\r\n </div>\r\n } @else if(inlineControls?.[column.field]?.typeInput === ETypeInput.DATE) {\r\n <div class=\"text-left\">\r\n {{ item.rowData[column.field] | date: \"dd/MM/yyyy\" }}\r\n </div>\r\n } @else if(inlineControls?.[column.field]?.typeInput === ETypeInput.DATETIME_LOCAL) {\r\n <div class=\"text-left\">\r\n {{ item.rowData[column.field] | date: \"dd/MM/yyyy HH:mm\" }}\r\n </div>\r\n } @else if(inlineControls?.[column.field]?.typeInput === ETypeInput.SWITCH) {\r\n <div class=\"text-center\">\r\n @if (item.rowData[column.field]) {\r\n <i class=\"fa-solid fa-check text-green-500\"></i>\r\n } @else {\r\n <i class=\"fa-solid fa-times text-red-500\"></i>\r\n }\r\n </div>\r\n } @else {\r\n @if (item.rowData[column.field]?.name) {\r\n {{ item.rowData[column.field]?.name }}\r\n } @else {\r\n {{ item.rowData[column.field] }}\r\n }\r\n }\r\n\r\n\r\n </ng-template>\r\n </p-cellEditor>\r\n\r\n @if (rowErrorConfig; as errorConfig) {\r\n @if (errorConfig.isEnabled && enableErrors && !rowFieldsHasValue()[column.field] && errorConfig.fieldErrors[item.id]?.[column.field]; as columnFieldError) {\r\n <span class=\"text-red-500 italic text-xs\">{{ columnFieldError.message }}</span>\r\n }\r\n }\r\n </div>\r\n </td>\r\n }\r\n } @else {\r\n @for (key of keys(); track $index){\r\n <td>\r\n <div class=\"flex flex-col gap-2\">\r\n <p-cellEditor>\r\n <ng-template #input>\r\n <lib-inline-input [(ngModel)]=\"item.rowData[key]\" (outputValue)=\"inlineChange($event, key)\"\r\n (outputDebounced)=\"onEditData()\" [config]=\"inlineControls?.[key] ?? {typeInput: ETypeInput.TEXT}\">\r\n </lib-inline-input>\r\n </ng-template>\r\n <ng-template #output>\r\n\r\n @if (inlineControls?.[key]?.typeInput === ETypeInput.NUMBER) {\r\n <div class=\"text-right\">\r\n {{ item.rowData[key] | number: '1.2-2' }}\r\n\r\n </div>\r\n }\r\n @else if(inlineControls?.[key]?.typeInput === ETypeInput.CURRENCY) {\r\n <div class=\"text-right\">\r\n {{ item.rowData[key] | currency: item?.currencyTypeCellConfig?.[key]?.currency ?? 'USD' }}\r\n </div>\r\n } @else if(inlineControls?.[key]?.typeInput === ETypeInput.SWITCH) {\r\n <div class=\"text-center\">\r\n @if (item.rowData[key]) {\r\n <i class=\"fa-solid fa-check text-green-500\"></i>\r\n } @else {\r\n <i class=\"fa-solid fa-times text-red-500\"></i>\r\n }\r\n </div>\r\n } @else {\r\n @if (item.rowData[key]?.name) {\r\n {{ item.rowData[key]?.name }}\r\n } @else {\r\n {{ item.rowData[key] }}\r\n }\r\n }\r\n\r\n\r\n </ng-template>\r\n </p-cellEditor>\r\n\r\n @if (rowErrorConfig; as errorConfig) {\r\n @if (errorConfig.isEnabled && enableErrors && !rowFieldsHasValue()[key] && errorConfig.fieldErrors[item.id]?.[key]; as keyFieldError) {\r\n <span class=\"text-red-500 italic text-xs\">{{ keyFieldError.message }}</span>\r\n }\r\n }\r\n </div>\r\n </td>\r\n }\r\n }\r\n <td>\r\n <div class=\"flex justify-center items-center gap-2\">\r\n @if(!editing){\r\n <lib-button-ng pButton pRipple pInitEditableRow [buttonConfig]=\"getEditInitButton(item.id)\"\r\n (onClick)=\"onRowEditInit(item)\"></lib-button-ng>\r\n @if(!editConfig()?.rowEditConfig?.isDisabledDeleteButton){\r\n <lib-button-ng [buttonConfig]=\"getDeleteRowButton()\" (onClick)=\"deleteRow(item)\"></lib-button-ng>\r\n }\r\n }\r\n @if(editing){\r\n @if (hasErrorValues(rowErrorConfig?.fieldErrors?.[item.id] ?? {})) {\r\n <lib-button-ng [buttonConfig]=\"editSaveButtonWithErrors()\"\r\n (onClick)=\"onEditSaveWithErrors()\"></lib-button-ng>\r\n }\r\n @else {\r\n <lib-button-ng pButton pRipple pSaveEditableRow [buttonConfig]=\"editSaveButton()\"\r\n (onClick)=\"onRowEditSave(item)\"></lib-button-ng>\r\n }\r\n <lib-button-ng pButton pRipple pCancelEditableRow [buttonConfig]=\"editCancelButton()\"\r\n (onClick)=\"onRowEditCancel(item, ri)\"></lib-button-ng>\r\n }\r\n </div>\r\n </td>\r\n </tr>\r\n </ng-template>\r\n }\r\n }\r\n } @else {\r\n\r\n <ng-template #body let-item let-expanded=\"expanded\">\r\n <tr class=\"p-datatable-row p-selectable-row\" [ngClass]=\"{\r\n 'bg-gray-50 dark:bg-gray-800 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700': item.onClick && !item.isSelected && !item.isLoading,\r\n 'bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600': !item.onClick && !item.isSelected && !item.isLoading,\r\n 'bg-blue-100 dark:bg-blue-900 border-l-4 border-blue-500 hover:bg-blue-200 dark:hover:bg-blue-800': item.isSelected && !item.isLoading,\r\n 'skeleton-row': item.isLoading\r\n }\" (click)=\"item?.isLoading ? null : onRowClick(item)\">\r\n\r\n @if (rowExpansionConfig?.isEnabled) {\r\n <td (click)=\"$event.stopPropagation()\" [class.skeleton-cell]=\"item.isLoading\"\r\n [style.height]=\"item.isLoading ? '3rem' : 'auto'\">\r\n @if (!item.isLoading) {\r\n <lib-button-ng [buttonConfig]=\"rowExpansionButton(expanded)()\" type=\"button\" pRipple\r\n [pRowToggler]=\"item\"></lib-button-ng>\r\n } @else {\r\n <div class=\"skeleton-content\"></div>\r\n }\r\n </td>\r\n }\r\n\r\n @if (selectionTableConfig?.isEnabled) {\r\n <td (click)=\"$event.stopPropagation()\" alignFrozen=\"left\" pFrozenColumn class=\"shadow-lg\"\r\n [class.skeleton-cell]=\"item.isLoading\" [style.height]=\"item.isLoading ? '3rem' : 'auto'\">\r\n @if (!item.isLoading) {\r\n <p-tableCheckbox [id]=\"item\" [value]=\"item\" />\r\n } @else {\r\n <div class=\"skeleton-content\"></div>\r\n }\r\n </td>\r\n }\r\n\r\n @for (key of keys(); track $index) {\r\n @if (isThatItemInTheProductSelection(key)) {\r\n <td [id]=\"key\" class=\"p-datatable-cell\" [style.height]=\"item.isLoading ? '3rem' : 'min-content'\"\r\n alignFrozen=\"right\" pFrozenColumn [ngClass]=\"{\r\n 'p-frozen-column': frozenHandle(frozenColumnConfigByKey?.[key]),\r\n 'text-center': item.rowDataButtons?.[key] || item.typeCell?.[key] === ETypeInput.BADGE,\r\n 'skeleton-cell': item.isLoading\r\n }\" [frozen]=\"frozenHandle(frozenColumnConfigByKey?.[key])\">\r\n @if (item.isLoading) {\r\n <div class=\"skeleton-content\"></div>\r\n } @else {\r\n @if (item.rowDataButtons?.[key]) {\r\n <div class=\"flex gap-4 w-full justify-center items-center\">\r\n @for (btn of item.rowDataButtons[key]; track $index) {\r\n @if (btn) {\r\n <lib-button-ng class=\"w-full\" (click)=\"$event.stopPropagation()\" [buttonConfig]=\"btn\"></lib-button-ng>\r\n }\r\n }\r\n </div>\r\n } @else {\r\n @switch (item.typeCell?.[key]) {\r\n @case (ETypeInput.IMAGE) {\r\n <img [src]=\"item.rowData[key]\" alt=\"Image\" class=\"w-10 h-10 mx-auto\">\r\n }\r\n @case (ETypeInput.DATE) {\r\n {{ item.rowData[key] | date: \"dd/MM/yyyy\" }}\r\n }\r\n @case (ETypeInput.DATETIME_LOCAL) {\r\n {{ item.rowData[key] | date: \"dd/MM/yyyy HH:mm\" }}\r\n }\r\n @case (ETypeInput.CURRENCY) {\r\n {{item?.currencyTypeCellConfig?.[key]?.currency}} {{ item.rowData[key] | currency:\r\n item?.currencyTypeCellConfig?.[key]?.currency ?? 'USD' }}\r\n }\r\n @case (ETypeInput.BADGE) {\r\n <lib-badge-ng [config]=\"item.rowData[key]\"></lib-badge-ng>\r\n }\r\n @case (ETypeInput.COMPONENT) {\r\n <ng-container\r\n *ngTemplateOutlet=\"item.rowDataComponents?.[key]; context: { $implicit: item.raw }\"></ng-container>\r\n }\r\n @case (ETypeInput.INPUT) {\r\n <lib-inline-input [(ngModel)]=\"item.rowData[key]\"\r\n [config]=\"item.rowDataInput?.[key] ?? {typeInput: ETypeInput.TEXT}\"\r\n (outputValue)=\"handleCheckValue()\"\r\n >\r\n </lib-inline-input>\r\n }\r\n @default {\r\n @if (isDate(item.rowData[key])) {\r\n {{ item.rowData[key] | date: \"dd/MM/yyyy\" }}\r\n } @else if (typeof item.rowData[key] === \"string\") {\r\n {{ item.rowData[key] }}\r\n } @else if (isPrimeNgSelection(item.rowData[key])) {\r\n {{ item.rowData[key].name }}\r\n } @else if(typeof item.rowData[key] === \"number\") {\r\n <p class=\"text-right\">\r\n {{\r\n item.rowData[key]\r\n | number: (\r\n item.rowDataInput?.[key]?.numberConfig?.minFractionDigits === 0 &&\r\n item.rowDataInput?.[key]?.numberConfig?.maxFractionDigits === 0\r\n ? '1.0-0'\r\n : '1.2-2'\r\n )\r\n }}\r\n </p>\r\n }\r\n }\r\n }\r\n }\r\n }\r\n </td>\r\n }\r\n }\r\n </tr>\r\n </ng-template>\r\n }\r\n }\r\n\r\n <ng-template #footer>\r\n @if (footerEnabled) {\r\n @for (row of footerRows; track $index) {\r\n <tr class=\"p-datatable-row p-datatable-footer-row\">\r\n @for (cell of row; track $index) {\r\n <td colSpan=\"{{ cell.colSpan }}\" class=\"{{ cell.class }} text-right font-bold p-3 pb-0\">{{\r\n applyPipe(cell.value,\r\n cell.pipeConfig) }}</td>\r\n\r\n }\r\n </tr>\r\n }\r\n\r\n }\r\n </ng-template>\r\n <ng-template #expandedrow let-item>\r\n <tr>\r\n <td colspan=\"100%\">\r\n <div class=\"p-datatable-row-expansion\">\r\n <ng-container *ngTemplateOutlet=\"currentItemTemplate; context: { $implicit: item }\"></ng-container>\r\n\r\n </div>\r\n </td>\r\n </tr>\r\n </ng-template>\r\n </p-table>\r\n @if (showBottomToolbar()) {\r\n <div class=\"mt-10 p-datatable-footer sticky bottom-2 z-9 animate__animated animate__fadeIn\">\r\n <lib-toolbar-ng>\r\n @if (showManagementSelectionConfig()) {\r\n <div toolbarStart\r\n class=\"p-datatable-footer-content flex items-center gap-3 px-4 rounded-lg animate__animated animate__fadeIn\">\r\n <span class=\"font-medium text-gray-700 dark:text-gray-300\">{{ getSelectedItemsLabel() }}</span>\r\n <div class=\"p-datatable-footer-badge flex items-center justify-center min-w-[28px] h-7 px-2 rounded-md\">\r\n <span class=\"font-semibold text-gray-900 dark:text-gray-100\">{{\r\n totalItemsSelected().toLocaleString()\r\n }}</span>\r\n </div>\r\n <span class=\"text-sm text-gray-600\">{{ getRecordsLabel() }}</span>\r\n <lib-button-ng [buttonConfig]=\"showSelectedItemsManagementButton()\"></lib-button-ng>\r\n </div>\r\n }\r\n </lib-toolbar-ng>\r\n </div>\r\n }\r\n</div>\r\n@if (httpMessage()) {\r\n<lib-http-message [(httpMessage)]=\"httpMessage\"></lib-http-message>\r\n}", styles: [".cursor-pointer{cursor:pointer}.empty-data-message{text-align:center;padding:2rem;color:#6c757d;font-style:italic}.table-title-container{background:var(--p-surface-50);border-bottom:1px solid var(--p-surface-200);padding:1.25rem 2rem;position:relative}.table-title{color:var(--p-text-color);font-size:1.5rem;font-weight:600;text-align:center;margin:0;letter-spacing:-.025em;text-shadow:0 1px 2px rgba(0,0,0,.05);background:linear-gradient(135deg,var(--p-text-color) 0%,var(--p-text-muted-color) 100%);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:transparent;position:relative}.table-title:after{content:\"\";position:absolute;bottom:-.5rem;left:50%;transform:translate(-50%);width:60px;height:2px;background:linear-gradient(90deg,var(--p-primary-color),var(--p-primary-600));border-radius:1px}:host ::ng-deep .p-datatable-paginator{background:var(--p-surface-100);border-top:1px solid var(--p-surface-300);padding:1rem}:host ::ng-deep .p-datatable-paginator .p-paginator{background:transparent;border:none;padding:0}:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-pages .p-paginator-page{background:var(--p-surface-200);border:1px solid var(--p-surface-300);color:var(--p-text-color)}:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-pages .p-paginator-page:hover{background:var(--p-surface-300);border-color:var(--p-primary-color)}:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-pages .p-paginator-page.p-highlight{background:var(--p-primary-color);border-color:var(--p-primary-color);color:var(--p-primary-contrast-color)}:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-first,:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-prev,:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-next,:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-last{background:var(--p-surface-200);border:1px solid var(--p-surface-300);color:var(--p-text-color)}:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-first:hover,:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-prev:hover,:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-next:hover,:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-last:hover{background:var(--p-surface-300);border-color:var(--p-primary-color)}:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-first:disabled,:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-prev:disabled,:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-next:disabled,:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-last:disabled{background:var(--p-surface-100);border-color:var(--p-surface-300);color:var(--p-text-muted-color)}:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-current{color:var(--p-text-color);font-weight:500}:host ::ng-deep .p-datatable-paginator .p-paginator .p-dropdown{background:var(--p-surface-200);border:1px solid var(--p-surface-300);color:var(--p-text-color)}:host ::ng-deep .p-datatable-paginator .p-paginator .p-dropdown:hover{border-color:var(--p-primary-color)}:host ::ng-deep .p-datatable-paginator .p-paginator .p-dropdown:focus{border-color:var(--p-primary-color);box-shadow:0 0 0 2px var(--p-primary-color-100)}.skeleton-row{pointer-events:none;-webkit-user-select:none;user-select:none;min-height:3rem}.skeleton-cell{position:relative;overflow:hidden;min-height:3rem;padding:.75rem .5rem!important}.skeleton-cell .skeleton-content{position:absolute;inset:.5rem;min-height:1.5rem;background:linear-gradient(90deg,#d1d5db33,#d1d5db66,#d1d5db33);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px}@keyframes skeleton-loading{0%{background-position:200% 0}to{background-position:-200% 0}}:host-context(.my-app-dark) .skeleton-cell .skeleton-content{background:linear-gradient(90deg,#4b556333,#4b556366,#4b556333);background-size:200% 100%}:host ::ng-deep .p-datatable .p-datatable-tbody .skeleton-row .skeleton-cell{width:auto;min-width:fit-content}:host-context(.my-app-dark) .table-title-container{background:var(--p-surface-800);border-bottom-color:var(--p-surface-700)}:host-context(.my-app-dark) .table-title{color:var(--p-text-color);background:linear-gradient(135deg,var(--p-text-color) 0%,var(--p-text-muted-color) 100%);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:transparent}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator{background:var(--p-surface-900);border-top-color:var(--p-surface-800)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-pages .p-paginator-page{background:var(--p-surface-800);border-color:var(--p-surface-700);color:var(--p-text-color)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-pages .p-paginator-page:hover{background:var(--p-surface-700);border-color:var(--p-primary-color)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-pages .p-paginator-page.p-highlight{background:var(--p-primary-color);border-color:var(--p-primary-color);color:var(--p-primary-contrast-color)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-first,:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-prev,:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-next,:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-last{background:var(--p-surface-800);border-color:var(--p-surface-700);color:var(--p-text-color)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-first:hover,:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-prev:hover,:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-next:hover,:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-last:hover{background:var(--p-surface-700);border-color:var(--p-primary-color)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-first:disabled,:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-prev:disabled,:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-next:disabled,:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-last:disabled{background:var(--p-surface-900);border-color:var(--p-surface-800);color:var(--p-text-muted-color)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-current{color:var(--p-text-color)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-dropdown{background:var(--p-surface-800);border-color:var(--p-surface-700);color:var(--p-text-color)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-dropdown:hover{border-color:var(--p-primary-color)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-dropdown:focus{border-color:var(--p-primary-color);box-shadow:0 0 0 2px var(--p-primary-color-100)}.flex{display:flex}.flex-col{flex-direction:column}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.justify-center{justify-content:center}.items-center{align-items:center}.text-center{text-align:center}.text-right{text-align:right}.text-left{text-align:left}.text-gray-400{color:#9ca3af}.text-gray-500{color:#6b7280}.text-gray-600{color:#4b5563}.text-gray-700{color:#374151}.text-gray-900{color:#111827}.text-blue-500{color:#3b82f6}.text-red-500{color:#ef4444}.text-green-500{color:#22c55e}.text-xs{font-size:.75rem;line-height:1rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.font-bold{font-weight:700}.italic{font-style:italic}.w-full{width:100%}.w-10{width:2.5rem}.h-10{height:2.5rem}.h-7{height:1.75rem}.min-w-28{min-width:28px}.mx-auto{margin-left:auto;margin-right:auto}.p-1{padding:.25rem}.p-3{padding:.75rem}.p-8{padding:2rem}.px-0{padding-left:0;padding-right:0}.py-0{padding-top:0;padding-bottom:0}.px-2{padding-left:.5rem;padding-right:.5rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.px-4{padding-left:1rem;padding-right:1rem}.pb-0{padding-bottom:0}.bg-gray-50{background-color:#f9fafb}.bg-gray-100{background-color:#f3f4f6}.bg-gray-200{background-color:#e5e7eb}.bg-gray-600{background-color:#4b5563}.bg-gray-700{background-color:#374151}.bg-gray-800{background-color:#1f2937}.bg-blue-100{background-color:#dbeafe}.bg-blue-200{background-color:#bfdbfe}.bg-blue-800{background-color:#1e40af}.bg-blue-900{background-color:#1e3a8a}.bg-green-200{background-color:#bbf7d0}.border-b{border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:var(--p-surface-300)}.border-l-4{border-left-width:4px;border-left-style:solid}.border-blue-500{border-color:#3b82f6}.rounded-full{border-radius:9999px}.rounded-md{border-radius:.375rem}.rounded-lg{border-radius:.5rem}.shadow-sm{box-shadow:0 1px 2px #0000000d}.shadow-lg{box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -2px #0000000d}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-300{transition-duration:.3s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.sticky{position:sticky}.top-0{top:0}.bottom-2{bottom:.5rem}.bottom-18{bottom:4.5rem}.z-9{z-index:9}.z-10{z-index:10}.z-30{z-index:30}.hover\\:bg-gray-50:hover{background-color:#f9fafb}.hover\\:bg-gray-100:hover{background-color:#f3f4f6}.hover\\:bg-gray-200:hover{background-color:#e5e7eb}.hover\\:bg-blue-200:hover{background-color:#bfdbfe}.hover\\:bg-blue-800:hover{background-color:#1e40af}:host-context(.my-app-dark) .dark\\:bg-gray-800{background-color:#1f2937}:host-context(.my-app-dark) .dark\\:bg-gray-700{background-color:#374151}:host-context(.my-app-dark) .dark\\:bg-gray-600{background-color:#4b5563}:host-context(.my-app-dark) .dark\\:bg-blue-900{background-color:#1e3a8a}:host-context(.my-app-dark) .dark\\:bg-blue-800{background-color:#1e40af}:host-context(.my-app-dark) .dark\\:hover\\:bg-gray-800:hover{background-color:#1f2937}:host-context(.my-app-dark) .dark\\:hover\\:bg-gray-700:hover{background-color:#374151}:host-context(.my-app-dark) .dark\\:hover\\:bg-gray-600:hover{background-color:#4b5563}:host-context(.my-app-dark) .dark\\:hover\\:bg-blue-800:hover{background-color:#1e40af}.animate__animated{animation-duration:1s;animation-fill-mode:both}.animate__fadeIn{animation-name:fadeIn}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1$1.DecimalPipe, name: "number" }, { kind: "pipe", type: i1$1.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i1$1.DatePipe, name: "date" }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i2$2.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "style", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "scrollDirection", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "responsive", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "autoLayout", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "virtualRowHeight", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i4$1.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i2$2.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "directive", type: i2$2.FrozenColumn, selector: "[pFrozenColumn]", inputs: ["frozen", "alignFrozen"] }, { kind: "directive", type: i2$2.RowToggler, selector: "[pRowToggler]", inputs: ["pRowToggler", "pRowTogglerDisabled"] }, { kind: "directive", type: i2$2.ResizableColumn, selector: "[pResizableColumn]", inputs: ["pResizableColumnDisabled"] }, { kind: "directive", type: i2$2.EditableColumn, selector: "[pEditableColumn]", inputs: ["pEditableColumn", "pEditableColumnField", "pEditableColumnRowIndex", "pEditableColumnDisabled", "pFocusCellSelector"] }, { kind: "component", type: i2$2.CellEditor, selector: "p-cellEditor" }, { kind: "component", type: i2$2.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "component", type: i2$2.TableCheckbox, selector: "p-tableCheckbox", inputs: ["value", "disabled", "required", "index", "inputId", "name", "ariaLabel"] }, { kind: "component", type: i2$2.TableHeaderCheckbox, selector: "p-tableHeaderCheckbox", inputs: ["disabled", "inputId", "name", "ariaLabel"] }, { kind: "directive", type: i2$2.EditableRow, selector: "[pEditableRow]", inputs: ["pEditableRow", "pEditableRowDisabled"] }, { kind: "directive", type: i2$2.InitEditableRow, selector: "[pInitEditableRow]" }, { kind: "directive", type: i2$2.SaveEditableRow, selector: "[pSaveEditableRow]" }, { kind: "directive", type: i2$2.CancelEditableRow, selector: "[pCancelEditableRow]" }, { kind: "component", type: i2$2.ColumnFilter, selector: "p-columnFilter", inputs: ["field", "type", "display", "showMenu", "matchMode", "operator", "showOperator", "showClearButton", "showApplyButton", "showMatchModes", "showAddButton", "hideOnClear", "placeholder", "matchModeOptions", "maxConstraints", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "locale", "localeMatcher", "currency", "currencyDisplay", "useGrouping", "showButtons", "ariaLabel", "filterButtonProps"], outputs: ["onShow", "onHide"] }, { kind: "component", type: ButtonNgComponent, selector: "lib-button-ng", inputs: ["buttonConfig"], outputs: ["buttonConfigChange", "onClick"] }, { kind: "component", type: ToolbarNgComponent, selector: "lib-toolbar-ng" }, { kind: "component", type: FormComponent, selector: "lib-form", inputs: ["formGroup", "controls", "formConfig", "httpMessage"], outputs: ["formGroupChange", "httpMessageChange", "formSubmit", "formChanges", "formChangesDebounced"] }, { kind: "pipe", type: KeyToDisplayNamePipe, name: "keyToDisplayName" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: InlineInputComponent, selector: "lib-inline-input", inputs: ["config", "value"], outputs: ["valueChange", "outputValue", "outputBlur", "outputDebounced"] }, { kind: "component", type: BadgeNgComponent, selector: "lib-badge-ng", inputs: ["config"], outputs: ["configChange"] }, { kind: "component", type: HttpMessageComponent, selector: "lib-http-message", inputs: ["httpMessage"], outputs: ["httpMessageChange"] }, { kind: "component", type: SpeedDialComponent, selector: "lib-speed-dial", inputs: ["speedDialConfig"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3652
+ }
3653
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TableNgComponent, decorators: [{
3654
+ type: Component,
3655
+ args: [{ selector: 'lib-table-ng', imports: [
3656
+ CommonModule,
3657
+ TableModule,
3658
+ ButtonNgComponent,
3659
+ ToolbarNgComponent,
3660
+ FormComponent,
3661
+ KeyToDisplayNamePipe,
3662
+ FormsModule,
3663
+ InlineInputComponent,
3664
+ BadgeNgComponent,
3665
+ HttpMessageComponent,
3666
+ SpeedDialComponent
3667
+ ], providers: [TableNgService, TableNgEditService], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let paginationConfig = config()?.paginationConfig;\r\n@let globalFilterConfig = config()?.globalFilterConfig;\r\n@let selectionTableConfig = config()?.selectionTableConfig;\r\n@let filterConfigByKey = config()?.filterConfigByKey;\r\n@let frozenColumnConfigByKey = config()?.frozenColumnConfigByKey;\r\n@let scrollConfig = config()?.scrollConfig;\r\n@let lazyLoadingConfig = config()?.lazyLoadingConfig;\r\n@let keysNames = config()?.keysNames;\r\n@let columnConfig = config()?.columnConfig;\r\n@let editEnabled = editConfig()?.isEnabled ?? false;\r\n@let editType = editConfig()?.type ?? 'cell';\r\n@let inlineControls = editConfig()?.inlineControls;\r\n@let rowErrorConfig = editConfig()?.rowEditConfig?.rowErrorConfig;\r\n@let footerRows = footerConfig()?.footerRows;\r\n@let footerEnabled = footerConfig()?.isEnabled ?? false;\r\n@let titleConfig = config()?.titleConfig;\r\n@let selectedColumns = config()?.selectedColumns;\r\n@let rowExpansionConfig = config()?.rowExpansionConfig;\r\n@let advancedIdentifierFiltersConfig = config()?.globalFilterConfig?.advancedIdentifierFiltersConfig;\r\n@let inputConfig = config()?.inputConfig;\r\n@let hasCheckRows = config()?.hasCheckRows ?? false;\r\n<div class=\"p-datatable-wrapper\">\r\n @if (titleConfig?.isEnabled && titleConfig?.title) {\r\n <div class=\"table-title-container\">\r\n <h2 class=\"table-title\">{{ titleConfig!.title }}</h2>\r\n </div>\r\n }\r\n @if (!hideToolbar || (filteredValue || advancedFiltersPerformed.length > 0)) {\r\n <lib-toolbar-ng class=\"p-toolbar-header sticky top-0 z-30 dark:bg-gray-800\">\r\n <div class=\"flex gap-2\" toolbarStart>\r\n @if (globalFilterConfig?.isEnabled && !lazyLoadingConfig?.isEnabled) {\r\n <lib-form [controls]=\"controlsGlobalFilter\" [(formGroup)]=\"searchFormGroupGlobalFilter\"\r\n (formSubmit)=\"submitGlobalSearch($event)\"></lib-form>\r\n }\r\n @if (advancedIdentifierFiltersConfig?.isEnabled) {\r\n <lib-button-ng class=\"animate__animated animate__fadeIn\"\r\n [buttonConfig]=\"advancedIdentifierFiltersButton()\"></lib-button-ng>\r\n }\r\n @if (filteredValue || advancedFiltersPerformed.length > 0) {\r\n <lib-button-ng class=\"animate__animated animate__fadeIn\" [buttonConfig]=\"clearFiltersButton()\"></lib-button-ng>\r\n }\r\n @if (hasCheckRows) {\r\n <div class=\"inline-flex\" (click)=\"$event.stopPropagation()\">\r\n <lib-inline-input\r\n [ngModel]=\"checkAllHeaderReflectValue()\"\r\n (ngModelChange)=\"checkAll($event)\"\r\n [config]=\"inlineConfigCheckHeaderCheckAll\">\r\n </lib-inline-input>\r\n </div>\r\n }\r\n </div>\r\n <div class=\"flex gap-2\" toolbarEnd>\r\n @if (toolbarSpeedDialButtons().length > 0) {\r\n @for (speedDial of toolbarSpeedDialButtons(); track $index) {\r\n <lib-speed-dial [speedDialConfig]=\"speedDial\"></lib-speed-dial>\r\n }\r\n }\r\n @if (toolbarButtons().length > 0) {\r\n @for (button of toolbarButtons(); track $index) {\r\n <lib-button-ng [buttonConfig]=\"button\"></lib-button-ng>\r\n }\r\n }\r\n @if ((editType === 'row' || editType === 'cell') && editEnabled) {\r\n <lib-button-ng [buttonConfig]=\"addRowButton()\"></lib-button-ng>\r\n }\r\n @if (enableExcelButton()) {\r\n <lib-button-ng [buttonConfig]=\"excelButton\" (onClick)=\"exportData(dt,'excel')\"></lib-button-ng>\r\n }\r\n @if (enablePdfButton()) {\r\n <lib-button-ng [buttonConfig]=\"pdfButton\" (onClick)=\"exportData(dt,'pdf')\"></lib-button-ng>\r\n }\r\n @if (enableRefreshButton) {\r\n <lib-button-ng [buttonConfig]=\"refreshButton\"></lib-button-ng>\r\n }\r\n </div>\r\n </lib-toolbar-ng>\r\n }\r\n <p-table #dt styleClass=\"p-datatable-sm\" tableStyleClass=\"table table-xs\" [value]=\"data()\" [lazy]=\"lazyLoadingConfig?.isEnabled ?? false\"\r\n [editMode]=\"editType\" [totalRecords]=\"\r\n lazyLoadingConfig?.isEnabled\r\n ? lazyLoadingConfig!.totalRecords\r\n : data().length\r\n \" [customSort]=\"true\" [paginator]=\"paginationConfig?.paginator ?? true\" [showCurrentPageReport]=\"true\"\r\n [rows]=\"paginationConfig?.rows ?? 5\" [rowsPerPageOptions]=\"paginationConfig?.rowsPerPageOptions ?? [5, 10, 20]\"\r\n [paginatorStyleClass]=\"paginatorStyleClass()\" [resizableColumns]=\"true\" [rowTrackBy]=\"trackById\"\r\n [columns]=\"selectedColumns\" [scrollable]=\"scrollConfig?.isEnabled ?? false\"\r\n [scrollHeight]=\"scrollConfig?.isEnabled ? scrollHeight() : undefined\" (onLazyLoad)=\"onLazyLoad($event)\"\r\n (sortFunction)=\"customSort($event)\" (onFilter)=\"onFilter($event)\" [(selection)]=\"selectedItems\"\r\n [currentPageReportTemplate]=\"getCustomPageReport()\" selectionPageOnly=\"true\" dataKey=\"id\" class=\"w-full\">\r\n <ng-template #header let-columns>\r\n <tr>\r\n @if (rowExpansionConfig?.isEnabled) {\r\n <th alignFrozen=\"left\" pFrozenColumn style=\"width: 2rem\" class=\"p-datatable-header-cell p-frozen-column\">\r\n\r\n </th>\r\n }\r\n @if (selectionTableConfig?.isEnabled) {\r\n <th alignFrozen=\"left\" pFrozenColumn style=\"width: 2rem\" class=\"p-datatable-header-cell p-frozen-column\">\r\n <p-tableHeaderCheckbox />\r\n </th>\r\n }\r\n\r\n @if (selectedColumns) {\r\n @for (column of columns; track $index) {\r\n <th pResizableColumn [id]=\"column.field\" alignFrozen=\"right\" pFrozenColumn\r\n [frozen]=\"frozenHandle(frozenColumnConfigByKey?.[column.field])\" [pSortableColumn]=\"column.field\"\r\n class=\"p-datatable-header-cell\" [style.width.%]=\"columnConfig?.sizeByKey?.[column.field] ?? null\" [ngClass]=\"{\r\n 'p-frozen-column': frozenHandle(\r\n frozenColumnConfigByKey?.[column.field]\r\n ),\r\n }\">\r\n <div class=\"flex gap-2 justify-center items-center py-0 px-0\">\r\n {{ column.field | keyToDisplayName: keysNames }}\r\n @if (inputConfig?.[column.field]?.isEnabled) {\r\n @let columnInputConfig = inputConfig![column.field]!;\r\n @if (columnInputConfig.type === ETypeInput.SWITCH || columnInputConfig.type === ETypeInput.CHECKBOX) {\r\n <div class=\"inline-flex\" (click)=\"$event.stopPropagation()\">\r\n <lib-inline-input\r\n [ngModel]=\"booleanColumnHeaderReflectValue(column.field)\"\r\n (ngModelChange)=\"applyBulkBooleanToColumn($event, column.field)\"\r\n [config]=\"inlineConfigCheckHeader(column.field, columnInputConfig.type)\">\r\n </lib-inline-input>\r\n </div>\r\n }\r\n }\r\n @if(!editEnabled){\r\n <p-sortIcon [field]=\"column.field\" />\r\n }\r\n @if (filterConfigByKey?.[column.field]?.isEnabled) {\r\n @let columnFilterConfig = filterConfigByKey![column.field]!;\r\n <p-columnFilter [field]=\"`rowData.${column.field}`\" display=\"menu\" [ngClass]=\"{\r\n 'bg-green-200 rounded-full p-1 shadow-sm text-green-500 transition-all duration-300 ease-in-out':\r\n advancedFiltersPerformed.includes(column.field),\r\n }\" [type]=\"columnFilterConfig.primeNgColumnFilterConfig?.type ?? 'text'\"\r\n [matchMode]=\"columnFilterConfig.primeNgColumnFilterConfig?.matchMode\"\r\n [showMatchModes]=\"columnFilterConfig.primeNgColumnFilterConfig?.showMatchModes ?? false\"\r\n [showOperator]=\"columnFilterConfig.primeNgColumnFilterConfig?.showOperator ?? false\"\r\n [showAddButton]=\"columnFilterConfig.primeNgColumnFilterConfig?.showAddButton ?? false\"\r\n [showApplyButton]=\"columnFilterConfig.primeNgColumnFilterConfig?.showApplyButton ?? false\"\r\n [showClearButton]=\"columnFilterConfig.primeNgColumnFilterConfig?.showClearButton ?? false\">\r\n @if (isCustomColumnFilterEnabled(columnFilterConfig)) {\r\n <ng-template pTemplate=\"filter\" let-value let-filter=\"filterCallback\">\r\n <div style=\"min-width: 20rem\">\r\n <lib-inline-input\r\n [ngModel]=\"value\"\r\n (outputValue)=\"inlineFormChanges($event, filter, columnFilterConfig.customColumnFilterConfig?.inlineControlConfig?.typeInput, column.field)\"\r\n [config]=\"columnFilterConfig.customColumnFilterConfig?.inlineControlConfig ?? {typeInput: ETypeInput.TEXT}\">\r\n </lib-inline-input>\r\n </div>\r\n </ng-template>\r\n }\r\n </p-columnFilter>\r\n }\r\n </div>\r\n </th>\r\n }\r\n }@else {\r\n @for (key of keys(); track $index) {\r\n <th [id]=\"key\" pResizableColumn alignFrozen=\"right\" pFrozenColumn\r\n [frozen]=\"frozenHandle(frozenColumnConfigByKey?.[key])\" [pSortableColumn]=\"key\"\r\n class=\"p-datatable-header-cell\" [style.width.%]=\"columnConfig?.sizeByKey?.[key] ?? null\" [ngClass]=\"{\r\n 'p-frozen-column': frozenHandle(frozenColumnConfigByKey?.[key]),\r\n }\">\r\n \r\n <div class=\"flex gap-2 justify-center items-center py-0 px-0\">\r\n {{ key | keyToDisplayName: keysNames }}\r\n @if (inputConfig?.[key]?.isEnabled) {\r\n @let keyInputConfig = inputConfig![key]!;\r\n @if (keyInputConfig.type === ETypeInput.SWITCH || keyInputConfig.type === ETypeInput.CHECKBOX) {\r\n <div class=\"inline-flex\" (click)=\"$event.stopPropagation()\">\r\n <lib-inline-input\r\n [ngModel]=\"booleanColumnHeaderReflectValue(key)\"\r\n (ngModelChange)=\"applyBulkBooleanToColumn($event, key)\"\r\n [config]=\"inlineConfigCheckHeader(key, keyInputConfig.type)\">\r\n </lib-inline-input>\r\n </div>\r\n }\r\n }\r\n @if(!editEnabled){\r\n <p-sortIcon [field]=\"key\" />\r\n }\r\n @if (filterConfigByKey?.[key]?.isEnabled) {\r\n @let columnFilterConfig = filterConfigByKey![key]!;\r\n <p-columnFilter [field]=\"`rowData.${key}`\" display=\"menu\" [ngClass]=\"{\r\n 'bg-green-200 rounded-full p-1 shadow-sm text-green-500 transition-all duration-300 ease-in-out':\r\n advancedFiltersPerformed.includes(key),\r\n }\" [type]=\"columnFilterConfig.primeNgColumnFilterConfig?.type ?? 'text'\"\r\n [matchMode]=\"columnFilterConfig.primeNgColumnFilterConfig?.matchMode\"\r\n [showMatchModes]=\"columnFilterConfig.primeNgColumnFilterConfig?.showMatchModes ?? false\"\r\n [showOperator]=\"columnFilterConfig.primeNgColumnFilterConfig?.showOperator ?? false\"\r\n [showAddButton]=\"columnFilterConfig.primeNgColumnFilterConfig?.showAddButton ?? false\"\r\n [showApplyButton]=\"columnFilterConfig.primeNgColumnFilterConfig?.showApplyButton ?? false\"\r\n [showClearButton]=\"columnFilterConfig.primeNgColumnFilterConfig?.showClearButton ?? false\">\r\n @if (isCustomColumnFilterEnabled(columnFilterConfig)) {\r\n <ng-template pTemplate=\"filter\" let-value let-filter=\"filterCallback\">\r\n <div style=\"min-width: 20rem\">\r\n <lib-inline-input\r\n [ngModel]=\"value\"\r\n (outputValue)=\"inlineFormChanges($event, filter, columnFilterConfig.customColumnFilterConfig?.inlineControlConfig?.typeInput, key)\"\r\n [config]=\"columnFilterConfig.customColumnFilterConfig?.inlineControlConfig ?? {typeInput: ETypeInput.TEXT}\">\r\n </lib-inline-input>\r\n </div>\r\n </ng-template>\r\n }\r\n </p-columnFilter>\r\n }\r\n </div>\r\n </th>\r\n }\r\n }\r\n\r\n @if (editType === 'cell' && editEnabled) {\r\n <th class=\"p-datatable-header-cell\" style=\"width: 100px\">\r\n </th>\r\n }\r\n @if (editType === 'row' && editEnabled) {\r\n <th class=\"p-datatable-header-cell\" style=\"width: 100px\">\r\n </th>\r\n }\r\n\r\n </tr>\r\n </ng-template>\r\n\r\n <ng-template #emptymessage>\r\n <tr>\r\n <td [attr.colspan]=\"totalColumns()\">\r\n @if (isLoading()) {\r\n <!-- Loading state -->\r\n <div class=\"p-8 text-center\">\r\n <div class=\"flex flex-col items-center justify-center gap-4\">\r\n <i class=\"pi pi-spin pi-spinner text-4xl text-blue-500\"></i>\r\n <p class=\"text-gray-600 text-lg\">{{ getLoadingMessage() }}</p>\r\n </div>\r\n </div>\r\n } @else if (timeoutExpired()) {\r\n <!-- No data available -->\r\n <div class=\"p-8 text-center text-gray-500\">\r\n <div class=\"flex flex-col items-center justify-center gap-3\">\r\n <i class=\"pi pi-info-circle text-4xl text-gray-400\"></i>\r\n <p class=\"text-lg\">{{ getNoDataMessage() }}</p>\r\n </div>\r\n </div>\r\n }\r\n </td>\r\n </tr>\r\n </ng-template>\r\n\r\n @if (hasRecords()) {\r\n @if (editEnabled) {\r\n @switch (editType) {\r\n @case ('cell') {\r\n <ng-template #body let-item let-editing=\"editing\">\r\n <tr class=\"p-datatable-row p-selectable-row\">\r\n @if (selectedColumns) {\r\n @for (column of selectedColumns; track $index){\r\n <td [pEditableColumn]=\"column.field\" pEditableColumnField=\"rowData.{{column.field}}\">\r\n <p-cellEditor>\r\n <ng-template #input>\r\n <lib-inline-input [(ngModel)]=\"item.rowData[column.field]\" (outputDebounced)=\"onEditData()\"\r\n [config]=\"inlineControls?.[column.field] ?? {typeInput: ETypeInput.TEXT}\">\r\n </lib-inline-input>\r\n </ng-template>\r\n <ng-template #output>\r\n @if (inlineControls?.[column.field]?.typeInput === ETypeInput.NUMBER) {\r\n <div class=\"text-right\">\r\n {{\r\n item.rowData[column.field]\r\n | number: (\r\n inlineControls?.[column.field]?.numberConfig?.minFractionDigits === 0 &&\r\n inlineControls?.[column.field]?.numberConfig?.maxFractionDigits === 0\r\n ? '1.0-0'\r\n : '1.2-2'\r\n )\r\n }}\r\n\r\n </div>\r\n } @else if(inlineControls?.[column.field]?.typeInput === ETypeInput.CURRENCY) {\r\n <div class=\"text-right\">\r\n {{ item.rowData[column.field] | currency: item?.currencyTypeCellConfig?.[column.field]?.currency ??\r\n 'USD' }}\r\n </div>\r\n } @else if(inlineControls?.[column.field]?.typeInput === ETypeInput.DATE) {\r\n <div class=\"text-left\">\r\n {{ item.rowData[column.field] | date: \"dd/MM/yyyy\" }}\r\n </div>\r\n } @else if(inlineControls?.[column.field]?.typeInput === ETypeInput.DATETIME_LOCAL) {\r\n <div class=\"text-left\">\r\n {{ item.rowData[column.field] | date: \"dd/MM/yyyy HH:mm\" }}\r\n </div>\r\n }@else if(inlineControls?.[column.field]?.typeInput === ETypeInput.SELECT) {\r\n <div class=\"text-left\">\r\n {{ item.rowData[column.field]?.name ?? item.rowData[column.field]?.value ?? '' }}\r\n </div>\r\n }\r\n @else if(inlineControls?.[column.field]?.typeInput === ETypeInput.SWITCH) {\r\n <div class=\"text-center\">\r\n @if (item.rowData[column.field]) {\r\n <i class=\"fa-solid fa-check text-green-500\"></i>\r\n } @else {\r\n <i class=\"fa-solid fa-times text-red-500\"></i>\r\n }\r\n </div>\r\n } @else {\r\n @if (item.rowData[column.field]?.name) {\r\n {{ item.rowData[column.field]?.name }}\r\n } @else {\r\n {{ item.rowData[column.field] }}\r\n }\r\n }\r\n\r\n </ng-template>\r\n </p-cellEditor>\r\n\r\n @if (rowErrorConfig; as errorConfig) {\r\n @if (errorConfig.isEnabled && enableErrors && errorConfig.fieldErrors[item.id]?.[column.field]; as columnFieldError) {\r\n <span class=\"text-red-500 italic text-xs\">\r\n {{ columnFieldError.message }}\r\n </span>\r\n }\r\n }\r\n </td>\r\n }\r\n } @else {\r\n @for (key of keys(); track $index){\r\n <td [pEditableColumn]=\"key\" pEditableColumnField=\"rowData.{{key}}\">\r\n <p-cellEditor>\r\n <ng-template #input>\r\n <lib-inline-input [(ngModel)]=\"item.rowData[key]\" (outputDebounced)=\"onEditData()\"\r\n [config]=\"inlineControls?.[key] ?? {typeInput: ETypeInput.TEXT}\">\r\n </lib-inline-input>\r\n </ng-template>\r\n <ng-template #output>\r\n @if (inlineControls?.[key]?.typeInput === ETypeInput.NUMBER) {\r\n <div class=\"text-right\">\r\n {{\r\n item.rowData[key]\r\n | number: (\r\n inlineControls?.[key]?.numberConfig?.minFractionDigits === 0 &&\r\n inlineControls?.[key]?.numberConfig?.maxFractionDigits === 0\r\n ? '1.0-0'\r\n : '1.2-2'\r\n )\r\n }}\r\n </div>\r\n } @else if(inlineControls?.[key]?.typeInput === ETypeInput.CURRENCY) {\r\n <div class=\"text-right\">\r\n {{ item.rowData[key] | currency: item?.currencyTypeCellConfig?.[key]?.currency ?? 'USD' }}\r\n </div>\r\n } @else if(inlineControls?.[key]?.typeInput === ETypeInput.DATE) {\r\n <div class=\"text-left\">\r\n {{ item.rowData[key] | date: \"dd/MM/yyyy\" }}\r\n </div>\r\n } @else if(inlineControls?.[key]?.typeInput === ETypeInput.DATETIME_LOCAL) {\r\n <div class=\"text-left\">\r\n {{ item.rowData[key] | date: \"dd/MM/yyyy HH:mm\" }}\r\n </div>\r\n } @else if(inlineControls?.[key]?.typeInput === ETypeInput.SELECT) {\r\n <div class=\"text-left\">\r\n {{ item.rowData[key]?.name ?? item.rowData[key]?.value ?? '' }}\r\n </div>\r\n } @else if (inlineControls?.[key]?.typeInput === ETypeInput.SWITCH) {\r\n <div class=\"text-center\">\r\n @if (item.rowData[key]) {\r\n <i class=\"fa-solid fa-check text-green-500\"></i>\r\n } @else {\r\n <i class=\"fa-solid fa-times text-red-500\"></i>\r\n }\r\n </div>\r\n } @else {\r\n @if (item.rowData[key]?.name) {\r\n {{ item.rowData[key]?.name }}\r\n } @else {\r\n {{ item.rowData[key] }}\r\n }\r\n }\r\n </ng-template>\r\n </p-cellEditor>\r\n\r\n @if (rowErrorConfig; as errorConfig) {\r\n @if (errorConfig.isEnabled && enableErrors && errorConfig.fieldErrors[item.id]?.[key]; as keyFieldError) {\r\n <span class=\"text-red-500 italic text-xs\">\r\n {{ keyFieldError.message }}\r\n </span>\r\n }\r\n }\r\n </td>\r\n }\r\n }\r\n @if (editType === 'cell' && editEnabled) {\r\n <td class=\"px-2 py-1 text-center\">\r\n <div class=\"flex justify-center items-center gap-2\">\r\n <lib-button-ng [buttonConfig]=\"getDeleteRowButton()\" (onClick)=\"deleteRow(item)\"></lib-button-ng>\r\n </div>\r\n </td>\r\n }\r\n </tr>\r\n </ng-template>\r\n }\r\n @case ('row') {\r\n <ng-template #body let-item let-editing=\"editing\" let-ri=\"rowIndex\">\r\n <tr [pEditableRow]=\"item\" class=\"cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 border-b\">\r\n @if (selectedColumns) {\r\n @for (column of selectedColumns; track $index){\r\n <td>\r\n <div class=\"flex flex-col gap-2\">\r\n <p-cellEditor>\r\n <ng-template #input>\r\n <lib-inline-input [(ngModel)]=\"item.rowData[column.field]\"\r\n (outputValue)=\"inlineChange($event, column.field)\" (outputDebounced)=\"onEditData()\"\r\n [config]=\"inlineControls?.[column.field] ?? {typeInput: ETypeInput.TEXT}\">\r\n </lib-inline-input>\r\n\r\n </ng-template>\r\n <ng-template #output>\r\n\r\n @if (inlineControls?.[column.field]?.typeInput === ETypeInput.NUMBER) {\r\n <div class=\"text-right\">\r\n {{ item.rowData[column.field] | number: '1.2-2' }}\r\n\r\n </div>\r\n } @else if(inlineControls?.[column.field]?.typeInput === ETypeInput.CURRENCY) {\r\n <div class=\"text-right\">\r\n {{ item.rowData[column.field] | currency: item?.currencyTypeCellConfig?.[column.field]?.currency ??\r\n 'USD' }}\r\n </div>\r\n } @else if(inlineControls?.[column.field]?.typeInput === ETypeInput.DATE) {\r\n <div class=\"text-left\">\r\n {{ item.rowData[column.field] | date: \"dd/MM/yyyy\" }}\r\n </div>\r\n } @else if(inlineControls?.[column.field]?.typeInput === ETypeInput.DATETIME_LOCAL) {\r\n <div class=\"text-left\">\r\n {{ item.rowData[column.field] | date: \"dd/MM/yyyy HH:mm\" }}\r\n </div>\r\n } @else if(inlineControls?.[column.field]?.typeInput === ETypeInput.SWITCH) {\r\n <div class=\"text-center\">\r\n @if (item.rowData[column.field]) {\r\n <i class=\"fa-solid fa-check text-green-500\"></i>\r\n } @else {\r\n <i class=\"fa-solid fa-times text-red-500\"></i>\r\n }\r\n </div>\r\n } @else {\r\n @if (item.rowData[column.field]?.name) {\r\n {{ item.rowData[column.field]?.name }}\r\n } @else {\r\n {{ item.rowData[column.field] }}\r\n }\r\n }\r\n\r\n\r\n </ng-template>\r\n </p-cellEditor>\r\n\r\n @if (rowErrorConfig; as errorConfig) {\r\n @if (errorConfig.isEnabled && enableErrors && !rowFieldsHasValue()[column.field] && errorConfig.fieldErrors[item.id]?.[column.field]; as columnFieldError) {\r\n <span class=\"text-red-500 italic text-xs\">{{ columnFieldError.message }}</span>\r\n }\r\n }\r\n </div>\r\n </td>\r\n }\r\n } @else {\r\n @for (key of keys(); track $index){\r\n <td>\r\n <div class=\"flex flex-col gap-2\">\r\n <p-cellEditor>\r\n <ng-template #input>\r\n <lib-inline-input [(ngModel)]=\"item.rowData[key]\" (outputValue)=\"inlineChange($event, key)\"\r\n (outputDebounced)=\"onEditData()\" [config]=\"inlineControls?.[key] ?? {typeInput: ETypeInput.TEXT}\">\r\n </lib-inline-input>\r\n </ng-template>\r\n <ng-template #output>\r\n\r\n @if (inlineControls?.[key]?.typeInput === ETypeInput.NUMBER) {\r\n <div class=\"text-right\">\r\n {{ item.rowData[key] | number: '1.2-2' }}\r\n\r\n </div>\r\n }\r\n @else if(inlineControls?.[key]?.typeInput === ETypeInput.CURRENCY) {\r\n <div class=\"text-right\">\r\n {{ item.rowData[key] | currency: item?.currencyTypeCellConfig?.[key]?.currency ?? 'USD' }}\r\n </div>\r\n } @else if(inlineControls?.[key]?.typeInput === ETypeInput.SWITCH) {\r\n <div class=\"text-center\">\r\n @if (item.rowData[key]) {\r\n <i class=\"fa-solid fa-check text-green-500\"></i>\r\n } @else {\r\n <i class=\"fa-solid fa-times text-red-500\"></i>\r\n }\r\n </div>\r\n } @else {\r\n @if (item.rowData[key]?.name) {\r\n {{ item.rowData[key]?.name }}\r\n } @else {\r\n {{ item.rowData[key] }}\r\n }\r\n }\r\n\r\n\r\n </ng-template>\r\n </p-cellEditor>\r\n\r\n @if (rowErrorConfig; as errorConfig) {\r\n @if (errorConfig.isEnabled && enableErrors && !rowFieldsHasValue()[key] && errorConfig.fieldErrors[item.id]?.[key]; as keyFieldError) {\r\n <span class=\"text-red-500 italic text-xs\">{{ keyFieldError.message }}</span>\r\n }\r\n }\r\n </div>\r\n </td>\r\n }\r\n }\r\n <td>\r\n <div class=\"flex justify-center items-center gap-2\">\r\n @if(!editing){\r\n <lib-button-ng pButton pRipple pInitEditableRow [buttonConfig]=\"getEditInitButton(item.id)\"\r\n (onClick)=\"onRowEditInit(item)\"></lib-button-ng>\r\n @if(!editConfig()?.rowEditConfig?.isDisabledDeleteButton){\r\n <lib-button-ng [buttonConfig]=\"getDeleteRowButton()\" (onClick)=\"deleteRow(item)\"></lib-button-ng>\r\n }\r\n }\r\n @if(editing){\r\n @if (hasErrorValues(rowErrorConfig?.fieldErrors?.[item.id] ?? {})) {\r\n <lib-button-ng [buttonConfig]=\"editSaveButtonWithErrors()\"\r\n (onClick)=\"onEditSaveWithErrors()\"></lib-button-ng>\r\n }\r\n @else {\r\n <lib-button-ng pButton pRipple pSaveEditableRow [buttonConfig]=\"editSaveButton()\"\r\n (onClick)=\"onRowEditSave(item)\"></lib-button-ng>\r\n }\r\n <lib-button-ng pButton pRipple pCancelEditableRow [buttonConfig]=\"editCancelButton()\"\r\n (onClick)=\"onRowEditCancel(item, ri)\"></lib-button-ng>\r\n }\r\n </div>\r\n </td>\r\n </tr>\r\n </ng-template>\r\n }\r\n }\r\n } @else {\r\n\r\n <ng-template #body let-item let-expanded=\"expanded\">\r\n <tr class=\"p-datatable-row p-selectable-row\" [ngClass]=\"{\r\n 'bg-gray-50 dark:bg-gray-800 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-700': item.onClick && !item.isSelected && !item.isLoading,\r\n 'bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600': !item.onClick && !item.isSelected && !item.isLoading,\r\n 'bg-blue-100 dark:bg-blue-900 border-l-4 border-blue-500 hover:bg-blue-200 dark:hover:bg-blue-800': item.isSelected && !item.isLoading,\r\n 'skeleton-row': item.isLoading\r\n }\" (click)=\"item?.isLoading ? null : onRowClick(item)\">\r\n\r\n @if (rowExpansionConfig?.isEnabled) {\r\n <td (click)=\"$event.stopPropagation()\" [class.skeleton-cell]=\"item.isLoading\"\r\n [style.height]=\"item.isLoading ? '3rem' : 'auto'\">\r\n @if (!item.isLoading) {\r\n <lib-button-ng [buttonConfig]=\"rowExpansionButton(expanded)()\" type=\"button\" pRipple\r\n [pRowToggler]=\"item\"></lib-button-ng>\r\n } @else {\r\n <div class=\"skeleton-content\"></div>\r\n }\r\n </td>\r\n }\r\n\r\n @if (selectionTableConfig?.isEnabled) {\r\n <td (click)=\"$event.stopPropagation()\" alignFrozen=\"left\" pFrozenColumn class=\"shadow-lg\"\r\n [class.skeleton-cell]=\"item.isLoading\" [style.height]=\"item.isLoading ? '3rem' : 'auto'\">\r\n @if (!item.isLoading) {\r\n <p-tableCheckbox [id]=\"item\" [value]=\"item\" />\r\n } @else {\r\n <div class=\"skeleton-content\"></div>\r\n }\r\n </td>\r\n }\r\n\r\n @for (key of keys(); track $index) {\r\n @if (isThatItemInTheProductSelection(key)) {\r\n <td [id]=\"key\" class=\"p-datatable-cell\" [style.height]=\"item.isLoading ? '3rem' : 'min-content'\"\r\n alignFrozen=\"right\" pFrozenColumn [ngClass]=\"{\r\n 'p-frozen-column': frozenHandle(frozenColumnConfigByKey?.[key]),\r\n 'text-center': item.rowDataButtons?.[key] || item.typeCell?.[key] === ETypeInput.BADGE,\r\n 'skeleton-cell': item.isLoading\r\n }\" [frozen]=\"frozenHandle(frozenColumnConfigByKey?.[key])\">\r\n @if (item.isLoading) {\r\n <div class=\"skeleton-content\"></div>\r\n } @else {\r\n @if (item.rowDataButtons?.[key]) {\r\n <div class=\"flex gap-4 w-full justify-center items-center\">\r\n @for (btn of item.rowDataButtons[key]; track $index) {\r\n @if (btn) {\r\n <lib-button-ng class=\"w-full\" (click)=\"$event.stopPropagation()\" [buttonConfig]=\"btn\"></lib-button-ng>\r\n }\r\n }\r\n </div>\r\n } @else {\r\n @switch (item.typeCell?.[key]) {\r\n @case (ETypeInput.IMAGE) {\r\n <img [src]=\"item.rowData[key]\" alt=\"Image\" class=\"w-10 h-10 mx-auto\">\r\n }\r\n @case (ETypeInput.DATE) {\r\n {{ item.rowData[key] | date: \"dd/MM/yyyy\" }}\r\n }\r\n @case (ETypeInput.DATETIME_LOCAL) {\r\n {{ item.rowData[key] | date: \"dd/MM/yyyy HH:mm\" }}\r\n }\r\n @case (ETypeInput.CURRENCY) {\r\n {{item?.currencyTypeCellConfig?.[key]?.currency}} {{ item.rowData[key] | currency:\r\n item?.currencyTypeCellConfig?.[key]?.currency ?? 'USD' }}\r\n }\r\n @case (ETypeInput.BADGE) {\r\n <lib-badge-ng [config]=\"item.rowData[key]\"></lib-badge-ng>\r\n }\r\n @case (ETypeInput.COMPONENT) {\r\n <ng-container\r\n *ngTemplateOutlet=\"item.rowDataComponents?.[key]; context: { $implicit: item.raw }\"></ng-container>\r\n }\r\n @case (ETypeInput.INPUT) {\r\n <lib-inline-input [(ngModel)]=\"item.rowData[key]\"\r\n [config]=\"item.rowDataInput?.[key] ?? {typeInput: ETypeInput.TEXT}\"\r\n (outputValue)=\"handleCheckValue()\"\r\n >\r\n </lib-inline-input>\r\n }\r\n @default {\r\n @if (isDate(item.rowData[key])) {\r\n {{ item.rowData[key] | date: \"dd/MM/yyyy\" }}\r\n } @else if (typeof item.rowData[key] === \"string\") {\r\n {{ item.rowData[key] }}\r\n } @else if (isPrimeNgSelection(item.rowData[key])) {\r\n {{ item.rowData[key].name }}\r\n } @else if(typeof item.rowData[key] === \"number\") {\r\n <p class=\"text-right\">\r\n {{\r\n item.rowData[key]\r\n | number: (\r\n item.rowDataInput?.[key]?.numberConfig?.minFractionDigits === 0 &&\r\n item.rowDataInput?.[key]?.numberConfig?.maxFractionDigits === 0\r\n ? '1.0-0'\r\n : '1.2-2'\r\n )\r\n }}\r\n </p>\r\n }\r\n }\r\n }\r\n }\r\n }\r\n </td>\r\n }\r\n }\r\n </tr>\r\n </ng-template>\r\n }\r\n }\r\n\r\n <ng-template #footer>\r\n @if (footerEnabled) {\r\n @for (row of footerRows; track $index) {\r\n <tr class=\"p-datatable-row p-datatable-footer-row\">\r\n @for (cell of row; track $index) {\r\n <td colSpan=\"{{ cell.colSpan }}\" class=\"{{ cell.class }} text-right font-bold p-3 pb-0\">{{\r\n applyPipe(cell.value,\r\n cell.pipeConfig) }}</td>\r\n\r\n }\r\n </tr>\r\n }\r\n\r\n }\r\n </ng-template>\r\n <ng-template #expandedrow let-item>\r\n <tr>\r\n <td colspan=\"100%\">\r\n <div class=\"p-datatable-row-expansion\">\r\n <ng-container *ngTemplateOutlet=\"currentItemTemplate; context: { $implicit: item }\"></ng-container>\r\n\r\n </div>\r\n </td>\r\n </tr>\r\n </ng-template>\r\n </p-table>\r\n @if (showBottomToolbar()) {\r\n <div class=\"mt-10 p-datatable-footer sticky bottom-2 z-9 animate__animated animate__fadeIn\">\r\n <lib-toolbar-ng>\r\n @if (showManagementSelectionConfig()) {\r\n <div toolbarStart\r\n class=\"p-datatable-footer-content flex items-center gap-3 px-4 rounded-lg animate__animated animate__fadeIn\">\r\n <span class=\"font-medium text-gray-700 dark:text-gray-300\">{{ getSelectedItemsLabel() }}</span>\r\n <div class=\"p-datatable-footer-badge flex items-center justify-center min-w-[28px] h-7 px-2 rounded-md\">\r\n <span class=\"font-semibold text-gray-900 dark:text-gray-100\">{{\r\n totalItemsSelected().toLocaleString()\r\n }}</span>\r\n </div>\r\n <span class=\"text-sm text-gray-600\">{{ getRecordsLabel() }}</span>\r\n <lib-button-ng [buttonConfig]=\"showSelectedItemsManagementButton()\"></lib-button-ng>\r\n </div>\r\n }\r\n </lib-toolbar-ng>\r\n </div>\r\n }\r\n</div>\r\n@if (httpMessage()) {\r\n<lib-http-message [(httpMessage)]=\"httpMessage\"></lib-http-message>\r\n}", styles: [".cursor-pointer{cursor:pointer}.empty-data-message{text-align:center;padding:2rem;color:#6c757d;font-style:italic}.table-title-container{background:var(--p-surface-50);border-bottom:1px solid var(--p-surface-200);padding:1.25rem 2rem;position:relative}.table-title{color:var(--p-text-color);font-size:1.5rem;font-weight:600;text-align:center;margin:0;letter-spacing:-.025em;text-shadow:0 1px 2px rgba(0,0,0,.05);background:linear-gradient(135deg,var(--p-text-color) 0%,var(--p-text-muted-color) 100%);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:transparent;position:relative}.table-title:after{content:\"\";position:absolute;bottom:-.5rem;left:50%;transform:translate(-50%);width:60px;height:2px;background:linear-gradient(90deg,var(--p-primary-color),var(--p-primary-600));border-radius:1px}:host ::ng-deep .p-datatable-paginator{background:var(--p-surface-100);border-top:1px solid var(--p-surface-300);padding:1rem}:host ::ng-deep .p-datatable-paginator .p-paginator{background:transparent;border:none;padding:0}:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-pages .p-paginator-page{background:var(--p-surface-200);border:1px solid var(--p-surface-300);color:var(--p-text-color)}:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-pages .p-paginator-page:hover{background:var(--p-surface-300);border-color:var(--p-primary-color)}:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-pages .p-paginator-page.p-highlight{background:var(--p-primary-color);border-color:var(--p-primary-color);color:var(--p-primary-contrast-color)}:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-first,:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-prev,:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-next,:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-last{background:var(--p-surface-200);border:1px solid var(--p-surface-300);color:var(--p-text-color)}:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-first:hover,:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-prev:hover,:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-next:hover,:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-last:hover{background:var(--p-surface-300);border-color:var(--p-primary-color)}:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-first:disabled,:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-prev:disabled,:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-next:disabled,:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-last:disabled{background:var(--p-surface-100);border-color:var(--p-surface-300);color:var(--p-text-muted-color)}:host ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-current{color:var(--p-text-color);font-weight:500}:host ::ng-deep .p-datatable-paginator .p-paginator .p-dropdown{background:var(--p-surface-200);border:1px solid var(--p-surface-300);color:var(--p-text-color)}:host ::ng-deep .p-datatable-paginator .p-paginator .p-dropdown:hover{border-color:var(--p-primary-color)}:host ::ng-deep .p-datatable-paginator .p-paginator .p-dropdown:focus{border-color:var(--p-primary-color);box-shadow:0 0 0 2px var(--p-primary-color-100)}.skeleton-row{pointer-events:none;-webkit-user-select:none;user-select:none;min-height:3rem}.skeleton-cell{position:relative;overflow:hidden;min-height:3rem;padding:.75rem .5rem!important}.skeleton-cell .skeleton-content{position:absolute;inset:.5rem;min-height:1.5rem;background:linear-gradient(90deg,#d1d5db33,#d1d5db66,#d1d5db33);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px}@keyframes skeleton-loading{0%{background-position:200% 0}to{background-position:-200% 0}}:host-context(.my-app-dark) .skeleton-cell .skeleton-content{background:linear-gradient(90deg,#4b556333,#4b556366,#4b556333);background-size:200% 100%}:host ::ng-deep .p-datatable .p-datatable-tbody .skeleton-row .skeleton-cell{width:auto;min-width:fit-content}:host-context(.my-app-dark) .table-title-container{background:var(--p-surface-800);border-bottom-color:var(--p-surface-700)}:host-context(.my-app-dark) .table-title{color:var(--p-text-color);background:linear-gradient(135deg,var(--p-text-color) 0%,var(--p-text-muted-color) 100%);background-clip:text;-webkit-background-clip:text;-webkit-text-fill-color:transparent}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator{background:var(--p-surface-900);border-top-color:var(--p-surface-800)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-pages .p-paginator-page{background:var(--p-surface-800);border-color:var(--p-surface-700);color:var(--p-text-color)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-pages .p-paginator-page:hover{background:var(--p-surface-700);border-color:var(--p-primary-color)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-pages .p-paginator-page.p-highlight{background:var(--p-primary-color);border-color:var(--p-primary-color);color:var(--p-primary-contrast-color)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-first,:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-prev,:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-next,:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-last{background:var(--p-surface-800);border-color:var(--p-surface-700);color:var(--p-text-color)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-first:hover,:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-prev:hover,:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-next:hover,:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-last:hover{background:var(--p-surface-700);border-color:var(--p-primary-color)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-first:disabled,:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-prev:disabled,:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-next:disabled,:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-last:disabled{background:var(--p-surface-900);border-color:var(--p-surface-800);color:var(--p-text-muted-color)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-paginator-current{color:var(--p-text-color)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-dropdown{background:var(--p-surface-800);border-color:var(--p-surface-700);color:var(--p-text-color)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-dropdown:hover{border-color:var(--p-primary-color)}:host-context(.my-app-dark) ::ng-deep .p-datatable-paginator .p-paginator .p-dropdown:focus{border-color:var(--p-primary-color);box-shadow:0 0 0 2px var(--p-primary-color-100)}.flex{display:flex}.flex-col{flex-direction:column}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.justify-center{justify-content:center}.items-center{align-items:center}.text-center{text-align:center}.text-right{text-align:right}.text-left{text-align:left}.text-gray-400{color:#9ca3af}.text-gray-500{color:#6b7280}.text-gray-600{color:#4b5563}.text-gray-700{color:#374151}.text-gray-900{color:#111827}.text-blue-500{color:#3b82f6}.text-red-500{color:#ef4444}.text-green-500{color:#22c55e}.text-xs{font-size:.75rem;line-height:1rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.font-bold{font-weight:700}.italic{font-style:italic}.w-full{width:100%}.w-10{width:2.5rem}.h-10{height:2.5rem}.h-7{height:1.75rem}.min-w-28{min-width:28px}.mx-auto{margin-left:auto;margin-right:auto}.p-1{padding:.25rem}.p-3{padding:.75rem}.p-8{padding:2rem}.px-0{padding-left:0;padding-right:0}.py-0{padding-top:0;padding-bottom:0}.px-2{padding-left:.5rem;padding-right:.5rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.px-4{padding-left:1rem;padding-right:1rem}.pb-0{padding-bottom:0}.bg-gray-50{background-color:#f9fafb}.bg-gray-100{background-color:#f3f4f6}.bg-gray-200{background-color:#e5e7eb}.bg-gray-600{background-color:#4b5563}.bg-gray-700{background-color:#374151}.bg-gray-800{background-color:#1f2937}.bg-blue-100{background-color:#dbeafe}.bg-blue-200{background-color:#bfdbfe}.bg-blue-800{background-color:#1e40af}.bg-blue-900{background-color:#1e3a8a}.bg-green-200{background-color:#bbf7d0}.border-b{border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:var(--p-surface-300)}.border-l-4{border-left-width:4px;border-left-style:solid}.border-blue-500{border-color:#3b82f6}.rounded-full{border-radius:9999px}.rounded-md{border-radius:.375rem}.rounded-lg{border-radius:.5rem}.shadow-sm{box-shadow:0 1px 2px #0000000d}.shadow-lg{box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -2px #0000000d}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-300{transition-duration:.3s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.sticky{position:sticky}.top-0{top:0}.bottom-2{bottom:.5rem}.bottom-18{bottom:4.5rem}.z-9{z-index:9}.z-10{z-index:10}.z-30{z-index:30}.hover\\:bg-gray-50:hover{background-color:#f9fafb}.hover\\:bg-gray-100:hover{background-color:#f3f4f6}.hover\\:bg-gray-200:hover{background-color:#e5e7eb}.hover\\:bg-blue-200:hover{background-color:#bfdbfe}.hover\\:bg-blue-800:hover{background-color:#1e40af}:host-context(.my-app-dark) .dark\\:bg-gray-800{background-color:#1f2937}:host-context(.my-app-dark) .dark\\:bg-gray-700{background-color:#374151}:host-context(.my-app-dark) .dark\\:bg-gray-600{background-color:#4b5563}:host-context(.my-app-dark) .dark\\:bg-blue-900{background-color:#1e3a8a}:host-context(.my-app-dark) .dark\\:bg-blue-800{background-color:#1e40af}:host-context(.my-app-dark) .dark\\:hover\\:bg-gray-800:hover{background-color:#1f2937}:host-context(.my-app-dark) .dark\\:hover\\:bg-gray-700:hover{background-color:#374151}:host-context(.my-app-dark) .dark\\:hover\\:bg-gray-600:hover{background-color:#4b5563}:host-context(.my-app-dark) .dark\\:hover\\:bg-blue-800:hover{background-color:#1e40af}.animate__animated{animation-duration:1s;animation-fill-mode:both}.animate__fadeIn{animation-name:fadeIn}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}\n"] }]
3668
+ }], ctorParameters: () => [], propDecorators: { dt: [{
3669
+ type: ViewChild,
3670
+ args: ['dt']
3671
+ }], itemTemplate: [{
3672
+ type: ContentChild,
3673
+ args: ['item', { static: true }]
3674
+ }] } });
3675
+
3676
+ class SpeedDialNgService {
3677
+ constructor() { }
3678
+ _config = signal({});
3679
+ config = this._config.asReadonly();
3680
+ items = computed(() => this.config().items);
3681
+ buttonProps = computed(() => this.config().buttonProps ?? { severity: 'primary', rounded: true });
3682
+ tooltipOptions = computed(() => this.config().tooltipOptions ?? { tooltipPosition: 'top' });
3683
+ style = computed(() => this.config().style ?? {});
3684
+ direction = computed(() => this.config().direction ?? 'down');
3685
+ setConfig(value) {
3686
+ this._config.set(value);
3687
+ }
3688
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SpeedDialNgService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
3689
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SpeedDialNgService, providedIn: 'root' });
3690
+ }
3691
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SpeedDialNgService, decorators: [{
3692
+ type: Injectable,
3693
+ args: [{
3694
+ providedIn: 'root'
3695
+ }]
3696
+ }], ctorParameters: () => [] });
3697
+
3698
+ class SpeedDialNgComponent {
3699
+ speedDialNgService = inject(SpeedDialNgService);
3700
+ configInput = input.required();
3701
+ constructor() {
3702
+ }
3703
+ ngOnInit() {
3704
+ this.speedDialNgService.setConfig(this.configInput());
3705
+ }
3706
+ get config() {
3707
+ return this.speedDialNgService.config();
3708
+ }
3709
+ get items() {
3710
+ return this.speedDialNgService.items();
3711
+ }
3712
+ get buttonProps() {
3713
+ return this.speedDialNgService.buttonProps();
3714
+ }
3715
+ get tooltipOptions() {
3716
+ return this.speedDialNgService.tooltipOptions();
3717
+ }
3718
+ get style() {
3719
+ return this.speedDialNgService.style();
3720
+ }
3721
+ get direction() {
3722
+ return this.speedDialNgService.direction();
3723
+ }
3724
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SpeedDialNgComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3725
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.17", type: SpeedDialNgComponent, isStandalone: true, selector: "lib-speed-dial-ng", inputs: { configInput: { classPropertyName: "configInput", publicName: "configInput", isSignal: true, isRequired: true, transformFunction: null } }, providers: [SpeedDialNgService], ngImport: i0, template: "\r\n<p-speeddial \r\n[model]=\"items\" \r\ndirection=\"up\" \r\n[style]=\"style\" \r\n[buttonProps]=\"buttonProps\" \r\n[tooltipOptions]=\"tooltipOptions\" \r\n[direction]=\"direction\"\r\n/>", styles: [""], dependencies: [{ kind: "ngmodule", type: SpeedDialModule }, { kind: "component", type: i1$5.SpeedDial, selector: "p-speeddial, p-speedDial, p-speed-dial", inputs: ["id", "model", "visible", "style", "className", "direction", "transitionDelay", "type", "radius", "mask", "disabled", "hideOnClickOutside", "buttonStyle", "buttonClassName", "maskStyle", "maskClassName", "showIcon", "hideIcon", "rotateAnimation", "ariaLabel", "ariaLabelledBy", "tooltipOptions", "buttonProps"], outputs: ["onVisibleChange", "visibleChange", "onClick", "onShow", "onHide"] }] });
3726
+ }
3727
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SpeedDialNgComponent, decorators: [{
3728
+ type: Component,
3729
+ args: [{ selector: 'lib-speed-dial-ng', imports: [SpeedDialModule], providers: [SpeedDialNgService], template: "\r\n<p-speeddial \r\n[model]=\"items\" \r\ndirection=\"up\" \r\n[style]=\"style\" \r\n[buttonProps]=\"buttonProps\" \r\n[tooltipOptions]=\"tooltipOptions\" \r\n[direction]=\"direction\"\r\n/>" }]
3730
+ }], ctorParameters: () => [] });
3731
+
3732
+ /*
3733
+ * Public API Surface of lib-components
3734
+
3735
+ NPM TOKEN:
3736
+ 4f5f941cb6703a2bea326507bd5098aa7dd8224ef4d9b434f6209c73855bf7ac
3737
+ 8b61ac2dab0cf90c13878339c755b09f868b34906ad196a1138433f76f41feb4
3738
+ 37b8f0500846352a33a9d1e2a8504e8a4332cd035a3819d9dc4b2dcdf557c3f0
3739
+ 31f1ccdf0a47736bd3851647d485385323328542c49de9d95498d875e3977f5e
3740
+ de13d65e8a0357ce9f2e18c899c8e7f6f728181baa031761ecdd7ef5cb166eb2
3741
+ */
3742
+
3743
+ /**
3744
+ * Generated bundle index. Do not edit.
3745
+ */
3746
+
3747
+ export { AminatedContainerComponent as A, BaseDialogComponent as B, DisabledContainerComponent as D, ETypeInput as E, FormComponent as F, HttpMessageComponent as H, InlineInputComponent as I, LibComponentsService as L, SpeedDialComponent as S, TableNgComponent as T, ButtonNgComponent as a, LibComponentsComponent as b, SpeedDialService as c, SpeedDialNgComponent as d };
3748
+ //# sourceMappingURL=ln-20-lib-components-ln-20-lib-components-B540TRU7.mjs.map