@up_si_vale/sivale-componentes-angular 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/esm2022/lib/atoms/button/button.component.mjs +55 -0
  2. package/esm2022/lib/atoms/checkbox/checkbox.component.mjs +174 -0
  3. package/esm2022/lib/atoms/date-picker/date-picker.component.mjs +835 -0
  4. package/esm2022/lib/atoms/input/input.component.mjs +218 -0
  5. package/esm2022/lib/atoms/loader/loader.component.mjs +81 -0
  6. package/esm2022/lib/atoms/radio/radio.component.mjs +142 -0
  7. package/esm2022/lib/atoms/textarea/textarea.component.mjs +126 -0
  8. package/esm2022/lib/directives/asset-source.directive.mjs +68 -0
  9. package/esm2022/lib/directives/icon-source.directive.mjs +65 -0
  10. package/esm2022/lib/directives/no-leading-space.directive.mjs +24 -0
  11. package/esm2022/lib/directives/only-letters.directive.mjs +25 -0
  12. package/esm2022/lib/directives/only-number.directive.mjs +21 -0
  13. package/esm2022/lib/directives/rfc.directive.mjs +67 -0
  14. package/esm2022/lib/directives/tooltip.directive.mjs +199 -0
  15. package/esm2022/lib/models/snackbar.models.mjs +2 -0
  16. package/esm2022/lib/molecules/alert/alert.component.mjs +79 -0
  17. package/esm2022/lib/molecules/copy-input/copy-input.component.mjs +46 -0
  18. package/esm2022/lib/molecules/multiselect/multiselect.component.mjs +466 -0
  19. package/esm2022/lib/molecules/option/option.component.mjs +55 -0
  20. package/esm2022/lib/molecules/phone-input/phone-input.component.mjs +64 -0
  21. package/esm2022/lib/molecules/select/select.component.mjs +498 -0
  22. package/esm2022/lib/molecules/snackbar/snackbar.component.mjs +581 -0
  23. package/esm2022/lib/organisms/sidebar/sidebar-icon.component.mjs +91 -0
  24. package/esm2022/lib/organisms/sidebar/sidebar.component.mjs +115 -0
  25. package/esm2022/lib/services/snackbar.service.mjs +96 -0
  26. package/esm2022/lib/tokens/asset-base-url.token.mjs +10 -0
  27. package/esm2022/public-api.mjs +37 -0
  28. package/esm2022/up_si_vale-sivale-componentes-angular.mjs +5 -0
  29. package/fesm2022/up_si_vale-sivale-componentes-angular.mjs +4116 -0
  30. package/fesm2022/up_si_vale-sivale-componentes-angular.mjs.map +1 -0
  31. package/index.d.ts +5 -0
  32. package/lib/atoms/button/button.component.d.ts +20 -0
  33. package/lib/atoms/checkbox/checkbox.component.d.ts +31 -0
  34. package/lib/atoms/date-picker/date-picker.component.d.ts +134 -0
  35. package/lib/atoms/input/input.component.d.ts +35 -0
  36. package/lib/atoms/loader/loader.component.d.ts +10 -0
  37. package/lib/atoms/radio/radio.component.d.ts +25 -0
  38. package/lib/atoms/textarea/textarea.component.d.ts +27 -0
  39. package/lib/directives/asset-source.directive.d.ts +19 -0
  40. package/lib/directives/icon-source.directive.d.ts +18 -0
  41. package/lib/directives/no-leading-space.directive.d.ts +6 -0
  42. package/lib/directives/only-letters.directive.d.ts +7 -0
  43. package/lib/directives/only-number.directive.d.ts +6 -0
  44. package/lib/directives/rfc.directive.d.ts +12 -0
  45. package/lib/directives/tooltip.directive.d.ts +27 -0
  46. package/{src/lib/models/snackbar.models.ts → lib/models/snackbar.models.d.ts} +8 -10
  47. package/lib/molecules/alert/alert.component.d.ts +29 -0
  48. package/lib/molecules/copy-input/copy-input.component.d.ts +14 -0
  49. package/lib/molecules/multiselect/multiselect.component.d.ts +74 -0
  50. package/lib/molecules/option/option.component.d.ts +19 -0
  51. package/lib/molecules/phone-input/phone-input.component.d.ts +12 -0
  52. package/lib/molecules/select/select.component.d.ts +88 -0
  53. package/lib/molecules/snackbar/snackbar.component.d.ts +17 -0
  54. package/lib/organisms/sidebar/sidebar-icon.component.d.ts +8 -0
  55. package/lib/organisms/sidebar/sidebar.component.d.ts +47 -0
  56. package/lib/services/snackbar.service.d.ts +40 -0
  57. package/{src/lib/tokens/asset-base-url.token.ts → lib/tokens/asset-base-url.token.d.ts} +1 -5
  58. package/package.json +39 -28
  59. package/{src/public-api.ts → public-api.d.ts} +3 -15
  60. package/ng-package.json +0 -9
  61. package/src/lib/atoms/button/button.component.html +0 -21
  62. package/src/lib/atoms/button/button.component.scss +0 -242
  63. package/src/lib/atoms/button/button.component.ts +0 -43
  64. package/src/lib/atoms/checkbox/checkbox.component.scss +0 -131
  65. package/src/lib/atoms/checkbox/checkbox.component.ts +0 -130
  66. package/src/lib/atoms/date-picker/date-picker.component.html +0 -295
  67. package/src/lib/atoms/date-picker/date-picker.component.scss +0 -1002
  68. package/src/lib/atoms/date-picker/date-picker.component.ts +0 -942
  69. package/src/lib/atoms/input/input.component.ts +0 -239
  70. package/src/lib/atoms/loader/loader.component.scss +0 -144
  71. package/src/lib/atoms/loader/loader.component.ts +0 -44
  72. package/src/lib/atoms/radio/radio.component.scss +0 -115
  73. package/src/lib/atoms/radio/radio.component.ts +0 -103
  74. package/src/lib/atoms/textarea/textarea.component.ts +0 -155
  75. package/src/lib/directives/asset-source.directive.ts +0 -64
  76. package/src/lib/directives/icon-source.directive.ts +0 -74
  77. package/src/lib/directives/no-leading-space.directive.ts +0 -18
  78. package/src/lib/directives/only-letters.directive.ts +0 -21
  79. package/src/lib/directives/only-number.directive.ts +0 -15
  80. package/src/lib/directives/rfc.directive.ts +0 -60
  81. package/src/lib/directives/tooltip.directive.ts +0 -211
  82. package/src/lib/molecules/copy-input/copy-input.component.html +0 -29
  83. package/src/lib/molecules/copy-input/copy-input.component.scss +0 -101
  84. package/src/lib/molecules/copy-input/copy-input.component.ts +0 -41
  85. package/src/lib/molecules/multiselect/multiselect.component.scss +0 -298
  86. package/src/lib/molecules/multiselect/multiselect.component.ts +0 -487
  87. package/src/lib/molecules/option/option.component.ts +0 -45
  88. package/src/lib/molecules/phone-input/phone-input.component.scss +0 -78
  89. package/src/lib/molecules/phone-input/phone-input.component.ts +0 -43
  90. package/src/lib/molecules/select/select.component.ts +0 -482
  91. package/src/lib/molecules/snackbar/snackbar.component.scss +0 -201
  92. package/src/lib/molecules/snackbar/snackbar.component.ts +0 -321
  93. package/src/lib/services/snackbar.service.ts +0 -103
  94. package/tsconfig.json +0 -31
@@ -0,0 +1,4116 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, Injectable, Input, Optional, Inject, Directive, HostListener, Self, HostBinding, EventEmitter, Output, Component, forwardRef, ChangeDetectionStrategy, ElementRef, ViewChild, TemplateRef, ContentChild, RendererStyleFlags2, ContentChildren } from '@angular/core';
3
+ import { Subject } from 'rxjs';
4
+ import * as i1 from '@angular/forms';
5
+ import { ReactiveFormsModule, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
6
+ import * as i1$1 from '@angular/common';
7
+ import { CommonModule, DOCUMENT } from '@angular/common';
8
+ import { RouterLink, RouterLinkActive } from '@angular/router';
9
+
10
+ /**
11
+ * Base URL para los assets remotos del microfrontend (íconos, imágenes).
12
+ * El consumidor debe proveerlo, normalmente con el valor de `environment.mfAssetsUrl`.
13
+ */
14
+ const ASSET_BASE_URL = new InjectionToken('ASSET_BASE_URL', {
15
+ providedIn: 'root',
16
+ factory: () => ''
17
+ });
18
+
19
+ class SnackbarService {
20
+ snackbarSubject = new Subject();
21
+ snackbar$ = this.snackbarSubject.asObservable();
22
+ dismissSubject = new Subject();
23
+ dismiss$ = this.dismissSubject.asObservable();
24
+ snackbarIdCounter = 0;
25
+ constructor() {
26
+ }
27
+ /**
28
+ * Show success snackbar
29
+ */
30
+ success(message, duration = 5000, position) {
31
+ this.show({
32
+ message,
33
+ type: 'success',
34
+ duration,
35
+ position
36
+ });
37
+ }
38
+ /**
39
+ * Show error snackbar
40
+ */
41
+ error(message, duration = 5000, position) {
42
+ this.show({
43
+ message,
44
+ type: 'error',
45
+ duration,
46
+ position
47
+ });
48
+ }
49
+ /**
50
+ * Show warning snackbar
51
+ */
52
+ warning(message, duration = 5000, position) {
53
+ this.show({
54
+ message,
55
+ type: 'warning',
56
+ duration,
57
+ position
58
+ });
59
+ }
60
+ /**
61
+ * Show info snackbar
62
+ */
63
+ info(message, duration = 5000, position) {
64
+ this.show({
65
+ message,
66
+ type: 'info',
67
+ duration,
68
+ position
69
+ });
70
+ }
71
+ /**
72
+ * Show snackbar with custom configuration
73
+ */
74
+ show(config) {
75
+ const id = `snackbar-${++this.snackbarIdCounter}`;
76
+ const snackbarData = {
77
+ ...config,
78
+ id,
79
+ duration: config.duration ?? 5000,
80
+ position: config.position ?? 'top-right'
81
+ };
82
+ this.snackbarSubject.next(snackbarData);
83
+ // Auto dismiss after duration
84
+ if (snackbarData.duration && snackbarData.duration > 0) {
85
+ setTimeout(() => {
86
+ this.dismiss(id);
87
+ }, snackbarData.duration);
88
+ }
89
+ }
90
+ /**
91
+ * Dismiss specific snackbar by id
92
+ */
93
+ dismiss(id) {
94
+ this.dismissSubject.next(id);
95
+ }
96
+ /**
97
+ * Dismiss all snackbars
98
+ */
99
+ dismissAll() {
100
+ this.dismissSubject.next('all');
101
+ }
102
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SnackbarService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
103
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SnackbarService, providedIn: 'root' });
104
+ }
105
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SnackbarService, decorators: [{
106
+ type: Injectable,
107
+ args: [{
108
+ providedIn: 'root'
109
+ }]
110
+ }], ctorParameters: () => [] });
111
+
112
+ class AssetSourceDirective {
113
+ el;
114
+ assetBaseUrl;
115
+ assetSource = 'mf';
116
+ assetPath;
117
+ originalSrc = null;
118
+ constructor(el, assetBaseUrl) {
119
+ this.el = el;
120
+ this.assetBaseUrl = assetBaseUrl;
121
+ }
122
+ ngOnInit() {
123
+ this.captureOriginalSrc();
124
+ }
125
+ ngAfterViewInit() {
126
+ this.updateSrc();
127
+ }
128
+ ngOnChanges() {
129
+ this.updateSrc();
130
+ }
131
+ captureOriginalSrc() {
132
+ if (this.el.nativeElement.tagName === 'IMG') {
133
+ this.originalSrc = this.el.nativeElement.getAttribute('src');
134
+ }
135
+ }
136
+ updateSrc() {
137
+ const assetPath = this.assetPath || this.originalSrc;
138
+ if (!assetPath) {
139
+ return;
140
+ }
141
+ const baseUrl = this.getBaseUrl();
142
+ const fullPath = `${baseUrl}/${assetPath}`;
143
+ if (this.el.nativeElement.tagName === 'IMG') {
144
+ this.el.nativeElement.src = fullPath;
145
+ }
146
+ }
147
+ getBaseUrl() {
148
+ switch (this.assetSource) {
149
+ case 'mf':
150
+ return this.assetBaseUrl ?? '';
151
+ case 'main':
152
+ return '/assets';
153
+ default:
154
+ return this.assetBaseUrl ?? '';
155
+ }
156
+ }
157
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AssetSourceDirective, deps: [{ token: i0.ElementRef }, { token: ASSET_BASE_URL, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
158
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: AssetSourceDirective, isStandalone: true, selector: "[assetSource]", inputs: { assetSource: "assetSource", assetPath: "assetPath" }, usesOnChanges: true, ngImport: i0 });
159
+ }
160
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AssetSourceDirective, decorators: [{
161
+ type: Directive,
162
+ args: [{
163
+ selector: '[assetSource]',
164
+ standalone: true
165
+ }]
166
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: undefined, decorators: [{
167
+ type: Optional
168
+ }, {
169
+ type: Inject,
170
+ args: [ASSET_BASE_URL]
171
+ }] }], propDecorators: { assetSource: [{
172
+ type: Input
173
+ }], assetPath: [{
174
+ type: Input
175
+ }] } });
176
+
177
+ class IconSourceDirective {
178
+ el;
179
+ assetBaseUrl;
180
+ iconName;
181
+ assetSource = 'mf';
182
+ constructor(el, assetBaseUrl) {
183
+ this.el = el;
184
+ this.assetBaseUrl = assetBaseUrl;
185
+ }
186
+ ngOnInit() {
187
+ this.addIconClass();
188
+ }
189
+ ngAfterViewInit() {
190
+ this.setIconUrl();
191
+ }
192
+ ngOnChanges() {
193
+ this.setIconUrl();
194
+ }
195
+ addIconClass() {
196
+ if (this.iconName) {
197
+ this.el.nativeElement.classList.add(`icon-${this.iconName}`);
198
+ }
199
+ }
200
+ setIconUrl() {
201
+ if (!this.iconName) {
202
+ return;
203
+ }
204
+ const baseUrl = this.getBaseUrl();
205
+ const iconUrl = `${baseUrl}/icons/${this.iconName}.svg`;
206
+ this.el.nativeElement.style.maskImage = `url('${iconUrl}')`;
207
+ this.el.nativeElement.style.webkitMaskImage = `url('${iconUrl}')`;
208
+ }
209
+ getBaseUrl() {
210
+ switch (this.assetSource) {
211
+ case 'mf':
212
+ return this.assetBaseUrl ?? '';
213
+ case 'main':
214
+ return '/assets';
215
+ default:
216
+ return this.assetBaseUrl ?? '';
217
+ }
218
+ }
219
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: IconSourceDirective, deps: [{ token: i0.ElementRef }, { token: ASSET_BASE_URL, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
220
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: IconSourceDirective, isStandalone: true, selector: "i[iconName]", inputs: { iconName: "iconName", assetSource: "assetSource" }, usesOnChanges: true, ngImport: i0 });
221
+ }
222
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: IconSourceDirective, decorators: [{
223
+ type: Directive,
224
+ args: [{
225
+ selector: 'i[iconName]',
226
+ standalone: true
227
+ }]
228
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: undefined, decorators: [{
229
+ type: Optional
230
+ }, {
231
+ type: Inject,
232
+ args: [ASSET_BASE_URL]
233
+ }] }], propDecorators: { iconName: [{
234
+ type: Input
235
+ }], assetSource: [{
236
+ type: Input
237
+ }] } });
238
+
239
+ class OnlyNumberDirective {
240
+ onInput(event) {
241
+ const value = event.target.value;
242
+ event.target.value = value.replace(/\D/g, '');
243
+ }
244
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: OnlyNumberDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
245
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: OnlyNumberDirective, isStandalone: true, selector: "[onlyNumber]", host: { listeners: { "input": "onInput($event)" } }, ngImport: i0 });
246
+ }
247
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: OnlyNumberDirective, decorators: [{
248
+ type: Directive,
249
+ args: [{
250
+ selector: '[onlyNumber]',
251
+ standalone: true
252
+ }]
253
+ }], propDecorators: { onInput: [{
254
+ type: HostListener,
255
+ args: ['input', ['$event']]
256
+ }] } });
257
+
258
+ class OnlyLettersDirective {
259
+ regex = /^[A-Za-zÁÉÍÓÚÜÑáéíóúüñ' -]*$/;
260
+ onInput(event) {
261
+ const value = event.target.value;
262
+ event.target.value = value
263
+ .split('')
264
+ .filter(char => this.regex.test(char))
265
+ .join('');
266
+ }
267
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: OnlyLettersDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
268
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: OnlyLettersDirective, isStandalone: true, selector: "[onlyLetters]", host: { listeners: { "input": "onInput($event)" } }, ngImport: i0 });
269
+ }
270
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: OnlyLettersDirective, decorators: [{
271
+ type: Directive,
272
+ args: [{
273
+ selector: '[onlyLetters]',
274
+ standalone: true
275
+ }]
276
+ }], propDecorators: { onInput: [{
277
+ type: HostListener,
278
+ args: ['input', ['$event']]
279
+ }] } });
280
+
281
+ class RfcDirective {
282
+ ngControl;
283
+ tipoContribuyente = null;
284
+ constructor(ngControl) {
285
+ this.ngControl = ngControl;
286
+ }
287
+ // Función para obtener el límite según el tipo de contribuyente
288
+ getMaxLength() {
289
+ if (this.tipoContribuyente === 'fisica')
290
+ return 13;
291
+ if (this.tipoContribuyente === 'moral')
292
+ return 12;
293
+ return 13; // Default por si no llega el valor
294
+ }
295
+ onInput(event) {
296
+ const input = event.target;
297
+ let value = input.value;
298
+ // Solo letras y números
299
+ value = value.replace(/[^a-zA-Z0-9]/g, '');
300
+ // Mayúsculas
301
+ value = value.toUpperCase();
302
+ // Aplicar límite dinámico
303
+ const max = this.getMaxLength();
304
+ if (value.length > max) {
305
+ value = value.substring(0, max);
306
+ }
307
+ this.ngControl?.control?.setValue(value, { emitEvent: false });
308
+ }
309
+ onPaste(event) {
310
+ const pasted = event.clipboardData?.getData('text') || '';
311
+ const max = this.getMaxLength();
312
+ // Bloquear pegado con caracteres inválidos
313
+ if (/[^a-zA-Z0-9]/.test(pasted)) {
314
+ event.preventDefault();
315
+ return;
316
+ }
317
+ // Bloquear pegado si excede el máximo
318
+ if (pasted.length > max) {
319
+ event.preventDefault();
320
+ }
321
+ }
322
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RfcDirective, deps: [{ token: i1.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
323
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: RfcDirective, isStandalone: true, selector: "[rfcValidator]", inputs: { tipoContribuyente: "tipoContribuyente" }, host: { listeners: { "input": "onInput($event)", "paste": "onPaste($event)" } }, ngImport: i0 });
324
+ }
325
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RfcDirective, decorators: [{
326
+ type: Directive,
327
+ args: [{
328
+ selector: '[rfcValidator]',
329
+ standalone: true
330
+ }]
331
+ }], ctorParameters: () => [{ type: i1.NgControl, decorators: [{
332
+ type: Optional
333
+ }, {
334
+ type: Self
335
+ }] }], propDecorators: { tipoContribuyente: [{
336
+ type: Input
337
+ }], onInput: [{
338
+ type: HostListener,
339
+ args: ['input', ['$event']]
340
+ }], onPaste: [{
341
+ type: HostListener,
342
+ args: ['paste', ['$event']]
343
+ }] } });
344
+
345
+ class NoLeadingSpaceDirective {
346
+ onInput(event) {
347
+ const value = event.target.value;
348
+ // Elimina espacios al inicio
349
+ if (value.startsWith(' ')) {
350
+ event.target.value = value.trimStart();
351
+ }
352
+ }
353
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NoLeadingSpaceDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
354
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: NoLeadingSpaceDirective, isStandalone: true, selector: "[noLeadingSpace]", host: { listeners: { "input": "onInput($event)" } }, ngImport: i0 });
355
+ }
356
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NoLeadingSpaceDirective, decorators: [{
357
+ type: Directive,
358
+ args: [{
359
+ selector: '[noLeadingSpace]',
360
+ standalone: true
361
+ }]
362
+ }], propDecorators: { onInput: [{
363
+ type: HostListener,
364
+ args: ['input', ['$event']]
365
+ }] } });
366
+
367
+ class TooltipDirective {
368
+ el;
369
+ renderer;
370
+ tooltipText = '';
371
+ tooltipPosition = 'auto';
372
+ tooltipDelay = 300;
373
+ tooltipMaxWidth = 280;
374
+ tooltipClass = '';
375
+ cursor = 'help';
376
+ tooltipElement = null;
377
+ showTimeout;
378
+ hideTimeout;
379
+ constructor(el, renderer) {
380
+ this.el = el;
381
+ this.renderer = renderer;
382
+ }
383
+ onMouseEnter() {
384
+ if (this.hideTimeout) {
385
+ clearTimeout(this.hideTimeout);
386
+ this.hideTimeout = undefined;
387
+ }
388
+ this.showTimeout = window.setTimeout(() => {
389
+ this.showTooltip();
390
+ }, this.tooltipDelay);
391
+ }
392
+ onMouseLeave() {
393
+ if (this.showTimeout) {
394
+ clearTimeout(this.showTimeout);
395
+ this.showTimeout = undefined;
396
+ }
397
+ this.hideTimeout = window.setTimeout(() => {
398
+ this.hideTooltip();
399
+ }, 100);
400
+ }
401
+ onClick() {
402
+ // Allow click events to propagate
403
+ }
404
+ showTooltip() {
405
+ if (!this.tooltipText || this.tooltipElement) {
406
+ return;
407
+ }
408
+ // Create tooltip element
409
+ this.tooltipElement = this.renderer.createElement('div');
410
+ this.renderer.addClass(this.tooltipElement, 'app-tooltip');
411
+ if (this.tooltipClass) {
412
+ this.renderer.addClass(this.tooltipElement, this.tooltipClass);
413
+ }
414
+ // Create tooltip content
415
+ const tooltipContent = this.renderer.createElement('div');
416
+ this.renderer.addClass(tooltipContent, 'app-tooltip-content');
417
+ this.renderer.setStyle(tooltipContent, 'max-width', `${this.tooltipMaxWidth}px`);
418
+ const textNode = this.renderer.createText(this.tooltipText);
419
+ this.renderer.appendChild(tooltipContent, textNode);
420
+ this.renderer.appendChild(this.tooltipElement, tooltipContent);
421
+ // Create arrow element
422
+ const arrow = this.renderer.createElement('div');
423
+ this.renderer.addClass(arrow, 'app-tooltip-arrow');
424
+ this.renderer.appendChild(this.tooltipElement, arrow);
425
+ // Add to body
426
+ this.renderer.appendChild(document.body, this.tooltipElement);
427
+ // Position tooltip
428
+ this.positionTooltip();
429
+ // Trigger animation
430
+ requestAnimationFrame(() => {
431
+ if (this.tooltipElement) {
432
+ this.renderer.addClass(this.tooltipElement, 'app-tooltip-show');
433
+ }
434
+ });
435
+ }
436
+ hideTooltip() {
437
+ if (!this.tooltipElement) {
438
+ return;
439
+ }
440
+ this.renderer.removeClass(this.tooltipElement, 'app-tooltip-show');
441
+ setTimeout(() => {
442
+ if (this.tooltipElement) {
443
+ this.renderer.removeChild(document.body, this.tooltipElement);
444
+ this.tooltipElement = null;
445
+ }
446
+ }, 200);
447
+ }
448
+ positionTooltip() {
449
+ if (!this.tooltipElement) {
450
+ return;
451
+ }
452
+ const hostRect = this.el.nativeElement.getBoundingClientRect();
453
+ const tooltipRect = this.tooltipElement.getBoundingClientRect();
454
+ const scrollX = window.scrollX || window.pageXOffset;
455
+ const scrollY = window.scrollY || window.pageYOffset;
456
+ const gap = 16; // Space between element and tooltip
457
+ // Calculate available space in each direction
458
+ const spaceTop = hostRect.top;
459
+ const spaceBottom = window.innerHeight - hostRect.bottom;
460
+ const spaceLeft = hostRect.left;
461
+ const spaceRight = window.innerWidth - hostRect.right;
462
+ let position = this.tooltipPosition;
463
+ let top = 0;
464
+ let left = 0;
465
+ // Auto-detect best position
466
+ if (position === 'auto') {
467
+ if (spaceTop >= tooltipRect.height + gap) {
468
+ position = 'top';
469
+ }
470
+ else if (spaceBottom >= tooltipRect.height + gap) {
471
+ position = 'bottom';
472
+ }
473
+ else if (spaceRight >= tooltipRect.width + gap) {
474
+ position = 'right';
475
+ }
476
+ else if (spaceLeft >= tooltipRect.width + gap) {
477
+ position = 'left';
478
+ }
479
+ else {
480
+ // Default to top if no space is sufficient
481
+ position = 'top';
482
+ }
483
+ }
484
+ // Calculate position based on detected/specified position
485
+ switch (position) {
486
+ case 'top':
487
+ top = hostRect.top + scrollY - tooltipRect.height - gap;
488
+ left = hostRect.left + scrollX + (hostRect.width / 2) - (tooltipRect.width / 2);
489
+ break;
490
+ case 'bottom':
491
+ top = hostRect.bottom + scrollY + gap;
492
+ left = hostRect.left + scrollX + (hostRect.width / 2) - (tooltipRect.width / 2);
493
+ break;
494
+ case 'left':
495
+ top = hostRect.top + scrollY + (hostRect.height / 2) - (tooltipRect.height / 2);
496
+ left = hostRect.left + scrollX - tooltipRect.width - gap;
497
+ break;
498
+ case 'right':
499
+ top = hostRect.top + scrollY + (hostRect.height / 2) - (tooltipRect.height / 2);
500
+ left = hostRect.right + scrollX + gap;
501
+ break;
502
+ }
503
+ // Adjust horizontal position to keep tooltip within viewport
504
+ if (position === 'top' || position === 'bottom') {
505
+ const minLeft = scrollX + 10;
506
+ const maxLeft = scrollX + window.innerWidth - tooltipRect.width - 10;
507
+ left = Math.max(minLeft, Math.min(left, maxLeft));
508
+ }
509
+ // Adjust vertical position to keep tooltip within viewport
510
+ if (position === 'left' || position === 'right') {
511
+ const minTop = scrollY + 10;
512
+ const maxTop = scrollY + window.innerHeight - tooltipRect.height - 10;
513
+ top = Math.max(minTop, Math.min(top, maxTop));
514
+ }
515
+ // Apply position
516
+ this.renderer.setStyle(this.tooltipElement, 'top', `${top}px`);
517
+ this.renderer.setStyle(this.tooltipElement, 'left', `${left}px`);
518
+ // Add position class for arrow styling
519
+ this.renderer.addClass(this.tooltipElement, `app-tooltip-${position}`);
520
+ }
521
+ ngOnDestroy() {
522
+ if (this.showTimeout) {
523
+ clearTimeout(this.showTimeout);
524
+ }
525
+ if (this.hideTimeout) {
526
+ clearTimeout(this.hideTimeout);
527
+ }
528
+ this.hideTooltip();
529
+ }
530
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TooltipDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
531
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: TooltipDirective, isStandalone: true, selector: "[appTooltip]", inputs: { tooltipText: ["appTooltip", "tooltipText"], tooltipPosition: "tooltipPosition", tooltipDelay: "tooltipDelay", tooltipMaxWidth: "tooltipMaxWidth", tooltipClass: "tooltipClass" }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()", "click": "onClick()" }, properties: { "style.cursor": "this.cursor" } }, ngImport: i0 });
532
+ }
533
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TooltipDirective, decorators: [{
534
+ type: Directive,
535
+ args: [{
536
+ selector: '[appTooltip]',
537
+ standalone: true
538
+ }]
539
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { tooltipText: [{
540
+ type: Input,
541
+ args: ['appTooltip']
542
+ }], tooltipPosition: [{
543
+ type: Input
544
+ }], tooltipDelay: [{
545
+ type: Input
546
+ }], tooltipMaxWidth: [{
547
+ type: Input
548
+ }], tooltipClass: [{
549
+ type: Input
550
+ }], cursor: [{
551
+ type: HostBinding,
552
+ args: ['style.cursor']
553
+ }], onMouseEnter: [{
554
+ type: HostListener,
555
+ args: ['mouseenter']
556
+ }], onMouseLeave: [{
557
+ type: HostListener,
558
+ args: ['mouseleave']
559
+ }], onClick: [{
560
+ type: HostListener,
561
+ args: ['click']
562
+ }] } });
563
+
564
+ class ButtonComponent {
565
+ variant = 'primary';
566
+ size = 'medium';
567
+ type = 'button';
568
+ disabled = false;
569
+ loading = false;
570
+ fullWidth = false;
571
+ id;
572
+ ariaLabel;
573
+ onClick = new EventEmitter();
574
+ get buttonClasses() {
575
+ return [
576
+ 'svu-btn',
577
+ `svu-btn--${this.variant}`,
578
+ `svu-btn--${this.size}`,
579
+ this.fullWidth ? 'svu-btn--full-width' : '',
580
+ this.loading ? 'svu-btn--loading' : '',
581
+ this.disabled ? 'svu-btn--disabled' : ''
582
+ ].filter(Boolean).join(' ');
583
+ }
584
+ handleClick(event) {
585
+ if (!this.disabled && !this.loading) {
586
+ this.onClick.emit(event);
587
+ }
588
+ }
589
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
590
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: ButtonComponent, isStandalone: true, selector: "app-button", inputs: { variant: "variant", size: "size", type: "type", disabled: "disabled", loading: "loading", fullWidth: "fullWidth", id: "id", ariaLabel: "ariaLabel" }, outputs: { onClick: "onClick" }, ngImport: i0, template: "<button\n [type]=\"type\"\n [class]=\"buttonClasses\"\n [disabled]=\"disabled || loading\"\n [id]=\"id\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-busy]=\"loading\"\n (click)=\"handleClick($event)\">\n\n <!-- Loading spinner -->\n <span *ngIf=\"loading\" class=\"svu-btn__spinner\">\n <svg class=\"svu-spinner\" viewBox=\"0 0 24 24\">\n <circle class=\"svu-spinner__circle\" cx=\"12\" cy=\"12\" r=\"10\" fill=\"none\" stroke-width=\"3\"></circle>\n </svg>\n </span>\n\n <!-- Content -->\n <span [class.svu-btn__content--hidden]=\"loading\" class=\"svu-btn__content\">\n <ng-content></ng-content>\n </span>\n</button>", styles: [".svu-btn{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:.5rem;font-family:Quicksand,sans-serif;font-weight:600;border:none;border-radius:8px;cursor:pointer;transition:all .2s ease-in-out;outline:none!important;text-decoration:none;white-space:nowrap;width:100%}.svu-btn:focus-visible{outline:2px solid transparent;outline-offset:2px}.svu-btn--small{padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem;height:inherit}.svu-btn--medium{padding:.75rem 1.5rem;font-size:1rem;line-height:1.5rem}.svu-btn--large{padding:1rem 2rem;font-size:1.125rem;line-height:1.75rem}.svu-btn--full-width{width:100%}.svu-btn--primary{background:#364b9f;color:#fff}.svu-btn--primary:hover:not(:disabled):not(.btn--loading){background:#2a3b7f;transform:translateY(-1px);box-shadow:0 4px 12px #364b9f4d}.svu-btn--primary:active:not(:disabled):not(.btn--loading){transform:translateY(0);background:#1f2d5f}.svu-btn--primary:focus-visible{box-shadow:0 0 0 3px #364b9f4d}.svu-btn--secondary{background:#f3f4f6;color:#374151}.svu-btn--secondary:hover:not(:disabled):not(.btn--loading){background:#e5e7eb;transform:translateY(-1px);box-shadow:0 4px 12px #0000001a}.svu-btn--secondary:active:not(:disabled):not(.btn--loading){transform:translateY(0)}.svu-btn--secondary:focus-visible{box-shadow:0 0 0 3px #37415133}.svu-btn--outline{background:transparent;color:#364b9f;border:1px solid #364B9F}.svu-btn--outline:hover:not(:disabled):not(.btn--loading){background:#364b9f0d;border-color:#2a3b7f;color:#2a3b7f;transform:translateY(-1px)}.svu-btn--outline:active:not(:disabled):not(.btn--loading){transform:translateY(0);background:#364b9f1a}.svu-btn--outline:focus-visible{box-shadow:0 0 0 3px #364b9f33}.svu-btn--ghost{background:transparent;color:#364b9f}.svu-btn--ghost:hover:not(:disabled):not(.btn--loading){background:#364b9f1a;transform:translateY(-1px)}.svu-btn--ghost:active:not(:disabled):not(.btn--loading){transform:translateY(0);background:#364b9f26}.svu-btn--ghost:focus-visible{box-shadow:0 0 0 3px #364b9f33}.svu-btn--danger{background:linear-gradient(135deg,#ef4444,#dc2626);color:#fff}.svu-btn--danger:hover:not(:disabled):not(.btn--loading){background:linear-gradient(135deg,#dc2626,#b91c1c);transform:translateY(-1px);box-shadow:0 4px 12px #ef44444d}.svu-btn--danger:active:not(:disabled):not(.btn--loading){transform:translateY(0)}.svu-btn--danger:focus-visible{box-shadow:0 0 0 3px #ef44444d}.svu-btn--success{background:linear-gradient(135deg,#10b981,#059669);color:#fff}.svu-btn--success:hover:not(:disabled):not(.btn--loading){background:linear-gradient(135deg,#059669,#047857);transform:translateY(-1px);box-shadow:0 4px 12px #10b9814d}.svu-btn--success:active:not(:disabled):not(.btn--loading){transform:translateY(0)}.svu-btn--success:focus-visible{box-shadow:0 0 0 3px #10b9814d}.svu-btn:disabled,.svu-btn--disabled{opacity:.5;cursor:not-allowed;transform:none!important;box-shadow:none!important}.svu-btn--loading{cursor:wait;pointer-events:none}.svu-btn__spinner{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);display:flex;align-items:center;justify-content:center}.svu-btn__content{display:flex;align-items:center;gap:.5rem}.svu-btn__content--hidden{visibility:hidden}.svu-spinner{width:1.25rem;height:1.25rem;animation:svu-spin .8s linear infinite}.svu-spinner__circle{stroke:currentColor;stroke-dasharray:50;stroke-dashoffset:25;stroke-linecap:round;animation:svu-spinner-dash 1.5s ease-in-out infinite}@keyframes svu-spin{to{transform:rotate(360deg)}}@keyframes svu-spinner-dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:90,150;stroke-dashoffset:-124}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
591
+ }
592
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ButtonComponent, decorators: [{
593
+ type: Component,
594
+ args: [{ selector: 'app-button', standalone: true, imports: [CommonModule], template: "<button\n [type]=\"type\"\n [class]=\"buttonClasses\"\n [disabled]=\"disabled || loading\"\n [id]=\"id\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-busy]=\"loading\"\n (click)=\"handleClick($event)\">\n\n <!-- Loading spinner -->\n <span *ngIf=\"loading\" class=\"svu-btn__spinner\">\n <svg class=\"svu-spinner\" viewBox=\"0 0 24 24\">\n <circle class=\"svu-spinner__circle\" cx=\"12\" cy=\"12\" r=\"10\" fill=\"none\" stroke-width=\"3\"></circle>\n </svg>\n </span>\n\n <!-- Content -->\n <span [class.svu-btn__content--hidden]=\"loading\" class=\"svu-btn__content\">\n <ng-content></ng-content>\n </span>\n</button>", styles: [".svu-btn{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:.5rem;font-family:Quicksand,sans-serif;font-weight:600;border:none;border-radius:8px;cursor:pointer;transition:all .2s ease-in-out;outline:none!important;text-decoration:none;white-space:nowrap;width:100%}.svu-btn:focus-visible{outline:2px solid transparent;outline-offset:2px}.svu-btn--small{padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem;height:inherit}.svu-btn--medium{padding:.75rem 1.5rem;font-size:1rem;line-height:1.5rem}.svu-btn--large{padding:1rem 2rem;font-size:1.125rem;line-height:1.75rem}.svu-btn--full-width{width:100%}.svu-btn--primary{background:#364b9f;color:#fff}.svu-btn--primary:hover:not(:disabled):not(.btn--loading){background:#2a3b7f;transform:translateY(-1px);box-shadow:0 4px 12px #364b9f4d}.svu-btn--primary:active:not(:disabled):not(.btn--loading){transform:translateY(0);background:#1f2d5f}.svu-btn--primary:focus-visible{box-shadow:0 0 0 3px #364b9f4d}.svu-btn--secondary{background:#f3f4f6;color:#374151}.svu-btn--secondary:hover:not(:disabled):not(.btn--loading){background:#e5e7eb;transform:translateY(-1px);box-shadow:0 4px 12px #0000001a}.svu-btn--secondary:active:not(:disabled):not(.btn--loading){transform:translateY(0)}.svu-btn--secondary:focus-visible{box-shadow:0 0 0 3px #37415133}.svu-btn--outline{background:transparent;color:#364b9f;border:1px solid #364B9F}.svu-btn--outline:hover:not(:disabled):not(.btn--loading){background:#364b9f0d;border-color:#2a3b7f;color:#2a3b7f;transform:translateY(-1px)}.svu-btn--outline:active:not(:disabled):not(.btn--loading){transform:translateY(0);background:#364b9f1a}.svu-btn--outline:focus-visible{box-shadow:0 0 0 3px #364b9f33}.svu-btn--ghost{background:transparent;color:#364b9f}.svu-btn--ghost:hover:not(:disabled):not(.btn--loading){background:#364b9f1a;transform:translateY(-1px)}.svu-btn--ghost:active:not(:disabled):not(.btn--loading){transform:translateY(0);background:#364b9f26}.svu-btn--ghost:focus-visible{box-shadow:0 0 0 3px #364b9f33}.svu-btn--danger{background:linear-gradient(135deg,#ef4444,#dc2626);color:#fff}.svu-btn--danger:hover:not(:disabled):not(.btn--loading){background:linear-gradient(135deg,#dc2626,#b91c1c);transform:translateY(-1px);box-shadow:0 4px 12px #ef44444d}.svu-btn--danger:active:not(:disabled):not(.btn--loading){transform:translateY(0)}.svu-btn--danger:focus-visible{box-shadow:0 0 0 3px #ef44444d}.svu-btn--success{background:linear-gradient(135deg,#10b981,#059669);color:#fff}.svu-btn--success:hover:not(:disabled):not(.btn--loading){background:linear-gradient(135deg,#059669,#047857);transform:translateY(-1px);box-shadow:0 4px 12px #10b9814d}.svu-btn--success:active:not(:disabled):not(.btn--loading){transform:translateY(0)}.svu-btn--success:focus-visible{box-shadow:0 0 0 3px #10b9814d}.svu-btn:disabled,.svu-btn--disabled{opacity:.5;cursor:not-allowed;transform:none!important;box-shadow:none!important}.svu-btn--loading{cursor:wait;pointer-events:none}.svu-btn__spinner{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);display:flex;align-items:center;justify-content:center}.svu-btn__content{display:flex;align-items:center;gap:.5rem}.svu-btn__content--hidden{visibility:hidden}.svu-spinner{width:1.25rem;height:1.25rem;animation:svu-spin .8s linear infinite}.svu-spinner__circle{stroke:currentColor;stroke-dasharray:50;stroke-dashoffset:25;stroke-linecap:round;animation:svu-spinner-dash 1.5s ease-in-out infinite}@keyframes svu-spin{to{transform:rotate(360deg)}}@keyframes svu-spinner-dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:90,150;stroke-dashoffset:-124}}\n"] }]
595
+ }], propDecorators: { variant: [{
596
+ type: Input
597
+ }], size: [{
598
+ type: Input
599
+ }], type: [{
600
+ type: Input
601
+ }], disabled: [{
602
+ type: Input
603
+ }], loading: [{
604
+ type: Input
605
+ }], fullWidth: [{
606
+ type: Input
607
+ }], id: [{
608
+ type: Input
609
+ }], ariaLabel: [{
610
+ type: Input
611
+ }], onClick: [{
612
+ type: Output
613
+ }] } });
614
+
615
+ class InputComponent {
616
+ cdr;
617
+ label = '';
618
+ id = '';
619
+ placeholder = '';
620
+ type = 'text';
621
+ maxLength;
622
+ hasError = false;
623
+ errorMessage = '';
624
+ disabled = false;
625
+ readonly = false;
626
+ format = 'alphanumeric';
627
+ unstyled = false; // Para usar dentro de componentes compuestos
628
+ value = '';
629
+ formattedValue = '';
630
+ onChange = () => { };
631
+ onTouched = () => { };
632
+ constructor(cdr) {
633
+ this.cdr = cdr;
634
+ }
635
+ writeValue(value) {
636
+ let processedValue = value || '';
637
+ // For currency format, enforce maxLength on the raw value (without commas)
638
+ if (this.format === 'currency' && this.maxLength) {
639
+ const rawValue = String(processedValue).replace(/[^0-9.]/g, '');
640
+ if (rawValue.length > this.maxLength) {
641
+ processedValue = rawValue.slice(0, this.maxLength);
642
+ }
643
+ }
644
+ // For number inputs, enforce maxLength on initial value
645
+ if (this.type === 'number' && this.maxLength && String(processedValue).length > this.maxLength) {
646
+ processedValue = String(processedValue).slice(0, this.maxLength);
647
+ }
648
+ this.value = processedValue;
649
+ this.formattedValue = this.applyFormat(this.value);
650
+ this.cdr.markForCheck();
651
+ }
652
+ registerOnChange(fn) {
653
+ this.onChange = fn;
654
+ }
655
+ registerOnTouched(fn) {
656
+ this.onTouched = fn;
657
+ }
658
+ setDisabledState(isDisabled) {
659
+ this.disabled = isDisabled;
660
+ this.cdr.markForCheck();
661
+ }
662
+ onInputChange(event) {
663
+ const target = event.target;
664
+ let inputValue = target.value;
665
+ // Parse the value first (removes formatting like commas)
666
+ let rawValue = this.parseValue(inputValue);
667
+ // For currency format, enforce maxLength on the raw value (without commas)
668
+ if (this.format === 'currency' && this.maxLength && String(rawValue).length > this.maxLength) {
669
+ rawValue = String(rawValue).slice(0, this.maxLength);
670
+ }
671
+ // For number inputs or numeric format, maxLength doesn't work natively, so we handle it manually
672
+ if ((this.type === 'number' || this.format === 'numeric') && this.maxLength) {
673
+ // Check the length of the raw value (without formatting)
674
+ const rawString = String(rawValue);
675
+ if (rawString.length > this.maxLength) {
676
+ rawValue = rawString.slice(0, this.maxLength);
677
+ // Update the input value to reflect the truncation
678
+ target.value = rawValue;
679
+ }
680
+ }
681
+ this.value = rawValue;
682
+ this.formattedValue = this.applyFormat(rawValue);
683
+ // Update the input display (for formatted inputs like currency)
684
+ if (this.format === 'currency') {
685
+ target.value = this.formattedValue;
686
+ }
687
+ this.onChange(rawValue);
688
+ }
689
+ onBlur() {
690
+ this.onTouched();
691
+ }
692
+ parseValue(value) {
693
+ switch (this.format) {
694
+ case 'currency':
695
+ // Remove all non-numeric characters except decimal point
696
+ return value.replace(/[^0-9.]/g, '');
697
+ case 'numeric':
698
+ // Remove all non-numeric characters (only digits allowed)
699
+ return value.replace(/[^0-9]/g, '');
700
+ case 'alphanumeric':
701
+ default:
702
+ return value;
703
+ }
704
+ }
705
+ applyFormat(value) {
706
+ if (!value && value !== 0)
707
+ return '';
708
+ switch (this.format) {
709
+ case 'currency':
710
+ return this.formatCurrency(value);
711
+ case 'alphanumeric':
712
+ default:
713
+ return String(value);
714
+ }
715
+ }
716
+ formatCurrency(value) {
717
+ const numValue = typeof value === 'string' ? parseFloat(value.replace(/[^0-9.]/g, '')) : value;
718
+ if (isNaN(numValue))
719
+ return '';
720
+ // Format with thousands separator
721
+ return numValue.toLocaleString('es-MX', {
722
+ minimumFractionDigits: 0,
723
+ maximumFractionDigits: 2
724
+ });
725
+ }
726
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: InputComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
727
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: InputComponent, isStandalone: true, selector: "app-input", inputs: { label: "label", id: "id", placeholder: "placeholder", type: "type", maxLength: "maxLength", hasError: "hasError", errorMessage: "errorMessage", disabled: "disabled", readonly: "readonly", format: "format", unstyled: "unstyled" }, providers: [
728
+ {
729
+ provide: NG_VALUE_ACCESSOR,
730
+ useExisting: forwardRef(() => InputComponent),
731
+ multi: true
732
+ }
733
+ ], ngImport: i0, template: `
734
+ <div class="input-wrapper" [class.input-wrapper--unstyled]="unstyled">
735
+ <label *ngIf="label && !unstyled" [for]="id">{{ label }}</label>
736
+ <div class="input-container" [class.error]="hasError && !unstyled" [class.input-container--unstyled]="unstyled">
737
+ <div class="input-prefix-wrapper">
738
+ <ng-content select="[prefix]"></ng-content>
739
+ </div>
740
+ <input
741
+ noLeadingSpace
742
+ [type]="type"
743
+ [id]="id"
744
+ [placeholder]="placeholder"
745
+ [attr.maxlength]="format === 'currency' ? null : maxLength"
746
+ [disabled]="disabled"
747
+ [readonly]="readonly"
748
+ class="input-field"
749
+ [class.error]="hasError && !unstyled"
750
+ [class.input-field--unstyled]="unstyled"
751
+ [value]="formattedValue"
752
+ (blur)="onBlur()"
753
+ (input)="onInputChange($event)">
754
+ <div class="input-suffix-wrapper">
755
+ <ng-content select="[suffix]"></ng-content>
756
+ </div>
757
+ </div>
758
+ <div *ngIf="hasError && errorMessage && !unstyled" class="field-error">
759
+ {{ errorMessage }}
760
+ </div>
761
+ </div>
762
+ `, isInline: true, styles: ["input:-webkit-autofill,input:-webkit-autofill:hover,input:-webkit-autofill:focus,input:-webkit-autofill:active{-webkit-box-shadow:0 0 0 30px white inset!important;box-shadow:0 0 0 30px #fff inset!important;-webkit-text-fill-color:#2E353A!important;transition:background-color 5000s ease-in-out 0s}.input-prefix-wrapper,.input-suffix-wrapper{flex-shrink:0;display:flex;align-items:center;gap:.5rem;font-family:Quicksand,sans-serif;font-size:14px;font-weight:500;color:#969a9c;position:relative;z-index:2;pointer-events:auto!important}.input-prefix-wrapper{margin-right:.5rem;&:empty{display:none;margin-right:0}}.input-suffix-wrapper{margin-left:.5rem;&:empty{display:none;margin-left:0}}.input-prefix-wrapper *,.input-suffix-wrapper *{pointer-events:auto!important}.input-field{position:relative;z-index:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: NoLeadingSpaceDirective, selector: "[noLeadingSpace]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
763
+ }
764
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: InputComponent, decorators: [{
765
+ type: Component,
766
+ args: [{ selector: 'app-input', standalone: true, imports: [CommonModule, ReactiveFormsModule, FormsModule, IconSourceDirective, NoLeadingSpaceDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: `
767
+ <div class="input-wrapper" [class.input-wrapper--unstyled]="unstyled">
768
+ <label *ngIf="label && !unstyled" [for]="id">{{ label }}</label>
769
+ <div class="input-container" [class.error]="hasError && !unstyled" [class.input-container--unstyled]="unstyled">
770
+ <div class="input-prefix-wrapper">
771
+ <ng-content select="[prefix]"></ng-content>
772
+ </div>
773
+ <input
774
+ noLeadingSpace
775
+ [type]="type"
776
+ [id]="id"
777
+ [placeholder]="placeholder"
778
+ [attr.maxlength]="format === 'currency' ? null : maxLength"
779
+ [disabled]="disabled"
780
+ [readonly]="readonly"
781
+ class="input-field"
782
+ [class.error]="hasError && !unstyled"
783
+ [class.input-field--unstyled]="unstyled"
784
+ [value]="formattedValue"
785
+ (blur)="onBlur()"
786
+ (input)="onInputChange($event)">
787
+ <div class="input-suffix-wrapper">
788
+ <ng-content select="[suffix]"></ng-content>
789
+ </div>
790
+ </div>
791
+ <div *ngIf="hasError && errorMessage && !unstyled" class="field-error">
792
+ {{ errorMessage }}
793
+ </div>
794
+ </div>
795
+ `, providers: [
796
+ {
797
+ provide: NG_VALUE_ACCESSOR,
798
+ useExisting: forwardRef(() => InputComponent),
799
+ multi: true
800
+ }
801
+ ], styles: ["input:-webkit-autofill,input:-webkit-autofill:hover,input:-webkit-autofill:focus,input:-webkit-autofill:active{-webkit-box-shadow:0 0 0 30px white inset!important;box-shadow:0 0 0 30px #fff inset!important;-webkit-text-fill-color:#2E353A!important;transition:background-color 5000s ease-in-out 0s}.input-prefix-wrapper,.input-suffix-wrapper{flex-shrink:0;display:flex;align-items:center;gap:.5rem;font-family:Quicksand,sans-serif;font-size:14px;font-weight:500;color:#969a9c;position:relative;z-index:2;pointer-events:auto!important}.input-prefix-wrapper{margin-right:.5rem;&:empty{display:none;margin-right:0}}.input-suffix-wrapper{margin-left:.5rem;&:empty{display:none;margin-left:0}}.input-prefix-wrapper *,.input-suffix-wrapper *{pointer-events:auto!important}.input-field{position:relative;z-index:1}\n"] }]
802
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { label: [{
803
+ type: Input
804
+ }], id: [{
805
+ type: Input
806
+ }], placeholder: [{
807
+ type: Input
808
+ }], type: [{
809
+ type: Input
810
+ }], maxLength: [{
811
+ type: Input
812
+ }], hasError: [{
813
+ type: Input
814
+ }], errorMessage: [{
815
+ type: Input
816
+ }], disabled: [{
817
+ type: Input
818
+ }], readonly: [{
819
+ type: Input
820
+ }], format: [{
821
+ type: Input
822
+ }], unstyled: [{
823
+ type: Input
824
+ }] } });
825
+
826
+ class TextareaComponent {
827
+ cdr;
828
+ label = '';
829
+ id = '';
830
+ placeholder = '';
831
+ rows = 4;
832
+ maxLength;
833
+ hasError = false;
834
+ errorMessage = '';
835
+ disabled = false;
836
+ readonly = false;
837
+ value = '';
838
+ onChange = () => { };
839
+ onTouched = () => { };
840
+ constructor(cdr) {
841
+ this.cdr = cdr;
842
+ }
843
+ writeValue(value) {
844
+ this.value = value || '';
845
+ this.cdr.markForCheck();
846
+ }
847
+ registerOnChange(fn) {
848
+ this.onChange = fn;
849
+ }
850
+ registerOnTouched(fn) {
851
+ this.onTouched = fn;
852
+ }
853
+ setDisabledState(isDisabled) {
854
+ this.disabled = isDisabled;
855
+ this.cdr.markForCheck();
856
+ }
857
+ onInputChange(event) {
858
+ const target = event.target;
859
+ this.value = target.value;
860
+ this.onChange(this.value);
861
+ }
862
+ onBlur() {
863
+ this.onTouched();
864
+ }
865
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TextareaComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
866
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: TextareaComponent, isStandalone: true, selector: "app-textarea", inputs: { label: "label", id: "id", placeholder: "placeholder", rows: "rows", maxLength: "maxLength", hasError: "hasError", errorMessage: "errorMessage", disabled: "disabled", readonly: "readonly" }, providers: [
867
+ {
868
+ provide: NG_VALUE_ACCESSOR,
869
+ useExisting: forwardRef(() => TextareaComponent),
870
+ multi: true
871
+ }
872
+ ], ngImport: i0, template: `
873
+ <div class="textarea-wrapper">
874
+ <label *ngIf="label" [for]="id" class="textarea-label">{{ label }}</label>
875
+ <div class="textarea-container" [class.error]="hasError">
876
+ <textarea
877
+ [id]="id"
878
+ [placeholder]="placeholder"
879
+ [rows]="rows"
880
+ [disabled]="disabled"
881
+ [readonly]="readonly"
882
+ [attr.maxlength]="maxLength"
883
+ class="textarea-field"
884
+ [class.error]="hasError"
885
+ [value]="value"
886
+ (blur)="onBlur()"
887
+ (input)="onInputChange($event)"
888
+ ></textarea>
889
+ </div>
890
+ <div *ngIf="hasError && errorMessage" class="field-error">
891
+ {{ errorMessage }}
892
+ </div>
893
+ </div>
894
+ `, isInline: true, styles: [".textarea-wrapper{width:100%;display:flex;flex-direction:column;gap:6px}.textarea-label{font-family:Quicksand,sans-serif;font-weight:500;font-size:14px;line-height:20px;color:#414651}.textarea-container{width:100%;&.error .textarea-field{border-color:#f04438}}.textarea-field{width:100%;padding:10px 14px;background:#fff;border:1px solid #D5D7DA;border-radius:8px;font-family:Quicksand,sans-serif;font-weight:400;font-size:16px;line-height:24px;color:#2e353a;resize:vertical;min-height:100px;transition:all .2s ease;box-sizing:border-box;&::placeholder{color:#a4a7ae}&:focus{outline:none;border-color:#f59100;box-shadow:0 0 0 4px #f591001a}&:disabled{background:#f9fafb;cursor:not-allowed}&.error{border-color:#f04438;&:focus{box-shadow:0 0 0 4px #f044381a}}}.field-error{color:#f04438;font-size:.875rem;font-family:Quicksand,sans-serif}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
895
+ }
896
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TextareaComponent, decorators: [{
897
+ type: Component,
898
+ args: [{ selector: 'app-textarea', standalone: true, imports: [CommonModule, ReactiveFormsModule, FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
899
+ <div class="textarea-wrapper">
900
+ <label *ngIf="label" [for]="id" class="textarea-label">{{ label }}</label>
901
+ <div class="textarea-container" [class.error]="hasError">
902
+ <textarea
903
+ [id]="id"
904
+ [placeholder]="placeholder"
905
+ [rows]="rows"
906
+ [disabled]="disabled"
907
+ [readonly]="readonly"
908
+ [attr.maxlength]="maxLength"
909
+ class="textarea-field"
910
+ [class.error]="hasError"
911
+ [value]="value"
912
+ (blur)="onBlur()"
913
+ (input)="onInputChange($event)"
914
+ ></textarea>
915
+ </div>
916
+ <div *ngIf="hasError && errorMessage" class="field-error">
917
+ {{ errorMessage }}
918
+ </div>
919
+ </div>
920
+ `, providers: [
921
+ {
922
+ provide: NG_VALUE_ACCESSOR,
923
+ useExisting: forwardRef(() => TextareaComponent),
924
+ multi: true
925
+ }
926
+ ], styles: [".textarea-wrapper{width:100%;display:flex;flex-direction:column;gap:6px}.textarea-label{font-family:Quicksand,sans-serif;font-weight:500;font-size:14px;line-height:20px;color:#414651}.textarea-container{width:100%;&.error .textarea-field{border-color:#f04438}}.textarea-field{width:100%;padding:10px 14px;background:#fff;border:1px solid #D5D7DA;border-radius:8px;font-family:Quicksand,sans-serif;font-weight:400;font-size:16px;line-height:24px;color:#2e353a;resize:vertical;min-height:100px;transition:all .2s ease;box-sizing:border-box;&::placeholder{color:#a4a7ae}&:focus{outline:none;border-color:#f59100;box-shadow:0 0 0 4px #f591001a}&:disabled{background:#f9fafb;cursor:not-allowed}&.error{border-color:#f04438;&:focus{box-shadow:0 0 0 4px #f044381a}}}.field-error{color:#f04438;font-size:.875rem;font-family:Quicksand,sans-serif}\n"] }]
927
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { label: [{
928
+ type: Input
929
+ }], id: [{
930
+ type: Input
931
+ }], placeholder: [{
932
+ type: Input
933
+ }], rows: [{
934
+ type: Input
935
+ }], maxLength: [{
936
+ type: Input
937
+ }], hasError: [{
938
+ type: Input
939
+ }], errorMessage: [{
940
+ type: Input
941
+ }], disabled: [{
942
+ type: Input
943
+ }], readonly: [{
944
+ type: Input
945
+ }] } });
946
+
947
+ class CheckboxComponent {
948
+ cdr;
949
+ elRef;
950
+ label = '';
951
+ id = '';
952
+ hasError = false;
953
+ errorMessage = '';
954
+ disabled = false;
955
+ indeterminate = false;
956
+ set checked(value) {
957
+ this.value = !!value;
958
+ this.cdr.markForCheck();
959
+ }
960
+ get checked() {
961
+ return this.value;
962
+ }
963
+ changed = new EventEmitter();
964
+ value = false;
965
+ onChange = () => { };
966
+ onTouched = () => { };
967
+ constructor(cdr, elRef) {
968
+ this.cdr = cdr;
969
+ this.elRef = elRef;
970
+ }
971
+ ngAfterViewInit() {
972
+ this.updateNativeIndeterminate();
973
+ }
974
+ ngOnChanges(changes) {
975
+ if (changes['indeterminate']) {
976
+ this.updateNativeIndeterminate();
977
+ }
978
+ }
979
+ updateNativeIndeterminate() {
980
+ const input = this.elRef.nativeElement.querySelector('input[type="checkbox"]');
981
+ if (input)
982
+ input.indeterminate = this.indeterminate;
983
+ }
984
+ onCheckboxChange(event) {
985
+ const target = event.target;
986
+ this.value = target.checked;
987
+ this.onChange(this.value);
988
+ this.changed.emit(this.value); // ← EMITE EVENTO MANUAL PARA USO EXTERNO
989
+ this.cdr.markForCheck();
990
+ }
991
+ onTextClick(event) {
992
+ const target = event.target;
993
+ if (target.tagName === 'A' || target.closest('a')) {
994
+ return;
995
+ }
996
+ if (this.disabled) {
997
+ return;
998
+ }
999
+ this.value = !this.value;
1000
+ this.onChange(this.value);
1001
+ this.changed.emit(this.value);
1002
+ this.cdr.markForCheck();
1003
+ }
1004
+ writeValue(value) {
1005
+ this.value = !!value;
1006
+ this.cdr.markForCheck();
1007
+ }
1008
+ registerOnChange(fn) {
1009
+ this.onChange = fn;
1010
+ }
1011
+ registerOnTouched(fn) {
1012
+ this.onTouched = fn;
1013
+ }
1014
+ setDisabledState(isDisabled) {
1015
+ this.disabled = isDisabled;
1016
+ this.cdr.markForCheck();
1017
+ }
1018
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CheckboxComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
1019
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: CheckboxComponent, isStandalone: true, selector: "app-checkbox", inputs: { label: "label", id: "id", hasError: "hasError", errorMessage: "errorMessage", disabled: "disabled", indeterminate: "indeterminate", checked: "checked" }, outputs: { changed: "changed" }, providers: [
1020
+ {
1021
+ provide: NG_VALUE_ACCESSOR,
1022
+ useExisting: forwardRef(() => CheckboxComponent),
1023
+ multi: true
1024
+ }
1025
+ ], usesOnChanges: true, ngImport: i0, template: `
1026
+ <div class="checkbox-wrapper" [class.disabled]="disabled">
1027
+ <div class="checkbox-container">
1028
+ <label [for]="id" class="checkbox-label-input">
1029
+ <input
1030
+ type="checkbox"
1031
+ [id]="id"
1032
+ [disabled]="disabled"
1033
+ [checked]="value"
1034
+ (blur)="onTouched()"
1035
+ (change)="onCheckboxChange($event)">
1036
+ <span class="checkbox-custom" [class.checked]="value" [class.indeterminate]="indeterminate">
1037
+ <!-- Paloma -->
1038
+ <svg *ngIf="value && !indeterminate" class="check-icon" width="14" height="10" viewBox="0 0 10 8" fill="none" xmlns="http://www.w3.org/2000/svg">
1039
+ <path d="M9 1L3.5 6.5L1 4" stroke="#F59100" stroke-width="1.6666" stroke-linecap="round" stroke-linejoin="round"/>
1040
+ </svg>
1041
+ <!-- Guion -->
1042
+ <svg *ngIf="indeterminate && !value" class="minus-icon" width="12" height="2" viewBox="0 0 12 2" fill="none" xmlns="http://www.w3.org/2000/svg">
1043
+ <rect width="12" height="2" rx="1" fill="#F59100"/>
1044
+ </svg>
1045
+ </span>
1046
+ </label>
1047
+ <span class="checkbox-text" (click)="onTextClick($event)">
1048
+ <ng-content></ng-content>
1049
+ <span *ngIf="label" [innerHTML]="label"></span>
1050
+ </span>
1051
+ </div>
1052
+ <div *ngIf="hasError && errorMessage" class="field-error">
1053
+ {{ errorMessage }}
1054
+ </div>
1055
+ </div>
1056
+ `, isInline: true, styles: [".checkbox-wrapper{width:100%;padding:0 4px}.checkbox-wrapper.disabled{opacity:.6;cursor:not-allowed}.checkbox-container{display:flex;align-items:flex-start;gap:.75rem}.checkbox-label-input{cursor:pointer;position:relative;display:flex;align-items:center}.checkbox-label-input input[type=checkbox]{position:absolute;opacity:0;cursor:pointer;width:22px;height:22px;margin:0;z-index:2;top:2px;left:0}.checkbox-label-input .checkbox-custom{width:22px;height:22px;min-width:22px;border:2.5px solid #D5D7D8;border-radius:6px;display:flex;align-items:center;justify-content:center;transition:all .25s cubic-bezier(.4,0,.2,1);background:#fff;margin-top:2px;position:relative}.checkbox-label-input .checkbox-custom:after{content:\"\";position:absolute;width:100%;height:100%;border-radius:4px;background:#f59100;opacity:0;transform:scale(.5);transition:all .25s cubic-bezier(.4,0,.2,1)}.checkbox-label-input .checkbox-custom.checked,.checkbox-label-input .checkbox-custom.indeterminate{background:#fff;border-color:#f59100;border-width:2.5px;box-shadow:0 3px 8px #f26d0040,0 1px 3px #f26d0026;transform:scale(1.05)}.checkbox-label-input .checkbox-custom.checked:after,.checkbox-label-input .checkbox-custom.indeterminate:after{opacity:0}.checkbox-label-input .checkbox-custom .check-icon{position:relative;z-index:1;display:flex;align-items:center;justify-content:center;animation:checkPop .3s cubic-bezier(.68,-.55,.265,1.55)}.checkbox-label-input:hover .checkbox-custom:not(.checked){border-color:#f26d00;transform:scale(1.05)}.checkbox-text{flex:1;font-family:Quicksand,sans-serif;font-size:14px;font-weight:500;line-height:1.7;-webkit-user-select:none;user-select:none;cursor:pointer}.checkbox-text ::ng-deep a{color:#364b9f;font-family:Quicksand,sans-serif;font-size:14px;font-weight:500;line-height:1.7;cursor:pointer}.checkbox-wrapper.disabled .checkbox-text{cursor:not-allowed}@keyframes checkPop{0%{transform:scale(0);opacity:0}50%{transform:scale(1.2)}to{transform:scale(1);opacity:1}}.field-error{color:#f04438;font-size:.875rem;margin-top:.25rem;font-family:Quicksand,sans-serif}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: FormsModule }] });
1057
+ }
1058
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CheckboxComponent, decorators: [{
1059
+ type: Component,
1060
+ args: [{ selector: 'app-checkbox', standalone: true, imports: [CommonModule, ReactiveFormsModule, FormsModule], template: `
1061
+ <div class="checkbox-wrapper" [class.disabled]="disabled">
1062
+ <div class="checkbox-container">
1063
+ <label [for]="id" class="checkbox-label-input">
1064
+ <input
1065
+ type="checkbox"
1066
+ [id]="id"
1067
+ [disabled]="disabled"
1068
+ [checked]="value"
1069
+ (blur)="onTouched()"
1070
+ (change)="onCheckboxChange($event)">
1071
+ <span class="checkbox-custom" [class.checked]="value" [class.indeterminate]="indeterminate">
1072
+ <!-- Paloma -->
1073
+ <svg *ngIf="value && !indeterminate" class="check-icon" width="14" height="10" viewBox="0 0 10 8" fill="none" xmlns="http://www.w3.org/2000/svg">
1074
+ <path d="M9 1L3.5 6.5L1 4" stroke="#F59100" stroke-width="1.6666" stroke-linecap="round" stroke-linejoin="round"/>
1075
+ </svg>
1076
+ <!-- Guion -->
1077
+ <svg *ngIf="indeterminate && !value" class="minus-icon" width="12" height="2" viewBox="0 0 12 2" fill="none" xmlns="http://www.w3.org/2000/svg">
1078
+ <rect width="12" height="2" rx="1" fill="#F59100"/>
1079
+ </svg>
1080
+ </span>
1081
+ </label>
1082
+ <span class="checkbox-text" (click)="onTextClick($event)">
1083
+ <ng-content></ng-content>
1084
+ <span *ngIf="label" [innerHTML]="label"></span>
1085
+ </span>
1086
+ </div>
1087
+ <div *ngIf="hasError && errorMessage" class="field-error">
1088
+ {{ errorMessage }}
1089
+ </div>
1090
+ </div>
1091
+ `, providers: [
1092
+ {
1093
+ provide: NG_VALUE_ACCESSOR,
1094
+ useExisting: forwardRef(() => CheckboxComponent),
1095
+ multi: true
1096
+ }
1097
+ ], styles: [".checkbox-wrapper{width:100%;padding:0 4px}.checkbox-wrapper.disabled{opacity:.6;cursor:not-allowed}.checkbox-container{display:flex;align-items:flex-start;gap:.75rem}.checkbox-label-input{cursor:pointer;position:relative;display:flex;align-items:center}.checkbox-label-input input[type=checkbox]{position:absolute;opacity:0;cursor:pointer;width:22px;height:22px;margin:0;z-index:2;top:2px;left:0}.checkbox-label-input .checkbox-custom{width:22px;height:22px;min-width:22px;border:2.5px solid #D5D7D8;border-radius:6px;display:flex;align-items:center;justify-content:center;transition:all .25s cubic-bezier(.4,0,.2,1);background:#fff;margin-top:2px;position:relative}.checkbox-label-input .checkbox-custom:after{content:\"\";position:absolute;width:100%;height:100%;border-radius:4px;background:#f59100;opacity:0;transform:scale(.5);transition:all .25s cubic-bezier(.4,0,.2,1)}.checkbox-label-input .checkbox-custom.checked,.checkbox-label-input .checkbox-custom.indeterminate{background:#fff;border-color:#f59100;border-width:2.5px;box-shadow:0 3px 8px #f26d0040,0 1px 3px #f26d0026;transform:scale(1.05)}.checkbox-label-input .checkbox-custom.checked:after,.checkbox-label-input .checkbox-custom.indeterminate:after{opacity:0}.checkbox-label-input .checkbox-custom .check-icon{position:relative;z-index:1;display:flex;align-items:center;justify-content:center;animation:checkPop .3s cubic-bezier(.68,-.55,.265,1.55)}.checkbox-label-input:hover .checkbox-custom:not(.checked){border-color:#f26d00;transform:scale(1.05)}.checkbox-text{flex:1;font-family:Quicksand,sans-serif;font-size:14px;font-weight:500;line-height:1.7;-webkit-user-select:none;user-select:none;cursor:pointer}.checkbox-text ::ng-deep a{color:#364b9f;font-family:Quicksand,sans-serif;font-size:14px;font-weight:500;line-height:1.7;cursor:pointer}.checkbox-wrapper.disabled .checkbox-text{cursor:not-allowed}@keyframes checkPop{0%{transform:scale(0);opacity:0}50%{transform:scale(1.2)}to{transform:scale(1);opacity:1}}.field-error{color:#f04438;font-size:.875rem;margin-top:.25rem;font-family:Quicksand,sans-serif}\n"] }]
1098
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }], propDecorators: { label: [{
1099
+ type: Input
1100
+ }], id: [{
1101
+ type: Input
1102
+ }], hasError: [{
1103
+ type: Input
1104
+ }], errorMessage: [{
1105
+ type: Input
1106
+ }], disabled: [{
1107
+ type: Input
1108
+ }], indeterminate: [{
1109
+ type: Input
1110
+ }], checked: [{
1111
+ type: Input
1112
+ }], changed: [{
1113
+ type: Output
1114
+ }] } });
1115
+
1116
+ class RadioComponent {
1117
+ cdr;
1118
+ label = '';
1119
+ id = '';
1120
+ name = '';
1121
+ radioValue = '';
1122
+ disabled = false;
1123
+ changed = new EventEmitter();
1124
+ value = null;
1125
+ onChange = () => { };
1126
+ onTouched = () => { };
1127
+ constructor(cdr) {
1128
+ this.cdr = cdr;
1129
+ }
1130
+ get isSelected() {
1131
+ return this.value === this.radioValue;
1132
+ }
1133
+ onContainerClick() {
1134
+ if (this.disabled)
1135
+ return;
1136
+ this.value = this.radioValue;
1137
+ this.onChange(this.value);
1138
+ this.changed.emit(this.value);
1139
+ this.cdr.markForCheck();
1140
+ }
1141
+ onRadioChange(event) {
1142
+ event.stopPropagation();
1143
+ const target = event.target;
1144
+ if (target.checked) {
1145
+ this.value = this.radioValue;
1146
+ this.onChange(this.value);
1147
+ this.changed.emit(this.value);
1148
+ this.cdr.markForCheck();
1149
+ }
1150
+ }
1151
+ writeValue(value) {
1152
+ this.value = value;
1153
+ this.cdr.markForCheck();
1154
+ }
1155
+ registerOnChange(fn) {
1156
+ this.onChange = fn;
1157
+ }
1158
+ registerOnTouched(fn) {
1159
+ this.onTouched = fn;
1160
+ }
1161
+ setDisabledState(isDisabled) {
1162
+ this.disabled = isDisabled;
1163
+ this.cdr.markForCheck();
1164
+ }
1165
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RadioComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1166
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: RadioComponent, isStandalone: true, selector: "app-radio", inputs: { label: "label", id: "id", name: "name", radioValue: "radioValue", disabled: "disabled" }, outputs: { changed: "changed" }, providers: [
1167
+ {
1168
+ provide: NG_VALUE_ACCESSOR,
1169
+ useExisting: forwardRef(() => RadioComponent),
1170
+ multi: true
1171
+ }
1172
+ ], ngImport: i0, template: `
1173
+ <div
1174
+ class="radio-wrapper"
1175
+ [class.disabled]="disabled"
1176
+ [class.radio-wrapper--selected]="isSelected"
1177
+ (click)="onContainerClick()"
1178
+ >
1179
+ <div class="radio-container">
1180
+ <input
1181
+ type="radio"
1182
+ [id]="id"
1183
+ [name]="name"
1184
+ [value]="radioValue"
1185
+ [disabled]="disabled"
1186
+ [checked]="isSelected"
1187
+ (blur)="onTouched()"
1188
+ (change)="onRadioChange($event)"
1189
+ class="radio-input"
1190
+ />
1191
+ <span class="radio-custom" [class.checked]="isSelected">
1192
+ <span class="radio-dot" *ngIf="isSelected"></span>
1193
+ </span>
1194
+ <span class="radio-text">
1195
+ <ng-content></ng-content>
1196
+ <span *ngIf="label">{{ label }}</span>
1197
+ </span>
1198
+ </div>
1199
+ </div>
1200
+ `, isInline: true, styles: [":host{display:block;outline:none!important}:host:focus,:host:focus-visible,:host:focus-within{outline:none!important;box-shadow:none!important}.radio-wrapper{cursor:pointer;outline:none!important;box-shadow:none!important}.radio-wrapper:focus,.radio-wrapper:focus-visible,.radio-wrapper:focus-within{outline:none!important;box-shadow:none!important}.radio-wrapper.disabled{opacity:.6;cursor:not-allowed;pointer-events:none}.radio-wrapper--selected .radio-custom{border-color:#f59100}.radio-container{display:flex;align-items:center;gap:12px;padding:0;background:transparent;border:none;outline:none!important;box-shadow:none!important}.radio-container:focus,.radio-container:focus-visible,.radio-container:focus-within{outline:none!important;box-shadow:none!important}.radio-container:hover .radio-custom:not(.checked){border-color:#f59100}.radio-input{position:absolute;opacity:0;pointer-events:none;width:0;height:0;margin:0;padding:0;border:none!important;outline:none!important;box-shadow:none!important}.radio-input:focus,.radio-input:focus-visible,.radio-input:checked{outline:none!important;box-shadow:none!important;border:none!important}.radio-custom{width:20px;height:20px;min-width:20px;border:2px solid #D5D7DA;border-radius:50%;display:flex;align-items:center;justify-content:center;transition:border-color .2s ease;background:#fff;flex-shrink:0;outline:none!important;box-shadow:none!important}.radio-custom.checked{border-color:#f59100}.radio-custom .radio-dot{width:10px;height:10px;border-radius:50%;background:#f59100}.radio-text{font-family:Quicksand,sans-serif;font-size:16px;font-weight:500;line-height:24px;color:#585d61;-webkit-user-select:none;user-select:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: FormsModule }] });
1201
+ }
1202
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RadioComponent, decorators: [{
1203
+ type: Component,
1204
+ args: [{ selector: 'app-radio', standalone: true, imports: [CommonModule, ReactiveFormsModule, FormsModule], template: `
1205
+ <div
1206
+ class="radio-wrapper"
1207
+ [class.disabled]="disabled"
1208
+ [class.radio-wrapper--selected]="isSelected"
1209
+ (click)="onContainerClick()"
1210
+ >
1211
+ <div class="radio-container">
1212
+ <input
1213
+ type="radio"
1214
+ [id]="id"
1215
+ [name]="name"
1216
+ [value]="radioValue"
1217
+ [disabled]="disabled"
1218
+ [checked]="isSelected"
1219
+ (blur)="onTouched()"
1220
+ (change)="onRadioChange($event)"
1221
+ class="radio-input"
1222
+ />
1223
+ <span class="radio-custom" [class.checked]="isSelected">
1224
+ <span class="radio-dot" *ngIf="isSelected"></span>
1225
+ </span>
1226
+ <span class="radio-text">
1227
+ <ng-content></ng-content>
1228
+ <span *ngIf="label">{{ label }}</span>
1229
+ </span>
1230
+ </div>
1231
+ </div>
1232
+ `, providers: [
1233
+ {
1234
+ provide: NG_VALUE_ACCESSOR,
1235
+ useExisting: forwardRef(() => RadioComponent),
1236
+ multi: true
1237
+ }
1238
+ ], styles: [":host{display:block;outline:none!important}:host:focus,:host:focus-visible,:host:focus-within{outline:none!important;box-shadow:none!important}.radio-wrapper{cursor:pointer;outline:none!important;box-shadow:none!important}.radio-wrapper:focus,.radio-wrapper:focus-visible,.radio-wrapper:focus-within{outline:none!important;box-shadow:none!important}.radio-wrapper.disabled{opacity:.6;cursor:not-allowed;pointer-events:none}.radio-wrapper--selected .radio-custom{border-color:#f59100}.radio-container{display:flex;align-items:center;gap:12px;padding:0;background:transparent;border:none;outline:none!important;box-shadow:none!important}.radio-container:focus,.radio-container:focus-visible,.radio-container:focus-within{outline:none!important;box-shadow:none!important}.radio-container:hover .radio-custom:not(.checked){border-color:#f59100}.radio-input{position:absolute;opacity:0;pointer-events:none;width:0;height:0;margin:0;padding:0;border:none!important;outline:none!important;box-shadow:none!important}.radio-input:focus,.radio-input:focus-visible,.radio-input:checked{outline:none!important;box-shadow:none!important;border:none!important}.radio-custom{width:20px;height:20px;min-width:20px;border:2px solid #D5D7DA;border-radius:50%;display:flex;align-items:center;justify-content:center;transition:border-color .2s ease;background:#fff;flex-shrink:0;outline:none!important;box-shadow:none!important}.radio-custom.checked{border-color:#f59100}.radio-custom .radio-dot{width:10px;height:10px;border-radius:50%;background:#f59100}.radio-text{font-family:Quicksand,sans-serif;font-size:16px;font-weight:500;line-height:24px;color:#585d61;-webkit-user-select:none;user-select:none}\n"] }]
1239
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { label: [{
1240
+ type: Input
1241
+ }], id: [{
1242
+ type: Input
1243
+ }], name: [{
1244
+ type: Input
1245
+ }], radioValue: [{
1246
+ type: Input
1247
+ }], disabled: [{
1248
+ type: Input
1249
+ }], changed: [{
1250
+ type: Output
1251
+ }] } });
1252
+
1253
+ class DatePickerComponent {
1254
+ renderer;
1255
+ document;
1256
+ label = '';
1257
+ id = '';
1258
+ placeholder = 'Seleccionar fecha';
1259
+ hasError = false;
1260
+ errorMessage = '';
1261
+ disabled = false;
1262
+ minDate;
1263
+ maxDate;
1264
+ rangeMode = false; // false = single date, true = date range
1265
+ iconPosition = 'left';
1266
+ trigger;
1267
+ dropdown;
1268
+ // Single date value
1269
+ singleValue = null;
1270
+ // Range value
1271
+ rangeValue = { startDate: null, endDate: null };
1272
+ isOpen = false;
1273
+ onChange = () => { };
1274
+ onTouched = () => { };
1275
+ leftMonthDate = new Date();
1276
+ rightMonthDate = new Date();
1277
+ tempStartDate = null;
1278
+ tempEndDate = null;
1279
+ tempSingleDate = null;
1280
+ hoverDate = null;
1281
+ // Store original calendar positions for cancel
1282
+ originalLeftMonthDate = new Date();
1283
+ originalRightMonthDate = new Date();
1284
+ // Cached calendar days
1285
+ leftCalendarDays = [];
1286
+ rightCalendarDays = [];
1287
+ filterOptions = [
1288
+ { value: 'hoy', label: 'Hoy' },
1289
+ { value: 'ayer', label: 'Ayer' },
1290
+ { value: 'esta-semana', label: 'Esta semana' },
1291
+ { value: 'semana-pasada', label: 'Semana pasada' },
1292
+ { value: 'este-mes', label: 'Este mes' },
1293
+ { value: 'mes-pasado', label: 'Mes pasado' },
1294
+ { value: 'este-ano', label: 'Este año' },
1295
+ { value: 'ano-pasado', label: 'Año pasado' },
1296
+ { value: 'mostrar-todo', label: 'Mostrar todo' }
1297
+ ];
1298
+ selectedFilter = '';
1299
+ weekDays = ['Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sa', 'Do'];
1300
+ months = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'];
1301
+ // Month/Year picker state
1302
+ showLeftMonthPicker = false;
1303
+ showRightMonthPicker = false;
1304
+ years = [];
1305
+ leftYearPickerPage = 0;
1306
+ rightYearPickerPage = 0;
1307
+ yearsPerPage = 12;
1308
+ scrollHandler = null;
1309
+ resizeHandler = null;
1310
+ dropdownPosition = { top: '0px', left: '0px' };
1311
+ constructor(renderer, document) {
1312
+ this.renderer = renderer;
1313
+ this.document = document;
1314
+ }
1315
+ ngOnInit() {
1316
+ this.initializeDates();
1317
+ }
1318
+ ngOnDestroy() {
1319
+ this.removeRepositionListeners();
1320
+ }
1321
+ initializeDates() {
1322
+ const today = new Date();
1323
+ this.leftMonthDate = new Date(today.getFullYear(), today.getMonth(), 1);
1324
+ this.rightMonthDate = new Date(today.getFullYear(), today.getMonth() + 1, 1);
1325
+ this.updateCalendarDays();
1326
+ }
1327
+ updateCalendarDays() {
1328
+ this.leftCalendarDays = this.generateCalendarDays(this.leftMonthDate);
1329
+ if (this.rangeMode) {
1330
+ this.rightCalendarDays = this.generateCalendarDays(this.rightMonthDate);
1331
+ }
1332
+ }
1333
+ onDocumentClick(event) {
1334
+ if (!this.isOpen)
1335
+ return;
1336
+ const triggerElement = this.trigger?.nativeElement;
1337
+ const dropdownElement = this.document.querySelector('.date-picker-dropdown');
1338
+ const monthYearPickers = this.document.querySelectorAll('.month-year-picker');
1339
+ const monthYearButtons = this.document.querySelectorAll('.month-year');
1340
+ let isOnMonthYearButton = false;
1341
+ monthYearButtons.forEach(button => {
1342
+ if (button.contains(event.target)) {
1343
+ isOnMonthYearButton = true;
1344
+ }
1345
+ });
1346
+ let isInsideMonthYearPicker = false;
1347
+ monthYearPickers.forEach(picker => {
1348
+ if (picker.contains(event.target)) {
1349
+ isInsideMonthYearPicker = true;
1350
+ }
1351
+ });
1352
+ if (isOnMonthYearButton || isInsideMonthYearPicker) {
1353
+ return;
1354
+ }
1355
+ if (dropdownElement && dropdownElement.contains(event.target)) {
1356
+ this.showLeftMonthPicker = false;
1357
+ this.showRightMonthPicker = false;
1358
+ return;
1359
+ }
1360
+ if (triggerElement && !triggerElement.contains(event.target)) {
1361
+ if (dropdownElement && !dropdownElement.contains(event.target)) {
1362
+ this.closeDropdown();
1363
+ }
1364
+ }
1365
+ }
1366
+ toggleDropdown(event) {
1367
+ event.stopPropagation();
1368
+ if (this.disabled)
1369
+ return;
1370
+ if (this.isOpen) {
1371
+ this.closeDropdown();
1372
+ }
1373
+ else {
1374
+ this.openDropdown();
1375
+ }
1376
+ }
1377
+ openDropdown() {
1378
+ if (!this.trigger)
1379
+ return;
1380
+ if (this.rangeMode) {
1381
+ this.tempStartDate = this.rangeValue.startDate;
1382
+ this.tempEndDate = this.rangeValue.endDate;
1383
+ }
1384
+ else {
1385
+ this.tempSingleDate = this.singleValue;
1386
+ }
1387
+ this.originalLeftMonthDate = new Date(this.leftMonthDate);
1388
+ this.originalRightMonthDate = new Date(this.rightMonthDate);
1389
+ this.leftYearPickerPage = 0;
1390
+ this.rightYearPickerPage = 0;
1391
+ this.isOpen = true;
1392
+ setTimeout(() => {
1393
+ this.updateDropdownPosition();
1394
+ this.addRepositionListeners();
1395
+ }, 0);
1396
+ }
1397
+ getDropdownStyle() {
1398
+ if (!this.trigger)
1399
+ return {};
1400
+ const position = this.calculatePosition();
1401
+ return {
1402
+ 'position': 'fixed',
1403
+ 'left': position.left,
1404
+ 'top': position.top,
1405
+ 'z-index': '10000'
1406
+ };
1407
+ }
1408
+ calculatePosition() {
1409
+ const triggerElement = this.trigger.nativeElement;
1410
+ const rect = triggerElement.getBoundingClientRect();
1411
+ let dropdownWidth = this.rangeMode ? 830 : 320;
1412
+ let dropdownHeight = this.rangeMode ? 520 : 400;
1413
+ if (this.dropdown) {
1414
+ const dropdownElement = this.dropdown.nativeElement;
1415
+ const dropdownRect = dropdownElement.getBoundingClientRect();
1416
+ if (dropdownRect.width > 0) {
1417
+ dropdownWidth = dropdownRect.width;
1418
+ }
1419
+ else {
1420
+ dropdownWidth = window.innerWidth < 768 ? 280 : (this.rangeMode ? 830 : 320);
1421
+ }
1422
+ if (dropdownRect.height > 0) {
1423
+ dropdownHeight = dropdownRect.height;
1424
+ }
1425
+ }
1426
+ else {
1427
+ dropdownWidth = window.innerWidth < 768 ? 280 : (this.rangeMode ? 830 : 320);
1428
+ }
1429
+ const spaceOnRight = window.innerWidth - rect.left;
1430
+ let left = rect.left;
1431
+ if (spaceOnRight < dropdownWidth) {
1432
+ left = rect.right - dropdownWidth;
1433
+ if (left < 0) {
1434
+ left = Math.max(8, window.innerWidth - dropdownWidth - 8);
1435
+ }
1436
+ }
1437
+ if (window.innerWidth < 768) {
1438
+ const centeredLeft = rect.left + (rect.width / 2) - (dropdownWidth / 2);
1439
+ const minLeft = 8;
1440
+ const maxLeft = window.innerWidth - dropdownWidth - 8;
1441
+ left = Math.max(minLeft, Math.min(centeredLeft, maxLeft));
1442
+ }
1443
+ const spaceBelow = window.innerHeight - rect.bottom;
1444
+ const spaceAbove = rect.top;
1445
+ let top = rect.bottom + 4;
1446
+ if (spaceBelow < dropdownHeight && spaceAbove > spaceBelow) {
1447
+ top = rect.top - dropdownHeight - 4;
1448
+ }
1449
+ return {
1450
+ top: `${top}px`,
1451
+ left: `${left}px`
1452
+ };
1453
+ }
1454
+ closeDropdown() {
1455
+ this.leftMonthDate = new Date(this.originalLeftMonthDate);
1456
+ this.rightMonthDate = new Date(this.originalRightMonthDate);
1457
+ if (this.rangeMode) {
1458
+ this.tempStartDate = this.rangeValue.startDate;
1459
+ this.tempEndDate = this.rangeValue.endDate;
1460
+ }
1461
+ else {
1462
+ this.tempSingleDate = this.singleValue;
1463
+ }
1464
+ this.updateCalendarDays();
1465
+ this.removeRepositionListeners();
1466
+ this.isOpen = false;
1467
+ this.hoverDate = null;
1468
+ this.showLeftMonthPicker = false;
1469
+ this.showRightMonthPicker = false;
1470
+ }
1471
+ addRepositionListeners() {
1472
+ const scrollHandler = () => this.updateDropdownPosition();
1473
+ const resizeHandler = () => this.updateDropdownPosition();
1474
+ window.addEventListener('scroll', scrollHandler, true);
1475
+ this.scrollHandler = () => window.removeEventListener('scroll', scrollHandler, true);
1476
+ window.addEventListener('resize', resizeHandler);
1477
+ this.resizeHandler = () => window.removeEventListener('resize', resizeHandler);
1478
+ }
1479
+ removeRepositionListeners() {
1480
+ if (this.scrollHandler) {
1481
+ this.scrollHandler();
1482
+ this.scrollHandler = null;
1483
+ }
1484
+ if (this.resizeHandler) {
1485
+ this.resizeHandler();
1486
+ this.resizeHandler = null;
1487
+ }
1488
+ }
1489
+ updateDropdownPosition() {
1490
+ if (!this.trigger)
1491
+ return;
1492
+ this.dropdownPosition = this.calculatePosition();
1493
+ }
1494
+ getDisplayValue() {
1495
+ if (this.rangeMode) {
1496
+ if (this.rangeValue.startDate && this.rangeValue.endDate) {
1497
+ const start = this.formatDateShort(this.rangeValue.startDate);
1498
+ const end = this.formatDateShort(this.rangeValue.endDate);
1499
+ return `${start} - ${end}`;
1500
+ }
1501
+ }
1502
+ else {
1503
+ if (this.singleValue) {
1504
+ return this.formatDateShort(this.singleValue);
1505
+ }
1506
+ }
1507
+ return '';
1508
+ }
1509
+ formatDateShort(date) {
1510
+ const day = String(date.getDate()).padStart(2, '0');
1511
+ const month = String(date.getMonth() + 1).padStart(2, '0');
1512
+ const year = date.getFullYear();
1513
+ return `${day}/${month}/${year}`;
1514
+ }
1515
+ generateCalendarDays(monthDate) {
1516
+ const year = monthDate.getFullYear();
1517
+ const month = monthDate.getMonth();
1518
+ const firstDay = new Date(year, month, 1);
1519
+ const lastDay = new Date(year, month + 1, 0);
1520
+ let startDay = firstDay.getDay() - 1;
1521
+ if (startDay === -1)
1522
+ startDay = 6;
1523
+ const days = [];
1524
+ const prevMonthLastDay = new Date(year, month, 0);
1525
+ for (let i = startDay - 1; i >= 0; i--) {
1526
+ const date = new Date(year, month - 1, prevMonthLastDay.getDate() - i);
1527
+ date.setHours(0, 0, 0, 0);
1528
+ days.push(this.createCalendarDay(date, false));
1529
+ }
1530
+ for (let day = 1; day <= lastDay.getDate(); day++) {
1531
+ const date = new Date(year, month, day);
1532
+ date.setHours(0, 0, 0, 0);
1533
+ days.push(this.createCalendarDay(date, true));
1534
+ }
1535
+ const remainingDays = 42 - days.length;
1536
+ for (let day = 1; day <= remainingDays; day++) {
1537
+ const date = new Date(year, month + 1, day);
1538
+ date.setHours(0, 0, 0, 0);
1539
+ days.push(this.createCalendarDay(date, false));
1540
+ }
1541
+ return days;
1542
+ }
1543
+ createCalendarDay(date, isCurrentMonth) {
1544
+ const today = new Date();
1545
+ today.setHours(0, 0, 0, 0);
1546
+ const dateOnly = new Date(date);
1547
+ dateOnly.setHours(0, 0, 0, 0);
1548
+ const isToday = dateOnly.getTime() === today.getTime();
1549
+ let isSelected = false;
1550
+ let isRangeStart = false;
1551
+ let isRangeEnd = false;
1552
+ let isInRange = false;
1553
+ if (this.rangeMode) {
1554
+ const startDate = this.tempStartDate ? new Date(this.tempStartDate) : null;
1555
+ const endDate = this.tempEndDate ? new Date(this.tempEndDate) : null;
1556
+ if (startDate)
1557
+ startDate.setHours(0, 0, 0, 0);
1558
+ if (endDate)
1559
+ endDate.setHours(0, 0, 0, 0);
1560
+ isRangeStart = isCurrentMonth && startDate ? dateOnly.getTime() === startDate.getTime() : false;
1561
+ isRangeEnd = isCurrentMonth && endDate ? dateOnly.getTime() === endDate.getTime() : false;
1562
+ isSelected = isRangeStart || isRangeEnd;
1563
+ if (isCurrentMonth && startDate && endDate) {
1564
+ isInRange = dateOnly > startDate && dateOnly < endDate;
1565
+ }
1566
+ else if (isCurrentMonth && startDate && this.hoverDate && !endDate) {
1567
+ const hoverDateOnly = new Date(this.hoverDate);
1568
+ hoverDateOnly.setHours(0, 0, 0, 0);
1569
+ if (hoverDateOnly > startDate) {
1570
+ isInRange = dateOnly > startDate && dateOnly < hoverDateOnly;
1571
+ }
1572
+ }
1573
+ }
1574
+ else {
1575
+ const selectedDate = this.tempSingleDate ? new Date(this.tempSingleDate) : null;
1576
+ if (selectedDate)
1577
+ selectedDate.setHours(0, 0, 0, 0);
1578
+ isSelected = isCurrentMonth && selectedDate ? dateOnly.getTime() === selectedDate.getTime() : false;
1579
+ }
1580
+ const isDisabled = !isCurrentMonth || this.isDateDisabled(date);
1581
+ return {
1582
+ date,
1583
+ isCurrentMonth,
1584
+ isToday,
1585
+ isSelected,
1586
+ isInRange,
1587
+ isRangeStart,
1588
+ isRangeEnd,
1589
+ isDisabled
1590
+ };
1591
+ }
1592
+ isDateDisabled(date) {
1593
+ if (this.minDate && date < this.minDate)
1594
+ return true;
1595
+ if (this.maxDate && date > this.maxDate)
1596
+ return true;
1597
+ return false;
1598
+ }
1599
+ trackByDate(index, day) {
1600
+ return day.date.getTime().toString();
1601
+ }
1602
+ isInRange(date) {
1603
+ if (!this.rangeMode)
1604
+ return false;
1605
+ const dateOnly = new Date(date);
1606
+ dateOnly.setHours(0, 0, 0, 0);
1607
+ const startDate = this.tempStartDate ? new Date(this.tempStartDate) : null;
1608
+ const endDate = this.tempEndDate ? new Date(this.tempEndDate) : null;
1609
+ if (startDate)
1610
+ startDate.setHours(0, 0, 0, 0);
1611
+ if (endDate)
1612
+ endDate.setHours(0, 0, 0, 0);
1613
+ if (startDate && endDate) {
1614
+ return dateOnly > startDate && dateOnly < endDate;
1615
+ }
1616
+ else if (startDate && this.hoverDate && !endDate) {
1617
+ const hoverDateOnly = new Date(this.hoverDate);
1618
+ hoverDateOnly.setHours(0, 0, 0, 0);
1619
+ if (hoverDateOnly > startDate) {
1620
+ return dateOnly > startDate && dateOnly < hoverDateOnly;
1621
+ }
1622
+ }
1623
+ return false;
1624
+ }
1625
+ onDayClick(day) {
1626
+ if (day.isDisabled)
1627
+ return;
1628
+ const clickedDate = new Date(day.date);
1629
+ clickedDate.setHours(0, 0, 0, 0);
1630
+ if (this.rangeMode) {
1631
+ this.selectedFilter = '';
1632
+ if (!this.tempStartDate || (this.tempStartDate && this.tempEndDate)) {
1633
+ this.tempStartDate = clickedDate;
1634
+ this.tempEndDate = null;
1635
+ this.hoverDate = null;
1636
+ }
1637
+ else if (this.tempStartDate && !this.tempEndDate) {
1638
+ const startDate = new Date(this.tempStartDate);
1639
+ startDate.setHours(0, 0, 0, 0);
1640
+ if (clickedDate.getTime() === startDate.getTime()) {
1641
+ this.tempEndDate = clickedDate;
1642
+ }
1643
+ else if (clickedDate > startDate) {
1644
+ this.tempEndDate = clickedDate;
1645
+ }
1646
+ else {
1647
+ this.tempEndDate = startDate;
1648
+ this.tempStartDate = clickedDate;
1649
+ }
1650
+ this.hoverDate = null;
1651
+ }
1652
+ }
1653
+ else {
1654
+ this.tempSingleDate = clickedDate;
1655
+ // Auto-apply for single date mode
1656
+ this.apply();
1657
+ return;
1658
+ }
1659
+ this.updateCalendarDays();
1660
+ }
1661
+ onDayHover(day) {
1662
+ if (day.isDisabled || !this.rangeMode)
1663
+ return;
1664
+ this.hoverDate = day.date;
1665
+ }
1666
+ onDayLeave() {
1667
+ this.hoverDate = null;
1668
+ }
1669
+ previousMonth() {
1670
+ if (!this.canNavigatePreviousMonth())
1671
+ return;
1672
+ this.leftMonthDate = new Date(this.leftMonthDate.getFullYear(), this.leftMonthDate.getMonth() - 1, 1);
1673
+ if (this.rangeMode) {
1674
+ this.rightMonthDate = new Date(this.rightMonthDate.getFullYear(), this.rightMonthDate.getMonth() - 1, 1);
1675
+ }
1676
+ this.updateCalendarDays();
1677
+ }
1678
+ nextMonth() {
1679
+ if (!this.canNavigateNextMonth())
1680
+ return;
1681
+ this.leftMonthDate = new Date(this.leftMonthDate.getFullYear(), this.leftMonthDate.getMonth() + 1, 1);
1682
+ if (this.rangeMode) {
1683
+ this.rightMonthDate = new Date(this.rightMonthDate.getFullYear(), this.rightMonthDate.getMonth() + 1, 1);
1684
+ }
1685
+ this.updateCalendarDays();
1686
+ }
1687
+ canNavigatePreviousMonth() {
1688
+ if (!this.minDate)
1689
+ return true;
1690
+ const newLeftMonth = new Date(this.leftMonthDate.getFullYear(), this.leftMonthDate.getMonth() - 1, 1);
1691
+ const minDateMonth = new Date(this.minDate.getFullYear(), this.minDate.getMonth(), 1);
1692
+ return newLeftMonth >= minDateMonth;
1693
+ }
1694
+ canNavigateNextMonth() {
1695
+ if (!this.maxDate)
1696
+ return true;
1697
+ const checkMonth = this.rangeMode ? this.rightMonthDate : this.leftMonthDate;
1698
+ const newMonth = new Date(checkMonth.getFullYear(), checkMonth.getMonth() + 1, 1);
1699
+ const maxDateMonth = new Date(this.maxDate.getFullYear(), this.maxDate.getMonth(), 1);
1700
+ return newMonth <= maxDateMonth;
1701
+ }
1702
+ getMonthYear(date) {
1703
+ return `${this.months[date.getMonth()]} ${date.getFullYear()}`;
1704
+ }
1705
+ selectFilter(filter) {
1706
+ this.selectedFilter = filter;
1707
+ this.applyFilter(filter);
1708
+ this.updateCalendarDays();
1709
+ }
1710
+ applyFilter(filter) {
1711
+ const today = new Date();
1712
+ today.setHours(0, 0, 0, 0);
1713
+ let startDate = null;
1714
+ let endDate = null;
1715
+ switch (filter) {
1716
+ case 'hoy':
1717
+ startDate = new Date(today);
1718
+ endDate = new Date(today);
1719
+ break;
1720
+ case 'ayer':
1721
+ startDate = new Date(today);
1722
+ startDate.setDate(startDate.getDate() - 1);
1723
+ endDate = new Date(startDate);
1724
+ break;
1725
+ case 'esta-semana':
1726
+ startDate = this.getStartOfWeek(today);
1727
+ endDate = new Date(today);
1728
+ break;
1729
+ case 'semana-pasada':
1730
+ const lastWeekEnd = new Date(this.getStartOfWeek(today));
1731
+ lastWeekEnd.setDate(lastWeekEnd.getDate() - 1);
1732
+ startDate = this.getStartOfWeek(lastWeekEnd);
1733
+ endDate = lastWeekEnd;
1734
+ break;
1735
+ case 'este-mes':
1736
+ startDate = new Date(today.getFullYear(), today.getMonth(), 1);
1737
+ endDate = new Date(today);
1738
+ break;
1739
+ case 'mes-pasado':
1740
+ startDate = new Date(today.getFullYear(), today.getMonth() - 1, 1);
1741
+ endDate = new Date(today.getFullYear(), today.getMonth(), 0);
1742
+ break;
1743
+ case 'este-ano':
1744
+ startDate = new Date(today.getFullYear(), 0, 1);
1745
+ endDate = new Date(today);
1746
+ break;
1747
+ case 'ano-pasado':
1748
+ startDate = new Date(today.getFullYear() - 1, 0, 1);
1749
+ endDate = new Date(today.getFullYear() - 1, 11, 31);
1750
+ break;
1751
+ case 'mostrar-todo':
1752
+ startDate = null;
1753
+ endDate = null;
1754
+ break;
1755
+ }
1756
+ this.tempStartDate = startDate;
1757
+ this.tempEndDate = endDate;
1758
+ if (startDate) {
1759
+ this.leftMonthDate = new Date(startDate.getFullYear(), startDate.getMonth(), 1);
1760
+ this.rightMonthDate = new Date(startDate.getFullYear(), startDate.getMonth() + 1, 1);
1761
+ }
1762
+ else {
1763
+ const currentDate = new Date();
1764
+ this.leftMonthDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1);
1765
+ this.rightMonthDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1);
1766
+ }
1767
+ }
1768
+ getStartOfWeek(date) {
1769
+ const day = date.getDay();
1770
+ const diff = day === 0 ? -6 : 1 - day;
1771
+ const startOfWeek = new Date(date);
1772
+ startOfWeek.setDate(date.getDate() + diff);
1773
+ return startOfWeek;
1774
+ }
1775
+ cancel() {
1776
+ if (this.rangeMode) {
1777
+ this.tempStartDate = this.rangeValue.startDate;
1778
+ this.tempEndDate = this.rangeValue.endDate;
1779
+ }
1780
+ else {
1781
+ this.tempSingleDate = this.singleValue;
1782
+ }
1783
+ this.selectedFilter = '';
1784
+ this.leftMonthDate = new Date(this.originalLeftMonthDate);
1785
+ this.rightMonthDate = new Date(this.originalRightMonthDate);
1786
+ this.updateCalendarDays();
1787
+ this.closeDropdown();
1788
+ }
1789
+ apply() {
1790
+ if (this.rangeMode) {
1791
+ this.rangeValue = {
1792
+ startDate: this.tempStartDate,
1793
+ endDate: this.tempEndDate
1794
+ };
1795
+ this.onChange(this.rangeValue);
1796
+ }
1797
+ else {
1798
+ this.singleValue = this.tempSingleDate;
1799
+ this.onChange(this.singleValue);
1800
+ }
1801
+ this.originalLeftMonthDate = new Date(this.leftMonthDate);
1802
+ this.originalRightMonthDate = new Date(this.rightMonthDate);
1803
+ this.onTouched();
1804
+ this.removeRepositionListeners();
1805
+ this.isOpen = false;
1806
+ this.hoverDate = null;
1807
+ this.showLeftMonthPicker = false;
1808
+ this.showRightMonthPicker = false;
1809
+ }
1810
+ getStartDateDisplay() {
1811
+ if (this.tempStartDate) {
1812
+ return this.formatDateForInput(this.tempStartDate);
1813
+ }
1814
+ return 'Fecha inicio';
1815
+ }
1816
+ getEndDateDisplay() {
1817
+ if (this.tempEndDate) {
1818
+ return this.formatDateForInput(this.tempEndDate);
1819
+ }
1820
+ return 'Fecha fin';
1821
+ }
1822
+ formatDateForInput(date) {
1823
+ const day = date.getDate();
1824
+ const month = date.toLocaleString('es-ES', { month: 'short' });
1825
+ const year = date.getFullYear();
1826
+ return `${day} ${month} ${year}`;
1827
+ }
1828
+ toggleLeftMonthPicker(event) {
1829
+ event.stopPropagation();
1830
+ this.showLeftMonthPicker = !this.showLeftMonthPicker;
1831
+ this.showRightMonthPicker = false;
1832
+ if (this.showLeftMonthPicker) {
1833
+ this.leftYearPickerPage = 0;
1834
+ }
1835
+ }
1836
+ toggleRightMonthPicker(event) {
1837
+ event.stopPropagation();
1838
+ this.showRightMonthPicker = !this.showRightMonthPicker;
1839
+ this.showLeftMonthPicker = false;
1840
+ if (this.showRightMonthPicker) {
1841
+ this.rightYearPickerPage = 0;
1842
+ }
1843
+ }
1844
+ getLeftYears() {
1845
+ const currentYear = this.leftMonthDate.getFullYear();
1846
+ const baseYear = currentYear + (this.leftYearPickerPage * this.yearsPerPage);
1847
+ const years = [];
1848
+ for (let i = 0; i < this.yearsPerPage; i++) {
1849
+ const year = baseYear - 5 + i;
1850
+ years.push(year);
1851
+ }
1852
+ return years;
1853
+ }
1854
+ getRightYears() {
1855
+ const currentYear = this.rightMonthDate.getFullYear();
1856
+ const baseYear = currentYear + (this.rightYearPickerPage * this.yearsPerPage);
1857
+ const years = [];
1858
+ for (let i = 0; i < this.yearsPerPage; i++) {
1859
+ const year = baseYear - 5 + i;
1860
+ years.push(year);
1861
+ }
1862
+ return years;
1863
+ }
1864
+ previousLeftYearPage(event) {
1865
+ event.stopPropagation();
1866
+ this.leftYearPickerPage--;
1867
+ }
1868
+ nextLeftYearPage(event) {
1869
+ event.stopPropagation();
1870
+ this.leftYearPickerPage++;
1871
+ }
1872
+ previousRightYearPage(event) {
1873
+ event.stopPropagation();
1874
+ this.rightYearPickerPage--;
1875
+ }
1876
+ nextRightYearPage(event) {
1877
+ event.stopPropagation();
1878
+ this.rightYearPickerPage++;
1879
+ }
1880
+ isMonthDisabled(monthIndex, calendarDate) {
1881
+ const testDate = new Date(calendarDate.getFullYear(), monthIndex, 1);
1882
+ if (this.minDate) {
1883
+ const minDateMonth = new Date(this.minDate.getFullYear(), this.minDate.getMonth(), 1);
1884
+ if (testDate < minDateMonth)
1885
+ return true;
1886
+ }
1887
+ if (this.maxDate) {
1888
+ const maxDateMonth = new Date(this.maxDate.getFullYear(), this.maxDate.getMonth(), 1);
1889
+ if (testDate > maxDateMonth)
1890
+ return true;
1891
+ }
1892
+ return false;
1893
+ }
1894
+ isYearDisabled(year) {
1895
+ if (this.minDate && year < this.minDate.getFullYear())
1896
+ return true;
1897
+ if (this.maxDate && year > this.maxDate.getFullYear())
1898
+ return true;
1899
+ return false;
1900
+ }
1901
+ getLeftYearRangeLabel() {
1902
+ const years = this.getLeftYears();
1903
+ return `${years[0]} - ${years[years.length - 1]}`;
1904
+ }
1905
+ getRightYearRangeLabel() {
1906
+ const years = this.getRightYears();
1907
+ return `${years[0]} - ${years[years.length - 1]}`;
1908
+ }
1909
+ canNavigateLeftYearsPrevious() {
1910
+ if (!this.minDate && !this.maxDate)
1911
+ return true;
1912
+ const currentYear = this.leftMonthDate.getFullYear();
1913
+ const baseYear = currentYear + ((this.leftYearPickerPage - 1) * this.yearsPerPage);
1914
+ const previousPageYears = [];
1915
+ for (let i = 0; i < this.yearsPerPage; i++) {
1916
+ previousPageYears.push(baseYear - 5 + i);
1917
+ }
1918
+ return previousPageYears.some(year => !this.isYearDisabled(year));
1919
+ }
1920
+ canNavigateLeftYearsNext() {
1921
+ if (!this.minDate && !this.maxDate)
1922
+ return true;
1923
+ const currentYear = this.leftMonthDate.getFullYear();
1924
+ const baseYear = currentYear + ((this.leftYearPickerPage + 1) * this.yearsPerPage);
1925
+ const nextPageYears = [];
1926
+ for (let i = 0; i < this.yearsPerPage; i++) {
1927
+ nextPageYears.push(baseYear - 5 + i);
1928
+ }
1929
+ return nextPageYears.some(year => !this.isYearDisabled(year));
1930
+ }
1931
+ canNavigateRightYearsPrevious() {
1932
+ if (!this.minDate && !this.maxDate)
1933
+ return true;
1934
+ const currentYear = this.rightMonthDate.getFullYear();
1935
+ const baseYear = currentYear + ((this.rightYearPickerPage - 1) * this.yearsPerPage);
1936
+ const previousPageYears = [];
1937
+ for (let i = 0; i < this.yearsPerPage; i++) {
1938
+ previousPageYears.push(baseYear - 5 + i);
1939
+ }
1940
+ return previousPageYears.some(year => !this.isYearDisabled(year));
1941
+ }
1942
+ canNavigateRightYearsNext() {
1943
+ if (!this.minDate && !this.maxDate)
1944
+ return true;
1945
+ const currentYear = this.rightMonthDate.getFullYear();
1946
+ const baseYear = currentYear + ((this.rightYearPickerPage + 1) * this.yearsPerPage);
1947
+ const nextPageYears = [];
1948
+ for (let i = 0; i < this.yearsPerPage; i++) {
1949
+ nextPageYears.push(baseYear - 5 + i);
1950
+ }
1951
+ return nextPageYears.some(year => !this.isYearDisabled(year));
1952
+ }
1953
+ selectLeftMonth(monthIndex, event) {
1954
+ if (event) {
1955
+ event.stopPropagation();
1956
+ }
1957
+ this.leftMonthDate = new Date(this.leftMonthDate.getFullYear(), monthIndex, 1);
1958
+ if (this.rangeMode) {
1959
+ this.rightMonthDate = new Date(this.leftMonthDate.getFullYear(), monthIndex + 1, 1);
1960
+ }
1961
+ this.updateCalendarDays();
1962
+ this.showLeftMonthPicker = false;
1963
+ }
1964
+ selectRightMonth(monthIndex, event) {
1965
+ if (event) {
1966
+ event.stopPropagation();
1967
+ }
1968
+ this.rightMonthDate = new Date(this.rightMonthDate.getFullYear(), monthIndex, 1);
1969
+ this.leftMonthDate = new Date(this.rightMonthDate.getFullYear(), monthIndex - 1, 1);
1970
+ this.updateCalendarDays();
1971
+ this.showRightMonthPicker = false;
1972
+ }
1973
+ selectLeftYear(year, event) {
1974
+ if (event) {
1975
+ event.stopPropagation();
1976
+ }
1977
+ this.leftMonthDate = new Date(year, this.leftMonthDate.getMonth(), 1);
1978
+ if (this.rangeMode) {
1979
+ this.rightMonthDate = new Date(year, this.leftMonthDate.getMonth() + 1, 1);
1980
+ }
1981
+ this.updateCalendarDays();
1982
+ this.showLeftMonthPicker = false;
1983
+ }
1984
+ selectRightYear(year, event) {
1985
+ if (event) {
1986
+ event.stopPropagation();
1987
+ }
1988
+ this.rightMonthDate = new Date(year, this.rightMonthDate.getMonth(), 1);
1989
+ this.leftMonthDate = new Date(year, this.rightMonthDate.getMonth() - 1, 1);
1990
+ this.updateCalendarDays();
1991
+ this.showRightMonthPicker = false;
1992
+ }
1993
+ writeValue(value) {
1994
+ if (this.rangeMode) {
1995
+ const rangeVal = value;
1996
+ this.rangeValue = rangeVal || { startDate: null, endDate: null };
1997
+ this.tempStartDate = this.rangeValue.startDate;
1998
+ this.tempEndDate = this.rangeValue.endDate;
1999
+ }
2000
+ else {
2001
+ this.singleValue = value;
2002
+ this.tempSingleDate = this.singleValue;
2003
+ }
2004
+ }
2005
+ registerOnChange(fn) {
2006
+ this.onChange = fn;
2007
+ }
2008
+ registerOnTouched(fn) {
2009
+ this.onTouched = fn;
2010
+ }
2011
+ setDisabledState(isDisabled) {
2012
+ this.disabled = isDisabled;
2013
+ }
2014
+ resetDatePicker() {
2015
+ if (this.rangeMode) {
2016
+ this.rangeValue = { startDate: null, endDate: null };
2017
+ this.tempStartDate = null;
2018
+ this.tempEndDate = null;
2019
+ this.onChange(this.rangeValue);
2020
+ }
2021
+ else {
2022
+ this.singleValue = null;
2023
+ this.tempSingleDate = null;
2024
+ this.onChange(this.singleValue);
2025
+ }
2026
+ this.selectedFilter = '';
2027
+ this.initializeDates();
2028
+ this.updateCalendarDays();
2029
+ }
2030
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DatePickerComponent, deps: [{ token: i0.Renderer2 }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component });
2031
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: DatePickerComponent, isStandalone: true, selector: "app-date-picker", inputs: { label: "label", id: "id", placeholder: "placeholder", hasError: "hasError", errorMessage: "errorMessage", disabled: "disabled", minDate: "minDate", maxDate: "maxDate", rangeMode: "rangeMode", iconPosition: "iconPosition" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, providers: [
2032
+ {
2033
+ provide: NG_VALUE_ACCESSOR,
2034
+ useExisting: forwardRef(() => DatePickerComponent),
2035
+ multi: true
2036
+ }
2037
+ ], viewQueries: [{ propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true, read: ElementRef }, { propertyName: "dropdown", first: true, predicate: ["dropdown"], descendants: true, read: ElementRef }], ngImport: i0, template: "<div class=\"date-picker-wrapper\">\n <label *ngIf=\"label\" [for]=\"id\">{{ label }}</label>\n\n <div class=\"date-picker-container\">\n <div\n #trigger\n class=\"date-picker-input\"\n [class.error]=\"hasError\"\n [class.disabled]=\"disabled\"\n [class.open]=\"isOpen\"\n [class.icon-right]=\"iconPosition === 'right'\"\n (click)=\"toggleDropdown($event)\">\n\n <svg *ngIf=\"iconPosition === 'left'\" class=\"calendar-icon\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6.66667 1.66667V4.16667M13.3333 1.66667V4.16667M2.5 7.5H17.5M4.16667 3.33333H15.8333C16.7538 3.33333 17.5 4.07953 17.5 5V16.6667C17.5 17.5871 16.7538 18.3333 15.8333 18.3333H4.16667C3.24619 18.3333 2.5 17.5871 2.5 16.6667V5C2.5 4.07953 3.24619 3.33333 4.16667 3.33333Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n\n <span class=\"date-picker-placeholder\" *ngIf=\"!getDisplayValue()\">\n {{ placeholder }}\n </span>\n <span class=\"date-picker-value\" *ngIf=\"getDisplayValue()\">\n {{ getDisplayValue() }}\n </span>\n\n <svg *ngIf=\"iconPosition === 'right'\" class=\"calendar-icon\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6.66667 1.66667V4.16667M13.3333 1.66667V4.16667M2.5 7.5H17.5M4.16667 3.33333H15.8333C16.7538 3.33333 17.5 4.07953 17.5 5V16.6667C17.5 17.5871 16.7538 18.3333 15.8333 18.3333H4.16667C3.24619 18.3333 2.5 17.5871 2.5 16.6667V5C2.5 4.07953 3.24619 3.33333 4.16667 3.33333Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n </div>\n\n <div *ngIf=\"hasError && errorMessage\" class=\"field-error\">\n {{ errorMessage }}\n </div>\n</div>\n\n<!-- Dropdown content (rendered with fixed position) -->\n<div *ngIf=\"isOpen\" class=\"date-picker-overlay\">\n <div #dropdown class=\"date-picker-dropdown\" [class.open]=\"isOpen\" [class.range-mode]=\"rangeMode\" [ngStyle]=\"getDropdownStyle()\">\n <div class=\"date-picker-content\">\n <!-- Sidebar with filters (only for range mode) -->\n <div class=\"filter-sidebar\" *ngIf=\"rangeMode\">\n <div\n *ngFor=\"let option of filterOptions\"\n class=\"filter-option\"\n [class.active]=\"selectedFilter === option.value\"\n (click)=\"selectFilter(option.value)\">\n {{ option.label }}\n </div>\n </div>\n\n <!-- Main content (calendars + footer) -->\n <div class=\"date-picker-main\">\n <!-- Calendars -->\n <div class=\"calendars-container\">\n <!-- Left Calendar (or single calendar in single mode) -->\n <div class=\"calendar\">\n <div class=\"calendar-header\">\n <button\n type=\"button\"\n class=\"nav-button\"\n [disabled]=\"!canNavigatePreviousMonth()\"\n [class.disabled]=\"!canNavigatePreviousMonth()\"\n (click)=\"previousMonth()\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7.5 2L3.5 6L7.5 10\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n <div class=\"month-year-selector\">\n <button type=\"button\" class=\"month-year\" (click)=\"toggleLeftMonthPicker($event)\">\n {{ getMonthYear(leftMonthDate) }}\n </button>\n\n <!-- Month/Year Picker Dropdown -->\n <div class=\"month-year-picker\" *ngIf=\"showLeftMonthPicker\" (click)=\"$event.stopPropagation()\">\n <div class=\"picker-section\">\n <div class=\"picker-title\">Mes</div>\n <div class=\"months-grid\">\n <button\n type=\"button\"\n *ngFor=\"let month of months; let i = index\"\n class=\"month-option\"\n [class.active]=\"i === leftMonthDate.getMonth()\"\n [class.disabled]=\"isMonthDisabled(i, leftMonthDate)\"\n [disabled]=\"isMonthDisabled(i, leftMonthDate)\"\n (click)=\"selectLeftMonth(i, $event)\">\n {{ month.substring(0, 3) }}\n </button>\n </div>\n </div>\n <div class=\"picker-section\">\n <div class=\"picker-header\">\n <button\n type=\"button\"\n class=\"year-nav-button\"\n [disabled]=\"!canNavigateLeftYearsPrevious()\"\n [class.disabled]=\"!canNavigateLeftYearsPrevious()\"\n (click)=\"previousLeftYearPage($event)\">\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6.25 2.5L3.75 5L6.25 7.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n <div class=\"picker-title\">{{ getLeftYearRangeLabel() }}</div>\n <button\n type=\"button\"\n class=\"year-nav-button\"\n [disabled]=\"!canNavigateLeftYearsNext()\"\n [class.disabled]=\"!canNavigateLeftYearsNext()\"\n (click)=\"nextLeftYearPage($event)\">\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M3.75 2.5L6.25 5L3.75 7.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n </div>\n <div class=\"years-grid\">\n <button\n type=\"button\"\n *ngFor=\"let year of getLeftYears()\"\n class=\"year-option\"\n [class.active]=\"year === leftMonthDate.getFullYear()\"\n [class.disabled]=\"isYearDisabled(year)\"\n [disabled]=\"isYearDisabled(year)\"\n (click)=\"selectLeftYear(year, $event)\">\n {{ year }}\n </button>\n </div>\n </div>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"nav-button\"\n [disabled]=\"!canNavigateNextMonth()\"\n [class.disabled]=\"!canNavigateNextMonth()\"\n (click)=\"nextMonth()\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4.5 2L8.5 6L4.5 10\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n </div>\n\n <div class=\"calendar-grid\">\n <div class=\"weekday-header\" *ngFor=\"let day of weekDays\">\n {{ day }}\n </div>\n\n <div\n *ngFor=\"let day of leftCalendarDays; trackBy: trackByDate\"\n class=\"calendar-day\"\n [class.other-month]=\"!day.isCurrentMonth\"\n [class.today]=\"day.isToday\"\n [class.selected]=\"day.isSelected\"\n [class.in-range]=\"rangeMode && isInRange(day.date)\"\n [class.range-start]=\"day.isRangeStart\"\n [class.range-end]=\"day.isRangeEnd\"\n [class.disabled]=\"day.isDisabled\"\n (click)=\"onDayClick(day)\"\n (mouseenter)=\"onDayHover(day)\"\n (mouseleave)=\"onDayLeave()\">\n <span>{{ day.date.getDate() }}</span>\n </div>\n </div>\n </div>\n\n <!-- Right Calendar (only for range mode) -->\n <div class=\"calendar\" *ngIf=\"rangeMode\">\n <div class=\"calendar-header\">\n <div class=\"nav-button-placeholder\"></div>\n <div class=\"month-year-selector\">\n <button type=\"button\" class=\"month-year\" (click)=\"toggleRightMonthPicker($event)\">\n {{ getMonthYear(rightMonthDate) }}\n </button>\n\n <!-- Month/Year Picker Dropdown -->\n <div class=\"month-year-picker\" *ngIf=\"showRightMonthPicker\" (click)=\"$event.stopPropagation()\">\n <div class=\"picker-section\">\n <div class=\"picker-title\">Mes</div>\n <div class=\"months-grid\">\n <button\n type=\"button\"\n *ngFor=\"let month of months; let i = index\"\n class=\"month-option\"\n [class.active]=\"i === rightMonthDate.getMonth()\"\n [class.disabled]=\"isMonthDisabled(i, rightMonthDate)\"\n [disabled]=\"isMonthDisabled(i, rightMonthDate)\"\n (click)=\"selectRightMonth(i, $event)\">\n {{ month.substring(0, 3) }}\n </button>\n </div>\n </div>\n <div class=\"picker-section\">\n <div class=\"picker-header\">\n <button\n type=\"button\"\n class=\"year-nav-button\"\n [disabled]=\"!canNavigateRightYearsPrevious()\"\n [class.disabled]=\"!canNavigateRightYearsPrevious()\"\n (click)=\"previousRightYearPage($event)\">\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6.25 2.5L3.75 5L6.25 7.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n <div class=\"picker-title\">{{ getRightYearRangeLabel() }}</div>\n <button\n type=\"button\"\n class=\"year-nav-button\"\n [disabled]=\"!canNavigateRightYearsNext()\"\n [class.disabled]=\"!canNavigateRightYearsNext()\"\n (click)=\"nextRightYearPage($event)\">\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M3.75 2.5L6.25 5L3.75 7.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n </div>\n <div class=\"years-grid\">\n <button\n type=\"button\"\n *ngFor=\"let year of getRightYears()\"\n class=\"year-option\"\n [class.active]=\"year === rightMonthDate.getFullYear()\"\n [class.disabled]=\"isYearDisabled(year)\"\n [disabled]=\"isYearDisabled(year)\"\n (click)=\"selectRightYear(year, $event)\">\n {{ year }}\n </button>\n </div>\n </div>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"nav-button\"\n [disabled]=\"!canNavigateNextMonth()\"\n [class.disabled]=\"!canNavigateNextMonth()\"\n (click)=\"nextMonth()\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4.5 2L8.5 6L4.5 10\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n </div>\n\n <div class=\"calendar-grid\">\n <div class=\"weekday-header\" *ngFor=\"let day of weekDays\">\n {{ day }}\n </div>\n\n <div\n *ngFor=\"let day of rightCalendarDays; trackBy: trackByDate\"\n class=\"calendar-day\"\n [class.other-month]=\"!day.isCurrentMonth\"\n [class.today]=\"day.isToday\"\n [class.selected]=\"day.isSelected\"\n [class.in-range]=\"isInRange(day.date)\"\n [class.range-start]=\"day.isRangeStart\"\n [class.range-end]=\"day.isRangeEnd\"\n [class.disabled]=\"day.isDisabled\"\n (click)=\"onDayClick(day)\"\n (mouseenter)=\"onDayHover(day)\"\n (mouseleave)=\"onDayLeave()\">\n <span>{{ day.date.getDate() }}</span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Footer with dates and actions (only for range mode) -->\n <div class=\"footer\" *ngIf=\"rangeMode\">\n <div class=\"selected-dates\">\n <div class=\"date-display\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M5.33333 1.33333V3.33333M10.6667 1.33333V3.33333M2 6H14M3.33333 2.66667H12.6667C13.403 2.66667 14 3.26362 14 4V13.3333C14 14.0697 13.403 14.6667 12.6667 14.6667H3.33333C2.59695 14.6667 2 14.0697 2 13.3333V4C2 3.26362 2.59695 2.66667 3.33333 2.66667Z\" stroke=\"#6B7280\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"date-text\">{{ getStartDateDisplay() }}</span>\n </div>\n <span class=\"date-separator\">-</span>\n <div class=\"date-display\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M5.33333 1.33333V3.33333M10.6667 1.33333V3.33333M2 6H14M3.33333 2.66667H12.6667C13.403 2.66667 14 3.26362 14 4V13.3333C14 14.0697 13.403 14.6667 12.6667 14.6667H3.33333C2.59695 14.6667 2 14.0697 2 13.3333V4C2 3.26362 2.59695 2.66667 3.33333 2.66667Z\" stroke=\"#6B7280\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"date-text\">{{ getEndDateDisplay() }}</span>\n </div>\n </div>\n\n <div class=\"action-buttons\">\n <button type=\"button\" class=\"btn-cancel\" (click)=\"cancel()\">\n Cancelar\n </button>\n <button type=\"button\" class=\"btn-apply\" (click)=\"apply()\">\n Aplicar\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [".date-picker-wrapper{display:flex;flex-direction:column;width:100%;margin-bottom:6px;padding:0 4px}.date-picker-wrapper label{display:block;margin-bottom:.5rem;font-family:Quicksand,sans-serif;font-weight:500;font-size:14px;color:#585d61}.date-picker-container{position:relative;width:100%}.date-picker-input{display:flex;align-items:center;gap:.5rem;width:100%;min-height:44px;height:44px;padding:0 .75rem;border:1px solid #EAECF5;box-shadow:0 1px 2px #a1afec66;border-radius:8px;background:#fff;cursor:pointer;transition:all .2s ease;font-family:Quicksand,sans-serif}.date-picker-input:hover:not(.disabled){border-color:#fbd399}.date-picker-input.open{border-color:#fbd399;box-shadow:0 0 0 4px #ffe8c8,0 1px 2px #0a0d120d}.date-picker-input.error{border-color:#f04438}.date-picker-input.disabled{background:#f9fafb;cursor:not-allowed;opacity:.6}.date-picker-input .calendar-icon{color:#a4a7ae;flex-shrink:0}.date-picker-input .date-picker-placeholder{color:#a4a7ae;font-size:14px;flex:1}.date-picker-input .date-picker-value{color:#2e353a;font-size:14px;font-weight:500;flex:1}.field-error{color:#f04438;font-size:.875rem;margin-top:.25rem;font-family:Quicksand,sans-serif}.date-picker-overlay{position:fixed;inset:0;z-index:9999;pointer-events:none}.date-picker-dropdown{pointer-events:all;background:#fff;border-radius:12px;box-shadow:0 10px 40px #00000026;opacity:0;transform:translateY(-10px);transition:all .2s ease;overflow:visible}.date-picker-dropdown.open{opacity:1;transform:translateY(0)}.date-picker-content{display:flex;font-family:Quicksand,sans-serif;overflow:visible}.date-picker-main{display:flex;flex-direction:column;flex:1;overflow:visible}.filter-sidebar{padding:.5rem .8rem;min-width:170px;display:flex;flex-direction:column;border-right:1px solid #F3F4F6}.filter-sidebar .filter-option{font-family:Quicksand,sans-serif;padding:.625rem .8rem;color:#6b7280;cursor:pointer;transition:all .15s ease;white-space:nowrap;position:relative;font-weight:400;font-size:14px}.filter-sidebar .filter-option:hover:not(.active){background:#f9fafb}.filter-sidebar .filter-option.active{background:#fef4e6;color:#f7a733;font-weight:500;border-radius:6px}.calendars-container{display:flex;gap:3rem;padding:1rem;overflow:visible}.date-picker-dropdown:not(.range-mode) .calendars-container{gap:0;justify-content:center}.calendar{display:flex;flex-direction:column;gap:1rem;position:relative;overflow:visible}.calendar .calendar-header{display:flex;align-items:center;justify-content:space-between;padding:0 .25rem;margin-bottom:.5rem;position:relative;overflow:visible}.calendar .calendar-header .month-year-selector{position:relative;flex:1;display:flex;justify-content:center}.calendar .calendar-header .month-year{font-size:.9375rem;font-weight:600;color:#1f2937;min-width:160px;text-align:center;background:transparent;border:none;cursor:pointer;padding:.375rem .5rem;border-radius:6px;transition:all .15s ease}.calendar .calendar-header .month-year:hover{background:#f3f4f6}.calendar .calendar-header .nav-button{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;background:transparent;border-radius:6px;cursor:pointer;color:#6b7280;transition:all .15s ease;padding:0}.calendar .calendar-header .nav-button:hover:not(:disabled):not(.disabled){background:#f3f4f6;color:#1f2937}.calendar .calendar-header .nav-button.disabled,.calendar .calendar-header .nav-button:disabled{color:#d1d5db;cursor:not-allowed;opacity:.4}.calendar .calendar-header .nav-button svg{width:10px;height:10px}.calendar .calendar-header .nav-button-placeholder{width:28px;height:28px}.calendar .month-year-picker{position:absolute;top:100%;left:50%;transform:translate(-50%);margin-top:.5rem;background:#fff;border-radius:8px;box-shadow:0 10px 30px #0003;z-index:10002;padding:1rem;min-width:280px;border:1px solid #E5E7EB}.calendar .month-year-picker .picker-section{margin-bottom:1rem}.calendar .month-year-picker .picker-section:last-child{margin-bottom:0}.calendar .month-year-picker .picker-section .picker-title{font-size:.75rem;font-weight:600;color:#6b7280;text-transform:uppercase;letter-spacing:.5px;margin-bottom:.5rem}.calendar .month-year-picker .picker-section .picker-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:.5rem}.calendar .month-year-picker .picker-section .picker-header .picker-title{margin-bottom:0;font-size:.75rem;font-weight:600;color:#1f2937;text-transform:none;letter-spacing:0}.calendar .month-year-picker .picker-section .picker-header .year-nav-button{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border:none;background:transparent;border-radius:4px;cursor:pointer;color:#6b7280;transition:all .15s ease;padding:0}.calendar .month-year-picker .picker-section .picker-header .year-nav-button:hover:not(:disabled):not(.disabled){background:#f3f4f6;color:#1f2937}.calendar .month-year-picker .picker-section .picker-header .year-nav-button.disabled,.calendar .month-year-picker .picker-section .picker-header .year-nav-button:disabled{color:#d1d5db;cursor:not-allowed;opacity:.5}.calendar .month-year-picker .picker-section .picker-header .year-nav-button svg{width:10px;height:10px}.calendar .month-year-picker .months-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:.375rem}.calendar .month-year-picker .months-grid .month-option{padding:.5rem;border:1px solid #E5E7EB;background:#fff;border-radius:6px;font-size:.75rem;font-weight:500;color:#6b7280;cursor:pointer;transition:all .15s ease}.calendar .month-year-picker .months-grid .month-option:hover{background:#f9fafb;border-color:#d1d5db}.calendar .month-year-picker .months-grid .month-option.active{background:#f59100;color:#fff;border-color:#f59100}.calendar .month-year-picker .months-grid .month-option.disabled,.calendar .month-year-picker .months-grid .month-option:disabled{background:#f9fafb;color:#d1d5db;border-color:#e5e7eb;cursor:not-allowed;pointer-events:none}.calendar .month-year-picker .years-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:.375rem;max-height:200px;overflow-y:auto}.calendar .month-year-picker .years-grid .year-option{padding:.5rem;border:1px solid #E5E7EB;background:#fff;border-radius:6px;font-size:.75rem;font-weight:500;color:#6b7280;cursor:pointer;transition:all .15s ease}.calendar .month-year-picker .years-grid .year-option:hover{background:#f9fafb;border-color:#d1d5db}.calendar .month-year-picker .years-grid .year-option.active{background:#f59100;color:#fff;border-color:#f59100}.calendar .month-year-picker .years-grid .year-option.disabled,.calendar .month-year-picker .years-grid .year-option:disabled{background:#f9fafb;color:#d1d5db;border-color:#e5e7eb;cursor:not-allowed;pointer-events:none}.calendar .calendar-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:4px 0}.calendar .calendar-grid .weekday-header{display:flex;align-items:center;justify-content:center;font-size:.6875rem;font-weight:500;color:#9ca3af;padding:.5rem 0;text-transform:uppercase;letter-spacing:.5px}.calendar .calendar-grid .calendar-day{display:flex;align-items:center;justify-content:center;width:36px;height:36px;font-size:.8125rem;color:#1f2937;cursor:pointer;transition:all .15s ease;position:relative;font-weight:400;border-radius:0}.calendar .calendar-grid .calendar-day.other-month{color:#d1d5db}.calendar .calendar-grid .calendar-day.today{font-weight:600;color:#f59100;background:transparent}.calendar .calendar-grid .calendar-day.today:after{content:\"\";position:absolute;bottom:4px;left:50%;transform:translate(-50%);width:4px;height:4px;background:#f59100;border-radius:50%}.calendar .calendar-grid .calendar-day:hover:not(.disabled):not(.selected):not(.range-start):not(.range-end):not(.in-range){background:#fef4e6;border-radius:50%}.calendar .calendar-grid .calendar-day.in-range:hover:not(.disabled):not(.range-start):not(.range-end){position:relative;background:transparent}.calendar .calendar-grid .calendar-day.in-range:hover:not(.disabled):not(.range-start):not(.range-end):before{content:\"\";position:absolute;inset:0;background:#fef4e6;z-index:-1;border-radius:0}.calendar .calendar-grid .calendar-day.in-range:hover:not(.disabled):not(.range-start):not(.range-end):after{content:\"\";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:100%;height:100%;background:#fef4e6;border-radius:50%;z-index:0}.calendar .calendar-grid .calendar-day.in-range:hover:not(.disabled):not(.range-start):not(.range-end) span{position:relative;z-index:1;color:#f59100}.calendar .calendar-grid .calendar-day.in-range:not(.disabled):not(.range-start):not(.range-end){background:#fef4e6;color:#f59100;border-radius:0}.calendar .calendar-grid .calendar-day.in-range:not(.disabled):not(.range-start):not(.range-end):nth-child(7n+8){border-radius:50% 0 0 50%}.calendar .calendar-grid .calendar-day.in-range:not(.disabled):not(.range-start):not(.range-end):nth-child(7n+14){border-radius:0 50% 50% 0}.calendar .calendar-grid .calendar-day.in-range:not(.disabled):not(.range-start):not(.range-end):nth-child(7n+8):nth-child(7n+14){border-radius:50%}.calendar .calendar-grid .calendar-day.range-start:not(.disabled){position:relative;background:transparent;color:#fff;font-weight:600;z-index:2}.calendar .calendar-grid .calendar-day.range-start:not(.disabled):before{content:\"\";position:absolute;inset:0;background:#fef4e6;z-index:-1;border-radius:50% 0 0 50%}.calendar .calendar-grid .calendar-day.range-start:not(.disabled):after{content:\"\";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:100%;height:100%;background:#f59100;border-radius:50%;z-index:1}.calendar .calendar-grid .calendar-day.range-start:not(.disabled) span{position:relative;z-index:2}.calendar .calendar-grid .calendar-day.range-start:not(.disabled).range-end:before{border-radius:50%}.calendar .calendar-grid .calendar-day.range-end:not(.disabled){position:relative;background:transparent;color:#fff;font-weight:600;z-index:2}.calendar .calendar-grid .calendar-day.range-end:not(.disabled):before{content:\"\";position:absolute;inset:0;background:#fef4e6;z-index:-1;border-radius:0 50% 50% 0}.calendar .calendar-grid .calendar-day.range-end:not(.disabled):after{content:\"\";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:100%;height:100%;background:#f59100;border-radius:50%;z-index:1}.calendar .calendar-grid .calendar-day.range-end:not(.disabled) span{position:relative;z-index:2}.calendar .calendar-grid .calendar-day.range-end:not(.disabled).range-start:before{border-radius:50%}.calendar .calendar-grid .calendar-day.range-start.in-range:not(.disabled){position:relative}.calendar .calendar-grid .calendar-day.range-start.in-range:not(.disabled):before{content:\"\";position:absolute;inset:0 -2px 0 50%;background:#fef4e6;z-index:-1}.calendar .calendar-grid .calendar-day.range-end.in-range:not(.disabled){position:relative}.calendar .calendar-grid .calendar-day.range-end.in-range:not(.disabled):before{content:\"\";position:absolute;inset:0 50% 0 -2px;background:#fef4e6;z-index:-1}.calendar .calendar-grid .calendar-day.selected:not(.range-start):not(.range-end){background:#f59100;color:#fff;font-weight:600;border-radius:50%}.calendar .calendar-grid .calendar-day.disabled{color:#e5e7eb;cursor:not-allowed;pointer-events:none}.footer{display:flex;align-items:center;justify-content:space-between;padding:1rem;border-top:1px solid #E5E7EB}.footer .selected-dates{display:flex;align-items:center;gap:.75rem}.footer .selected-dates .date-display{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;background:#fff;border:1px solid #E5E7EB;border-radius:6px;font-size:.8125rem;color:#6b7280}.footer .selected-dates .date-display svg{flex-shrink:0;color:#9ca3af}.footer .selected-dates .date-display .date-text{font-weight:400;white-space:nowrap;-webkit-user-select:none;user-select:none}.footer .selected-dates .date-separator{color:#9ca3af;font-weight:400;font-size:.875rem}.footer .action-buttons{display:flex;gap:.75rem}.footer .action-buttons button{padding:.625rem 1.75rem;border-radius:8px;font-size:.875rem;font-weight:500;font-family:Quicksand,sans-serif;cursor:pointer;transition:all .15s ease;border:none;outline:none}.footer .action-buttons button:focus-visible{outline:2px solid rgba(245,145,0,.3);outline-offset:2px}.footer .action-buttons .btn-cancel{background:#fff;color:#6b7280;border:1px solid #D1D5DB}.footer .action-buttons .btn-cancel:hover{background:#f9fafb;border-color:#9ca3af}.footer .action-buttons .btn-apply{background:#f59100;color:#fff;border:1px solid #F59100}.footer .action-buttons .btn-apply:hover{background:#e08500;border-color:#e08500}.footer .action-buttons .btn-apply:active{background:#cc7a00;border-color:#cc7a00}@media (max-width: 768px){.date-picker-content{flex-direction:column}.filter-sidebar{display:none}.calendars-container{padding:.75rem;gap:0;justify-content:center}.calendars-container .calendar:last-child:not(:first-child){display:none}.calendar .calendar-header .month-year-selector{flex:1}.calendar .calendar-header .month-year{min-width:auto;font-size:.875rem;padding:.25rem .375rem}.calendar .calendar-header .nav-button{width:28px;height:28px}.calendar .calendar-header .nav-button svg{width:10px;height:10px}.calendar .calendar-header .nav-button-placeholder{display:none}.calendar .month-year-picker{min-width:240px;padding:.75rem}.calendar .month-year-picker .picker-section .picker-title{font-size:.7rem}.calendar .month-year-picker .months-grid{grid-template-columns:repeat(3,1fr);gap:.25rem}.calendar .month-year-picker .months-grid .month-option{padding:.4rem;font-size:.7rem}.calendar .month-year-picker .years-grid{grid-template-columns:repeat(3,1fr);gap:.25rem;max-height:150px}.calendar .month-year-picker .years-grid .year-option{padding:.4rem;font-size:.7rem}.calendar .calendar-grid{gap:2px 0}.calendar .calendar-grid .calendar-day{width:30px;height:30px;font-size:.75rem}.calendar .calendar-grid .weekday-header{font-size:.65rem}.footer{flex-direction:column;gap:.75rem;padding:.75rem}.footer .selected-dates{width:100%;justify-content:center;flex-wrap:wrap;gap:.5rem}.footer .selected-dates .date-display{font-size:.7rem;padding:.35rem .5rem}.footer .selected-dates .date-display svg{width:12px;height:12px}.footer .selected-dates .date-separator{font-size:.7rem}.footer .action-buttons{width:100%;gap:.5rem}.footer .action-buttons button{flex:1;padding:.625rem .75rem;font-size:.75rem}.date-picker-dropdown{width:280px!important;max-width:calc(100vw - 2rem);max-height:calc(100vh - 4rem);overflow-y:auto}.date-picker-dropdown.range-mode{width:280px!important}}@media (max-width: 480px){.calendars-container{padding:.5rem}.calendar .calendar-header .month-year{font-size:.8125rem;padding:.2rem .3rem}.calendar .calendar-header .nav-button{width:26px;height:26px}.calendar .calendar-header .nav-button svg{width:9px;height:9px}.calendar .month-year-picker{min-width:220px;padding:.625rem}.calendar .month-year-picker .picker-section{margin-bottom:.75rem}.calendar .month-year-picker .picker-section .picker-title{font-size:.65rem;margin-bottom:.375rem}.calendar .month-year-picker .months-grid{gap:.2rem}.calendar .month-year-picker .months-grid .month-option{padding:.35rem;font-size:.65rem}.calendar .month-year-picker .years-grid{gap:.2rem;max-height:120px}.calendar .month-year-picker .years-grid .year-option{padding:.35rem;font-size:.65rem}.calendar .calendar-grid{gap:1px 0}.calendar .calendar-grid .weekday-header{font-size:.6rem;padding:.35rem 0}.calendar .calendar-grid .calendar-day{width:28px;height:28px;font-size:.7rem}.footer{padding:.5rem;gap:.5rem}.footer .selected-dates{gap:.4rem}.footer .selected-dates .date-display{font-size:.65rem;padding:.3rem .4rem}.footer .selected-dates .date-display svg{width:11px;height:11px}.footer .selected-dates .date-separator{font-size:.65rem}.footer .action-buttons{gap:.4rem}.footer .action-buttons button{padding:.5rem .625rem;font-size:.7rem}.date-picker-dropdown{width:260px!important;max-width:calc(100vw - 1rem)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: FormsModule }] });
2038
+ }
2039
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DatePickerComponent, decorators: [{
2040
+ type: Component,
2041
+ args: [{ selector: 'app-date-picker', standalone: true, imports: [CommonModule, ReactiveFormsModule, FormsModule], providers: [
2042
+ {
2043
+ provide: NG_VALUE_ACCESSOR,
2044
+ useExisting: forwardRef(() => DatePickerComponent),
2045
+ multi: true
2046
+ }
2047
+ ], template: "<div class=\"date-picker-wrapper\">\n <label *ngIf=\"label\" [for]=\"id\">{{ label }}</label>\n\n <div class=\"date-picker-container\">\n <div\n #trigger\n class=\"date-picker-input\"\n [class.error]=\"hasError\"\n [class.disabled]=\"disabled\"\n [class.open]=\"isOpen\"\n [class.icon-right]=\"iconPosition === 'right'\"\n (click)=\"toggleDropdown($event)\">\n\n <svg *ngIf=\"iconPosition === 'left'\" class=\"calendar-icon\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6.66667 1.66667V4.16667M13.3333 1.66667V4.16667M2.5 7.5H17.5M4.16667 3.33333H15.8333C16.7538 3.33333 17.5 4.07953 17.5 5V16.6667C17.5 17.5871 16.7538 18.3333 15.8333 18.3333H4.16667C3.24619 18.3333 2.5 17.5871 2.5 16.6667V5C2.5 4.07953 3.24619 3.33333 4.16667 3.33333Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n\n <span class=\"date-picker-placeholder\" *ngIf=\"!getDisplayValue()\">\n {{ placeholder }}\n </span>\n <span class=\"date-picker-value\" *ngIf=\"getDisplayValue()\">\n {{ getDisplayValue() }}\n </span>\n\n <svg *ngIf=\"iconPosition === 'right'\" class=\"calendar-icon\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6.66667 1.66667V4.16667M13.3333 1.66667V4.16667M2.5 7.5H17.5M4.16667 3.33333H15.8333C16.7538 3.33333 17.5 4.07953 17.5 5V16.6667C17.5 17.5871 16.7538 18.3333 15.8333 18.3333H4.16667C3.24619 18.3333 2.5 17.5871 2.5 16.6667V5C2.5 4.07953 3.24619 3.33333 4.16667 3.33333Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n </div>\n\n <div *ngIf=\"hasError && errorMessage\" class=\"field-error\">\n {{ errorMessage }}\n </div>\n</div>\n\n<!-- Dropdown content (rendered with fixed position) -->\n<div *ngIf=\"isOpen\" class=\"date-picker-overlay\">\n <div #dropdown class=\"date-picker-dropdown\" [class.open]=\"isOpen\" [class.range-mode]=\"rangeMode\" [ngStyle]=\"getDropdownStyle()\">\n <div class=\"date-picker-content\">\n <!-- Sidebar with filters (only for range mode) -->\n <div class=\"filter-sidebar\" *ngIf=\"rangeMode\">\n <div\n *ngFor=\"let option of filterOptions\"\n class=\"filter-option\"\n [class.active]=\"selectedFilter === option.value\"\n (click)=\"selectFilter(option.value)\">\n {{ option.label }}\n </div>\n </div>\n\n <!-- Main content (calendars + footer) -->\n <div class=\"date-picker-main\">\n <!-- Calendars -->\n <div class=\"calendars-container\">\n <!-- Left Calendar (or single calendar in single mode) -->\n <div class=\"calendar\">\n <div class=\"calendar-header\">\n <button\n type=\"button\"\n class=\"nav-button\"\n [disabled]=\"!canNavigatePreviousMonth()\"\n [class.disabled]=\"!canNavigatePreviousMonth()\"\n (click)=\"previousMonth()\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7.5 2L3.5 6L7.5 10\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n <div class=\"month-year-selector\">\n <button type=\"button\" class=\"month-year\" (click)=\"toggleLeftMonthPicker($event)\">\n {{ getMonthYear(leftMonthDate) }}\n </button>\n\n <!-- Month/Year Picker Dropdown -->\n <div class=\"month-year-picker\" *ngIf=\"showLeftMonthPicker\" (click)=\"$event.stopPropagation()\">\n <div class=\"picker-section\">\n <div class=\"picker-title\">Mes</div>\n <div class=\"months-grid\">\n <button\n type=\"button\"\n *ngFor=\"let month of months; let i = index\"\n class=\"month-option\"\n [class.active]=\"i === leftMonthDate.getMonth()\"\n [class.disabled]=\"isMonthDisabled(i, leftMonthDate)\"\n [disabled]=\"isMonthDisabled(i, leftMonthDate)\"\n (click)=\"selectLeftMonth(i, $event)\">\n {{ month.substring(0, 3) }}\n </button>\n </div>\n </div>\n <div class=\"picker-section\">\n <div class=\"picker-header\">\n <button\n type=\"button\"\n class=\"year-nav-button\"\n [disabled]=\"!canNavigateLeftYearsPrevious()\"\n [class.disabled]=\"!canNavigateLeftYearsPrevious()\"\n (click)=\"previousLeftYearPage($event)\">\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6.25 2.5L3.75 5L6.25 7.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n <div class=\"picker-title\">{{ getLeftYearRangeLabel() }}</div>\n <button\n type=\"button\"\n class=\"year-nav-button\"\n [disabled]=\"!canNavigateLeftYearsNext()\"\n [class.disabled]=\"!canNavigateLeftYearsNext()\"\n (click)=\"nextLeftYearPage($event)\">\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M3.75 2.5L6.25 5L3.75 7.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n </div>\n <div class=\"years-grid\">\n <button\n type=\"button\"\n *ngFor=\"let year of getLeftYears()\"\n class=\"year-option\"\n [class.active]=\"year === leftMonthDate.getFullYear()\"\n [class.disabled]=\"isYearDisabled(year)\"\n [disabled]=\"isYearDisabled(year)\"\n (click)=\"selectLeftYear(year, $event)\">\n {{ year }}\n </button>\n </div>\n </div>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"nav-button\"\n [disabled]=\"!canNavigateNextMonth()\"\n [class.disabled]=\"!canNavigateNextMonth()\"\n (click)=\"nextMonth()\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4.5 2L8.5 6L4.5 10\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n </div>\n\n <div class=\"calendar-grid\">\n <div class=\"weekday-header\" *ngFor=\"let day of weekDays\">\n {{ day }}\n </div>\n\n <div\n *ngFor=\"let day of leftCalendarDays; trackBy: trackByDate\"\n class=\"calendar-day\"\n [class.other-month]=\"!day.isCurrentMonth\"\n [class.today]=\"day.isToday\"\n [class.selected]=\"day.isSelected\"\n [class.in-range]=\"rangeMode && isInRange(day.date)\"\n [class.range-start]=\"day.isRangeStart\"\n [class.range-end]=\"day.isRangeEnd\"\n [class.disabled]=\"day.isDisabled\"\n (click)=\"onDayClick(day)\"\n (mouseenter)=\"onDayHover(day)\"\n (mouseleave)=\"onDayLeave()\">\n <span>{{ day.date.getDate() }}</span>\n </div>\n </div>\n </div>\n\n <!-- Right Calendar (only for range mode) -->\n <div class=\"calendar\" *ngIf=\"rangeMode\">\n <div class=\"calendar-header\">\n <div class=\"nav-button-placeholder\"></div>\n <div class=\"month-year-selector\">\n <button type=\"button\" class=\"month-year\" (click)=\"toggleRightMonthPicker($event)\">\n {{ getMonthYear(rightMonthDate) }}\n </button>\n\n <!-- Month/Year Picker Dropdown -->\n <div class=\"month-year-picker\" *ngIf=\"showRightMonthPicker\" (click)=\"$event.stopPropagation()\">\n <div class=\"picker-section\">\n <div class=\"picker-title\">Mes</div>\n <div class=\"months-grid\">\n <button\n type=\"button\"\n *ngFor=\"let month of months; let i = index\"\n class=\"month-option\"\n [class.active]=\"i === rightMonthDate.getMonth()\"\n [class.disabled]=\"isMonthDisabled(i, rightMonthDate)\"\n [disabled]=\"isMonthDisabled(i, rightMonthDate)\"\n (click)=\"selectRightMonth(i, $event)\">\n {{ month.substring(0, 3) }}\n </button>\n </div>\n </div>\n <div class=\"picker-section\">\n <div class=\"picker-header\">\n <button\n type=\"button\"\n class=\"year-nav-button\"\n [disabled]=\"!canNavigateRightYearsPrevious()\"\n [class.disabled]=\"!canNavigateRightYearsPrevious()\"\n (click)=\"previousRightYearPage($event)\">\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6.25 2.5L3.75 5L6.25 7.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n <div class=\"picker-title\">{{ getRightYearRangeLabel() }}</div>\n <button\n type=\"button\"\n class=\"year-nav-button\"\n [disabled]=\"!canNavigateRightYearsNext()\"\n [class.disabled]=\"!canNavigateRightYearsNext()\"\n (click)=\"nextRightYearPage($event)\">\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M3.75 2.5L6.25 5L3.75 7.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n </div>\n <div class=\"years-grid\">\n <button\n type=\"button\"\n *ngFor=\"let year of getRightYears()\"\n class=\"year-option\"\n [class.active]=\"year === rightMonthDate.getFullYear()\"\n [class.disabled]=\"isYearDisabled(year)\"\n [disabled]=\"isYearDisabled(year)\"\n (click)=\"selectRightYear(year, $event)\">\n {{ year }}\n </button>\n </div>\n </div>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"nav-button\"\n [disabled]=\"!canNavigateNextMonth()\"\n [class.disabled]=\"!canNavigateNextMonth()\"\n (click)=\"nextMonth()\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M4.5 2L8.5 6L4.5 10\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n </div>\n\n <div class=\"calendar-grid\">\n <div class=\"weekday-header\" *ngFor=\"let day of weekDays\">\n {{ day }}\n </div>\n\n <div\n *ngFor=\"let day of rightCalendarDays; trackBy: trackByDate\"\n class=\"calendar-day\"\n [class.other-month]=\"!day.isCurrentMonth\"\n [class.today]=\"day.isToday\"\n [class.selected]=\"day.isSelected\"\n [class.in-range]=\"isInRange(day.date)\"\n [class.range-start]=\"day.isRangeStart\"\n [class.range-end]=\"day.isRangeEnd\"\n [class.disabled]=\"day.isDisabled\"\n (click)=\"onDayClick(day)\"\n (mouseenter)=\"onDayHover(day)\"\n (mouseleave)=\"onDayLeave()\">\n <span>{{ day.date.getDate() }}</span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Footer with dates and actions (only for range mode) -->\n <div class=\"footer\" *ngIf=\"rangeMode\">\n <div class=\"selected-dates\">\n <div class=\"date-display\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M5.33333 1.33333V3.33333M10.6667 1.33333V3.33333M2 6H14M3.33333 2.66667H12.6667C13.403 2.66667 14 3.26362 14 4V13.3333C14 14.0697 13.403 14.6667 12.6667 14.6667H3.33333C2.59695 14.6667 2 14.0697 2 13.3333V4C2 3.26362 2.59695 2.66667 3.33333 2.66667Z\" stroke=\"#6B7280\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"date-text\">{{ getStartDateDisplay() }}</span>\n </div>\n <span class=\"date-separator\">-</span>\n <div class=\"date-display\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M5.33333 1.33333V3.33333M10.6667 1.33333V3.33333M2 6H14M3.33333 2.66667H12.6667C13.403 2.66667 14 3.26362 14 4V13.3333C14 14.0697 13.403 14.6667 12.6667 14.6667H3.33333C2.59695 14.6667 2 14.0697 2 13.3333V4C2 3.26362 2.59695 2.66667 3.33333 2.66667Z\" stroke=\"#6B7280\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"date-text\">{{ getEndDateDisplay() }}</span>\n </div>\n </div>\n\n <div class=\"action-buttons\">\n <button type=\"button\" class=\"btn-cancel\" (click)=\"cancel()\">\n Cancelar\n </button>\n <button type=\"button\" class=\"btn-apply\" (click)=\"apply()\">\n Aplicar\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [".date-picker-wrapper{display:flex;flex-direction:column;width:100%;margin-bottom:6px;padding:0 4px}.date-picker-wrapper label{display:block;margin-bottom:.5rem;font-family:Quicksand,sans-serif;font-weight:500;font-size:14px;color:#585d61}.date-picker-container{position:relative;width:100%}.date-picker-input{display:flex;align-items:center;gap:.5rem;width:100%;min-height:44px;height:44px;padding:0 .75rem;border:1px solid #EAECF5;box-shadow:0 1px 2px #a1afec66;border-radius:8px;background:#fff;cursor:pointer;transition:all .2s ease;font-family:Quicksand,sans-serif}.date-picker-input:hover:not(.disabled){border-color:#fbd399}.date-picker-input.open{border-color:#fbd399;box-shadow:0 0 0 4px #ffe8c8,0 1px 2px #0a0d120d}.date-picker-input.error{border-color:#f04438}.date-picker-input.disabled{background:#f9fafb;cursor:not-allowed;opacity:.6}.date-picker-input .calendar-icon{color:#a4a7ae;flex-shrink:0}.date-picker-input .date-picker-placeholder{color:#a4a7ae;font-size:14px;flex:1}.date-picker-input .date-picker-value{color:#2e353a;font-size:14px;font-weight:500;flex:1}.field-error{color:#f04438;font-size:.875rem;margin-top:.25rem;font-family:Quicksand,sans-serif}.date-picker-overlay{position:fixed;inset:0;z-index:9999;pointer-events:none}.date-picker-dropdown{pointer-events:all;background:#fff;border-radius:12px;box-shadow:0 10px 40px #00000026;opacity:0;transform:translateY(-10px);transition:all .2s ease;overflow:visible}.date-picker-dropdown.open{opacity:1;transform:translateY(0)}.date-picker-content{display:flex;font-family:Quicksand,sans-serif;overflow:visible}.date-picker-main{display:flex;flex-direction:column;flex:1;overflow:visible}.filter-sidebar{padding:.5rem .8rem;min-width:170px;display:flex;flex-direction:column;border-right:1px solid #F3F4F6}.filter-sidebar .filter-option{font-family:Quicksand,sans-serif;padding:.625rem .8rem;color:#6b7280;cursor:pointer;transition:all .15s ease;white-space:nowrap;position:relative;font-weight:400;font-size:14px}.filter-sidebar .filter-option:hover:not(.active){background:#f9fafb}.filter-sidebar .filter-option.active{background:#fef4e6;color:#f7a733;font-weight:500;border-radius:6px}.calendars-container{display:flex;gap:3rem;padding:1rem;overflow:visible}.date-picker-dropdown:not(.range-mode) .calendars-container{gap:0;justify-content:center}.calendar{display:flex;flex-direction:column;gap:1rem;position:relative;overflow:visible}.calendar .calendar-header{display:flex;align-items:center;justify-content:space-between;padding:0 .25rem;margin-bottom:.5rem;position:relative;overflow:visible}.calendar .calendar-header .month-year-selector{position:relative;flex:1;display:flex;justify-content:center}.calendar .calendar-header .month-year{font-size:.9375rem;font-weight:600;color:#1f2937;min-width:160px;text-align:center;background:transparent;border:none;cursor:pointer;padding:.375rem .5rem;border-radius:6px;transition:all .15s ease}.calendar .calendar-header .month-year:hover{background:#f3f4f6}.calendar .calendar-header .nav-button{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;background:transparent;border-radius:6px;cursor:pointer;color:#6b7280;transition:all .15s ease;padding:0}.calendar .calendar-header .nav-button:hover:not(:disabled):not(.disabled){background:#f3f4f6;color:#1f2937}.calendar .calendar-header .nav-button.disabled,.calendar .calendar-header .nav-button:disabled{color:#d1d5db;cursor:not-allowed;opacity:.4}.calendar .calendar-header .nav-button svg{width:10px;height:10px}.calendar .calendar-header .nav-button-placeholder{width:28px;height:28px}.calendar .month-year-picker{position:absolute;top:100%;left:50%;transform:translate(-50%);margin-top:.5rem;background:#fff;border-radius:8px;box-shadow:0 10px 30px #0003;z-index:10002;padding:1rem;min-width:280px;border:1px solid #E5E7EB}.calendar .month-year-picker .picker-section{margin-bottom:1rem}.calendar .month-year-picker .picker-section:last-child{margin-bottom:0}.calendar .month-year-picker .picker-section .picker-title{font-size:.75rem;font-weight:600;color:#6b7280;text-transform:uppercase;letter-spacing:.5px;margin-bottom:.5rem}.calendar .month-year-picker .picker-section .picker-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:.5rem}.calendar .month-year-picker .picker-section .picker-header .picker-title{margin-bottom:0;font-size:.75rem;font-weight:600;color:#1f2937;text-transform:none;letter-spacing:0}.calendar .month-year-picker .picker-section .picker-header .year-nav-button{display:flex;align-items:center;justify-content:center;width:24px;height:24px;border:none;background:transparent;border-radius:4px;cursor:pointer;color:#6b7280;transition:all .15s ease;padding:0}.calendar .month-year-picker .picker-section .picker-header .year-nav-button:hover:not(:disabled):not(.disabled){background:#f3f4f6;color:#1f2937}.calendar .month-year-picker .picker-section .picker-header .year-nav-button.disabled,.calendar .month-year-picker .picker-section .picker-header .year-nav-button:disabled{color:#d1d5db;cursor:not-allowed;opacity:.5}.calendar .month-year-picker .picker-section .picker-header .year-nav-button svg{width:10px;height:10px}.calendar .month-year-picker .months-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:.375rem}.calendar .month-year-picker .months-grid .month-option{padding:.5rem;border:1px solid #E5E7EB;background:#fff;border-radius:6px;font-size:.75rem;font-weight:500;color:#6b7280;cursor:pointer;transition:all .15s ease}.calendar .month-year-picker .months-grid .month-option:hover{background:#f9fafb;border-color:#d1d5db}.calendar .month-year-picker .months-grid .month-option.active{background:#f59100;color:#fff;border-color:#f59100}.calendar .month-year-picker .months-grid .month-option.disabled,.calendar .month-year-picker .months-grid .month-option:disabled{background:#f9fafb;color:#d1d5db;border-color:#e5e7eb;cursor:not-allowed;pointer-events:none}.calendar .month-year-picker .years-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:.375rem;max-height:200px;overflow-y:auto}.calendar .month-year-picker .years-grid .year-option{padding:.5rem;border:1px solid #E5E7EB;background:#fff;border-radius:6px;font-size:.75rem;font-weight:500;color:#6b7280;cursor:pointer;transition:all .15s ease}.calendar .month-year-picker .years-grid .year-option:hover{background:#f9fafb;border-color:#d1d5db}.calendar .month-year-picker .years-grid .year-option.active{background:#f59100;color:#fff;border-color:#f59100}.calendar .month-year-picker .years-grid .year-option.disabled,.calendar .month-year-picker .years-grid .year-option:disabled{background:#f9fafb;color:#d1d5db;border-color:#e5e7eb;cursor:not-allowed;pointer-events:none}.calendar .calendar-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:4px 0}.calendar .calendar-grid .weekday-header{display:flex;align-items:center;justify-content:center;font-size:.6875rem;font-weight:500;color:#9ca3af;padding:.5rem 0;text-transform:uppercase;letter-spacing:.5px}.calendar .calendar-grid .calendar-day{display:flex;align-items:center;justify-content:center;width:36px;height:36px;font-size:.8125rem;color:#1f2937;cursor:pointer;transition:all .15s ease;position:relative;font-weight:400;border-radius:0}.calendar .calendar-grid .calendar-day.other-month{color:#d1d5db}.calendar .calendar-grid .calendar-day.today{font-weight:600;color:#f59100;background:transparent}.calendar .calendar-grid .calendar-day.today:after{content:\"\";position:absolute;bottom:4px;left:50%;transform:translate(-50%);width:4px;height:4px;background:#f59100;border-radius:50%}.calendar .calendar-grid .calendar-day:hover:not(.disabled):not(.selected):not(.range-start):not(.range-end):not(.in-range){background:#fef4e6;border-radius:50%}.calendar .calendar-grid .calendar-day.in-range:hover:not(.disabled):not(.range-start):not(.range-end){position:relative;background:transparent}.calendar .calendar-grid .calendar-day.in-range:hover:not(.disabled):not(.range-start):not(.range-end):before{content:\"\";position:absolute;inset:0;background:#fef4e6;z-index:-1;border-radius:0}.calendar .calendar-grid .calendar-day.in-range:hover:not(.disabled):not(.range-start):not(.range-end):after{content:\"\";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:100%;height:100%;background:#fef4e6;border-radius:50%;z-index:0}.calendar .calendar-grid .calendar-day.in-range:hover:not(.disabled):not(.range-start):not(.range-end) span{position:relative;z-index:1;color:#f59100}.calendar .calendar-grid .calendar-day.in-range:not(.disabled):not(.range-start):not(.range-end){background:#fef4e6;color:#f59100;border-radius:0}.calendar .calendar-grid .calendar-day.in-range:not(.disabled):not(.range-start):not(.range-end):nth-child(7n+8){border-radius:50% 0 0 50%}.calendar .calendar-grid .calendar-day.in-range:not(.disabled):not(.range-start):not(.range-end):nth-child(7n+14){border-radius:0 50% 50% 0}.calendar .calendar-grid .calendar-day.in-range:not(.disabled):not(.range-start):not(.range-end):nth-child(7n+8):nth-child(7n+14){border-radius:50%}.calendar .calendar-grid .calendar-day.range-start:not(.disabled){position:relative;background:transparent;color:#fff;font-weight:600;z-index:2}.calendar .calendar-grid .calendar-day.range-start:not(.disabled):before{content:\"\";position:absolute;inset:0;background:#fef4e6;z-index:-1;border-radius:50% 0 0 50%}.calendar .calendar-grid .calendar-day.range-start:not(.disabled):after{content:\"\";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:100%;height:100%;background:#f59100;border-radius:50%;z-index:1}.calendar .calendar-grid .calendar-day.range-start:not(.disabled) span{position:relative;z-index:2}.calendar .calendar-grid .calendar-day.range-start:not(.disabled).range-end:before{border-radius:50%}.calendar .calendar-grid .calendar-day.range-end:not(.disabled){position:relative;background:transparent;color:#fff;font-weight:600;z-index:2}.calendar .calendar-grid .calendar-day.range-end:not(.disabled):before{content:\"\";position:absolute;inset:0;background:#fef4e6;z-index:-1;border-radius:0 50% 50% 0}.calendar .calendar-grid .calendar-day.range-end:not(.disabled):after{content:\"\";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:100%;height:100%;background:#f59100;border-radius:50%;z-index:1}.calendar .calendar-grid .calendar-day.range-end:not(.disabled) span{position:relative;z-index:2}.calendar .calendar-grid .calendar-day.range-end:not(.disabled).range-start:before{border-radius:50%}.calendar .calendar-grid .calendar-day.range-start.in-range:not(.disabled){position:relative}.calendar .calendar-grid .calendar-day.range-start.in-range:not(.disabled):before{content:\"\";position:absolute;inset:0 -2px 0 50%;background:#fef4e6;z-index:-1}.calendar .calendar-grid .calendar-day.range-end.in-range:not(.disabled){position:relative}.calendar .calendar-grid .calendar-day.range-end.in-range:not(.disabled):before{content:\"\";position:absolute;inset:0 50% 0 -2px;background:#fef4e6;z-index:-1}.calendar .calendar-grid .calendar-day.selected:not(.range-start):not(.range-end){background:#f59100;color:#fff;font-weight:600;border-radius:50%}.calendar .calendar-grid .calendar-day.disabled{color:#e5e7eb;cursor:not-allowed;pointer-events:none}.footer{display:flex;align-items:center;justify-content:space-between;padding:1rem;border-top:1px solid #E5E7EB}.footer .selected-dates{display:flex;align-items:center;gap:.75rem}.footer .selected-dates .date-display{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;background:#fff;border:1px solid #E5E7EB;border-radius:6px;font-size:.8125rem;color:#6b7280}.footer .selected-dates .date-display svg{flex-shrink:0;color:#9ca3af}.footer .selected-dates .date-display .date-text{font-weight:400;white-space:nowrap;-webkit-user-select:none;user-select:none}.footer .selected-dates .date-separator{color:#9ca3af;font-weight:400;font-size:.875rem}.footer .action-buttons{display:flex;gap:.75rem}.footer .action-buttons button{padding:.625rem 1.75rem;border-radius:8px;font-size:.875rem;font-weight:500;font-family:Quicksand,sans-serif;cursor:pointer;transition:all .15s ease;border:none;outline:none}.footer .action-buttons button:focus-visible{outline:2px solid rgba(245,145,0,.3);outline-offset:2px}.footer .action-buttons .btn-cancel{background:#fff;color:#6b7280;border:1px solid #D1D5DB}.footer .action-buttons .btn-cancel:hover{background:#f9fafb;border-color:#9ca3af}.footer .action-buttons .btn-apply{background:#f59100;color:#fff;border:1px solid #F59100}.footer .action-buttons .btn-apply:hover{background:#e08500;border-color:#e08500}.footer .action-buttons .btn-apply:active{background:#cc7a00;border-color:#cc7a00}@media (max-width: 768px){.date-picker-content{flex-direction:column}.filter-sidebar{display:none}.calendars-container{padding:.75rem;gap:0;justify-content:center}.calendars-container .calendar:last-child:not(:first-child){display:none}.calendar .calendar-header .month-year-selector{flex:1}.calendar .calendar-header .month-year{min-width:auto;font-size:.875rem;padding:.25rem .375rem}.calendar .calendar-header .nav-button{width:28px;height:28px}.calendar .calendar-header .nav-button svg{width:10px;height:10px}.calendar .calendar-header .nav-button-placeholder{display:none}.calendar .month-year-picker{min-width:240px;padding:.75rem}.calendar .month-year-picker .picker-section .picker-title{font-size:.7rem}.calendar .month-year-picker .months-grid{grid-template-columns:repeat(3,1fr);gap:.25rem}.calendar .month-year-picker .months-grid .month-option{padding:.4rem;font-size:.7rem}.calendar .month-year-picker .years-grid{grid-template-columns:repeat(3,1fr);gap:.25rem;max-height:150px}.calendar .month-year-picker .years-grid .year-option{padding:.4rem;font-size:.7rem}.calendar .calendar-grid{gap:2px 0}.calendar .calendar-grid .calendar-day{width:30px;height:30px;font-size:.75rem}.calendar .calendar-grid .weekday-header{font-size:.65rem}.footer{flex-direction:column;gap:.75rem;padding:.75rem}.footer .selected-dates{width:100%;justify-content:center;flex-wrap:wrap;gap:.5rem}.footer .selected-dates .date-display{font-size:.7rem;padding:.35rem .5rem}.footer .selected-dates .date-display svg{width:12px;height:12px}.footer .selected-dates .date-separator{font-size:.7rem}.footer .action-buttons{width:100%;gap:.5rem}.footer .action-buttons button{flex:1;padding:.625rem .75rem;font-size:.75rem}.date-picker-dropdown{width:280px!important;max-width:calc(100vw - 2rem);max-height:calc(100vh - 4rem);overflow-y:auto}.date-picker-dropdown.range-mode{width:280px!important}}@media (max-width: 480px){.calendars-container{padding:.5rem}.calendar .calendar-header .month-year{font-size:.8125rem;padding:.2rem .3rem}.calendar .calendar-header .nav-button{width:26px;height:26px}.calendar .calendar-header .nav-button svg{width:9px;height:9px}.calendar .month-year-picker{min-width:220px;padding:.625rem}.calendar .month-year-picker .picker-section{margin-bottom:.75rem}.calendar .month-year-picker .picker-section .picker-title{font-size:.65rem;margin-bottom:.375rem}.calendar .month-year-picker .months-grid{gap:.2rem}.calendar .month-year-picker .months-grid .month-option{padding:.35rem;font-size:.65rem}.calendar .month-year-picker .years-grid{gap:.2rem;max-height:120px}.calendar .month-year-picker .years-grid .year-option{padding:.35rem;font-size:.65rem}.calendar .calendar-grid{gap:1px 0}.calendar .calendar-grid .weekday-header{font-size:.6rem;padding:.35rem 0}.calendar .calendar-grid .calendar-day{width:28px;height:28px;font-size:.7rem}.footer{padding:.5rem;gap:.5rem}.footer .selected-dates{gap:.4rem}.footer .selected-dates .date-display{font-size:.65rem;padding:.3rem .4rem}.footer .selected-dates .date-display svg{width:11px;height:11px}.footer .selected-dates .date-separator{font-size:.65rem}.footer .action-buttons{gap:.4rem}.footer .action-buttons button{padding:.5rem .625rem;font-size:.7rem}.date-picker-dropdown{width:260px!important;max-width:calc(100vw - 1rem)}}\n"] }]
2048
+ }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: Document, decorators: [{
2049
+ type: Inject,
2050
+ args: [DOCUMENT]
2051
+ }] }], propDecorators: { label: [{
2052
+ type: Input
2053
+ }], id: [{
2054
+ type: Input
2055
+ }], placeholder: [{
2056
+ type: Input
2057
+ }], hasError: [{
2058
+ type: Input
2059
+ }], errorMessage: [{
2060
+ type: Input
2061
+ }], disabled: [{
2062
+ type: Input
2063
+ }], minDate: [{
2064
+ type: Input
2065
+ }], maxDate: [{
2066
+ type: Input
2067
+ }], rangeMode: [{
2068
+ type: Input
2069
+ }], iconPosition: [{
2070
+ type: Input
2071
+ }], trigger: [{
2072
+ type: ViewChild,
2073
+ args: ['trigger', { read: ElementRef }]
2074
+ }], dropdown: [{
2075
+ type: ViewChild,
2076
+ args: ['dropdown', { read: ElementRef }]
2077
+ }], onDocumentClick: [{
2078
+ type: HostListener,
2079
+ args: ['document:click', ['$event']]
2080
+ }] } });
2081
+
2082
+ class LoaderComponent {
2083
+ show = false;
2084
+ message;
2085
+ logo;
2086
+ image;
2087
+ imageAlt = 'Loading';
2088
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LoaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2089
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: LoaderComponent, isStandalone: true, selector: "app-loader", inputs: { show: "show", message: "message", logo: "logo", image: "image", imageAlt: "imageAlt" }, ngImport: i0, template: `
2090
+ <div class="svu-loader-overlay" *ngIf="show">
2091
+ <div class="svu-loader-content">
2092
+ <!-- Logo -->
2093
+ <div class="svu-loader-logo" *ngIf="logo">
2094
+ <img [src]="logo" assetSource="mf" alt="Logo">
2095
+ </div>
2096
+
2097
+ <!-- Image/Icon -->
2098
+ <div class="svu-loader-image" *ngIf="image">
2099
+ <img [src]="image" assetSource="mf" [alt]="imageAlt">
2100
+ </div>
2101
+
2102
+ <!-- Loading Dots Animation -->
2103
+ <div class="svu-loader-dots">
2104
+ <span class="svu-loader-dot"></span>
2105
+ <span class="svu-loader-dot"></span>
2106
+ <span class="svu-loader-dot"></span>
2107
+ </div>
2108
+
2109
+ <!-- Message -->
2110
+ <div class="svu-loader-message" *ngIf="message">
2111
+ <span [innerHTML]="message"></span>
2112
+ </div>
2113
+ </div>
2114
+ </div>
2115
+ `, isInline: true, styles: [".svu-loader-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background:#f8f9fc;display:flex;align-items:center;justify-content:center;z-index:99999;animation:fadeIn .3s ease-in-out}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.svu-loader-content{display:flex;flex-direction:column;align-items:center;gap:2rem;min-height:500px;justify-content:center}.svu-loader-logo{margin-bottom:2rem}.svu-loader-logo img{height:60px;width:auto}.svu-loader-image{display:flex;align-items:center;justify-content:center;animation:float 3s ease-in-out infinite}.svu-loader-image img{max-width:300px;height:auto}@keyframes float{0%,to{transform:translateY(0)}50%{transform:translateY(-20px)}}.svu-loader-dots{display:flex;gap:12px;align-items:center;justify-content:center;padding:1rem 0;height:80px}.svu-loader-dot{width:20px;height:20px;border-radius:50%;background:#f59100;position:relative;transform-origin:center}.svu-loader-dot:nth-child(1){animation:bounce 1.4s ease-in-out infinite}.svu-loader-dot:nth-child(2){animation:bounce 1.4s ease-in-out infinite;animation-delay:.2s}.svu-loader-dot:nth-child(3){animation:bounce 1.4s ease-in-out infinite;animation-delay:.4s}@keyframes bounce{0%,80%,to{transform:scale(.6);opacity:.5}40%{transform:scale(1);opacity:1}}.svu-loader-message{font-family:DM Sans,sans-serif;color:#2e353a;text-align:center;font-weight:900;font-size:30px}.svu-loader-message ::ng-deep strong,.svu-loader-message ::ng-deep b{color:#f26d00;font-weight:900}@media (max-width: 768px){.svu-loader-logo img{height:48px}.svu-loader-image img{max-width:200px}.svu-loader-message{font-size:20px;padding:0 1rem}.svu-loader-dots{height:50px;gap:5px}.svu-loader-dot{width:12px;height:12px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: AssetSourceDirective, selector: "[assetSource]", inputs: ["assetSource", "assetPath"] }] });
2116
+ }
2117
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LoaderComponent, decorators: [{
2118
+ type: Component,
2119
+ args: [{ selector: 'app-loader', standalone: true, imports: [CommonModule, AssetSourceDirective], template: `
2120
+ <div class="svu-loader-overlay" *ngIf="show">
2121
+ <div class="svu-loader-content">
2122
+ <!-- Logo -->
2123
+ <div class="svu-loader-logo" *ngIf="logo">
2124
+ <img [src]="logo" assetSource="mf" alt="Logo">
2125
+ </div>
2126
+
2127
+ <!-- Image/Icon -->
2128
+ <div class="svu-loader-image" *ngIf="image">
2129
+ <img [src]="image" assetSource="mf" [alt]="imageAlt">
2130
+ </div>
2131
+
2132
+ <!-- Loading Dots Animation -->
2133
+ <div class="svu-loader-dots">
2134
+ <span class="svu-loader-dot"></span>
2135
+ <span class="svu-loader-dot"></span>
2136
+ <span class="svu-loader-dot"></span>
2137
+ </div>
2138
+
2139
+ <!-- Message -->
2140
+ <div class="svu-loader-message" *ngIf="message">
2141
+ <span [innerHTML]="message"></span>
2142
+ </div>
2143
+ </div>
2144
+ </div>
2145
+ `, styles: [".svu-loader-overlay{position:fixed;top:0;left:0;width:100vw;height:100vh;background:#f8f9fc;display:flex;align-items:center;justify-content:center;z-index:99999;animation:fadeIn .3s ease-in-out}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.svu-loader-content{display:flex;flex-direction:column;align-items:center;gap:2rem;min-height:500px;justify-content:center}.svu-loader-logo{margin-bottom:2rem}.svu-loader-logo img{height:60px;width:auto}.svu-loader-image{display:flex;align-items:center;justify-content:center;animation:float 3s ease-in-out infinite}.svu-loader-image img{max-width:300px;height:auto}@keyframes float{0%,to{transform:translateY(0)}50%{transform:translateY(-20px)}}.svu-loader-dots{display:flex;gap:12px;align-items:center;justify-content:center;padding:1rem 0;height:80px}.svu-loader-dot{width:20px;height:20px;border-radius:50%;background:#f59100;position:relative;transform-origin:center}.svu-loader-dot:nth-child(1){animation:bounce 1.4s ease-in-out infinite}.svu-loader-dot:nth-child(2){animation:bounce 1.4s ease-in-out infinite;animation-delay:.2s}.svu-loader-dot:nth-child(3){animation:bounce 1.4s ease-in-out infinite;animation-delay:.4s}@keyframes bounce{0%,80%,to{transform:scale(.6);opacity:.5}40%{transform:scale(1);opacity:1}}.svu-loader-message{font-family:DM Sans,sans-serif;color:#2e353a;text-align:center;font-weight:900;font-size:30px}.svu-loader-message ::ng-deep strong,.svu-loader-message ::ng-deep b{color:#f26d00;font-weight:900}@media (max-width: 768px){.svu-loader-logo img{height:48px}.svu-loader-image img{max-width:200px}.svu-loader-message{font-size:20px;padding:0 1rem}.svu-loader-dots{height:50px;gap:5px}.svu-loader-dot{width:12px;height:12px}}\n"] }]
2146
+ }], propDecorators: { show: [{
2147
+ type: Input
2148
+ }], message: [{
2149
+ type: Input
2150
+ }], logo: [{
2151
+ type: Input
2152
+ }], image: [{
2153
+ type: Input
2154
+ }], imageAlt: [{
2155
+ type: Input
2156
+ }] } });
2157
+
2158
+ class SidebarIconComponent {
2159
+ name;
2160
+ size = 24;
2161
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SidebarIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2162
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: SidebarIconComponent, isStandalone: true, selector: "svu-sidebar-icon", inputs: { name: "name", size: "size" }, ngImport: i0, template: `
2163
+ <ng-container [ngSwitch]="name">
2164
+ <svg *ngSwitchCase="'dashboard'" [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2165
+ <path d="M8 17h8M11.018 2.764L4.235 8.039c-.453.353-.68.53-.843.75a2 2 0 00-.318.65C3 9.704 3 9.991 3 10.565V17.8c0 1.12 0 1.68.218 2.108a2 2 0 00.874.874C4.52 21 5.08 21 6.2 21h11.6c1.12 0 1.68 0 2.108-.218a2 2 0 00.874-.874C21 19.48 21 18.92 21 17.8v-7.235c0-.574 0-.861-.074-1.126a2 2 0 00-.318-.65c-.163-.22-.39-.397-.843-.75l-6.783-5.275c-.351-.273-.527-.41-.72-.462a1 1 0 00-.508 0c-.193.052-.369.189-.72.462z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2166
+ </svg>
2167
+
2168
+ <svg *ngSwitchCase="'file-users'" [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2169
+ <path d="M14 2.27V6.4c0 .56 0 .84.109 1.054a1 1 0 00.437.437C14.76 8 15.04 8 15.6 8h4.13M8 15h8M8 11h4M14 2H8.8c-1.68 0-2.52 0-3.162.327a3 3 0 00-1.311 1.311C4 4.28 4 5.12 4 6.8v10.4c0 1.68 0 2.52.327 3.162a3 3 0 001.311 1.311C6.28 22 7.12 22 8.8 22h6.4c1.68 0 2.52 0 3.162-.327a3 3 0 001.311-1.311C20 19.72 20 18.88 20 17.2V8l-6-6z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2170
+ </svg>
2171
+
2172
+ <svg *ngSwitchCase="'card'" [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2173
+ <path d="M22 10H2M22 11V8.2C22 7.08 22 6.52 21.782 6.092a2 2 0 00-.874-.874C20.48 5 19.92 5 18.8 5H5.2C4.08 5 3.52 5 3.092 5.218a2 2 0 00-.874.874C2 6.52 2 7.08 2 8.2V15.8c0 1.12 0 1.68.218 2.108a2 2 0 00.874.874C3.52 19 4.08 19 5.2 19H18.8c1.12 0 1.68 0 2.108-.218a2 2 0 00.874-.874C22 17.48 22 16.92 22 15.8V11z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2174
+ </svg>
2175
+
2176
+ <svg *ngSwitchCase="'logout'" [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2177
+ <path d="M16 17l5-5m0 0l-5-5m5 5H9m0-9H7.8c-1.68 0-2.52 0-3.162.327a3 3 0 00-1.311 1.311C3 5.28 3 6.12 3 7.8v8.4c0 1.68 0 2.52.327 3.162a3 3 0 001.311 1.311C5.28 21 6.12 21 7.8 21H9" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2178
+ </svg>
2179
+
2180
+ <svg *ngSwitchCase="'chevron-down'" [attr.width]="size" [attr.height]="size" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
2181
+ <path d="M5 7.5l5 5 5-5" stroke="currentColor" stroke-width="1.667" stroke-linecap="round" stroke-linejoin="round"/>
2182
+ </svg>
2183
+
2184
+ <svg *ngSwitchCase="'settings'" [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2185
+ <path d="M12 15a3 3 0 100-6 3 3 0 000 6z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2186
+ <path d="M19.622 10.395l-1.097-2.65L20 6l-2-2-1.735 1.483-2.707-1.113L12.935 2h-1.954l-.632 2.401-2.645 1.115L6 4 4 6l1.453 1.789-1.08 2.657L2 11v2l2.401.655L5.516 16.3 4 18l2 2 1.791-1.46 2.606 1.072L11 22h2l.604-2.387 2.651-1.098C16.697 18.831 18 20 18 20l2-2-1.484-1.75 1.098-2.652 2.386-.62V11l-2.378-.605z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2187
+ </svg>
2188
+
2189
+ <svg *ngSwitchCase="'user'" [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2190
+ <path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2M12 11a4 4 0 100-8 4 4 0 000 8z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2191
+ </svg>
2192
+
2193
+ <svg *ngSwitchCase="'home'" [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2194
+ <path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2V9z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2195
+ <path d="M9 22V12h6v10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2196
+ </svg>
2197
+ </ng-container>
2198
+ `, isInline: true, styles: [":host{display:inline-flex;line-height:0;color:currentColor}svg{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2199
+ }
2200
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SidebarIconComponent, decorators: [{
2201
+ type: Component,
2202
+ args: [{ selector: 'svu-sidebar-icon', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
2203
+ <ng-container [ngSwitch]="name">
2204
+ <svg *ngSwitchCase="'dashboard'" [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2205
+ <path d="M8 17h8M11.018 2.764L4.235 8.039c-.453.353-.68.53-.843.75a2 2 0 00-.318.65C3 9.704 3 9.991 3 10.565V17.8c0 1.12 0 1.68.218 2.108a2 2 0 00.874.874C4.52 21 5.08 21 6.2 21h11.6c1.12 0 1.68 0 2.108-.218a2 2 0 00.874-.874C21 19.48 21 18.92 21 17.8v-7.235c0-.574 0-.861-.074-1.126a2 2 0 00-.318-.65c-.163-.22-.39-.397-.843-.75l-6.783-5.275c-.351-.273-.527-.41-.72-.462a1 1 0 00-.508 0c-.193.052-.369.189-.72.462z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2206
+ </svg>
2207
+
2208
+ <svg *ngSwitchCase="'file-users'" [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2209
+ <path d="M14 2.27V6.4c0 .56 0 .84.109 1.054a1 1 0 00.437.437C14.76 8 15.04 8 15.6 8h4.13M8 15h8M8 11h4M14 2H8.8c-1.68 0-2.52 0-3.162.327a3 3 0 00-1.311 1.311C4 4.28 4 5.12 4 6.8v10.4c0 1.68 0 2.52.327 3.162a3 3 0 001.311 1.311C6.28 22 7.12 22 8.8 22h6.4c1.68 0 2.52 0 3.162-.327a3 3 0 001.311-1.311C20 19.72 20 18.88 20 17.2V8l-6-6z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2210
+ </svg>
2211
+
2212
+ <svg *ngSwitchCase="'card'" [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2213
+ <path d="M22 10H2M22 11V8.2C22 7.08 22 6.52 21.782 6.092a2 2 0 00-.874-.874C20.48 5 19.92 5 18.8 5H5.2C4.08 5 3.52 5 3.092 5.218a2 2 0 00-.874.874C2 6.52 2 7.08 2 8.2V15.8c0 1.12 0 1.68.218 2.108a2 2 0 00.874.874C3.52 19 4.08 19 5.2 19H18.8c1.12 0 1.68 0 2.108-.218a2 2 0 00.874-.874C22 17.48 22 16.92 22 15.8V11z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2214
+ </svg>
2215
+
2216
+ <svg *ngSwitchCase="'logout'" [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2217
+ <path d="M16 17l5-5m0 0l-5-5m5 5H9m0-9H7.8c-1.68 0-2.52 0-3.162.327a3 3 0 00-1.311 1.311C3 5.28 3 6.12 3 7.8v8.4c0 1.68 0 2.52.327 3.162a3 3 0 001.311 1.311C5.28 21 6.12 21 7.8 21H9" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2218
+ </svg>
2219
+
2220
+ <svg *ngSwitchCase="'chevron-down'" [attr.width]="size" [attr.height]="size" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
2221
+ <path d="M5 7.5l5 5 5-5" stroke="currentColor" stroke-width="1.667" stroke-linecap="round" stroke-linejoin="round"/>
2222
+ </svg>
2223
+
2224
+ <svg *ngSwitchCase="'settings'" [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2225
+ <path d="M12 15a3 3 0 100-6 3 3 0 000 6z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2226
+ <path d="M19.622 10.395l-1.097-2.65L20 6l-2-2-1.735 1.483-2.707-1.113L12.935 2h-1.954l-.632 2.401-2.645 1.115L6 4 4 6l1.453 1.789-1.08 2.657L2 11v2l2.401.655L5.516 16.3 4 18l2 2 1.791-1.46 2.606 1.072L11 22h2l.604-2.387 2.651-1.098C16.697 18.831 18 20 18 20l2-2-1.484-1.75 1.098-2.652 2.386-.62V11l-2.378-.605z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2227
+ </svg>
2228
+
2229
+ <svg *ngSwitchCase="'user'" [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2230
+ <path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2M12 11a4 4 0 100-8 4 4 0 000 8z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2231
+ </svg>
2232
+
2233
+ <svg *ngSwitchCase="'home'" [attr.width]="size" [attr.height]="size" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2234
+ <path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2V9z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2235
+ <path d="M9 22V12h6v10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2236
+ </svg>
2237
+ </ng-container>
2238
+ `, styles: [":host{display:inline-flex;line-height:0;color:currentColor}svg{display:block}\n"] }]
2239
+ }], propDecorators: { name: [{
2240
+ type: Input
2241
+ }], size: [{
2242
+ type: Input
2243
+ }] } });
2244
+
2245
+ class SidebarComponent {
2246
+ hostRef;
2247
+ /** Items del menú (datos-driven). Soporta children para sub-navegación. */
2248
+ items = [];
2249
+ /** Logo: si se pasa la URL se renderiza; alternativamente proyecta contenido con `[sidebarLogo]`. */
2250
+ logoSrc;
2251
+ logoAlt = 'Logo';
2252
+ /** Footer hibrido: si se pasan los inputs se usa el footer por defecto.
2253
+ * Para footer custom, proyectar con `[sidebarFooter]` (gana sobre los inputs). */
2254
+ userName;
2255
+ userEmail;
2256
+ /** Si no se pasa, se usa la primera letra de userName. */
2257
+ userInitial;
2258
+ /** Mostrar/ocultar el botón de logout en el menú de cuenta. */
2259
+ showLogout = true;
2260
+ logoutLabel = 'Cerrar sesión';
2261
+ /** Click en un item (incluye expandibles y hojas). */
2262
+ itemClick = new EventEmitter();
2263
+ logout = new EventEmitter();
2264
+ logoTpl;
2265
+ footerTpl;
2266
+ expandedKeys = new Set();
2267
+ accountMenuOpen = false;
2268
+ subsetMatch = {
2269
+ paths: 'subset',
2270
+ queryParams: 'ignored',
2271
+ fragment: 'ignored',
2272
+ matrixParams: 'ignored'
2273
+ };
2274
+ exactMatch = {
2275
+ paths: 'exact',
2276
+ queryParams: 'ignored',
2277
+ fragment: 'ignored',
2278
+ matrixParams: 'ignored'
2279
+ };
2280
+ constructor(hostRef) {
2281
+ this.hostRef = hostRef;
2282
+ }
2283
+ get computedInitial() {
2284
+ if (this.userInitial)
2285
+ return this.userInitial;
2286
+ return (this.userName?.trim().charAt(0) || '').toUpperCase();
2287
+ }
2288
+ isExpanded(item) {
2289
+ return this.expandedKeys.has(item.label);
2290
+ }
2291
+ onItemClick(item) {
2292
+ if (item.children?.length) {
2293
+ if (this.expandedKeys.has(item.label)) {
2294
+ this.expandedKeys.delete(item.label);
2295
+ }
2296
+ else {
2297
+ this.expandedKeys.add(item.label);
2298
+ }
2299
+ }
2300
+ this.itemClick.emit(item);
2301
+ }
2302
+ toggleAccountMenu() {
2303
+ this.accountMenuOpen = !this.accountMenuOpen;
2304
+ }
2305
+ onLogoutClick() {
2306
+ this.accountMenuOpen = false;
2307
+ this.logout.emit();
2308
+ }
2309
+ onDocumentClick(event) {
2310
+ if (!this.accountMenuOpen)
2311
+ return;
2312
+ const footer = this.hostRef.nativeElement.querySelector('.svu-sidebar__footer');
2313
+ if (footer && !footer.contains(event.target)) {
2314
+ this.accountMenuOpen = false;
2315
+ }
2316
+ }
2317
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SidebarComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
2318
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: SidebarComponent, isStandalone: true, selector: "svu-sidebar", inputs: { items: "items", logoSrc: "logoSrc", logoAlt: "logoAlt", userName: "userName", userEmail: "userEmail", userInitial: "userInitial", showLogout: "showLogout", logoutLabel: "logoutLabel" }, outputs: { itemClick: "itemClick", logout: "logout" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, queries: [{ propertyName: "logoTpl", first: true, predicate: ["sidebarLogo"], descendants: true, read: TemplateRef }, { propertyName: "footerTpl", first: true, predicate: ["sidebarFooter"], descendants: true, read: TemplateRef }], ngImport: i0, template: "<aside class=\"svu-sidebar\">\n <div class=\"svu-sidebar__content\">\n <div class=\"svu-sidebar__top\">\n <!-- Logo: slot proyectable o input -->\n <div class=\"svu-sidebar__logo\">\n <ng-container *ngIf=\"logoTpl; else defaultLogo\" [ngTemplateOutlet]=\"logoTpl\"></ng-container>\n <ng-template #defaultLogo>\n <img *ngIf=\"logoSrc\" [src]=\"logoSrc\" [alt]=\"logoAlt\" class=\"svu-sidebar__logo-img\" />\n </ng-template>\n </div>\n\n <!-- Navigation -->\n <nav class=\"svu-sidebar__nav\">\n <ng-container *ngFor=\"let item of items\">\n <!-- Item con children (expandible) -->\n <ng-container *ngIf=\"item.children?.length; else leafItem\">\n <div\n class=\"svu-sidebar__nav-item\"\n [class.svu-sidebar__nav-item--active]=\"parentActive.isActive\"\n (click)=\"onItemClick(item)\"\n [routerLink]=\"item.route || null\"\n routerLinkActive\n #parentActive=\"routerLinkActive\"\n [routerLinkActiveOptions]=\"subsetMatch\">\n <div class=\"svu-sidebar__nav-item-content\">\n <svu-sidebar-icon *ngIf=\"item.icon\" [name]=\"item.icon\" class=\"svu-sidebar__nav-icon\"></svu-sidebar-icon>\n <span class=\"svu-sidebar__nav-text\">{{ item.label }}</span>\n </div>\n <svu-sidebar-icon\n name=\"chevron-down\"\n [size]=\"20\"\n class=\"svu-sidebar__nav-chevron\"\n [class.svu-sidebar__nav-chevron--open]=\"isExpanded(item)\">\n </svu-sidebar-icon>\n </div>\n\n <div class=\"svu-sidebar__subnav\" *ngIf=\"isExpanded(item)\">\n <a\n *ngFor=\"let child of item.children\"\n class=\"svu-sidebar__subnav-item\"\n [routerLink]=\"child.route\"\n routerLinkActive=\"svu-sidebar__subnav-item--active\"\n [routerLinkActiveOptions]=\"child.exact ? exactMatch : subsetMatch\"\n (click)=\"onItemClick(child)\">\n {{ child.label }}\n </a>\n </div>\n </ng-container>\n\n <!-- Item simple (hoja) -->\n <ng-template #leafItem>\n <a\n class=\"svu-sidebar__nav-item\"\n [routerLink]=\"item.route\"\n routerLinkActive=\"svu-sidebar__nav-item--active\"\n [routerLinkActiveOptions]=\"item.exact ? exactMatch : subsetMatch\"\n (click)=\"onItemClick(item)\">\n <div class=\"svu-sidebar__nav-item-content\">\n <svu-sidebar-icon *ngIf=\"item.icon\" [name]=\"item.icon\" class=\"svu-sidebar__nav-icon\"></svu-sidebar-icon>\n <span class=\"svu-sidebar__nav-text\">{{ item.label }}</span>\n </div>\n </a>\n </ng-template>\n </ng-container>\n </nav>\n </div>\n\n <!-- Footer: slot custom o default (user + logout) -->\n <div class=\"svu-sidebar__footer\">\n <div class=\"svu-sidebar__divider\"></div>\n\n <ng-container *ngIf=\"footerTpl; else defaultFooter\" [ngTemplateOutlet]=\"footerTpl\"></ng-container>\n\n <ng-template #defaultFooter>\n <div class=\"svu-sidebar__account-wrapper\" *ngIf=\"userName\">\n <div class=\"svu-sidebar__account\" (click)=\"toggleAccountMenu()\">\n <div class=\"svu-sidebar__avatar\">\n <span class=\"svu-sidebar__avatar-text\">{{ computedInitial }}</span>\n </div>\n <div class=\"svu-sidebar__user-info\">\n <span class=\"svu-sidebar__user-name\">{{ userName }}</span>\n <span class=\"svu-sidebar__user-email\" *ngIf=\"userEmail\">{{ userEmail }}</span>\n </div>\n </div>\n\n <div *ngIf=\"accountMenuOpen && showLogout\" class=\"svu-sidebar__account-menu\">\n <button type=\"button\" class=\"svu-sidebar__account-menu-item\" (click)=\"onLogoutClick()\">\n <svu-sidebar-icon name=\"logout\" [size]=\"20\"></svu-sidebar-icon>\n <span>{{ logoutLabel }}</span>\n </button>\n </div>\n </div>\n </ng-template>\n </div>\n </div>\n\n <div class=\"svu-sidebar__border\"></div>\n</aside>\n", styles: [".svu-sidebar{display:flex;width:312px;height:100%;background:#fff;flex-shrink:0}.svu-sidebar__content{display:flex;flex-direction:column;justify-content:space-between;flex:1;height:100%;min-width:0}.svu-sidebar__border{width:1px;height:100%;background-color:#e9eaeb;flex-shrink:0}.svu-sidebar__top{display:flex;flex-direction:column;gap:24px;padding-top:32px}.svu-sidebar__logo{padding:0 20px 0 24px}.svu-sidebar__logo-img{height:48px;width:auto}.svu-sidebar__nav{display:flex;flex-direction:column;gap:4px;padding:0 16px}.svu-sidebar__nav-item{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;border-radius:6px;cursor:pointer;transition:background-color .2s ease;text-decoration:none;color:inherit}.svu-sidebar__nav-item:hover,.svu-sidebar__nav-item--active{background-color:#fafafa}.svu-sidebar__nav-item--active .svu-sidebar__nav-text,.svu-sidebar__nav-item--active .svu-sidebar__nav-icon{color:#2e353a}.svu-sidebar__nav-item-content{display:flex;align-items:center;gap:12px}.svu-sidebar__nav-icon{flex-shrink:0;color:#585d61}.svu-sidebar__nav-text{font-family:Roboto,sans-serif;font-weight:600;font-size:16px;line-height:24px;color:#585d61}.svu-sidebar__nav-chevron{flex-shrink:0;color:#585d61;transition:transform .2s ease}.svu-sidebar__nav-chevron--open{transform:rotate(180deg)}.svu-sidebar__subnav{display:flex;flex-direction:column;gap:2px;padding-left:48px}.svu-sidebar__subnav-item{display:block;padding:6px 12px;border-radius:6px;font-family:Roboto,sans-serif;font-weight:400;font-size:14px;line-height:20px;color:#6d7275;text-decoration:none;cursor:pointer;transition:background-color .2s ease}.svu-sidebar__subnav-item:hover{background-color:#fafafa}.svu-sidebar__subnav-item--active{background-color:#fafafa;color:#2e353a;font-weight:600}.svu-sidebar__footer{display:flex;flex-direction:column;gap:24px;padding:0 16px 32px}.svu-sidebar__divider{height:1px;width:100%;background-color:#e9eaeb}.svu-sidebar__account-wrapper{position:relative}.svu-sidebar__account{display:flex;align-items:center;gap:12px;padding:8px;border-radius:8px;cursor:pointer;transition:background-color .2s ease}.svu-sidebar__account:hover{background-color:#fafafa}.svu-sidebar__account-menu{position:absolute;bottom:calc(100% + 8px);left:0;right:0;background:#fff;border:1px solid #E9EAEB;border-radius:8px;box-shadow:0 4px 16px #0000001a;padding:4px;z-index:10}.svu-sidebar__account-menu-item{display:flex;align-items:center;gap:8px;width:100%;padding:10px 12px;border:none;background:none;border-radius:6px;font-family:Roboto,sans-serif;font-weight:400;font-size:14px;line-height:20px;color:#d92d20;cursor:pointer;transition:background-color .2s ease}.svu-sidebar__account-menu-item:hover{background-color:#fef3f2}.svu-sidebar__avatar{width:40px;height:40px;border-radius:50%;background-color:#364b9f;display:flex;align-items:center;justify-content:center;flex-shrink:0}.svu-sidebar__avatar-text{font-family:Roboto,sans-serif;font-weight:600;font-size:16px;color:#fff}.svu-sidebar__user-info{display:flex;flex-direction:column;min-width:0}.svu-sidebar__user-name{font-family:Roboto,sans-serif;font-weight:600;font-size:14px;line-height:20px;color:#2e353a;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.svu-sidebar__user-email{font-family:Roboto,sans-serif;font-weight:400;font-size:14px;line-height:20px;color:#6d7275;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: SidebarIconComponent, selector: "svu-sidebar-icon", inputs: ["name", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2319
+ }
2320
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SidebarComponent, decorators: [{
2321
+ type: Component,
2322
+ args: [{ selector: 'svu-sidebar', standalone: true, imports: [CommonModule, RouterLink, RouterLinkActive, SidebarIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<aside class=\"svu-sidebar\">\n <div class=\"svu-sidebar__content\">\n <div class=\"svu-sidebar__top\">\n <!-- Logo: slot proyectable o input -->\n <div class=\"svu-sidebar__logo\">\n <ng-container *ngIf=\"logoTpl; else defaultLogo\" [ngTemplateOutlet]=\"logoTpl\"></ng-container>\n <ng-template #defaultLogo>\n <img *ngIf=\"logoSrc\" [src]=\"logoSrc\" [alt]=\"logoAlt\" class=\"svu-sidebar__logo-img\" />\n </ng-template>\n </div>\n\n <!-- Navigation -->\n <nav class=\"svu-sidebar__nav\">\n <ng-container *ngFor=\"let item of items\">\n <!-- Item con children (expandible) -->\n <ng-container *ngIf=\"item.children?.length; else leafItem\">\n <div\n class=\"svu-sidebar__nav-item\"\n [class.svu-sidebar__nav-item--active]=\"parentActive.isActive\"\n (click)=\"onItemClick(item)\"\n [routerLink]=\"item.route || null\"\n routerLinkActive\n #parentActive=\"routerLinkActive\"\n [routerLinkActiveOptions]=\"subsetMatch\">\n <div class=\"svu-sidebar__nav-item-content\">\n <svu-sidebar-icon *ngIf=\"item.icon\" [name]=\"item.icon\" class=\"svu-sidebar__nav-icon\"></svu-sidebar-icon>\n <span class=\"svu-sidebar__nav-text\">{{ item.label }}</span>\n </div>\n <svu-sidebar-icon\n name=\"chevron-down\"\n [size]=\"20\"\n class=\"svu-sidebar__nav-chevron\"\n [class.svu-sidebar__nav-chevron--open]=\"isExpanded(item)\">\n </svu-sidebar-icon>\n </div>\n\n <div class=\"svu-sidebar__subnav\" *ngIf=\"isExpanded(item)\">\n <a\n *ngFor=\"let child of item.children\"\n class=\"svu-sidebar__subnav-item\"\n [routerLink]=\"child.route\"\n routerLinkActive=\"svu-sidebar__subnav-item--active\"\n [routerLinkActiveOptions]=\"child.exact ? exactMatch : subsetMatch\"\n (click)=\"onItemClick(child)\">\n {{ child.label }}\n </a>\n </div>\n </ng-container>\n\n <!-- Item simple (hoja) -->\n <ng-template #leafItem>\n <a\n class=\"svu-sidebar__nav-item\"\n [routerLink]=\"item.route\"\n routerLinkActive=\"svu-sidebar__nav-item--active\"\n [routerLinkActiveOptions]=\"item.exact ? exactMatch : subsetMatch\"\n (click)=\"onItemClick(item)\">\n <div class=\"svu-sidebar__nav-item-content\">\n <svu-sidebar-icon *ngIf=\"item.icon\" [name]=\"item.icon\" class=\"svu-sidebar__nav-icon\"></svu-sidebar-icon>\n <span class=\"svu-sidebar__nav-text\">{{ item.label }}</span>\n </div>\n </a>\n </ng-template>\n </ng-container>\n </nav>\n </div>\n\n <!-- Footer: slot custom o default (user + logout) -->\n <div class=\"svu-sidebar__footer\">\n <div class=\"svu-sidebar__divider\"></div>\n\n <ng-container *ngIf=\"footerTpl; else defaultFooter\" [ngTemplateOutlet]=\"footerTpl\"></ng-container>\n\n <ng-template #defaultFooter>\n <div class=\"svu-sidebar__account-wrapper\" *ngIf=\"userName\">\n <div class=\"svu-sidebar__account\" (click)=\"toggleAccountMenu()\">\n <div class=\"svu-sidebar__avatar\">\n <span class=\"svu-sidebar__avatar-text\">{{ computedInitial }}</span>\n </div>\n <div class=\"svu-sidebar__user-info\">\n <span class=\"svu-sidebar__user-name\">{{ userName }}</span>\n <span class=\"svu-sidebar__user-email\" *ngIf=\"userEmail\">{{ userEmail }}</span>\n </div>\n </div>\n\n <div *ngIf=\"accountMenuOpen && showLogout\" class=\"svu-sidebar__account-menu\">\n <button type=\"button\" class=\"svu-sidebar__account-menu-item\" (click)=\"onLogoutClick()\">\n <svu-sidebar-icon name=\"logout\" [size]=\"20\"></svu-sidebar-icon>\n <span>{{ logoutLabel }}</span>\n </button>\n </div>\n </div>\n </ng-template>\n </div>\n </div>\n\n <div class=\"svu-sidebar__border\"></div>\n</aside>\n", styles: [".svu-sidebar{display:flex;width:312px;height:100%;background:#fff;flex-shrink:0}.svu-sidebar__content{display:flex;flex-direction:column;justify-content:space-between;flex:1;height:100%;min-width:0}.svu-sidebar__border{width:1px;height:100%;background-color:#e9eaeb;flex-shrink:0}.svu-sidebar__top{display:flex;flex-direction:column;gap:24px;padding-top:32px}.svu-sidebar__logo{padding:0 20px 0 24px}.svu-sidebar__logo-img{height:48px;width:auto}.svu-sidebar__nav{display:flex;flex-direction:column;gap:4px;padding:0 16px}.svu-sidebar__nav-item{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;border-radius:6px;cursor:pointer;transition:background-color .2s ease;text-decoration:none;color:inherit}.svu-sidebar__nav-item:hover,.svu-sidebar__nav-item--active{background-color:#fafafa}.svu-sidebar__nav-item--active .svu-sidebar__nav-text,.svu-sidebar__nav-item--active .svu-sidebar__nav-icon{color:#2e353a}.svu-sidebar__nav-item-content{display:flex;align-items:center;gap:12px}.svu-sidebar__nav-icon{flex-shrink:0;color:#585d61}.svu-sidebar__nav-text{font-family:Roboto,sans-serif;font-weight:600;font-size:16px;line-height:24px;color:#585d61}.svu-sidebar__nav-chevron{flex-shrink:0;color:#585d61;transition:transform .2s ease}.svu-sidebar__nav-chevron--open{transform:rotate(180deg)}.svu-sidebar__subnav{display:flex;flex-direction:column;gap:2px;padding-left:48px}.svu-sidebar__subnav-item{display:block;padding:6px 12px;border-radius:6px;font-family:Roboto,sans-serif;font-weight:400;font-size:14px;line-height:20px;color:#6d7275;text-decoration:none;cursor:pointer;transition:background-color .2s ease}.svu-sidebar__subnav-item:hover{background-color:#fafafa}.svu-sidebar__subnav-item--active{background-color:#fafafa;color:#2e353a;font-weight:600}.svu-sidebar__footer{display:flex;flex-direction:column;gap:24px;padding:0 16px 32px}.svu-sidebar__divider{height:1px;width:100%;background-color:#e9eaeb}.svu-sidebar__account-wrapper{position:relative}.svu-sidebar__account{display:flex;align-items:center;gap:12px;padding:8px;border-radius:8px;cursor:pointer;transition:background-color .2s ease}.svu-sidebar__account:hover{background-color:#fafafa}.svu-sidebar__account-menu{position:absolute;bottom:calc(100% + 8px);left:0;right:0;background:#fff;border:1px solid #E9EAEB;border-radius:8px;box-shadow:0 4px 16px #0000001a;padding:4px;z-index:10}.svu-sidebar__account-menu-item{display:flex;align-items:center;gap:8px;width:100%;padding:10px 12px;border:none;background:none;border-radius:6px;font-family:Roboto,sans-serif;font-weight:400;font-size:14px;line-height:20px;color:#d92d20;cursor:pointer;transition:background-color .2s ease}.svu-sidebar__account-menu-item:hover{background-color:#fef3f2}.svu-sidebar__avatar{width:40px;height:40px;border-radius:50%;background-color:#364b9f;display:flex;align-items:center;justify-content:center;flex-shrink:0}.svu-sidebar__avatar-text{font-family:Roboto,sans-serif;font-weight:600;font-size:16px;color:#fff}.svu-sidebar__user-info{display:flex;flex-direction:column;min-width:0}.svu-sidebar__user-name{font-family:Roboto,sans-serif;font-weight:600;font-size:14px;line-height:20px;color:#2e353a;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.svu-sidebar__user-email{font-family:Roboto,sans-serif;font-weight:400;font-size:14px;line-height:20px;color:#6d7275;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"] }]
2323
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { items: [{
2324
+ type: Input
2325
+ }], logoSrc: [{
2326
+ type: Input
2327
+ }], logoAlt: [{
2328
+ type: Input
2329
+ }], userName: [{
2330
+ type: Input
2331
+ }], userEmail: [{
2332
+ type: Input
2333
+ }], userInitial: [{
2334
+ type: Input
2335
+ }], showLogout: [{
2336
+ type: Input
2337
+ }], logoutLabel: [{
2338
+ type: Input
2339
+ }], itemClick: [{
2340
+ type: Output
2341
+ }], logout: [{
2342
+ type: Output
2343
+ }], logoTpl: [{
2344
+ type: ContentChild,
2345
+ args: ['sidebarLogo', { read: TemplateRef }]
2346
+ }], footerTpl: [{
2347
+ type: ContentChild,
2348
+ args: ['sidebarFooter', { read: TemplateRef }]
2349
+ }], onDocumentClick: [{
2350
+ type: HostListener,
2351
+ args: ['document:click', ['$event']]
2352
+ }] } });
2353
+
2354
+ class OptionComponent {
2355
+ elementRef;
2356
+ value;
2357
+ disabled = false;
2358
+ selected = false;
2359
+ optionClass = true;
2360
+ // Internal property to store text content
2361
+ _viewValue = '';
2362
+ get viewValue() {
2363
+ return this._viewValue || this.getTextContent();
2364
+ }
2365
+ set viewValue(value) {
2366
+ this._viewValue = value;
2367
+ }
2368
+ constructor(elementRef) {
2369
+ this.elementRef = elementRef;
2370
+ }
2371
+ /**
2372
+ * Get the text content from the element
2373
+ */
2374
+ getTextContent() {
2375
+ return this.elementRef.nativeElement.textContent?.trim() || '';
2376
+ }
2377
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: OptionComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
2378
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: OptionComponent, isStandalone: true, selector: "app-option", inputs: { value: "value", disabled: "disabled" }, host: { properties: { "class.disabled": "disabled", "class.selected": "this.selected", "class.app-option": "this.optionClass" }, classAttribute: "app-option" }, ngImport: i0, template: `<ng-content></ng-content>`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2379
+ }
2380
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: OptionComponent, decorators: [{
2381
+ type: Component,
2382
+ args: [{
2383
+ selector: 'app-option',
2384
+ standalone: true,
2385
+ imports: [CommonModule],
2386
+ template: `<ng-content></ng-content>`,
2387
+ changeDetection: ChangeDetectionStrategy.OnPush,
2388
+ host: {
2389
+ 'class': 'app-option',
2390
+ '[class.disabled]': 'disabled',
2391
+ '[class.selected]': 'selected'
2392
+ }
2393
+ }]
2394
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { value: [{
2395
+ type: Input
2396
+ }], disabled: [{
2397
+ type: Input
2398
+ }], selected: [{
2399
+ type: HostBinding,
2400
+ args: ['class.selected']
2401
+ }], optionClass: [{
2402
+ type: HostBinding,
2403
+ args: ['class.app-option']
2404
+ }] } });
2405
+
2406
+ class SelectPrefixDirective {
2407
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectPrefixDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2408
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: SelectPrefixDirective, isStandalone: true, selector: "[prefix]", ngImport: i0 });
2409
+ }
2410
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectPrefixDirective, decorators: [{
2411
+ type: Directive,
2412
+ args: [{
2413
+ selector: '[prefix]',
2414
+ standalone: true
2415
+ }]
2416
+ }] });
2417
+ class SelectSuffixDirective {
2418
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectSuffixDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2419
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: SelectSuffixDirective, isStandalone: true, selector: "[suffix]", ngImport: i0 });
2420
+ }
2421
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectSuffixDirective, decorators: [{
2422
+ type: Directive,
2423
+ args: [{
2424
+ selector: '[suffix]',
2425
+ standalone: true
2426
+ }]
2427
+ }] });
2428
+ class SelectComponent {
2429
+ renderer;
2430
+ document;
2431
+ label = '';
2432
+ id = '';
2433
+ placeholder = '';
2434
+ options = [];
2435
+ hasError = false;
2436
+ errorMessage = '';
2437
+ disabled = false;
2438
+ unstyled = false;
2439
+ displayKey = 'label'; // Property to display as label
2440
+ valueKey = 'value'; // Property to use as value
2441
+ customClass = ''; // Custom CSS class for styling
2442
+ trigger;
2443
+ contentOptions;
2444
+ prefixDirective;
2445
+ suffixDirective;
2446
+ get hasPrefix() {
2447
+ return !!this.prefixDirective;
2448
+ }
2449
+ get hasSuffix() {
2450
+ return !!this.suffixDirective;
2451
+ }
2452
+ value = '';
2453
+ isOpen = false;
2454
+ onChange = () => { };
2455
+ onTouched = () => { };
2456
+ _usingContentOptions = false;
2457
+ dropdownElement = null;
2458
+ backdropElement = null;
2459
+ scrollHandler = null;
2460
+ resizeHandler = null;
2461
+ constructor(renderer, document) {
2462
+ this.renderer = renderer;
2463
+ this.document = document;
2464
+ }
2465
+ ngAfterContentInit() {
2466
+ // Determine if using content projection or input options
2467
+ this._usingContentOptions = this.contentOptions && this.contentOptions.length > 0;
2468
+ // Subscribe to changes in content options
2469
+ if (this.contentOptions) {
2470
+ this.contentOptions.changes.subscribe(() => {
2471
+ this._usingContentOptions = this.contentOptions.length > 0;
2472
+ });
2473
+ }
2474
+ }
2475
+ ngOnDestroy() {
2476
+ this.destroyDropdown();
2477
+ }
2478
+ onEsc() {
2479
+ this.closeDropdown();
2480
+ this.onTouched();
2481
+ }
2482
+ handleBlur() {
2483
+ this.onTouched();
2484
+ }
2485
+ /**
2486
+ * Get all options (from content or input)
2487
+ */
2488
+ getAllOptions() {
2489
+ if (this._usingContentOptions && this.contentOptions) {
2490
+ return this.contentOptions.toArray();
2491
+ }
2492
+ return this.options || [];
2493
+ }
2494
+ /**
2495
+ * Get display label from option
2496
+ */
2497
+ getOptionLabel(option) {
2498
+ if (option instanceof OptionComponent) {
2499
+ return option.viewValue;
2500
+ }
2501
+ return option?.[this.displayKey] || '';
2502
+ }
2503
+ /**
2504
+ * Get value from option
2505
+ */
2506
+ getOptionValue(option) {
2507
+ if (option instanceof OptionComponent) {
2508
+ return option.value;
2509
+ }
2510
+ return option?.[this.valueKey];
2511
+ }
2512
+ /**
2513
+ * Check if option is disabled
2514
+ */
2515
+ isOptionDisabled(option) {
2516
+ if (option instanceof OptionComponent) {
2517
+ return option.disabled;
2518
+ }
2519
+ return option?.disabled || false;
2520
+ }
2521
+ onDocumentClick(event) {
2522
+ // Close dropdown if click is outside
2523
+ if (this.isOpen && this.dropdownElement && !this.dropdownElement.contains(event.target)) {
2524
+ const triggerElement = this.trigger?.nativeElement;
2525
+ if (triggerElement && !triggerElement.contains(event.target)) {
2526
+ this.closeDropdown();
2527
+ }
2528
+ }
2529
+ }
2530
+ toggleDropdown(event) {
2531
+ event.stopPropagation();
2532
+ if (this.disabled)
2533
+ return;
2534
+ if (this.isOpen) {
2535
+ this.closeDropdown();
2536
+ }
2537
+ else {
2538
+ this.openDropdown();
2539
+ }
2540
+ }
2541
+ openDropdown() {
2542
+ if (!this.trigger)
2543
+ return;
2544
+ // Create backdrop
2545
+ this.backdropElement = this.renderer.createElement('div');
2546
+ this.renderer.addClass(this.backdropElement, 'select-custom-backdrop');
2547
+ this.renderer.listen(this.backdropElement, 'click', () => this.closeDropdown());
2548
+ this.renderer.appendChild(this.document.body, this.backdropElement);
2549
+ // Create dropdown
2550
+ this.dropdownElement = this.renderer.createElement('div');
2551
+ this.renderer.addClass(this.dropdownElement, 'select-custom-dropdown');
2552
+ this.renderer.addClass(this.dropdownElement, 'select-overlay-pane');
2553
+ // Calculate position
2554
+ const position = this.calculatePosition();
2555
+ // Apply positioning styles
2556
+ this.renderer.setStyle(this.dropdownElement, 'position', 'fixed');
2557
+ this.renderer.setStyle(this.dropdownElement, 'left', position.left);
2558
+ this.renderer.setStyle(this.dropdownElement, 'width', position.width);
2559
+ this.renderer.setStyle(this.dropdownElement, 'max-height', position.maxHeight);
2560
+ this.renderer.setStyle(this.dropdownElement, 'z-index', '100000', RendererStyleFlags2.Important);
2561
+ if (position.top) {
2562
+ this.renderer.setStyle(this.dropdownElement, 'top', position.top);
2563
+ }
2564
+ else if (position.bottom) {
2565
+ this.renderer.setStyle(this.dropdownElement, 'bottom', position.bottom);
2566
+ }
2567
+ // Create dropdown content wrapper
2568
+ const dropdownContent = this.renderer.createElement('div');
2569
+ this.renderer.addClass(dropdownContent, 'select-dropdown');
2570
+ // Add options
2571
+ const allOptions = this.getAllOptions();
2572
+ allOptions.forEach(option => {
2573
+ const optionElement = this.createOptionElement(option);
2574
+ this.renderer.appendChild(dropdownContent, optionElement);
2575
+ });
2576
+ this.renderer.appendChild(this.dropdownElement, dropdownContent);
2577
+ this.renderer.appendChild(this.document.body, this.dropdownElement);
2578
+ this.isOpen = true;
2579
+ // Add scroll and resize listeners to reposition dropdown
2580
+ this.addRepositionListeners();
2581
+ // Trigger animation
2582
+ setTimeout(() => {
2583
+ if (this.dropdownElement) {
2584
+ this.renderer.addClass(this.dropdownElement, 'select-dropdown-open');
2585
+ }
2586
+ }, 10);
2587
+ }
2588
+ calculatePosition() {
2589
+ const triggerElement = this.trigger.nativeElement;
2590
+ const rect = triggerElement.getBoundingClientRect();
2591
+ const spaceBelow = window.innerHeight - rect.bottom;
2592
+ const spaceAbove = rect.top;
2593
+ const dropdownMaxHeight = 300;
2594
+ const offsetY = 4;
2595
+ const shouldOpenAbove = spaceBelow < 200 && spaceAbove > spaceBelow;
2596
+ const position = {
2597
+ left: `${rect.left}px`,
2598
+ width: `${rect.width}px`,
2599
+ maxHeight: `${dropdownMaxHeight}px`
2600
+ };
2601
+ if (shouldOpenAbove) {
2602
+ position.bottom = `${window.innerHeight - rect.top + offsetY}px`;
2603
+ }
2604
+ else {
2605
+ position.top = `${rect.bottom + offsetY}px`;
2606
+ }
2607
+ return position;
2608
+ }
2609
+ addRepositionListeners() {
2610
+ // Create handlers
2611
+ const scrollHandler = () => this.updateDropdownPosition();
2612
+ const resizeHandler = () => this.updateDropdownPosition();
2613
+ // Add scroll listener to window with capture phase to catch all scroll events
2614
+ window.addEventListener('scroll', scrollHandler, true);
2615
+ this.scrollHandler = () => window.removeEventListener('scroll', scrollHandler, true);
2616
+ // Add resize listener
2617
+ window.addEventListener('resize', resizeHandler);
2618
+ this.resizeHandler = () => window.removeEventListener('resize', resizeHandler);
2619
+ }
2620
+ updateDropdownPosition() {
2621
+ if (!this.dropdownElement || !this.trigger)
2622
+ return;
2623
+ const position = this.calculatePosition();
2624
+ // Update position styles
2625
+ this.renderer.setStyle(this.dropdownElement, 'left', position.left);
2626
+ this.renderer.setStyle(this.dropdownElement, 'width', position.width);
2627
+ // Remove old top/bottom styles
2628
+ this.renderer.removeStyle(this.dropdownElement, 'top');
2629
+ this.renderer.removeStyle(this.dropdownElement, 'bottom');
2630
+ // Apply new top/bottom position
2631
+ if (position.top) {
2632
+ this.renderer.setStyle(this.dropdownElement, 'top', position.top);
2633
+ }
2634
+ else if (position.bottom) {
2635
+ this.renderer.setStyle(this.dropdownElement, 'bottom', position.bottom);
2636
+ }
2637
+ }
2638
+ createOptionElement(option) {
2639
+ const optionElement = this.renderer.createElement('div');
2640
+ this.renderer.addClass(optionElement, 'select-option');
2641
+ const optionValue = this.getOptionValue(option);
2642
+ const optionLabel = this.getOptionLabel(option);
2643
+ const optionDisabled = this.isOptionDisabled(option);
2644
+ if (this.isEmptyValue(optionValue)) {
2645
+ this.renderer.addClass(optionElement, 'select-option-placeholder');
2646
+ }
2647
+ if (this.isSelected(optionValue)) {
2648
+ this.renderer.addClass(optionElement, 'selected');
2649
+ }
2650
+ if (optionDisabled) {
2651
+ this.renderer.addClass(optionElement, 'disabled');
2652
+ }
2653
+ // Option text
2654
+ const textSpan = this.renderer.createElement('span');
2655
+ this.renderer.addClass(textSpan, 'option-text');
2656
+ const text = this.renderer.createText(optionLabel);
2657
+ this.renderer.appendChild(textSpan, text);
2658
+ this.renderer.appendChild(optionElement, textSpan);
2659
+ // Check icon for selected option
2660
+ if (this.isSelected(optionValue)) {
2661
+ const svg = this.createCheckIcon();
2662
+ this.renderer.appendChild(optionElement, svg);
2663
+ }
2664
+ // Click handler
2665
+ if (!optionDisabled) {
2666
+ this.renderer.listen(optionElement, 'click', (event) => {
2667
+ event.stopPropagation();
2668
+ this.selectOption(option);
2669
+ });
2670
+ }
2671
+ return optionElement;
2672
+ }
2673
+ createCheckIcon() {
2674
+ const svg = this.renderer.createElement('svg', 'svg');
2675
+ this.renderer.addClass(svg, 'check-icon');
2676
+ this.renderer.setAttribute(svg, 'width', '14');
2677
+ this.renderer.setAttribute(svg, 'height', '10');
2678
+ this.renderer.setAttribute(svg, 'viewBox', '0 0 10 8');
2679
+ this.renderer.setAttribute(svg, 'fill', 'none');
2680
+ this.renderer.setAttribute(svg, 'xmlns', 'http://www.w3.org/2000/svg');
2681
+ const path = this.renderer.createElement('path', 'svg');
2682
+ this.renderer.setAttribute(path, 'd', 'M9 1L3.5 6.5L1 4');
2683
+ this.renderer.setAttribute(path, 'stroke', '#F59100');
2684
+ this.renderer.setAttribute(path, 'stroke-width', '1.6666');
2685
+ this.renderer.setAttribute(path, 'stroke-linecap', 'round');
2686
+ this.renderer.setAttribute(path, 'stroke-linejoin', 'round');
2687
+ this.renderer.appendChild(svg, path);
2688
+ return svg;
2689
+ }
2690
+ closeDropdown() {
2691
+ this.destroyDropdown();
2692
+ this.isOpen = false;
2693
+ }
2694
+ destroyDropdown() {
2695
+ // Remove listeners
2696
+ if (this.scrollHandler) {
2697
+ this.scrollHandler();
2698
+ this.scrollHandler = null;
2699
+ }
2700
+ if (this.resizeHandler) {
2701
+ this.resizeHandler();
2702
+ this.resizeHandler = null;
2703
+ }
2704
+ if (this.dropdownElement) {
2705
+ this.renderer.removeChild(this.document.body, this.dropdownElement);
2706
+ this.dropdownElement = null;
2707
+ }
2708
+ if (this.backdropElement) {
2709
+ this.renderer.removeChild(this.document.body, this.backdropElement);
2710
+ this.backdropElement = null;
2711
+ }
2712
+ }
2713
+ selectOption(option) {
2714
+ if (this.isOptionDisabled(option))
2715
+ return;
2716
+ this.value = this.getOptionValue(option);
2717
+ this.onChange(this.value);
2718
+ this.onTouched();
2719
+ this.closeDropdown();
2720
+ }
2721
+ isSelected(value) {
2722
+ return this.value === value;
2723
+ }
2724
+ isEmptyValue(value) {
2725
+ return value === '' || value === null || value === undefined;
2726
+ }
2727
+ getSelectedLabel() {
2728
+ const allOptions = this.getAllOptions();
2729
+ const selectedOption = allOptions.find(opt => this.getOptionValue(opt) === this.value);
2730
+ return selectedOption ? this.getOptionLabel(selectedOption) : '';
2731
+ }
2732
+ writeValue(value) {
2733
+ this.value = value || '';
2734
+ }
2735
+ registerOnChange(fn) {
2736
+ this.onChange = fn;
2737
+ }
2738
+ registerOnTouched(fn) {
2739
+ this.onTouched = fn;
2740
+ }
2741
+ setDisabledState(isDisabled) {
2742
+ this.disabled = isDisabled;
2743
+ }
2744
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectComponent, deps: [{ token: i0.Renderer2 }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component });
2745
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: SelectComponent, isStandalone: true, selector: "app-select", inputs: { label: "label", id: "id", placeholder: "placeholder", options: "options", hasError: "hasError", errorMessage: "errorMessage", disabled: "disabled", unstyled: "unstyled", displayKey: "displayKey", valueKey: "valueKey", customClass: "customClass" }, host: { listeners: { "keydown.escape": "onEsc()", "document:click": "onDocumentClick($event)" } }, providers: [
2746
+ {
2747
+ provide: NG_VALUE_ACCESSOR,
2748
+ useExisting: forwardRef(() => SelectComponent),
2749
+ multi: true
2750
+ }
2751
+ ], queries: [{ propertyName: "prefixDirective", first: true, predicate: SelectPrefixDirective, descendants: true }, { propertyName: "suffixDirective", first: true, predicate: SelectSuffixDirective, descendants: true }, { propertyName: "contentOptions", predicate: OptionComponent }], viewQueries: [{ propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true, read: ElementRef }], ngImport: i0, template: `
2752
+ <div class="select-wrapper" [class.select-wrapper--unstyled]="unstyled" [ngClass]="customClass">
2753
+ <label *ngIf="label && !unstyled" [for]="id">{{ label }}</label>
2754
+ <div class="select-container" [class.select-container--unstyled]="unstyled">
2755
+ <div
2756
+ #trigger
2757
+ class="select-header"
2758
+ [attr.tabindex]="disabled ? -1 : 0"
2759
+ [class.error]="hasError && !unstyled"
2760
+ [class.disabled]="disabled"
2761
+ [class.open]="isOpen"
2762
+ [class.select-header--unstyled]="unstyled"
2763
+ [class.select-header--has-prefix]="hasPrefix"
2764
+ (blur)="handleBlur()"
2765
+ (click)="!disabled && toggleDropdown($event)">
2766
+ <span class="select-prefix" *ngIf="hasPrefix">
2767
+ <ng-content select="[prefix]"></ng-content>
2768
+ </span>
2769
+ <span class="select-placeholder" *ngIf="!getSelectedLabel()">
2770
+ {{ placeholder }}
2771
+ </span>
2772
+ <span class="select-selected" *ngIf="getSelectedLabel()">
2773
+ {{ getSelectedLabel() }}
2774
+ </span>
2775
+ <span class="select-suffix" *ngIf="hasSuffix">
2776
+ <ng-content select="[suffix]"></ng-content>
2777
+ </span>
2778
+ <svg class="select-arrow" [class.open]="isOpen" width="12" height="8" viewBox="0 0 12 8" fill="none" xmlns="http://www.w3.org/2000/svg">
2779
+ <path d="M1 1.5L6 6.5L11 1.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
2780
+ </svg>
2781
+ </div>
2782
+ </div>
2783
+ <div *ngIf="hasError && errorMessage && !unstyled" class="field-error">
2784
+ {{ errorMessage }}
2785
+ </div>
2786
+
2787
+ <!-- Hidden container for projected options -->
2788
+ <div style="display: none;">
2789
+ <ng-content></ng-content>
2790
+ </div>
2791
+ </div>
2792
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: FormsModule }] });
2793
+ }
2794
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectComponent, decorators: [{
2795
+ type: Component,
2796
+ args: [{
2797
+ selector: 'app-select',
2798
+ standalone: true,
2799
+ imports: [CommonModule, ReactiveFormsModule, FormsModule, SelectPrefixDirective, SelectSuffixDirective],
2800
+ template: `
2801
+ <div class="select-wrapper" [class.select-wrapper--unstyled]="unstyled" [ngClass]="customClass">
2802
+ <label *ngIf="label && !unstyled" [for]="id">{{ label }}</label>
2803
+ <div class="select-container" [class.select-container--unstyled]="unstyled">
2804
+ <div
2805
+ #trigger
2806
+ class="select-header"
2807
+ [attr.tabindex]="disabled ? -1 : 0"
2808
+ [class.error]="hasError && !unstyled"
2809
+ [class.disabled]="disabled"
2810
+ [class.open]="isOpen"
2811
+ [class.select-header--unstyled]="unstyled"
2812
+ [class.select-header--has-prefix]="hasPrefix"
2813
+ (blur)="handleBlur()"
2814
+ (click)="!disabled && toggleDropdown($event)">
2815
+ <span class="select-prefix" *ngIf="hasPrefix">
2816
+ <ng-content select="[prefix]"></ng-content>
2817
+ </span>
2818
+ <span class="select-placeholder" *ngIf="!getSelectedLabel()">
2819
+ {{ placeholder }}
2820
+ </span>
2821
+ <span class="select-selected" *ngIf="getSelectedLabel()">
2822
+ {{ getSelectedLabel() }}
2823
+ </span>
2824
+ <span class="select-suffix" *ngIf="hasSuffix">
2825
+ <ng-content select="[suffix]"></ng-content>
2826
+ </span>
2827
+ <svg class="select-arrow" [class.open]="isOpen" width="12" height="8" viewBox="0 0 12 8" fill="none" xmlns="http://www.w3.org/2000/svg">
2828
+ <path d="M1 1.5L6 6.5L11 1.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
2829
+ </svg>
2830
+ </div>
2831
+ </div>
2832
+ <div *ngIf="hasError && errorMessage && !unstyled" class="field-error">
2833
+ {{ errorMessage }}
2834
+ </div>
2835
+
2836
+ <!-- Hidden container for projected options -->
2837
+ <div style="display: none;">
2838
+ <ng-content></ng-content>
2839
+ </div>
2840
+ </div>
2841
+ `,
2842
+ providers: [
2843
+ {
2844
+ provide: NG_VALUE_ACCESSOR,
2845
+ useExisting: forwardRef(() => SelectComponent),
2846
+ multi: true
2847
+ }
2848
+ ]
2849
+ }]
2850
+ }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: Document, decorators: [{
2851
+ type: Inject,
2852
+ args: [DOCUMENT]
2853
+ }] }], propDecorators: { label: [{
2854
+ type: Input
2855
+ }], id: [{
2856
+ type: Input
2857
+ }], placeholder: [{
2858
+ type: Input
2859
+ }], options: [{
2860
+ type: Input
2861
+ }], hasError: [{
2862
+ type: Input
2863
+ }], errorMessage: [{
2864
+ type: Input
2865
+ }], disabled: [{
2866
+ type: Input
2867
+ }], unstyled: [{
2868
+ type: Input
2869
+ }], displayKey: [{
2870
+ type: Input
2871
+ }], valueKey: [{
2872
+ type: Input
2873
+ }], customClass: [{
2874
+ type: Input
2875
+ }], trigger: [{
2876
+ type: ViewChild,
2877
+ args: ['trigger', { read: ElementRef }]
2878
+ }], contentOptions: [{
2879
+ type: ContentChildren,
2880
+ args: [OptionComponent]
2881
+ }], prefixDirective: [{
2882
+ type: ContentChild,
2883
+ args: [SelectPrefixDirective]
2884
+ }], suffixDirective: [{
2885
+ type: ContentChild,
2886
+ args: [SelectSuffixDirective]
2887
+ }], onEsc: [{
2888
+ type: HostListener,
2889
+ args: ['keydown.escape']
2890
+ }], onDocumentClick: [{
2891
+ type: HostListener,
2892
+ args: ['document:click', ['$event']]
2893
+ }] } });
2894
+
2895
+ class MultiselectComponent {
2896
+ renderer;
2897
+ document;
2898
+ label = '';
2899
+ id = '';
2900
+ placeholder = '';
2901
+ options = [];
2902
+ hasError = false;
2903
+ errorMessage = '';
2904
+ disabled = false;
2905
+ displayKey = 'label'; // Property to display as label
2906
+ valueKey = 'value'; // Property to use as value
2907
+ customClass = ''; // Custom CSS class for styling
2908
+ trigger;
2909
+ contentOptions;
2910
+ value = [];
2911
+ isOpen = false;
2912
+ onChange = () => { };
2913
+ onTouched = () => { };
2914
+ _usingContentOptions = false;
2915
+ dropdownElement = null;
2916
+ backdropElement = null;
2917
+ scrollHandler = null;
2918
+ resizeHandler = null;
2919
+ constructor(renderer, document) {
2920
+ this.renderer = renderer;
2921
+ this.document = document;
2922
+ }
2923
+ ngAfterContentInit() {
2924
+ // Determine if using content projection or input options
2925
+ this._usingContentOptions = this.contentOptions && this.contentOptions.length > 0;
2926
+ // Subscribe to changes in content options
2927
+ if (this.contentOptions) {
2928
+ this.contentOptions.changes.subscribe(() => {
2929
+ this._usingContentOptions = this.contentOptions.length > 0;
2930
+ });
2931
+ }
2932
+ }
2933
+ ngOnDestroy() {
2934
+ this.destroyDropdown();
2935
+ }
2936
+ /**
2937
+ * Get all options (from content or input)
2938
+ */
2939
+ getAllOptions() {
2940
+ if (this._usingContentOptions && this.contentOptions) {
2941
+ return this.contentOptions.toArray();
2942
+ }
2943
+ return this.options || [];
2944
+ }
2945
+ /**
2946
+ * Get display label from option
2947
+ */
2948
+ getOptionLabel(option) {
2949
+ if (option instanceof OptionComponent) {
2950
+ return option.viewValue;
2951
+ }
2952
+ return option?.[this.displayKey] || '';
2953
+ }
2954
+ /**
2955
+ * Get value from option
2956
+ */
2957
+ getOptionValue(option) {
2958
+ if (option instanceof OptionComponent) {
2959
+ return option.value;
2960
+ }
2961
+ return option?.[this.valueKey];
2962
+ }
2963
+ /**
2964
+ * Check if option is disabled
2965
+ */
2966
+ isOptionDisabled(option) {
2967
+ if (option instanceof OptionComponent) {
2968
+ return option.disabled;
2969
+ }
2970
+ return option?.disabled || false;
2971
+ }
2972
+ onDocumentClick(event) {
2973
+ // Close dropdown if click is outside
2974
+ if (this.isOpen && this.dropdownElement && !this.dropdownElement.contains(event.target)) {
2975
+ const triggerElement = this.trigger?.nativeElement;
2976
+ if (triggerElement && !triggerElement.contains(event.target)) {
2977
+ this.closeDropdown();
2978
+ }
2979
+ }
2980
+ }
2981
+ toggleDropdown(event) {
2982
+ event.stopPropagation();
2983
+ if (this.disabled)
2984
+ return;
2985
+ if (this.isOpen) {
2986
+ this.closeDropdown();
2987
+ }
2988
+ else {
2989
+ this.openDropdown();
2990
+ }
2991
+ }
2992
+ openDropdown() {
2993
+ if (!this.trigger)
2994
+ return;
2995
+ // Create backdrop
2996
+ this.backdropElement = this.renderer.createElement('div');
2997
+ this.renderer.addClass(this.backdropElement, 'multiselect-custom-backdrop');
2998
+ this.renderer.listen(this.backdropElement, 'click', () => this.closeDropdown());
2999
+ this.renderer.appendChild(this.document.body, this.backdropElement);
3000
+ // Create dropdown
3001
+ this.dropdownElement = this.renderer.createElement('div');
3002
+ this.renderer.addClass(this.dropdownElement, 'multiselect-custom-dropdown');
3003
+ this.renderer.addClass(this.dropdownElement, 'multiselect-overlay-pane');
3004
+ // Calculate position
3005
+ const position = this.calculatePosition();
3006
+ // Apply positioning styles
3007
+ this.renderer.setStyle(this.dropdownElement, 'position', 'fixed');
3008
+ this.renderer.setStyle(this.dropdownElement, 'left', position.left);
3009
+ this.renderer.setStyle(this.dropdownElement, 'width', position.width);
3010
+ this.renderer.setStyle(this.dropdownElement, 'max-height', position.maxHeight);
3011
+ this.renderer.setStyle(this.dropdownElement, 'z-index', '100000', RendererStyleFlags2.Important);
3012
+ if (position.top) {
3013
+ this.renderer.setStyle(this.dropdownElement, 'top', position.top);
3014
+ }
3015
+ else if (position.bottom) {
3016
+ this.renderer.setStyle(this.dropdownElement, 'bottom', position.bottom);
3017
+ }
3018
+ // Create dropdown content wrapper
3019
+ const dropdownContent = this.renderer.createElement('div');
3020
+ this.renderer.addClass(dropdownContent, 'multiselect-dropdown');
3021
+ // Add options
3022
+ const allOptions = this.getAllOptions();
3023
+ allOptions.forEach(option => {
3024
+ const optionElement = this.createOptionElement(option);
3025
+ this.renderer.appendChild(dropdownContent, optionElement);
3026
+ });
3027
+ this.renderer.appendChild(this.dropdownElement, dropdownContent);
3028
+ this.renderer.appendChild(this.document.body, this.dropdownElement);
3029
+ this.isOpen = true;
3030
+ // Add scroll and resize listeners to reposition dropdown
3031
+ this.addRepositionListeners();
3032
+ // Trigger animation
3033
+ setTimeout(() => {
3034
+ if (this.dropdownElement) {
3035
+ this.renderer.addClass(this.dropdownElement, 'multiselect-dropdown-open');
3036
+ }
3037
+ }, 10);
3038
+ }
3039
+ calculatePosition() {
3040
+ const triggerElement = this.trigger.nativeElement;
3041
+ const rect = triggerElement.getBoundingClientRect();
3042
+ const spaceBelow = window.innerHeight - rect.bottom;
3043
+ const spaceAbove = rect.top;
3044
+ const dropdownMaxHeight = 300;
3045
+ const offsetY = 4;
3046
+ const shouldOpenAbove = spaceBelow < 200 && spaceAbove > spaceBelow;
3047
+ const position = {
3048
+ left: `${rect.left}px`,
3049
+ width: `${rect.width}px`,
3050
+ maxHeight: `${dropdownMaxHeight}px`
3051
+ };
3052
+ if (shouldOpenAbove) {
3053
+ position.bottom = `${window.innerHeight - rect.top + offsetY}px`;
3054
+ }
3055
+ else {
3056
+ position.top = `${rect.bottom + offsetY}px`;
3057
+ }
3058
+ return position;
3059
+ }
3060
+ addRepositionListeners() {
3061
+ // Create handlers
3062
+ const scrollHandler = () => this.updateDropdownPosition();
3063
+ const resizeHandler = () => this.updateDropdownPosition();
3064
+ // Add scroll listener to window with capture phase to catch all scroll events
3065
+ window.addEventListener('scroll', scrollHandler, true);
3066
+ this.scrollHandler = () => window.removeEventListener('scroll', scrollHandler, true);
3067
+ // Add resize listener
3068
+ window.addEventListener('resize', resizeHandler);
3069
+ this.resizeHandler = () => window.removeEventListener('resize', resizeHandler);
3070
+ }
3071
+ updateDropdownPosition() {
3072
+ if (!this.dropdownElement || !this.trigger)
3073
+ return;
3074
+ const position = this.calculatePosition();
3075
+ // Update position styles
3076
+ this.renderer.setStyle(this.dropdownElement, 'left', position.left);
3077
+ this.renderer.setStyle(this.dropdownElement, 'width', position.width);
3078
+ // Remove old top/bottom styles
3079
+ this.renderer.removeStyle(this.dropdownElement, 'top');
3080
+ this.renderer.removeStyle(this.dropdownElement, 'bottom');
3081
+ // Apply new top/bottom position
3082
+ if (position.top) {
3083
+ this.renderer.setStyle(this.dropdownElement, 'top', position.top);
3084
+ }
3085
+ else if (position.bottom) {
3086
+ this.renderer.setStyle(this.dropdownElement, 'bottom', position.bottom);
3087
+ }
3088
+ }
3089
+ createOptionElement(option) {
3090
+ const labelElement = this.renderer.createElement('label');
3091
+ this.renderer.addClass(labelElement, 'multiselect-option');
3092
+ const optionValue = this.getOptionValue(option);
3093
+ const optionLabel = this.getOptionLabel(option);
3094
+ const optionDisabled = this.isOptionDisabled(option);
3095
+ if (this.isSelected(optionValue)) {
3096
+ this.renderer.addClass(labelElement, 'selected');
3097
+ }
3098
+ if (optionDisabled) {
3099
+ this.renderer.addClass(labelElement, 'disabled');
3100
+ }
3101
+ // Stop propagation on label click
3102
+ this.renderer.listen(labelElement, 'click', (event) => {
3103
+ event.stopPropagation();
3104
+ });
3105
+ // Checkbox container
3106
+ const checkboxDiv = this.renderer.createElement('div');
3107
+ this.renderer.addClass(checkboxDiv, 'option-checkbox');
3108
+ // Hidden native checkbox
3109
+ const checkbox = this.renderer.createElement('input');
3110
+ this.renderer.setAttribute(checkbox, 'type', 'checkbox');
3111
+ this.renderer.setProperty(checkbox, 'checked', this.isSelected(optionValue));
3112
+ if (optionDisabled) {
3113
+ this.renderer.setProperty(checkbox, 'disabled', true);
3114
+ }
3115
+ // Custom checkbox span
3116
+ const customCheckbox = this.renderer.createElement('span');
3117
+ this.renderer.addClass(customCheckbox, 'checkbox-custom');
3118
+ if (this.isSelected(optionValue)) {
3119
+ this.renderer.addClass(customCheckbox, 'checked');
3120
+ }
3121
+ // Check icon
3122
+ if (this.isSelected(optionValue)) {
3123
+ const svg = this.createCheckIcon();
3124
+ this.renderer.appendChild(customCheckbox, svg);
3125
+ }
3126
+ // Listen to change event
3127
+ this.renderer.listen(checkbox, 'change', (event) => {
3128
+ event.stopPropagation();
3129
+ // Toggle the value
3130
+ this.toggleOption(option);
3131
+ // Update visual state
3132
+ const isNowSelected = this.isSelected(optionValue);
3133
+ this.renderer.setProperty(checkbox, 'checked', isNowSelected);
3134
+ if (isNowSelected) {
3135
+ this.renderer.addClass(labelElement, 'selected');
3136
+ this.renderer.addClass(customCheckbox, 'checked');
3137
+ // Add check icon if not present
3138
+ if (!customCheckbox.querySelector('.check-icon')) {
3139
+ const svg = this.createCheckIcon();
3140
+ this.renderer.appendChild(customCheckbox, svg);
3141
+ }
3142
+ }
3143
+ else {
3144
+ this.renderer.removeClass(labelElement, 'selected');
3145
+ this.renderer.removeClass(customCheckbox, 'checked');
3146
+ // Remove check icon
3147
+ const existingIcon = customCheckbox.querySelector('.check-icon');
3148
+ if (existingIcon) {
3149
+ this.renderer.removeChild(customCheckbox, existingIcon);
3150
+ }
3151
+ }
3152
+ });
3153
+ this.renderer.appendChild(checkboxDiv, checkbox);
3154
+ this.renderer.appendChild(checkboxDiv, customCheckbox);
3155
+ this.renderer.appendChild(labelElement, checkboxDiv);
3156
+ // Option text
3157
+ const textSpan = this.renderer.createElement('span');
3158
+ this.renderer.addClass(textSpan, 'option-text');
3159
+ const text = this.renderer.createText(optionLabel);
3160
+ this.renderer.appendChild(textSpan, text);
3161
+ this.renderer.appendChild(labelElement, textSpan);
3162
+ return labelElement;
3163
+ }
3164
+ createCheckIcon() {
3165
+ const svg = this.renderer.createElement('svg', 'svg');
3166
+ this.renderer.addClass(svg, 'check-icon');
3167
+ this.renderer.setAttribute(svg, 'width', '14');
3168
+ this.renderer.setAttribute(svg, 'height', '10');
3169
+ this.renderer.setAttribute(svg, 'viewBox', '0 0 10 8');
3170
+ this.renderer.setAttribute(svg, 'fill', 'none');
3171
+ this.renderer.setAttribute(svg, 'xmlns', 'http://www.w3.org/2000/svg');
3172
+ const path = this.renderer.createElement('path', 'svg');
3173
+ this.renderer.setAttribute(path, 'd', 'M9 1L3.5 6.5L1 4');
3174
+ this.renderer.setAttribute(path, 'stroke', '#F59100');
3175
+ this.renderer.setAttribute(path, 'stroke-width', '1.6666');
3176
+ this.renderer.setAttribute(path, 'stroke-linecap', 'round');
3177
+ this.renderer.setAttribute(path, 'stroke-linejoin', 'round');
3178
+ this.renderer.appendChild(svg, path);
3179
+ return svg;
3180
+ }
3181
+ closeDropdown() {
3182
+ this.destroyDropdown();
3183
+ this.isOpen = false;
3184
+ this.onTouched();
3185
+ }
3186
+ destroyDropdown() {
3187
+ // Remove listeners
3188
+ if (this.scrollHandler) {
3189
+ this.scrollHandler();
3190
+ this.scrollHandler = null;
3191
+ }
3192
+ if (this.resizeHandler) {
3193
+ this.resizeHandler();
3194
+ this.resizeHandler = null;
3195
+ }
3196
+ if (this.dropdownElement) {
3197
+ this.renderer.removeChild(this.document.body, this.dropdownElement);
3198
+ this.dropdownElement = null;
3199
+ }
3200
+ if (this.backdropElement) {
3201
+ this.renderer.removeChild(this.document.body, this.backdropElement);
3202
+ this.backdropElement = null;
3203
+ }
3204
+ }
3205
+ toggleOption(option) {
3206
+ if (this.isOptionDisabled(option))
3207
+ return;
3208
+ const optionValue = this.getOptionValue(option);
3209
+ const index = this.value.indexOf(optionValue);
3210
+ if (index > -1) {
3211
+ this.value = this.value.filter(v => v !== optionValue);
3212
+ }
3213
+ else {
3214
+ this.value = [...this.value, optionValue];
3215
+ }
3216
+ this.onChange(this.value);
3217
+ }
3218
+ isSelected(value) {
3219
+ return this.value.includes(value);
3220
+ }
3221
+ getSelectedCount() {
3222
+ return this.value.length;
3223
+ }
3224
+ getSelectedLabels() {
3225
+ const allOptions = this.getAllOptions();
3226
+ const selectedOptions = allOptions.filter(opt => this.isSelected(this.getOptionValue(opt)));
3227
+ return selectedOptions.map(opt => this.getOptionLabel(opt)).join(', ');
3228
+ }
3229
+ writeValue(value) {
3230
+ this.value = Array.isArray(value) ? value : [];
3231
+ }
3232
+ registerOnChange(fn) {
3233
+ this.onChange = fn;
3234
+ }
3235
+ registerOnTouched(fn) {
3236
+ this.onTouched = fn;
3237
+ }
3238
+ setDisabledState(isDisabled) {
3239
+ this.disabled = isDisabled;
3240
+ }
3241
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MultiselectComponent, deps: [{ token: i0.Renderer2 }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component });
3242
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: MultiselectComponent, isStandalone: true, selector: "app-multiselect", inputs: { label: "label", id: "id", placeholder: "placeholder", options: "options", hasError: "hasError", errorMessage: "errorMessage", disabled: "disabled", displayKey: "displayKey", valueKey: "valueKey", customClass: "customClass" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, providers: [
3243
+ {
3244
+ provide: NG_VALUE_ACCESSOR,
3245
+ useExisting: forwardRef(() => MultiselectComponent),
3246
+ multi: true
3247
+ }
3248
+ ], queries: [{ propertyName: "contentOptions", predicate: OptionComponent }], viewQueries: [{ propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true, read: ElementRef }], ngImport: i0, template: `
3249
+ <div class="multiselect-wrapper" [ngClass]="customClass">
3250
+ <label *ngIf="label" [for]="id">{{ label }}</label>
3251
+ <div class="multiselect-container">
3252
+ <div
3253
+ #trigger
3254
+ class="multiselect-header"
3255
+ (click)="toggleDropdown($event)"
3256
+ [class.disabled]="disabled"
3257
+ [class.open]="isOpen"
3258
+ [class.error]="hasError">
3259
+ <span class="multiselect-placeholder" *ngIf="getSelectedCount() === 0">
3260
+ {{ placeholder || 'Selecciona uno o más...' }}
3261
+ </span>
3262
+ <span class="multiselect-selected" *ngIf="getSelectedCount() > 0">
3263
+ {{ getSelectedLabels() }}
3264
+ </span>
3265
+ <svg class="multiselect-arrow" [class.open]="isOpen" width="12" height="8" viewBox="0 0 12 8" fill="none" xmlns="http://www.w3.org/2000/svg">
3266
+ <path d="M1 1.5L6 6.5L11 1.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
3267
+ </svg>
3268
+ </div>
3269
+ </div>
3270
+ <div *ngIf="hasError && errorMessage" class="field-error">
3271
+ {{ errorMessage }}
3272
+ </div>
3273
+
3274
+ <!-- Hidden container for projected options -->
3275
+ <div style="display: none;">
3276
+ <ng-content></ng-content>
3277
+ </div>
3278
+ </div>
3279
+ `, isInline: true, styles: [".multiselect-wrapper{width:100%;margin-bottom:6px;padding:0 4px}.multiselect-wrapper label{display:block;margin-bottom:.5rem;font-family:Quicksand,sans-serif;font-weight:500;font-size:14px;color:#585d61}.multiselect-container{position:relative;width:100%}.multiselect-header{display:flex;align-items:center;justify-content:space-between;padding:.75rem 1rem;border:1px solid #EAECF5;box-shadow:0 1px 2px #a1afec66;border-radius:8px;background:#fff;cursor:pointer;transition:all .2s;min-height:44px;height:44px}.multiselect-header:hover:not(.disabled){border-color:#fbd399}.multiselect-header:focus-within{border-color:#fbd399;box-shadow:0 0 0 4px #ffe8c8,0 1px 2px #0a0d120d}.multiselect-header.disabled{background:#f5f5f5;cursor:not-allowed;opacity:.6}.multiselect-header.error{border-color:#dc3545!important}.multiselect-header.error.open{box-shadow:0 0 0 3px #dc35451a!important}.multiselect-header .multiselect-placeholder{font-family:Quicksand,sans-serif;font-size:14px;color:#969a9c}.multiselect-header .multiselect-selected{font-family:Quicksand,sans-serif;font-size:14px;color:#1a1d20;font-weight:500;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.multiselect-header .multiselect-arrow{color:#969a9c;transition:transform .3s ease;margin-left:.5rem;flex-shrink:0;display:flex;align-items:center}.multiselect-header .multiselect-arrow.open{transform:rotate(180deg)}.multiselect-dropdown{margin-top:8px;background:#fff;border:1px solid #EAECF5;border-radius:8px;box-shadow:0 10px 16px -4px #edeffb;max-height:290px!important;width:100%;overflow-x:hidden;overflow-y:auto;animation:dropdownSlide .25s cubic-bezier(.4,0,.2,1)}.multiselect-dropdown::-webkit-scrollbar{width:8px}.multiselect-dropdown::-webkit-scrollbar-track{background:#f1f1f1;border-radius:0 12px 12px 0}.multiselect-dropdown::-webkit-scrollbar-thumb{background:#d5d7d8;border-radius:4px}.multiselect-dropdown::-webkit-scrollbar-thumb:hover{background:#969a9c}@keyframes dropdownSlide{0%{opacity:0;transform:translateY(-8px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}.multiselect-option{display:flex!important;align-items:center;padding:.6rem 1.25rem;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);border-bottom:1px solid #F1F2F4;gap:1rem;margin:0!important;position:relative}.multiselect-option:first-child{border-radius:12px 12px 0 0}.multiselect-option:last-child{border-bottom:none;border-radius:0 0 12px 12px}.multiselect-option:hover:not(.disabled){background:linear-gradient(90deg,#fff9f0,#fffef9)}.multiselect-option:hover:not(.disabled):before{opacity:.5}.multiselect-option.disabled{opacity:.5;cursor:not-allowed;background:#f8f9fc}.multiselect-option.disabled:hover{transform:none;background:#f8f9fc}.multiselect-option .option-checkbox{position:relative;display:flex;align-items:center;flex-shrink:0}.multiselect-option .option-checkbox input[type=checkbox]{position:absolute;opacity:0;cursor:pointer;width:22px;height:22px;margin:0}.multiselect-option .option-checkbox .checkbox-custom{width:22px;height:22px;border:2.5px solid #D5D7D8;border-radius:6px;display:flex;align-items:center;justify-content:center;transition:all .25s cubic-bezier(.4,0,.2,1);background:#fff;position:relative}.multiselect-option .option-checkbox .checkbox-custom:after{content:\"\";position:absolute;width:100%;height:100%;border-radius:4px;background:#f59100;opacity:0;transform:scale(.5);transition:all .25s cubic-bezier(.4,0,.2,1)}.multiselect-option .option-checkbox .checkbox-custom.checked{background:#fff;border-color:#f59100;border-width:2.5px;transform:scale(1.05)}.multiselect-option .option-checkbox .checkbox-custom.checked:after{opacity:0}.multiselect-option .option-checkbox .checkbox-custom .check-icon{position:relative;z-index:1;display:flex;align-items:center;justify-content:center;animation:checkPop .3s cubic-bezier(.68,-.55,.265,1.55)}.multiselect-option .option-checkbox input[type=checkbox]:hover~.checkbox-custom:not(.checked){border-color:#f26d00;transform:scale(1.05)}.multiselect-option .option-text{flex:1;font-family:Quicksand,sans-serif;font-weight:500;font-size:14px;color:#1a1d20;line-height:1.5;transition:color .2s ease,font-weight .2s ease}@keyframes checkPop{0%{transform:scale(0);opacity:0}50%{transform:scale(1.2)}to{transform:scale(1);opacity:1}}.field-error{color:#f04438;font-size:.875rem;margin-top:.25rem;font-family:Quicksand,sans-serif}::ng-deep .multiselect-custom-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background:transparent;z-index:99999;pointer-events:auto}::ng-deep .multiselect-custom-dropdown{position:fixed;background:#fff;border-radius:8px;overflow:hidden;z-index:1000;opacity:0;transform:translateY(-8px) scale(.98);transition:opacity .25s cubic-bezier(.4,0,.2,1),transform .25s cubic-bezier(.4,0,.2,1)}::ng-deep .multiselect-custom-dropdown.multiselect-dropdown-open{opacity:1;transform:translateY(0) scale(1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: FormsModule }] });
3280
+ }
3281
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MultiselectComponent, decorators: [{
3282
+ type: Component,
3283
+ args: [{ selector: 'app-multiselect', standalone: true, imports: [CommonModule, ReactiveFormsModule, FormsModule], template: `
3284
+ <div class="multiselect-wrapper" [ngClass]="customClass">
3285
+ <label *ngIf="label" [for]="id">{{ label }}</label>
3286
+ <div class="multiselect-container">
3287
+ <div
3288
+ #trigger
3289
+ class="multiselect-header"
3290
+ (click)="toggleDropdown($event)"
3291
+ [class.disabled]="disabled"
3292
+ [class.open]="isOpen"
3293
+ [class.error]="hasError">
3294
+ <span class="multiselect-placeholder" *ngIf="getSelectedCount() === 0">
3295
+ {{ placeholder || 'Selecciona uno o más...' }}
3296
+ </span>
3297
+ <span class="multiselect-selected" *ngIf="getSelectedCount() > 0">
3298
+ {{ getSelectedLabels() }}
3299
+ </span>
3300
+ <svg class="multiselect-arrow" [class.open]="isOpen" width="12" height="8" viewBox="0 0 12 8" fill="none" xmlns="http://www.w3.org/2000/svg">
3301
+ <path d="M1 1.5L6 6.5L11 1.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
3302
+ </svg>
3303
+ </div>
3304
+ </div>
3305
+ <div *ngIf="hasError && errorMessage" class="field-error">
3306
+ {{ errorMessage }}
3307
+ </div>
3308
+
3309
+ <!-- Hidden container for projected options -->
3310
+ <div style="display: none;">
3311
+ <ng-content></ng-content>
3312
+ </div>
3313
+ </div>
3314
+ `, providers: [
3315
+ {
3316
+ provide: NG_VALUE_ACCESSOR,
3317
+ useExisting: forwardRef(() => MultiselectComponent),
3318
+ multi: true
3319
+ }
3320
+ ], styles: [".multiselect-wrapper{width:100%;margin-bottom:6px;padding:0 4px}.multiselect-wrapper label{display:block;margin-bottom:.5rem;font-family:Quicksand,sans-serif;font-weight:500;font-size:14px;color:#585d61}.multiselect-container{position:relative;width:100%}.multiselect-header{display:flex;align-items:center;justify-content:space-between;padding:.75rem 1rem;border:1px solid #EAECF5;box-shadow:0 1px 2px #a1afec66;border-radius:8px;background:#fff;cursor:pointer;transition:all .2s;min-height:44px;height:44px}.multiselect-header:hover:not(.disabled){border-color:#fbd399}.multiselect-header:focus-within{border-color:#fbd399;box-shadow:0 0 0 4px #ffe8c8,0 1px 2px #0a0d120d}.multiselect-header.disabled{background:#f5f5f5;cursor:not-allowed;opacity:.6}.multiselect-header.error{border-color:#dc3545!important}.multiselect-header.error.open{box-shadow:0 0 0 3px #dc35451a!important}.multiselect-header .multiselect-placeholder{font-family:Quicksand,sans-serif;font-size:14px;color:#969a9c}.multiselect-header .multiselect-selected{font-family:Quicksand,sans-serif;font-size:14px;color:#1a1d20;font-weight:500;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.multiselect-header .multiselect-arrow{color:#969a9c;transition:transform .3s ease;margin-left:.5rem;flex-shrink:0;display:flex;align-items:center}.multiselect-header .multiselect-arrow.open{transform:rotate(180deg)}.multiselect-dropdown{margin-top:8px;background:#fff;border:1px solid #EAECF5;border-radius:8px;box-shadow:0 10px 16px -4px #edeffb;max-height:290px!important;width:100%;overflow-x:hidden;overflow-y:auto;animation:dropdownSlide .25s cubic-bezier(.4,0,.2,1)}.multiselect-dropdown::-webkit-scrollbar{width:8px}.multiselect-dropdown::-webkit-scrollbar-track{background:#f1f1f1;border-radius:0 12px 12px 0}.multiselect-dropdown::-webkit-scrollbar-thumb{background:#d5d7d8;border-radius:4px}.multiselect-dropdown::-webkit-scrollbar-thumb:hover{background:#969a9c}@keyframes dropdownSlide{0%{opacity:0;transform:translateY(-8px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}.multiselect-option{display:flex!important;align-items:center;padding:.6rem 1.25rem;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);border-bottom:1px solid #F1F2F4;gap:1rem;margin:0!important;position:relative}.multiselect-option:first-child{border-radius:12px 12px 0 0}.multiselect-option:last-child{border-bottom:none;border-radius:0 0 12px 12px}.multiselect-option:hover:not(.disabled){background:linear-gradient(90deg,#fff9f0,#fffef9)}.multiselect-option:hover:not(.disabled):before{opacity:.5}.multiselect-option.disabled{opacity:.5;cursor:not-allowed;background:#f8f9fc}.multiselect-option.disabled:hover{transform:none;background:#f8f9fc}.multiselect-option .option-checkbox{position:relative;display:flex;align-items:center;flex-shrink:0}.multiselect-option .option-checkbox input[type=checkbox]{position:absolute;opacity:0;cursor:pointer;width:22px;height:22px;margin:0}.multiselect-option .option-checkbox .checkbox-custom{width:22px;height:22px;border:2.5px solid #D5D7D8;border-radius:6px;display:flex;align-items:center;justify-content:center;transition:all .25s cubic-bezier(.4,0,.2,1);background:#fff;position:relative}.multiselect-option .option-checkbox .checkbox-custom:after{content:\"\";position:absolute;width:100%;height:100%;border-radius:4px;background:#f59100;opacity:0;transform:scale(.5);transition:all .25s cubic-bezier(.4,0,.2,1)}.multiselect-option .option-checkbox .checkbox-custom.checked{background:#fff;border-color:#f59100;border-width:2.5px;transform:scale(1.05)}.multiselect-option .option-checkbox .checkbox-custom.checked:after{opacity:0}.multiselect-option .option-checkbox .checkbox-custom .check-icon{position:relative;z-index:1;display:flex;align-items:center;justify-content:center;animation:checkPop .3s cubic-bezier(.68,-.55,.265,1.55)}.multiselect-option .option-checkbox input[type=checkbox]:hover~.checkbox-custom:not(.checked){border-color:#f26d00;transform:scale(1.05)}.multiselect-option .option-text{flex:1;font-family:Quicksand,sans-serif;font-weight:500;font-size:14px;color:#1a1d20;line-height:1.5;transition:color .2s ease,font-weight .2s ease}@keyframes checkPop{0%{transform:scale(0);opacity:0}50%{transform:scale(1.2)}to{transform:scale(1);opacity:1}}.field-error{color:#f04438;font-size:.875rem;margin-top:.25rem;font-family:Quicksand,sans-serif}::ng-deep .multiselect-custom-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background:transparent;z-index:99999;pointer-events:auto}::ng-deep .multiselect-custom-dropdown{position:fixed;background:#fff;border-radius:8px;overflow:hidden;z-index:1000;opacity:0;transform:translateY(-8px) scale(.98);transition:opacity .25s cubic-bezier(.4,0,.2,1),transform .25s cubic-bezier(.4,0,.2,1)}::ng-deep .multiselect-custom-dropdown.multiselect-dropdown-open{opacity:1;transform:translateY(0) scale(1)}\n"] }]
3321
+ }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: Document, decorators: [{
3322
+ type: Inject,
3323
+ args: [DOCUMENT]
3324
+ }] }], propDecorators: { label: [{
3325
+ type: Input
3326
+ }], id: [{
3327
+ type: Input
3328
+ }], placeholder: [{
3329
+ type: Input
3330
+ }], options: [{
3331
+ type: Input
3332
+ }], hasError: [{
3333
+ type: Input
3334
+ }], errorMessage: [{
3335
+ type: Input
3336
+ }], disabled: [{
3337
+ type: Input
3338
+ }], displayKey: [{
3339
+ type: Input
3340
+ }], valueKey: [{
3341
+ type: Input
3342
+ }], customClass: [{
3343
+ type: Input
3344
+ }], trigger: [{
3345
+ type: ViewChild,
3346
+ args: ['trigger', { read: ElementRef }]
3347
+ }], contentOptions: [{
3348
+ type: ContentChildren,
3349
+ args: [OptionComponent]
3350
+ }], onDocumentClick: [{
3351
+ type: HostListener,
3352
+ args: ['document:click', ['$event']]
3353
+ }] } });
3354
+
3355
+ class PhoneInputComponent {
3356
+ label = 'Teléfono';
3357
+ hasError = false;
3358
+ errorMessage = '';
3359
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PhoneInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3360
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: PhoneInputComponent, isStandalone: true, selector: "app-phone-input", inputs: { label: "label", hasError: "hasError", errorMessage: "errorMessage" }, ngImport: i0, template: `
3361
+ <div class="svu-phone-input" [class.svu-phone-input--error]="hasError">
3362
+ <label *ngIf="label" class="svu-phone-input__label">
3363
+ {{ label }}
3364
+ </label>
3365
+
3366
+ <div class="svu-phone-input__field">
3367
+ <div class="svu-phone-input__country">
3368
+ <ng-content select="[countrySelect]"></ng-content>
3369
+ </div>
3370
+
3371
+ <div class="svu-phone-input__number">
3372
+ <ng-content select="[phoneInput]"></ng-content>
3373
+ </div>
3374
+ </div>
3375
+
3376
+ <span *ngIf="hasError && errorMessage" class="svu-phone-input__error">
3377
+ {{ errorMessage }}
3378
+ </span>
3379
+ </div>
3380
+ `, isInline: true, styles: [".svu-phone-input{display:flex;flex-direction:column;width:100%;margin-bottom:6px;padding:0 4px}.svu-phone-input__label{display:block;margin-bottom:.5rem;font-family:Quicksand,sans-serif;font-weight:500;font-size:14px;color:#585d61}.svu-phone-input__field{position:relative;display:flex;align-items:stretch;min-height:44px;height:44px;border:1px solid #EAECF5;box-shadow:0 1px 2px #a1afec66;border-radius:8px;transition:all .2s ease;background:#fff}.svu-phone-input__field:hover{border-color:#fbd399}.svu-phone-input__field:focus-within{border-color:#fbd399;box-shadow:0 0 0 4px #ffe8c8,0 1px 2px #0a0d120d}.svu-phone-input__country{flex:0;width:120px;display:flex;align-items:stretch;min-width:64px}.svu-phone-input__number{flex:1;min-width:0;display:flex;align-items:stretch}.svu-phone-input.svu-phone-input--error .svu-phone-input__field{border-color:#dc3545!important}.svu-phone-input.svu-phone-input--error .svu-phone-input__field:focus-within{box-shadow:0 0 0 3px #dc35451a!important}.svu-phone-input__error{color:#f04438;font-size:.875rem;margin-top:.25rem;font-family:Quicksand,sans-serif}@media (max-width: 640px){.svu-phone-input__country{width:100px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
3381
+ }
3382
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PhoneInputComponent, decorators: [{
3383
+ type: Component,
3384
+ args: [{ selector: 'app-phone-input', standalone: true, imports: [CommonModule, InputComponent, SelectComponent], template: `
3385
+ <div class="svu-phone-input" [class.svu-phone-input--error]="hasError">
3386
+ <label *ngIf="label" class="svu-phone-input__label">
3387
+ {{ label }}
3388
+ </label>
3389
+
3390
+ <div class="svu-phone-input__field">
3391
+ <div class="svu-phone-input__country">
3392
+ <ng-content select="[countrySelect]"></ng-content>
3393
+ </div>
3394
+
3395
+ <div class="svu-phone-input__number">
3396
+ <ng-content select="[phoneInput]"></ng-content>
3397
+ </div>
3398
+ </div>
3399
+
3400
+ <span *ngIf="hasError && errorMessage" class="svu-phone-input__error">
3401
+ {{ errorMessage }}
3402
+ </span>
3403
+ </div>
3404
+ `, styles: [".svu-phone-input{display:flex;flex-direction:column;width:100%;margin-bottom:6px;padding:0 4px}.svu-phone-input__label{display:block;margin-bottom:.5rem;font-family:Quicksand,sans-serif;font-weight:500;font-size:14px;color:#585d61}.svu-phone-input__field{position:relative;display:flex;align-items:stretch;min-height:44px;height:44px;border:1px solid #EAECF5;box-shadow:0 1px 2px #a1afec66;border-radius:8px;transition:all .2s ease;background:#fff}.svu-phone-input__field:hover{border-color:#fbd399}.svu-phone-input__field:focus-within{border-color:#fbd399;box-shadow:0 0 0 4px #ffe8c8,0 1px 2px #0a0d120d}.svu-phone-input__country{flex:0;width:120px;display:flex;align-items:stretch;min-width:64px}.svu-phone-input__number{flex:1;min-width:0;display:flex;align-items:stretch}.svu-phone-input.svu-phone-input--error .svu-phone-input__field{border-color:#dc3545!important}.svu-phone-input.svu-phone-input--error .svu-phone-input__field:focus-within{box-shadow:0 0 0 3px #dc35451a!important}.svu-phone-input__error{color:#f04438;font-size:.875rem;margin-top:.25rem;font-family:Quicksand,sans-serif}@media (max-width: 640px){.svu-phone-input__country{width:100px}}\n"] }]
3405
+ }], propDecorators: { label: [{
3406
+ type: Input
3407
+ }], hasError: [{
3408
+ type: Input
3409
+ }], errorMessage: [{
3410
+ type: Input
3411
+ }] } });
3412
+
3413
+ class CopyInputComponent {
3414
+ value = '';
3415
+ icon = 'icon-copy-clipboard';
3416
+ copiedIcon = 'icon-done';
3417
+ ariaLabel = 'Copiar';
3418
+ copied = new EventEmitter();
3419
+ isCopied = false;
3420
+ timeoutRef;
3421
+ async copyToClipboard() {
3422
+ try {
3423
+ await navigator.clipboard.writeText(this.value);
3424
+ this.isCopied = true;
3425
+ this.copied.emit();
3426
+ clearTimeout(this.timeoutRef);
3427
+ this.timeoutRef = setTimeout(() => {
3428
+ this.isCopied = false;
3429
+ }, 1200);
3430
+ }
3431
+ catch (err) {
3432
+ console.error('Error copiando:', err);
3433
+ }
3434
+ }
3435
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CopyInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3436
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: CopyInputComponent, isStandalone: true, selector: "copy-input", inputs: { value: "value", icon: "icon", copiedIcon: "copiedIcon", ariaLabel: "ariaLabel" }, outputs: { copied: "copied" }, ngImport: i0, template: "<div class=\"copy-input-wrapper\">\n\n <!-- Tooltip -->\n <div\n class=\"copy-tooltip\"\n *ngIf=\"isCopied\"\n >\n Copiado\n </div>\n\n <!-- Componente -->\n <div\n class=\"copy-input\"\n (click)=\"copyToClipboard()\"\n tabindex=\"0\"\n role=\"button\"\n [attr.aria-label]=\"ariaLabel\"\n (keydown.enter)=\"copyToClipboard()\"\n >\n <i\n class=\"copy-input__icon\"\n [ngClass]=\"isCopied ? copiedIcon : icon\">\n </i>\n\n <span class=\"copy-input__text\">\n {{ value }}\n </span>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";.copy-input-wrapper{position:relative;display:inline-block;max-width:100%}.copy-tooltip{position:absolute;top:-2rem;left:50%;transform:translate(-50%);padding:.375rem .625rem;background:#2f2f2f;color:#fff;font-size:.75rem;border-radius:.375rem;white-space:nowrap;opacity:0;animation:fadeSlide .25s forwards}.copy-tooltip:after{content:\"\";position:absolute;bottom:-.375rem;left:50%;transform:translate(-50%);border-width:.375rem;border-style:solid;border-color:#2f2f2f transparent transparent transparent}@keyframes fadeSlide{0%{opacity:0;transform:translate(-50%,-5px)}to{opacity:1;transform:translate(-50%)}}.copy-input{display:flex;align-items:center;gap:.5rem;width:100%;box-sizing:border-box;padding:.625rem 1.125rem;border:2px solid #6D7275;border-radius:.5rem;cursor:pointer;-webkit-user-select:none;user-select:none;transition:background .2s ease,border-color .2s ease}.copy-input:hover{background:#f9f9f9;border-color:#d8d8d8}.copy-input:active{background:#f0f0f0}.copy-input:focus{outline-offset:2px}.copy-input__icon{font-size:1.1rem;color:#444;transition:transform .2s ease,color .2s ease}.copy-input__icon.icon-done{transform:scale(1.2);color:#27ae60}.copy-input__text{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-family:Quicksand,sans-serif;font-weight:600;font-size:1rem;line-height:1.5rem;color:#2e353a}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
3437
+ }
3438
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: CopyInputComponent, decorators: [{
3439
+ type: Component,
3440
+ args: [{ selector: 'copy-input', standalone: true, imports: [
3441
+ CommonModule
3442
+ ], template: "<div class=\"copy-input-wrapper\">\n\n <!-- Tooltip -->\n <div\n class=\"copy-tooltip\"\n *ngIf=\"isCopied\"\n >\n Copiado\n </div>\n\n <!-- Componente -->\n <div\n class=\"copy-input\"\n (click)=\"copyToClipboard()\"\n tabindex=\"0\"\n role=\"button\"\n [attr.aria-label]=\"ariaLabel\"\n (keydown.enter)=\"copyToClipboard()\"\n >\n <i\n class=\"copy-input__icon\"\n [ngClass]=\"isCopied ? copiedIcon : icon\">\n </i>\n\n <span class=\"copy-input__text\">\n {{ value }}\n </span>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";.copy-input-wrapper{position:relative;display:inline-block;max-width:100%}.copy-tooltip{position:absolute;top:-2rem;left:50%;transform:translate(-50%);padding:.375rem .625rem;background:#2f2f2f;color:#fff;font-size:.75rem;border-radius:.375rem;white-space:nowrap;opacity:0;animation:fadeSlide .25s forwards}.copy-tooltip:after{content:\"\";position:absolute;bottom:-.375rem;left:50%;transform:translate(-50%);border-width:.375rem;border-style:solid;border-color:#2f2f2f transparent transparent transparent}@keyframes fadeSlide{0%{opacity:0;transform:translate(-50%,-5px)}to{opacity:1;transform:translate(-50%)}}.copy-input{display:flex;align-items:center;gap:.5rem;width:100%;box-sizing:border-box;padding:.625rem 1.125rem;border:2px solid #6D7275;border-radius:.5rem;cursor:pointer;-webkit-user-select:none;user-select:none;transition:background .2s ease,border-color .2s ease}.copy-input:hover{background:#f9f9f9;border-color:#d8d8d8}.copy-input:active{background:#f0f0f0}.copy-input:focus{outline-offset:2px}.copy-input__icon{font-size:1.1rem;color:#444;transition:transform .2s ease,color .2s ease}.copy-input__icon.icon-done{transform:scale(1.2);color:#27ae60}.copy-input__text{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-family:Quicksand,sans-serif;font-weight:600;font-size:1rem;line-height:1.5rem;color:#2e353a}\n"] }]
3443
+ }], propDecorators: { value: [{
3444
+ type: Input
3445
+ }], icon: [{
3446
+ type: Input
3447
+ }], copiedIcon: [{
3448
+ type: Input
3449
+ }], ariaLabel: [{
3450
+ type: Input
3451
+ }], copied: [{
3452
+ type: Output
3453
+ }] } });
3454
+
3455
+ class SnackbarComponent {
3456
+ snackbarService;
3457
+ snackbars = [];
3458
+ subscriptions = [];
3459
+ constructor(snackbarService) {
3460
+ this.snackbarService = snackbarService;
3461
+ }
3462
+ ngOnInit() {
3463
+ // Subscribe to new snackbars
3464
+ const snackbarSub = this.snackbarService.snackbar$.subscribe((snackbar) => {
3465
+ this.snackbars.push(snackbar);
3466
+ });
3467
+ this.subscriptions.push(snackbarSub);
3468
+ // Subscribe to dismiss events
3469
+ const dismissSub = this.snackbarService.dismiss$.subscribe((id) => {
3470
+ if (id === 'all') {
3471
+ this.snackbars = [];
3472
+ }
3473
+ else {
3474
+ this.snackbars = this.snackbars.filter(s => s.id !== id);
3475
+ }
3476
+ });
3477
+ this.subscriptions.push(dismissSub);
3478
+ }
3479
+ ngOnDestroy() {
3480
+ this.subscriptions.forEach(sub => sub.unsubscribe());
3481
+ }
3482
+ getSnackbarsByPosition(position) {
3483
+ return this.snackbars.filter(s => s.position === position);
3484
+ }
3485
+ dismiss(id) {
3486
+ this.snackbars = this.snackbars.filter(s => s.id !== id);
3487
+ this.snackbarService.dismiss(id);
3488
+ }
3489
+ handleAction(snackbar) {
3490
+ if (snackbar.actionCallback) {
3491
+ snackbar.actionCallback();
3492
+ }
3493
+ this.dismiss(snackbar.id);
3494
+ }
3495
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SnackbarComponent, deps: [{ token: SnackbarService }], target: i0.ɵɵFactoryTarget.Component });
3496
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: SnackbarComponent, isStandalone: true, selector: "app-snackbar", ngImport: i0, template: `
3497
+ <!-- Top Right -->
3498
+ <div class="snackbar-container snackbar-container--top-right" *ngIf="getSnackbarsByPosition('top-right').length > 0">
3499
+ <div
3500
+ *ngFor="let snackbar of getSnackbarsByPosition('top-right')"
3501
+ class="snackbar"
3502
+ [class.snackbar--success]="snackbar.type === 'success'"
3503
+ [class.snackbar--error]="snackbar.type === 'error'"
3504
+ [class.snackbar--warning]="snackbar.type === 'warning'"
3505
+ [class.snackbar--info]="snackbar.type === 'info'"
3506
+ >
3507
+ <div class="snackbar__icon">
3508
+ <svg *ngIf="snackbar.type === 'success'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3509
+ <path d="M16.6667 5L7.50004 14.1667L3.33337 10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3510
+ </svg>
3511
+ <svg *ngIf="snackbar.type === 'error'" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
3512
+ <path d="M11.96 2.37695C13.2212 2.38797 14.4681 2.65061 15.627 3.14844C16.7858 3.64631 17.8337 4.37013 18.71 5.27734L18.7158 5.2832L18.7227 5.28906C19.63 6.1654 20.3537 7.21402 20.8516 8.37305C21.3494 9.53204 21.6111 10.7787 21.6221 12.04C21.633 13.3014 21.3927 14.5523 20.915 15.7197C20.4374 16.8872 19.7318 17.9479 18.8398 18.8398C17.9479 19.7318 16.8872 20.4374 15.7197 20.915C14.5523 21.3927 13.3014 21.633 12.04 21.6221C10.7787 21.6111 9.53204 21.3494 8.37305 20.8516C7.21402 20.3537 6.1654 19.63 5.28906 18.7227L5.2832 18.7158L5.27734 18.71L4.94531 18.374C4.19221 17.5705 3.58408 16.641 3.14844 15.627C2.65061 14.4681 2.38797 13.2212 2.37695 11.96C2.36599 10.6986 2.60632 9.44681 3.08398 8.2793C3.56165 7.11184 4.26724 6.05112 5.15918 5.15918C6.05112 4.26724 7.11184 3.56165 8.2793 3.08398C9.44681 2.60632 10.6986 2.36599 11.96 2.37695ZM13.6523 3.66797C11.7234 3.28574 9.7209 3.58451 7.9873 4.5127C6.25388 5.4409 4.89578 6.94166 4.14453 8.75879C3.39335 10.5759 3.29528 12.5973 3.86719 14.4785C4.43922 16.3599 5.64653 17.9847 7.28223 19.0762C8.91789 20.1676 10.8811 20.6587 12.8379 20.4648C14.7947 20.271 16.623 19.4038 18.0127 18.0127C18.8041 17.2243 19.4316 16.2872 19.8584 15.2549C20.2319 14.3515 20.4462 13.3914 20.4912 12.417L20.5 11.998C20.4981 10.0321 19.8148 8.12717 18.5664 6.6084C17.3178 5.08945 15.5811 4.05022 13.6523 3.66797ZM15 8.49414C15.0659 8.49416 15.1315 8.50686 15.1924 8.53223C15.2531 8.55755 15.3081 8.59493 15.3545 8.6416L15.3574 8.64453C15.4043 8.69099 15.4414 8.74672 15.4668 8.80762C15.4922 8.86855 15.5059 8.93399 15.5059 9C15.5058 9.06595 15.4922 9.1315 15.4668 9.19238C15.4414 9.25316 15.4042 9.3081 15.3574 9.35449V9.35547L13.0566 11.6455L12.7012 12L13.0566 12.3545L15.3574 14.6445C15.4043 14.691 15.4414 14.7467 15.4668 14.8076C15.4922 14.8685 15.5059 14.934 15.5059 15C15.5058 15.0659 15.4922 15.1315 15.4668 15.1924C15.4414 15.2532 15.4042 15.3081 15.3574 15.3545L15.3545 15.3574C15.3081 15.4042 15.2532 15.4414 15.1924 15.4668C15.1315 15.4922 15.0659 15.5058 15 15.5059C14.934 15.5059 14.8685 15.4922 14.8076 15.4668C14.7467 15.4414 14.691 15.4043 14.6445 15.3574L12.3545 13.0566L12 12.7012L11.6455 13.0566L9.35547 15.3574H9.35449C9.3081 15.4042 9.25316 15.4414 9.19238 15.4668C9.1315 15.4922 9.06595 15.5058 9 15.5059C8.93399 15.5059 8.86855 15.4922 8.80762 15.4668C8.74672 15.4414 8.69099 15.4043 8.64453 15.3574L8.6416 15.3545C8.59493 15.3081 8.55755 15.2531 8.53223 15.1924C8.50686 15.1315 8.49416 15.0659 8.49414 15C8.49414 14.9341 8.50688 14.8685 8.53223 14.8076C8.55761 14.7467 8.59475 14.691 8.6416 14.6445H8.64258L10.9424 12.3545L11.2988 12L10.9424 11.6455L8.64258 9.35547C8.54859 9.26105 8.49614 9.13325 8.49609 9C8.49609 8.86631 8.54902 8.73809 8.64355 8.64355C8.73809 8.54902 8.86631 8.49609 9 8.49609C9.10009 8.49613 9.1972 8.52542 9.2793 8.58008L9.35645 8.64355L11.6455 10.9424L12 11.2988L12.3545 10.9424L14.6445 8.64258V8.6416C14.691 8.59475 14.7467 8.55761 14.8076 8.53223C14.8685 8.50688 14.9341 8.49414 15 8.49414Z" stroke="#F04438"/>
3513
+ </svg>
3514
+ <svg *ngIf="snackbar.type === 'warning'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3515
+ <path d="M10 7V11M10 15H10.01M8.60001 3.5L1.95001 15C1.69137 15.4584 1.55396 15.9753 1.55189 16.5015C1.54982 17.0277 1.68317 17.5456 1.93827 18.006C2.19337 18.4663 2.56117 18.8535 3.00616 19.1305C3.45115 19.4075 3.95928 19.5648 4.48001 19.5882H17.52C18.0407 19.5648 18.5489 19.4075 18.9939 19.1305C19.4388 18.8535 19.8066 18.4663 20.0617 18.006C20.3168 17.5456 20.4502 17.0277 20.4481 16.5015C20.446 15.9753 20.3086 15.4584 20.05 15L13.4 3.5C13.1332 3.05942 12.7619 2.69355 12.3198 2.43406C11.8777 2.17458 11.3783 2.02954 10.87 2.00967C10.3617 1.98981 9.85362 2.09565 9.39278 2.31848C8.93194 2.5413 8.53223 2.87461 8.23001 3.29L8.60001 3.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3516
+ </svg>
3517
+ <svg *ngIf="snackbar.type === 'info'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3518
+ <path d="M10 14V10M10 6H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3519
+ </svg>
3520
+ </div>
3521
+ <div class="snackbar__content">
3522
+ <p class="snackbar__message">{{ snackbar.message }}</p>
3523
+ </div>
3524
+ <button
3525
+ *ngIf="snackbar.action"
3526
+ class="snackbar__action"
3527
+ (click)="handleAction(snackbar)">
3528
+ {{ snackbar.action }}
3529
+ </button>
3530
+ <button
3531
+ class="snackbar__close"
3532
+ (click)="dismiss(snackbar.id)"
3533
+ aria-label="Cerrar">
3534
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
3535
+ <path d="M13 1L1 13M1 1L13 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3536
+ </svg>
3537
+ </button>
3538
+ </div>
3539
+ </div>
3540
+
3541
+ <!-- Top Left -->
3542
+ <div class="snackbar-container snackbar-container--top-left" *ngIf="getSnackbarsByPosition('top-left').length > 0">
3543
+ <div
3544
+ *ngFor="let snackbar of getSnackbarsByPosition('top-left')"
3545
+ class="snackbar"
3546
+ [class.snackbar--success]="snackbar.type === 'success'"
3547
+ [class.snackbar--error]="snackbar.type === 'error'"
3548
+ [class.snackbar--warning]="snackbar.type === 'warning'"
3549
+ [class.snackbar--info]="snackbar.type === 'info'"
3550
+ >
3551
+ <div class="snackbar__icon">
3552
+ <svg *ngIf="snackbar.type === 'success'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3553
+ <path d="M16.6667 5L7.50004 14.1667L3.33337 10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3554
+ </svg>
3555
+ <svg *ngIf="snackbar.type === 'error'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3556
+ <path d="M10 6V10M10 14H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3557
+ </svg>
3558
+ <svg *ngIf="snackbar.type === 'warning'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3559
+ <path d="M10 7V11M10 15H10.01M8.60001 3.5L1.95001 15C1.69137 15.4584 1.55396 15.9753 1.55189 16.5015C1.54982 17.0277 1.68317 17.5456 1.93827 18.006C2.19337 18.4663 2.56117 18.8535 3.00616 19.1305C3.45115 19.4075 3.95928 19.5648 4.48001 19.5882H17.52C18.0407 19.5648 18.5489 19.4075 18.9939 19.1305C19.4388 18.8535 19.8066 18.4663 20.0617 18.006C20.3168 17.5456 20.4502 17.0277 20.4481 16.5015C20.446 15.9753 20.3086 15.4584 20.05 15L13.4 3.5C13.1332 3.05942 12.7619 2.69355 12.3198 2.43406C11.8777 2.17458 11.3783 2.02954 10.87 2.00967C10.3617 1.98981 9.85362 2.09565 9.39278 2.31848C8.93194 2.5413 8.53223 2.87461 8.23001 3.29L8.60001 3.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3560
+ </svg>
3561
+ <svg *ngIf="snackbar.type === 'info'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3562
+ <path d="M10 14V10M10 6H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3563
+ </svg>
3564
+ </div>
3565
+ <div class="snackbar__content">
3566
+ <p class="snackbar__message">{{ snackbar.message }}</p>
3567
+ </div>
3568
+ <button
3569
+ *ngIf="snackbar.action"
3570
+ class="snackbar__action"
3571
+ (click)="handleAction(snackbar)">
3572
+ {{ snackbar.action }}
3573
+ </button>
3574
+ <button
3575
+ class="snackbar__close"
3576
+ (click)="dismiss(snackbar.id)"
3577
+ aria-label="Cerrar">
3578
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
3579
+ <path d="M13 1L1 13M1 1L13 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3580
+ </svg>
3581
+ </button>
3582
+ </div>
3583
+ </div>
3584
+
3585
+ <!-- Top Center -->
3586
+ <div class="snackbar-container snackbar-container--top-center" *ngIf="getSnackbarsByPosition('top-center').length > 0">
3587
+ <div
3588
+ *ngFor="let snackbar of getSnackbarsByPosition('top-center')"
3589
+ class="snackbar"
3590
+ [class.snackbar--success]="snackbar.type === 'success'"
3591
+ [class.snackbar--error]="snackbar.type === 'error'"
3592
+ [class.snackbar--warning]="snackbar.type === 'warning'"
3593
+ [class.snackbar--info]="snackbar.type === 'info'"
3594
+ >
3595
+ <div class="snackbar__icon">
3596
+ <svg *ngIf="snackbar.type === 'success'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3597
+ <path d="M16.6667 5L7.50004 14.1667L3.33337 10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3598
+ </svg>
3599
+ <svg *ngIf="snackbar.type === 'error'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3600
+ <path d="M10 6V10M10 14H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3601
+ </svg>
3602
+ <svg *ngIf="snackbar.type === 'warning'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3603
+ <path d="M10 7V11M10 15H10.01M8.60001 3.5L1.95001 15C1.69137 15.4584 1.55396 15.9753 1.55189 16.5015C1.54982 17.0277 1.68317 17.5456 1.93827 18.006C2.19337 18.4663 2.56117 18.8535 3.00616 19.1305C3.45115 19.4075 3.95928 19.5648 4.48001 19.5882H17.52C18.0407 19.5648 18.5489 19.4075 18.9939 19.1305C19.4388 18.8535 19.8066 18.4663 20.0617 18.006C20.3168 17.5456 20.4502 17.0277 20.4481 16.5015C20.446 15.9753 20.3086 15.4584 20.05 15L13.4 3.5C13.1332 3.05942 12.7619 2.69355 12.3198 2.43406C11.8777 2.17458 11.3783 2.02954 10.87 2.00967C10.3617 1.98981 9.85362 2.09565 9.39278 2.31848C8.93194 2.5413 8.53223 2.87461 8.23001 3.29L8.60001 3.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3604
+ </svg>
3605
+ <svg *ngIf="snackbar.type === 'info'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3606
+ <path d="M10 14V10M10 6H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3607
+ </svg>
3608
+ </div>
3609
+ <div class="snackbar__content">
3610
+ <p class="snackbar__message">{{ snackbar.message }}</p>
3611
+ </div>
3612
+ <button
3613
+ *ngIf="snackbar.action"
3614
+ class="snackbar__action"
3615
+ (click)="handleAction(snackbar)">
3616
+ {{ snackbar.action }}
3617
+ </button>
3618
+ <button
3619
+ class="snackbar__close"
3620
+ (click)="dismiss(snackbar.id)"
3621
+ aria-label="Cerrar">
3622
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
3623
+ <path d="M13 1L1 13M1 1L13 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3624
+ </svg>
3625
+ </button>
3626
+ </div>
3627
+ </div>
3628
+
3629
+ <!-- Bottom Right -->
3630
+ <div class="snackbar-container snackbar-container--bottom-right" *ngIf="getSnackbarsByPosition('bottom-right').length > 0">
3631
+ <div
3632
+ *ngFor="let snackbar of getSnackbarsByPosition('bottom-right')"
3633
+ class="snackbar"
3634
+ [class.snackbar--success]="snackbar.type === 'success'"
3635
+ [class.snackbar--error]="snackbar.type === 'error'"
3636
+ [class.snackbar--warning]="snackbar.type === 'warning'"
3637
+ [class.snackbar--info]="snackbar.type === 'info'"
3638
+ >
3639
+ <div class="snackbar__icon">
3640
+ <svg *ngIf="snackbar.type === 'success'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3641
+ <path d="M16.6667 5L7.50004 14.1667L3.33337 10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3642
+ </svg>
3643
+ <svg *ngIf="snackbar.type === 'error'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3644
+ <path d="M10 6V10M10 14H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3645
+ </svg>
3646
+ <svg *ngIf="snackbar.type === 'warning'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3647
+ <path d="M10 7V11M10 15H10.01M8.60001 3.5L1.95001 15C1.69137 15.4584 1.55396 15.9753 1.55189 16.5015C1.54982 17.0277 1.68317 17.5456 1.93827 18.006C2.19337 18.4663 2.56117 18.8535 3.00616 19.1305C3.45115 19.4075 3.95928 19.5648 4.48001 19.5882H17.52C18.0407 19.5648 18.5489 19.4075 18.9939 19.1305C19.4388 18.8535 19.8066 18.4663 20.0617 18.006C20.3168 17.5456 20.4502 17.0277 20.4481 16.5015C20.446 15.9753 20.3086 15.4584 20.05 15L13.4 3.5C13.1332 3.05942 12.7619 2.69355 12.3198 2.43406C11.8777 2.17458 11.3783 2.02954 10.87 2.00967C10.3617 1.98981 9.85362 2.09565 9.39278 2.31848C8.93194 2.5413 8.53223 2.87461 8.23001 3.29L8.60001 3.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3648
+ </svg>
3649
+ <svg *ngIf="snackbar.type === 'info'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3650
+ <path d="M10 14V10M10 6H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3651
+ </svg>
3652
+ </div>
3653
+ <div class="snackbar__content">
3654
+ <p class="snackbar__message">{{ snackbar.message }}</p>
3655
+ </div>
3656
+ <button
3657
+ *ngIf="snackbar.action"
3658
+ class="snackbar__action"
3659
+ (click)="handleAction(snackbar)">
3660
+ {{ snackbar.action }}
3661
+ </button>
3662
+ <button
3663
+ class="snackbar__close"
3664
+ (click)="dismiss(snackbar.id)"
3665
+ aria-label="Cerrar">
3666
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
3667
+ <path d="M13 1L1 13M1 1L13 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3668
+ </svg>
3669
+ </button>
3670
+ </div>
3671
+ </div>
3672
+
3673
+ <!-- Bottom Left -->
3674
+ <div class="snackbar-container snackbar-container--bottom-left" *ngIf="getSnackbarsByPosition('bottom-left').length > 0">
3675
+ <div
3676
+ *ngFor="let snackbar of getSnackbarsByPosition('bottom-left')"
3677
+ class="snackbar"
3678
+ [class.snackbar--success]="snackbar.type === 'success'"
3679
+ [class.snackbar--error]="snackbar.type === 'error'"
3680
+ [class.snackbar--warning]="snackbar.type === 'warning'"
3681
+ [class.snackbar--info]="snackbar.type === 'info'"
3682
+ >
3683
+ <div class="snackbar__icon">
3684
+ <svg *ngIf="snackbar.type === 'success'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3685
+ <path d="M16.6667 5L7.50004 14.1667L3.33337 10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3686
+ </svg>
3687
+ <svg *ngIf="snackbar.type === 'error'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3688
+ <path d="M10 6V10M10 14H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3689
+ </svg>
3690
+ <svg *ngIf="snackbar.type === 'warning'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3691
+ <path d="M10 7V11M10 15H10.01M8.60001 3.5L1.95001 15C1.69137 15.4584 1.55396 15.9753 1.55189 16.5015C1.54982 17.0277 1.68317 17.5456 1.93827 18.006C2.19337 18.4663 2.56117 18.8535 3.00616 19.1305C3.45115 19.4075 3.95928 19.5648 4.48001 19.5882H17.52C18.0407 19.5648 18.5489 19.4075 18.9939 19.1305C19.4388 18.8535 19.8066 18.4663 20.0617 18.006C20.3168 17.5456 20.4502 17.0277 20.4481 16.5015C20.446 15.9753 20.3086 15.4584 20.05 15L13.4 3.5C13.1332 3.05942 12.7619 2.69355 12.3198 2.43406C11.8777 2.17458 11.3783 2.02954 10.87 2.00967C10.3617 1.98981 9.85362 2.09565 9.39278 2.31848C8.93194 2.5413 8.53223 2.87461 8.23001 3.29L8.60001 3.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3692
+ </svg>
3693
+ <svg *ngIf="snackbar.type === 'info'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3694
+ <path d="M10 14V10M10 6H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3695
+ </svg>
3696
+ </div>
3697
+ <div class="snackbar__content">
3698
+ <p class="snackbar__message">{{ snackbar.message }}</p>
3699
+ </div>
3700
+ <button
3701
+ *ngIf="snackbar.action"
3702
+ class="snackbar__action"
3703
+ (click)="handleAction(snackbar)">
3704
+ {{ snackbar.action }}
3705
+ </button>
3706
+ <button
3707
+ class="snackbar__close"
3708
+ (click)="dismiss(snackbar.id)"
3709
+ aria-label="Cerrar">
3710
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
3711
+ <path d="M13 1L1 13M1 1L13 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3712
+ </svg>
3713
+ </button>
3714
+ </div>
3715
+ </div>
3716
+
3717
+ <!-- Bottom Center -->
3718
+ <div class="snackbar-container snackbar-container--bottom-center" *ngIf="getSnackbarsByPosition('bottom-center').length > 0">
3719
+ <div
3720
+ *ngFor="let snackbar of getSnackbarsByPosition('bottom-center')"
3721
+ class="snackbar"
3722
+ [class.snackbar--success]="snackbar.type === 'success'"
3723
+ [class.snackbar--error]="snackbar.type === 'error'"
3724
+ [class.snackbar--warning]="snackbar.type === 'warning'"
3725
+ [class.snackbar--info]="snackbar.type === 'info'"
3726
+ >
3727
+ <div class="snackbar__icon">
3728
+ <svg *ngIf="snackbar.type === 'success'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3729
+ <path d="M16.6667 5L7.50004 14.1667L3.33337 10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3730
+ </svg>
3731
+ <svg *ngIf="snackbar.type === 'error'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3732
+ <path d="M10 6V10M10 14H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3733
+ </svg>
3734
+ <svg *ngIf="snackbar.type === 'warning'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3735
+ <path d="M10 7V11M10 15H10.01M8.60001 3.5L1.95001 15C1.69137 15.4584 1.55396 15.9753 1.55189 16.5015C1.54982 17.0277 1.68317 17.5456 1.93827 18.006C2.19337 18.4663 2.56117 18.8535 3.00616 19.1305C3.45115 19.4075 3.95928 19.5648 4.48001 19.5882H17.52C18.0407 19.5648 18.5489 19.4075 18.9939 19.1305C19.4388 18.8535 19.8066 18.4663 20.0617 18.006C20.3168 17.5456 20.4502 17.0277 20.4481 16.5015C20.446 15.9753 20.3086 15.4584 20.05 15L13.4 3.5C13.1332 3.05942 12.7619 2.69355 12.3198 2.43406C11.8777 2.17458 11.3783 2.02954 10.87 2.00967C10.3617 1.98981 9.85362 2.09565 9.39278 2.31848C8.93194 2.5413 8.53223 2.87461 8.23001 3.29L8.60001 3.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3736
+ </svg>
3737
+ <svg *ngIf="snackbar.type === 'info'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3738
+ <path d="M10 14V10M10 6H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3739
+ </svg>
3740
+ </div>
3741
+ <div class="snackbar__content">
3742
+ <p class="snackbar__message">{{ snackbar.message }}</p>
3743
+ </div>
3744
+ <button
3745
+ *ngIf="snackbar.action"
3746
+ class="snackbar__action"
3747
+ (click)="handleAction(snackbar)">
3748
+ {{ snackbar.action }}
3749
+ </button>
3750
+ <button
3751
+ class="snackbar__close"
3752
+ (click)="dismiss(snackbar.id)"
3753
+ aria-label="Cerrar">
3754
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
3755
+ <path d="M13 1L1 13M1 1L13 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3756
+ </svg>
3757
+ </button>
3758
+ </div>
3759
+ </div>
3760
+ `, isInline: true, styles: [".snackbar-container{position:fixed;z-index:999999;display:flex;flex-direction:column;gap:12px;max-width:644px;pointer-events:none}.snackbar-container--top-right{top:24px;right:24px}.snackbar-container--top-left{top:24px;left:24px}.snackbar-container--top-center{top:24px;left:50%;transform:translate(-50%)}.snackbar-container--bottom-right{bottom:24px;right:24px}.snackbar-container--bottom-left{bottom:24px;left:24px}.snackbar-container--bottom-center{bottom:24px;left:50%;transform:translate(-50%)}@media (max-width: 640px){.snackbar-container{left:16px!important;right:16px!important;max-width:none;transform:none!important}.snackbar-container--top-right,.snackbar-container--top-left,.snackbar-container--top-center{top:16px}.snackbar-container--bottom-right,.snackbar-container--bottom-left,.snackbar-container--bottom-center{bottom:16px}}.snackbar{display:flex;align-items:center;gap:12px;padding:16px;border-radius:8px;box-shadow:0 4px 12px #00000026;background:#fff;pointer-events:auto;min-width:300px;max-width:644px;animation:slideIn .3s ease-out}@keyframes slideIn{0%{transform:translateY(-100%);opacity:0}to{transform:translateY(0);opacity:1}}@media (max-width: 640px){.snackbar{min-width:auto;max-width:none}}.snackbar--success{background:#f0fdf4;border:1px solid #22c55e}.snackbar--success .snackbar__icon{color:#22c55e}.snackbar--error{background:#fef3f2;border:1px solid #F04438}.snackbar--error .snackbar__icon{color:#f04438}.snackbar--warning{background:#fffbeb;border:1px solid #f59e0b}.snackbar--warning .snackbar__icon{color:#f59e0b}.snackbar--info{background:#eff6ff;border:1px solid #3b82f6}.snackbar--info .snackbar__icon{color:#3b82f6}.snackbar__icon{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:20px;height:20px}.snackbar__content{flex:1;min-width:0}.snackbar__message{margin:0;line-height:20px;word-wrap:break-word;font-family:Quicksand,sans-serif;font-weight:600;font-size:14px;color:#2e353a}.snackbar__action{flex-shrink:0;padding:6px 12px;border:none;border-radius:4px;background:transparent;color:inherit;font-size:14px;font-weight:600;cursor:pointer;transition:background-color .2s}.snackbar__action:hover{background:#0000000d}.snackbar__action:active{background:#0000001a}.snackbar__close{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;border-radius:4px;background:transparent;color:#2e353a;cursor:pointer;transition:all .2s}.snackbar__close:hover{background:#0000000d;color:#1f2937}.snackbar__close:active{background:#0000001a}.snackbar__close svg{width:14px;height:14px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
3761
+ }
3762
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SnackbarComponent, decorators: [{
3763
+ type: Component,
3764
+ args: [{ selector: 'app-snackbar', standalone: true, imports: [CommonModule], template: `
3765
+ <!-- Top Right -->
3766
+ <div class="snackbar-container snackbar-container--top-right" *ngIf="getSnackbarsByPosition('top-right').length > 0">
3767
+ <div
3768
+ *ngFor="let snackbar of getSnackbarsByPosition('top-right')"
3769
+ class="snackbar"
3770
+ [class.snackbar--success]="snackbar.type === 'success'"
3771
+ [class.snackbar--error]="snackbar.type === 'error'"
3772
+ [class.snackbar--warning]="snackbar.type === 'warning'"
3773
+ [class.snackbar--info]="snackbar.type === 'info'"
3774
+ >
3775
+ <div class="snackbar__icon">
3776
+ <svg *ngIf="snackbar.type === 'success'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3777
+ <path d="M16.6667 5L7.50004 14.1667L3.33337 10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3778
+ </svg>
3779
+ <svg *ngIf="snackbar.type === 'error'" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
3780
+ <path d="M11.96 2.37695C13.2212 2.38797 14.4681 2.65061 15.627 3.14844C16.7858 3.64631 17.8337 4.37013 18.71 5.27734L18.7158 5.2832L18.7227 5.28906C19.63 6.1654 20.3537 7.21402 20.8516 8.37305C21.3494 9.53204 21.6111 10.7787 21.6221 12.04C21.633 13.3014 21.3927 14.5523 20.915 15.7197C20.4374 16.8872 19.7318 17.9479 18.8398 18.8398C17.9479 19.7318 16.8872 20.4374 15.7197 20.915C14.5523 21.3927 13.3014 21.633 12.04 21.6221C10.7787 21.6111 9.53204 21.3494 8.37305 20.8516C7.21402 20.3537 6.1654 19.63 5.28906 18.7227L5.2832 18.7158L5.27734 18.71L4.94531 18.374C4.19221 17.5705 3.58408 16.641 3.14844 15.627C2.65061 14.4681 2.38797 13.2212 2.37695 11.96C2.36599 10.6986 2.60632 9.44681 3.08398 8.2793C3.56165 7.11184 4.26724 6.05112 5.15918 5.15918C6.05112 4.26724 7.11184 3.56165 8.2793 3.08398C9.44681 2.60632 10.6986 2.36599 11.96 2.37695ZM13.6523 3.66797C11.7234 3.28574 9.7209 3.58451 7.9873 4.5127C6.25388 5.4409 4.89578 6.94166 4.14453 8.75879C3.39335 10.5759 3.29528 12.5973 3.86719 14.4785C4.43922 16.3599 5.64653 17.9847 7.28223 19.0762C8.91789 20.1676 10.8811 20.6587 12.8379 20.4648C14.7947 20.271 16.623 19.4038 18.0127 18.0127C18.8041 17.2243 19.4316 16.2872 19.8584 15.2549C20.2319 14.3515 20.4462 13.3914 20.4912 12.417L20.5 11.998C20.4981 10.0321 19.8148 8.12717 18.5664 6.6084C17.3178 5.08945 15.5811 4.05022 13.6523 3.66797ZM15 8.49414C15.0659 8.49416 15.1315 8.50686 15.1924 8.53223C15.2531 8.55755 15.3081 8.59493 15.3545 8.6416L15.3574 8.64453C15.4043 8.69099 15.4414 8.74672 15.4668 8.80762C15.4922 8.86855 15.5059 8.93399 15.5059 9C15.5058 9.06595 15.4922 9.1315 15.4668 9.19238C15.4414 9.25316 15.4042 9.3081 15.3574 9.35449V9.35547L13.0566 11.6455L12.7012 12L13.0566 12.3545L15.3574 14.6445C15.4043 14.691 15.4414 14.7467 15.4668 14.8076C15.4922 14.8685 15.5059 14.934 15.5059 15C15.5058 15.0659 15.4922 15.1315 15.4668 15.1924C15.4414 15.2532 15.4042 15.3081 15.3574 15.3545L15.3545 15.3574C15.3081 15.4042 15.2532 15.4414 15.1924 15.4668C15.1315 15.4922 15.0659 15.5058 15 15.5059C14.934 15.5059 14.8685 15.4922 14.8076 15.4668C14.7467 15.4414 14.691 15.4043 14.6445 15.3574L12.3545 13.0566L12 12.7012L11.6455 13.0566L9.35547 15.3574H9.35449C9.3081 15.4042 9.25316 15.4414 9.19238 15.4668C9.1315 15.4922 9.06595 15.5058 9 15.5059C8.93399 15.5059 8.86855 15.4922 8.80762 15.4668C8.74672 15.4414 8.69099 15.4043 8.64453 15.3574L8.6416 15.3545C8.59493 15.3081 8.55755 15.2531 8.53223 15.1924C8.50686 15.1315 8.49416 15.0659 8.49414 15C8.49414 14.9341 8.50688 14.8685 8.53223 14.8076C8.55761 14.7467 8.59475 14.691 8.6416 14.6445H8.64258L10.9424 12.3545L11.2988 12L10.9424 11.6455L8.64258 9.35547C8.54859 9.26105 8.49614 9.13325 8.49609 9C8.49609 8.86631 8.54902 8.73809 8.64355 8.64355C8.73809 8.54902 8.86631 8.49609 9 8.49609C9.10009 8.49613 9.1972 8.52542 9.2793 8.58008L9.35645 8.64355L11.6455 10.9424L12 11.2988L12.3545 10.9424L14.6445 8.64258V8.6416C14.691 8.59475 14.7467 8.55761 14.8076 8.53223C14.8685 8.50688 14.9341 8.49414 15 8.49414Z" stroke="#F04438"/>
3781
+ </svg>
3782
+ <svg *ngIf="snackbar.type === 'warning'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3783
+ <path d="M10 7V11M10 15H10.01M8.60001 3.5L1.95001 15C1.69137 15.4584 1.55396 15.9753 1.55189 16.5015C1.54982 17.0277 1.68317 17.5456 1.93827 18.006C2.19337 18.4663 2.56117 18.8535 3.00616 19.1305C3.45115 19.4075 3.95928 19.5648 4.48001 19.5882H17.52C18.0407 19.5648 18.5489 19.4075 18.9939 19.1305C19.4388 18.8535 19.8066 18.4663 20.0617 18.006C20.3168 17.5456 20.4502 17.0277 20.4481 16.5015C20.446 15.9753 20.3086 15.4584 20.05 15L13.4 3.5C13.1332 3.05942 12.7619 2.69355 12.3198 2.43406C11.8777 2.17458 11.3783 2.02954 10.87 2.00967C10.3617 1.98981 9.85362 2.09565 9.39278 2.31848C8.93194 2.5413 8.53223 2.87461 8.23001 3.29L8.60001 3.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3784
+ </svg>
3785
+ <svg *ngIf="snackbar.type === 'info'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3786
+ <path d="M10 14V10M10 6H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3787
+ </svg>
3788
+ </div>
3789
+ <div class="snackbar__content">
3790
+ <p class="snackbar__message">{{ snackbar.message }}</p>
3791
+ </div>
3792
+ <button
3793
+ *ngIf="snackbar.action"
3794
+ class="snackbar__action"
3795
+ (click)="handleAction(snackbar)">
3796
+ {{ snackbar.action }}
3797
+ </button>
3798
+ <button
3799
+ class="snackbar__close"
3800
+ (click)="dismiss(snackbar.id)"
3801
+ aria-label="Cerrar">
3802
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
3803
+ <path d="M13 1L1 13M1 1L13 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3804
+ </svg>
3805
+ </button>
3806
+ </div>
3807
+ </div>
3808
+
3809
+ <!-- Top Left -->
3810
+ <div class="snackbar-container snackbar-container--top-left" *ngIf="getSnackbarsByPosition('top-left').length > 0">
3811
+ <div
3812
+ *ngFor="let snackbar of getSnackbarsByPosition('top-left')"
3813
+ class="snackbar"
3814
+ [class.snackbar--success]="snackbar.type === 'success'"
3815
+ [class.snackbar--error]="snackbar.type === 'error'"
3816
+ [class.snackbar--warning]="snackbar.type === 'warning'"
3817
+ [class.snackbar--info]="snackbar.type === 'info'"
3818
+ >
3819
+ <div class="snackbar__icon">
3820
+ <svg *ngIf="snackbar.type === 'success'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3821
+ <path d="M16.6667 5L7.50004 14.1667L3.33337 10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3822
+ </svg>
3823
+ <svg *ngIf="snackbar.type === 'error'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3824
+ <path d="M10 6V10M10 14H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3825
+ </svg>
3826
+ <svg *ngIf="snackbar.type === 'warning'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3827
+ <path d="M10 7V11M10 15H10.01M8.60001 3.5L1.95001 15C1.69137 15.4584 1.55396 15.9753 1.55189 16.5015C1.54982 17.0277 1.68317 17.5456 1.93827 18.006C2.19337 18.4663 2.56117 18.8535 3.00616 19.1305C3.45115 19.4075 3.95928 19.5648 4.48001 19.5882H17.52C18.0407 19.5648 18.5489 19.4075 18.9939 19.1305C19.4388 18.8535 19.8066 18.4663 20.0617 18.006C20.3168 17.5456 20.4502 17.0277 20.4481 16.5015C20.446 15.9753 20.3086 15.4584 20.05 15L13.4 3.5C13.1332 3.05942 12.7619 2.69355 12.3198 2.43406C11.8777 2.17458 11.3783 2.02954 10.87 2.00967C10.3617 1.98981 9.85362 2.09565 9.39278 2.31848C8.93194 2.5413 8.53223 2.87461 8.23001 3.29L8.60001 3.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3828
+ </svg>
3829
+ <svg *ngIf="snackbar.type === 'info'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3830
+ <path d="M10 14V10M10 6H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3831
+ </svg>
3832
+ </div>
3833
+ <div class="snackbar__content">
3834
+ <p class="snackbar__message">{{ snackbar.message }}</p>
3835
+ </div>
3836
+ <button
3837
+ *ngIf="snackbar.action"
3838
+ class="snackbar__action"
3839
+ (click)="handleAction(snackbar)">
3840
+ {{ snackbar.action }}
3841
+ </button>
3842
+ <button
3843
+ class="snackbar__close"
3844
+ (click)="dismiss(snackbar.id)"
3845
+ aria-label="Cerrar">
3846
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
3847
+ <path d="M13 1L1 13M1 1L13 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3848
+ </svg>
3849
+ </button>
3850
+ </div>
3851
+ </div>
3852
+
3853
+ <!-- Top Center -->
3854
+ <div class="snackbar-container snackbar-container--top-center" *ngIf="getSnackbarsByPosition('top-center').length > 0">
3855
+ <div
3856
+ *ngFor="let snackbar of getSnackbarsByPosition('top-center')"
3857
+ class="snackbar"
3858
+ [class.snackbar--success]="snackbar.type === 'success'"
3859
+ [class.snackbar--error]="snackbar.type === 'error'"
3860
+ [class.snackbar--warning]="snackbar.type === 'warning'"
3861
+ [class.snackbar--info]="snackbar.type === 'info'"
3862
+ >
3863
+ <div class="snackbar__icon">
3864
+ <svg *ngIf="snackbar.type === 'success'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3865
+ <path d="M16.6667 5L7.50004 14.1667L3.33337 10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3866
+ </svg>
3867
+ <svg *ngIf="snackbar.type === 'error'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3868
+ <path d="M10 6V10M10 14H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3869
+ </svg>
3870
+ <svg *ngIf="snackbar.type === 'warning'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3871
+ <path d="M10 7V11M10 15H10.01M8.60001 3.5L1.95001 15C1.69137 15.4584 1.55396 15.9753 1.55189 16.5015C1.54982 17.0277 1.68317 17.5456 1.93827 18.006C2.19337 18.4663 2.56117 18.8535 3.00616 19.1305C3.45115 19.4075 3.95928 19.5648 4.48001 19.5882H17.52C18.0407 19.5648 18.5489 19.4075 18.9939 19.1305C19.4388 18.8535 19.8066 18.4663 20.0617 18.006C20.3168 17.5456 20.4502 17.0277 20.4481 16.5015C20.446 15.9753 20.3086 15.4584 20.05 15L13.4 3.5C13.1332 3.05942 12.7619 2.69355 12.3198 2.43406C11.8777 2.17458 11.3783 2.02954 10.87 2.00967C10.3617 1.98981 9.85362 2.09565 9.39278 2.31848C8.93194 2.5413 8.53223 2.87461 8.23001 3.29L8.60001 3.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3872
+ </svg>
3873
+ <svg *ngIf="snackbar.type === 'info'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3874
+ <path d="M10 14V10M10 6H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3875
+ </svg>
3876
+ </div>
3877
+ <div class="snackbar__content">
3878
+ <p class="snackbar__message">{{ snackbar.message }}</p>
3879
+ </div>
3880
+ <button
3881
+ *ngIf="snackbar.action"
3882
+ class="snackbar__action"
3883
+ (click)="handleAction(snackbar)">
3884
+ {{ snackbar.action }}
3885
+ </button>
3886
+ <button
3887
+ class="snackbar__close"
3888
+ (click)="dismiss(snackbar.id)"
3889
+ aria-label="Cerrar">
3890
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
3891
+ <path d="M13 1L1 13M1 1L13 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3892
+ </svg>
3893
+ </button>
3894
+ </div>
3895
+ </div>
3896
+
3897
+ <!-- Bottom Right -->
3898
+ <div class="snackbar-container snackbar-container--bottom-right" *ngIf="getSnackbarsByPosition('bottom-right').length > 0">
3899
+ <div
3900
+ *ngFor="let snackbar of getSnackbarsByPosition('bottom-right')"
3901
+ class="snackbar"
3902
+ [class.snackbar--success]="snackbar.type === 'success'"
3903
+ [class.snackbar--error]="snackbar.type === 'error'"
3904
+ [class.snackbar--warning]="snackbar.type === 'warning'"
3905
+ [class.snackbar--info]="snackbar.type === 'info'"
3906
+ >
3907
+ <div class="snackbar__icon">
3908
+ <svg *ngIf="snackbar.type === 'success'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3909
+ <path d="M16.6667 5L7.50004 14.1667L3.33337 10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3910
+ </svg>
3911
+ <svg *ngIf="snackbar.type === 'error'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3912
+ <path d="M10 6V10M10 14H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3913
+ </svg>
3914
+ <svg *ngIf="snackbar.type === 'warning'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3915
+ <path d="M10 7V11M10 15H10.01M8.60001 3.5L1.95001 15C1.69137 15.4584 1.55396 15.9753 1.55189 16.5015C1.54982 17.0277 1.68317 17.5456 1.93827 18.006C2.19337 18.4663 2.56117 18.8535 3.00616 19.1305C3.45115 19.4075 3.95928 19.5648 4.48001 19.5882H17.52C18.0407 19.5648 18.5489 19.4075 18.9939 19.1305C19.4388 18.8535 19.8066 18.4663 20.0617 18.006C20.3168 17.5456 20.4502 17.0277 20.4481 16.5015C20.446 15.9753 20.3086 15.4584 20.05 15L13.4 3.5C13.1332 3.05942 12.7619 2.69355 12.3198 2.43406C11.8777 2.17458 11.3783 2.02954 10.87 2.00967C10.3617 1.98981 9.85362 2.09565 9.39278 2.31848C8.93194 2.5413 8.53223 2.87461 8.23001 3.29L8.60001 3.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3916
+ </svg>
3917
+ <svg *ngIf="snackbar.type === 'info'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3918
+ <path d="M10 14V10M10 6H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3919
+ </svg>
3920
+ </div>
3921
+ <div class="snackbar__content">
3922
+ <p class="snackbar__message">{{ snackbar.message }}</p>
3923
+ </div>
3924
+ <button
3925
+ *ngIf="snackbar.action"
3926
+ class="snackbar__action"
3927
+ (click)="handleAction(snackbar)">
3928
+ {{ snackbar.action }}
3929
+ </button>
3930
+ <button
3931
+ class="snackbar__close"
3932
+ (click)="dismiss(snackbar.id)"
3933
+ aria-label="Cerrar">
3934
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
3935
+ <path d="M13 1L1 13M1 1L13 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3936
+ </svg>
3937
+ </button>
3938
+ </div>
3939
+ </div>
3940
+
3941
+ <!-- Bottom Left -->
3942
+ <div class="snackbar-container snackbar-container--bottom-left" *ngIf="getSnackbarsByPosition('bottom-left').length > 0">
3943
+ <div
3944
+ *ngFor="let snackbar of getSnackbarsByPosition('bottom-left')"
3945
+ class="snackbar"
3946
+ [class.snackbar--success]="snackbar.type === 'success'"
3947
+ [class.snackbar--error]="snackbar.type === 'error'"
3948
+ [class.snackbar--warning]="snackbar.type === 'warning'"
3949
+ [class.snackbar--info]="snackbar.type === 'info'"
3950
+ >
3951
+ <div class="snackbar__icon">
3952
+ <svg *ngIf="snackbar.type === 'success'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3953
+ <path d="M16.6667 5L7.50004 14.1667L3.33337 10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3954
+ </svg>
3955
+ <svg *ngIf="snackbar.type === 'error'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3956
+ <path d="M10 6V10M10 14H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3957
+ </svg>
3958
+ <svg *ngIf="snackbar.type === 'warning'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3959
+ <path d="M10 7V11M10 15H10.01M8.60001 3.5L1.95001 15C1.69137 15.4584 1.55396 15.9753 1.55189 16.5015C1.54982 17.0277 1.68317 17.5456 1.93827 18.006C2.19337 18.4663 2.56117 18.8535 3.00616 19.1305C3.45115 19.4075 3.95928 19.5648 4.48001 19.5882H17.52C18.0407 19.5648 18.5489 19.4075 18.9939 19.1305C19.4388 18.8535 19.8066 18.4663 20.0617 18.006C20.3168 17.5456 20.4502 17.0277 20.4481 16.5015C20.446 15.9753 20.3086 15.4584 20.05 15L13.4 3.5C13.1332 3.05942 12.7619 2.69355 12.3198 2.43406C11.8777 2.17458 11.3783 2.02954 10.87 2.00967C10.3617 1.98981 9.85362 2.09565 9.39278 2.31848C8.93194 2.5413 8.53223 2.87461 8.23001 3.29L8.60001 3.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3960
+ </svg>
3961
+ <svg *ngIf="snackbar.type === 'info'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3962
+ <path d="M10 14V10M10 6H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3963
+ </svg>
3964
+ </div>
3965
+ <div class="snackbar__content">
3966
+ <p class="snackbar__message">{{ snackbar.message }}</p>
3967
+ </div>
3968
+ <button
3969
+ *ngIf="snackbar.action"
3970
+ class="snackbar__action"
3971
+ (click)="handleAction(snackbar)">
3972
+ {{ snackbar.action }}
3973
+ </button>
3974
+ <button
3975
+ class="snackbar__close"
3976
+ (click)="dismiss(snackbar.id)"
3977
+ aria-label="Cerrar">
3978
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
3979
+ <path d="M13 1L1 13M1 1L13 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3980
+ </svg>
3981
+ </button>
3982
+ </div>
3983
+ </div>
3984
+
3985
+ <!-- Bottom Center -->
3986
+ <div class="snackbar-container snackbar-container--bottom-center" *ngIf="getSnackbarsByPosition('bottom-center').length > 0">
3987
+ <div
3988
+ *ngFor="let snackbar of getSnackbarsByPosition('bottom-center')"
3989
+ class="snackbar"
3990
+ [class.snackbar--success]="snackbar.type === 'success'"
3991
+ [class.snackbar--error]="snackbar.type === 'error'"
3992
+ [class.snackbar--warning]="snackbar.type === 'warning'"
3993
+ [class.snackbar--info]="snackbar.type === 'info'"
3994
+ >
3995
+ <div class="snackbar__icon">
3996
+ <svg *ngIf="snackbar.type === 'success'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3997
+ <path d="M16.6667 5L7.50004 14.1667L3.33337 10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3998
+ </svg>
3999
+ <svg *ngIf="snackbar.type === 'error'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
4000
+ <path d="M10 6V10M10 14H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
4001
+ </svg>
4002
+ <svg *ngIf="snackbar.type === 'warning'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
4003
+ <path d="M10 7V11M10 15H10.01M8.60001 3.5L1.95001 15C1.69137 15.4584 1.55396 15.9753 1.55189 16.5015C1.54982 17.0277 1.68317 17.5456 1.93827 18.006C2.19337 18.4663 2.56117 18.8535 3.00616 19.1305C3.45115 19.4075 3.95928 19.5648 4.48001 19.5882H17.52C18.0407 19.5648 18.5489 19.4075 18.9939 19.1305C19.4388 18.8535 19.8066 18.4663 20.0617 18.006C20.3168 17.5456 20.4502 17.0277 20.4481 16.5015C20.446 15.9753 20.3086 15.4584 20.05 15L13.4 3.5C13.1332 3.05942 12.7619 2.69355 12.3198 2.43406C11.8777 2.17458 11.3783 2.02954 10.87 2.00967C10.3617 1.98981 9.85362 2.09565 9.39278 2.31848C8.93194 2.5413 8.53223 2.87461 8.23001 3.29L8.60001 3.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
4004
+ </svg>
4005
+ <svg *ngIf="snackbar.type === 'info'" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
4006
+ <path d="M10 14V10M10 6H10.01M18 10C18 14.4183 14.4183 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2C14.4183 2 18 5.58172 18 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
4007
+ </svg>
4008
+ </div>
4009
+ <div class="snackbar__content">
4010
+ <p class="snackbar__message">{{ snackbar.message }}</p>
4011
+ </div>
4012
+ <button
4013
+ *ngIf="snackbar.action"
4014
+ class="snackbar__action"
4015
+ (click)="handleAction(snackbar)">
4016
+ {{ snackbar.action }}
4017
+ </button>
4018
+ <button
4019
+ class="snackbar__close"
4020
+ (click)="dismiss(snackbar.id)"
4021
+ aria-label="Cerrar">
4022
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
4023
+ <path d="M13 1L1 13M1 1L13 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
4024
+ </svg>
4025
+ </button>
4026
+ </div>
4027
+ </div>
4028
+ `, styles: [".snackbar-container{position:fixed;z-index:999999;display:flex;flex-direction:column;gap:12px;max-width:644px;pointer-events:none}.snackbar-container--top-right{top:24px;right:24px}.snackbar-container--top-left{top:24px;left:24px}.snackbar-container--top-center{top:24px;left:50%;transform:translate(-50%)}.snackbar-container--bottom-right{bottom:24px;right:24px}.snackbar-container--bottom-left{bottom:24px;left:24px}.snackbar-container--bottom-center{bottom:24px;left:50%;transform:translate(-50%)}@media (max-width: 640px){.snackbar-container{left:16px!important;right:16px!important;max-width:none;transform:none!important}.snackbar-container--top-right,.snackbar-container--top-left,.snackbar-container--top-center{top:16px}.snackbar-container--bottom-right,.snackbar-container--bottom-left,.snackbar-container--bottom-center{bottom:16px}}.snackbar{display:flex;align-items:center;gap:12px;padding:16px;border-radius:8px;box-shadow:0 4px 12px #00000026;background:#fff;pointer-events:auto;min-width:300px;max-width:644px;animation:slideIn .3s ease-out}@keyframes slideIn{0%{transform:translateY(-100%);opacity:0}to{transform:translateY(0);opacity:1}}@media (max-width: 640px){.snackbar{min-width:auto;max-width:none}}.snackbar--success{background:#f0fdf4;border:1px solid #22c55e}.snackbar--success .snackbar__icon{color:#22c55e}.snackbar--error{background:#fef3f2;border:1px solid #F04438}.snackbar--error .snackbar__icon{color:#f04438}.snackbar--warning{background:#fffbeb;border:1px solid #f59e0b}.snackbar--warning .snackbar__icon{color:#f59e0b}.snackbar--info{background:#eff6ff;border:1px solid #3b82f6}.snackbar--info .snackbar__icon{color:#3b82f6}.snackbar__icon{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:20px;height:20px}.snackbar__content{flex:1;min-width:0}.snackbar__message{margin:0;line-height:20px;word-wrap:break-word;font-family:Quicksand,sans-serif;font-weight:600;font-size:14px;color:#2e353a}.snackbar__action{flex-shrink:0;padding:6px 12px;border:none;border-radius:4px;background:transparent;color:inherit;font-size:14px;font-weight:600;cursor:pointer;transition:background-color .2s}.snackbar__action:hover{background:#0000000d}.snackbar__action:active{background:#0000001a}.snackbar__close{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:none;border-radius:4px;background:transparent;color:#2e353a;cursor:pointer;transition:all .2s}.snackbar__close:hover{background:#0000000d;color:#1f2937}.snackbar__close:active{background:#0000001a}.snackbar__close svg{width:14px;height:14px}\n"] }]
4029
+ }], ctorParameters: () => [{ type: SnackbarService }] });
4030
+
4031
+ class AlertComponent {
4032
+ color = 'default';
4033
+ size = 'floating';
4034
+ alertTitle = '';
4035
+ supportingText;
4036
+ showIcon = true;
4037
+ showActions = true;
4038
+ actionVariant = 'link';
4039
+ dismissLabel = 'Descartar';
4040
+ primaryActionLabel = 'Ver cambios';
4041
+ showClose = true;
4042
+ closeAriaLabel = 'Cerrar';
4043
+ dismiss = new EventEmitter();
4044
+ primaryAction = new EventEmitter();
4045
+ closed = new EventEmitter();
4046
+ get alertClasses() {
4047
+ return [
4048
+ 'sv-alert',
4049
+ `sv-alert--${this.color}`,
4050
+ this.size === 'full-width' ? 'sv-alert--full-width' : ''
4051
+ ].filter(Boolean).join(' ');
4052
+ }
4053
+ get actionClass() {
4054
+ return this.actionVariant === 'button' ? 'sv-alert__btn' : 'sv-alert__action';
4055
+ }
4056
+ get primaryActionClass() {
4057
+ return this.actionVariant === 'button'
4058
+ ? 'sv-alert__btn sv-alert__btn--primary'
4059
+ : 'sv-alert__action sv-alert__action--primary';
4060
+ }
4061
+ handleDismiss() {
4062
+ this.dismiss.emit();
4063
+ }
4064
+ handlePrimaryAction() {
4065
+ this.primaryAction.emit();
4066
+ }
4067
+ handleClose() {
4068
+ this.closed.emit();
4069
+ }
4070
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4071
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: AlertComponent, isStandalone: true, selector: "app-alert", inputs: { color: "color", size: "size", alertTitle: "alertTitle", supportingText: "supportingText", showIcon: "showIcon", showActions: "showActions", actionVariant: "actionVariant", dismissLabel: "dismissLabel", primaryActionLabel: "primaryActionLabel", showClose: "showClose", closeAriaLabel: "closeAriaLabel" }, outputs: { dismiss: "dismiss", primaryAction: "primaryAction", closed: "closed" }, ngImport: i0, template: "<div [class]=\"alertClasses\" role=\"alert\">\n <div class=\"sv-alert__container\">\n <div class=\"sv-alert__icon\" *ngIf=\"showIcon\" aria-hidden=\"true\">\n <svg *ngIf=\"color === 'error'\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7.86 2h8.28L22 7.86v8.28L16.14 22H7.86L2 16.14V7.86L7.86 2Z\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M12 8v4M12 16h.01\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <svg *ngIf=\"color === 'warning'\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M12 9v4M12 17h.01\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <svg *ngIf=\"color === 'success'\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M22 4 12 14.01l-3-3\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <svg *ngIf=\"color !== 'error' && color !== 'warning' && color !== 'success'\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10Z\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M12 16v-4M12 8h.01\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n\n <div class=\"sv-alert__content\">\n <div class=\"sv-alert__body\">\n <p class=\"sv-alert__title\">{{ alertTitle }}</p>\n <p class=\"sv-alert__text\" *ngIf=\"supportingText\">{{ supportingText }}</p>\n </div>\n\n <div class=\"sv-alert__actions\" *ngIf=\"showActions\">\n <button type=\"button\" [class]=\"actionClass\" (click)=\"handleDismiss()\">{{ dismissLabel }}</button>\n <button type=\"button\" [class]=\"primaryActionClass\" (click)=\"handlePrimaryAction()\">{{ primaryActionLabel }}</button>\n </div>\n </div>\n\n <button\n type=\"button\"\n class=\"sv-alert__close\"\n *ngIf=\"showClose\"\n [attr.aria-label]=\"closeAriaLabel\"\n (click)=\"handleClose()\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M18 6 6 18M6 6l12 12\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n </div>\n</div>\n", styles: [".sv-alert{--sv-alert-bg: #ffffff;--sv-alert-border: #d4d4d4;--sv-alert-icon-fg: #737373;--sv-alert-icon-bg: #ffffff;--sv-alert-title: #404040;--sv-alert-text: #525252;--sv-alert-link: #2b3c7f;--sv-alert-solid: #364b9f;position:relative;display:flex;flex-direction:column;align-items:center;width:100%;padding:32px;background-color:var(--sv-alert-bg);border:1px solid var(--sv-alert-border);border-radius:12px;box-shadow:0 1px 2px #0000000d;font-family:Roboto,sans-serif;box-sizing:border-box}.sv-alert *{box-sizing:border-box}.sv-alert__container{display:flex;align-items:flex-start;gap:32px;width:100%}.sv-alert__icon{position:relative;flex-shrink:0;display:flex;align-items:center;justify-content:center;width:40px;height:40px;border:1px solid var(--sv-alert-border);border-radius:8px;background-color:var(--sv-alert-icon-bg);color:var(--sv-alert-icon-fg);box-shadow:0 1px 2px #0000000d,inset 0 0 0 1px #0000002e,inset 0 -2px #0000000d}.sv-alert__icon svg{width:20px;height:20px;display:block}.sv-alert__content{display:flex;flex:1 0 0;flex-direction:column;align-items:flex-start;gap:24px;min-width:0}.sv-alert__body{display:flex;flex-direction:column;align-items:flex-start;gap:8px;width:100%}.sv-alert__title{margin:0;padding-right:56px;width:100%;font-family:Roboto,sans-serif;font-weight:600;font-size:14px;line-height:20px;color:var(--sv-alert-title);word-break:break-word}.sv-alert__text{margin:0;width:100%;font-family:Roboto,sans-serif;font-weight:400;font-size:14px;line-height:20px;color:var(--sv-alert-text);word-break:break-word}.sv-alert__actions{display:flex;align-items:center;gap:24px;flex-shrink:0}.sv-alert__action{padding:0;border:none;background:none;font-family:Roboto,sans-serif;font-weight:600;font-size:14px;line-height:20px;color:var(--sv-alert-text);white-space:nowrap;cursor:pointer;transition:opacity .2s ease-in-out}.sv-alert__action:hover{opacity:.7}.sv-alert__action:focus-visible{outline:2px solid var(--sv-alert-link);outline-offset:2px;border-radius:4px}.sv-alert__action--primary{color:var(--sv-alert-link)}.sv-alert__close{position:absolute;top:7px;right:7px;display:flex;align-items:center;justify-content:center;flex-shrink:0;width:36px;height:36px;padding:0;border:none;border-radius:8px;background:none;color:var(--sv-alert-icon-fg);cursor:pointer;transition:background-color .2s ease-in-out}.sv-alert__close:hover{background-color:#0000000d}.sv-alert__close:focus-visible{outline:2px solid var(--sv-alert-link);outline-offset:-2px}.sv-alert__close svg{width:20px;height:20px;display:block}.sv-alert--brand{--sv-alert-bg: #f3f4f9;--sv-alert-border: #2b3c7f;--sv-alert-icon-fg: #364b9f;--sv-alert-icon-bg: #e5e8f3}.sv-alert--gray{--sv-alert-icon-fg: #737373;--sv-alert-icon-bg: #f5f5f5}.sv-alert--error{--sv-alert-bg: #fef2f2;--sv-alert-border: #dc2626;--sv-alert-icon-fg: #dc2626;--sv-alert-icon-bg: #fee2e2}.sv-alert--warning{--sv-alert-bg: #fefce8;--sv-alert-border: #ca8a04;--sv-alert-icon-fg: #ca8a04;--sv-alert-icon-bg: #fef9c3}.sv-alert--success{--sv-alert-bg: #f0fdf4;--sv-alert-border: #16a34a;--sv-alert-icon-fg: #16a34a;--sv-alert-icon-bg: #dcfce7}.sv-alert--brand .sv-alert__icon,.sv-alert--gray .sv-alert__icon,.sv-alert--error .sv-alert__icon,.sv-alert--warning .sv-alert__icon,.sv-alert--success .sv-alert__icon{border:none;border-radius:9999px;box-shadow:none}.sv-alert--full-width{padding:0;border:none;border-bottom:1px solid var(--sv-alert-border);border-radius:0;box-shadow:none}.sv-alert--full-width .sv-alert__container{align-items:center;gap:24px;max-width:1280px;padding:24px 32px}.sv-alert--full-width .sv-alert__content{flex-direction:row;align-items:center;gap:24px}.sv-alert--full-width .sv-alert__body{flex-direction:row;flex-wrap:wrap;align-items:baseline;gap:2px 12px;width:auto;flex:1 0 0;min-width:0}.sv-alert--full-width .sv-alert__title,.sv-alert--full-width .sv-alert__text{width:auto;padding-right:0}.sv-alert--full-width .sv-alert__close{position:static;align-self:center}.sv-alert__btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:12px 28px;border:1px solid var(--sv-alert-solid);border-radius:8px;background-color:#fff;font-family:Roboto,sans-serif;font-weight:600;font-size:14px;line-height:20px;color:var(--sv-alert-title);white-space:nowrap;cursor:pointer;box-shadow:0 1px 2px #0000000d,inset 0 0 0 1px #0000002e,inset 0 -2px #0000000d;transition:filter .2s ease-in-out}.sv-alert__btn:hover{filter:brightness(.97)}.sv-alert__btn:focus-visible{outline:2px solid var(--sv-alert-solid);outline-offset:2px}.sv-alert__btn--primary{border-color:#ffffff1f;border-width:2px;background-color:var(--sv-alert-solid);color:#fff}@media (max-width: 768px){.sv-alert{padding:16px}.sv-alert__container{flex-direction:column;align-items:flex-start;gap:16px}.sv-alert__content{width:100%}.sv-alert__title{padding-right:40px}.sv-alert--full-width{padding:0}.sv-alert--full-width .sv-alert__container{flex-direction:column;align-items:flex-start;gap:32px;padding:32px 16px}.sv-alert--full-width .sv-alert__content{flex-direction:column;align-items:flex-start;gap:16px;width:100%}.sv-alert--full-width .sv-alert__body{flex-direction:column;gap:4px;width:100%}.sv-alert--full-width .sv-alert__actions:has(.sv-alert__btn){flex-direction:column-reverse;align-items:stretch;gap:12px;width:100%}.sv-alert--full-width .sv-alert__close{position:absolute;top:16px;right:8px}.sv-alert__btn{width:100%}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
4072
+ }
4073
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AlertComponent, decorators: [{
4074
+ type: Component,
4075
+ args: [{ selector: 'app-alert', standalone: true, imports: [CommonModule], template: "<div [class]=\"alertClasses\" role=\"alert\">\n <div class=\"sv-alert__container\">\n <div class=\"sv-alert__icon\" *ngIf=\"showIcon\" aria-hidden=\"true\">\n <svg *ngIf=\"color === 'error'\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M7.86 2h8.28L22 7.86v8.28L16.14 22H7.86L2 16.14V7.86L7.86 2Z\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M12 8v4M12 16h.01\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <svg *ngIf=\"color === 'warning'\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M12 9v4M12 17h.01\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <svg *ngIf=\"color === 'success'\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M22 4 12 14.01l-3-3\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n <svg *ngIf=\"color !== 'error' && color !== 'warning' && color !== 'success'\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10Z\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M12 16v-4M12 8h.01\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n\n <div class=\"sv-alert__content\">\n <div class=\"sv-alert__body\">\n <p class=\"sv-alert__title\">{{ alertTitle }}</p>\n <p class=\"sv-alert__text\" *ngIf=\"supportingText\">{{ supportingText }}</p>\n </div>\n\n <div class=\"sv-alert__actions\" *ngIf=\"showActions\">\n <button type=\"button\" [class]=\"actionClass\" (click)=\"handleDismiss()\">{{ dismissLabel }}</button>\n <button type=\"button\" [class]=\"primaryActionClass\" (click)=\"handlePrimaryAction()\">{{ primaryActionLabel }}</button>\n </div>\n </div>\n\n <button\n type=\"button\"\n class=\"sv-alert__close\"\n *ngIf=\"showClose\"\n [attr.aria-label]=\"closeAriaLabel\"\n (click)=\"handleClose()\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M18 6 6 18M6 6l12 12\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n </div>\n</div>\n", styles: [".sv-alert{--sv-alert-bg: #ffffff;--sv-alert-border: #d4d4d4;--sv-alert-icon-fg: #737373;--sv-alert-icon-bg: #ffffff;--sv-alert-title: #404040;--sv-alert-text: #525252;--sv-alert-link: #2b3c7f;--sv-alert-solid: #364b9f;position:relative;display:flex;flex-direction:column;align-items:center;width:100%;padding:32px;background-color:var(--sv-alert-bg);border:1px solid var(--sv-alert-border);border-radius:12px;box-shadow:0 1px 2px #0000000d;font-family:Roboto,sans-serif;box-sizing:border-box}.sv-alert *{box-sizing:border-box}.sv-alert__container{display:flex;align-items:flex-start;gap:32px;width:100%}.sv-alert__icon{position:relative;flex-shrink:0;display:flex;align-items:center;justify-content:center;width:40px;height:40px;border:1px solid var(--sv-alert-border);border-radius:8px;background-color:var(--sv-alert-icon-bg);color:var(--sv-alert-icon-fg);box-shadow:0 1px 2px #0000000d,inset 0 0 0 1px #0000002e,inset 0 -2px #0000000d}.sv-alert__icon svg{width:20px;height:20px;display:block}.sv-alert__content{display:flex;flex:1 0 0;flex-direction:column;align-items:flex-start;gap:24px;min-width:0}.sv-alert__body{display:flex;flex-direction:column;align-items:flex-start;gap:8px;width:100%}.sv-alert__title{margin:0;padding-right:56px;width:100%;font-family:Roboto,sans-serif;font-weight:600;font-size:14px;line-height:20px;color:var(--sv-alert-title);word-break:break-word}.sv-alert__text{margin:0;width:100%;font-family:Roboto,sans-serif;font-weight:400;font-size:14px;line-height:20px;color:var(--sv-alert-text);word-break:break-word}.sv-alert__actions{display:flex;align-items:center;gap:24px;flex-shrink:0}.sv-alert__action{padding:0;border:none;background:none;font-family:Roboto,sans-serif;font-weight:600;font-size:14px;line-height:20px;color:var(--sv-alert-text);white-space:nowrap;cursor:pointer;transition:opacity .2s ease-in-out}.sv-alert__action:hover{opacity:.7}.sv-alert__action:focus-visible{outline:2px solid var(--sv-alert-link);outline-offset:2px;border-radius:4px}.sv-alert__action--primary{color:var(--sv-alert-link)}.sv-alert__close{position:absolute;top:7px;right:7px;display:flex;align-items:center;justify-content:center;flex-shrink:0;width:36px;height:36px;padding:0;border:none;border-radius:8px;background:none;color:var(--sv-alert-icon-fg);cursor:pointer;transition:background-color .2s ease-in-out}.sv-alert__close:hover{background-color:#0000000d}.sv-alert__close:focus-visible{outline:2px solid var(--sv-alert-link);outline-offset:-2px}.sv-alert__close svg{width:20px;height:20px;display:block}.sv-alert--brand{--sv-alert-bg: #f3f4f9;--sv-alert-border: #2b3c7f;--sv-alert-icon-fg: #364b9f;--sv-alert-icon-bg: #e5e8f3}.sv-alert--gray{--sv-alert-icon-fg: #737373;--sv-alert-icon-bg: #f5f5f5}.sv-alert--error{--sv-alert-bg: #fef2f2;--sv-alert-border: #dc2626;--sv-alert-icon-fg: #dc2626;--sv-alert-icon-bg: #fee2e2}.sv-alert--warning{--sv-alert-bg: #fefce8;--sv-alert-border: #ca8a04;--sv-alert-icon-fg: #ca8a04;--sv-alert-icon-bg: #fef9c3}.sv-alert--success{--sv-alert-bg: #f0fdf4;--sv-alert-border: #16a34a;--sv-alert-icon-fg: #16a34a;--sv-alert-icon-bg: #dcfce7}.sv-alert--brand .sv-alert__icon,.sv-alert--gray .sv-alert__icon,.sv-alert--error .sv-alert__icon,.sv-alert--warning .sv-alert__icon,.sv-alert--success .sv-alert__icon{border:none;border-radius:9999px;box-shadow:none}.sv-alert--full-width{padding:0;border:none;border-bottom:1px solid var(--sv-alert-border);border-radius:0;box-shadow:none}.sv-alert--full-width .sv-alert__container{align-items:center;gap:24px;max-width:1280px;padding:24px 32px}.sv-alert--full-width .sv-alert__content{flex-direction:row;align-items:center;gap:24px}.sv-alert--full-width .sv-alert__body{flex-direction:row;flex-wrap:wrap;align-items:baseline;gap:2px 12px;width:auto;flex:1 0 0;min-width:0}.sv-alert--full-width .sv-alert__title,.sv-alert--full-width .sv-alert__text{width:auto;padding-right:0}.sv-alert--full-width .sv-alert__close{position:static;align-self:center}.sv-alert__btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:12px 28px;border:1px solid var(--sv-alert-solid);border-radius:8px;background-color:#fff;font-family:Roboto,sans-serif;font-weight:600;font-size:14px;line-height:20px;color:var(--sv-alert-title);white-space:nowrap;cursor:pointer;box-shadow:0 1px 2px #0000000d,inset 0 0 0 1px #0000002e,inset 0 -2px #0000000d;transition:filter .2s ease-in-out}.sv-alert__btn:hover{filter:brightness(.97)}.sv-alert__btn:focus-visible{outline:2px solid var(--sv-alert-solid);outline-offset:2px}.sv-alert__btn--primary{border-color:#ffffff1f;border-width:2px;background-color:var(--sv-alert-solid);color:#fff}@media (max-width: 768px){.sv-alert{padding:16px}.sv-alert__container{flex-direction:column;align-items:flex-start;gap:16px}.sv-alert__content{width:100%}.sv-alert__title{padding-right:40px}.sv-alert--full-width{padding:0}.sv-alert--full-width .sv-alert__container{flex-direction:column;align-items:flex-start;gap:32px;padding:32px 16px}.sv-alert--full-width .sv-alert__content{flex-direction:column;align-items:flex-start;gap:16px;width:100%}.sv-alert--full-width .sv-alert__body{flex-direction:column;gap:4px;width:100%}.sv-alert--full-width .sv-alert__actions:has(.sv-alert__btn){flex-direction:column-reverse;align-items:stretch;gap:12px;width:100%}.sv-alert--full-width .sv-alert__close{position:absolute;top:16px;right:8px}.sv-alert__btn{width:100%}}\n"] }]
4076
+ }], propDecorators: { color: [{
4077
+ type: Input
4078
+ }], size: [{
4079
+ type: Input
4080
+ }], alertTitle: [{
4081
+ type: Input
4082
+ }], supportingText: [{
4083
+ type: Input
4084
+ }], showIcon: [{
4085
+ type: Input
4086
+ }], showActions: [{
4087
+ type: Input
4088
+ }], actionVariant: [{
4089
+ type: Input
4090
+ }], dismissLabel: [{
4091
+ type: Input
4092
+ }], primaryActionLabel: [{
4093
+ type: Input
4094
+ }], showClose: [{
4095
+ type: Input
4096
+ }], closeAriaLabel: [{
4097
+ type: Input
4098
+ }], dismiss: [{
4099
+ type: Output
4100
+ }], primaryAction: [{
4101
+ type: Output
4102
+ }], closed: [{
4103
+ type: Output
4104
+ }] } });
4105
+
4106
+ /*
4107
+ * Public API Surface of @up_si_vale/sivale-componentes-angular
4108
+ */
4109
+ // Tokens
4110
+
4111
+ /**
4112
+ * Generated bundle index. Do not edit.
4113
+ */
4114
+
4115
+ export { ASSET_BASE_URL, AlertComponent, AssetSourceDirective, ButtonComponent, CheckboxComponent, CopyInputComponent, DatePickerComponent, IconSourceDirective, InputComponent, LoaderComponent, MultiselectComponent, NoLeadingSpaceDirective, OnlyLettersDirective, OnlyNumberDirective, OptionComponent, PhoneInputComponent, RadioComponent, RfcDirective, SelectComponent, SelectPrefixDirective, SelectSuffixDirective, SidebarComponent, SidebarIconComponent, SnackbarComponent, SnackbarService, TextareaComponent, TooltipDirective };
4116
+ //# sourceMappingURL=up_si_vale-sivale-componentes-angular.mjs.map