@catarina-ds/angular 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1610 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, inject, PLATFORM_ID, signal, Input, Component, EventEmitter, HostBinding, Output, ViewChild, ContentChildren, ElementRef, Optional, Self, Directive, forwardRef, HostListener, DOCUMENT, Inject, ViewContainerRef, Injectable } from '@angular/core';
3
+ import { DomSanitizer } from '@angular/platform-browser';
4
+ import { isPlatformBrowser, NgClass, NgIf } from '@angular/common';
5
+ import { NgControl, NG_VALUE_ACCESSOR } from '@angular/forms';
6
+ import { Overlay } from '@angular/cdk/overlay';
7
+ import { TemplatePortal } from '@angular/cdk/portal';
8
+ import { BehaviorSubject } from 'rxjs';
9
+
10
+ const ICON_PROVIDER = new InjectionToken('ICON_PROVIDER', {
11
+ providedIn: 'root',
12
+ factory: () => ({
13
+ // Proporciona un fallback por defecto si no se configura
14
+ getPath: (name) => `icons/${name}.svg`
15
+ })
16
+ });
17
+
18
+ class Icon {
19
+ sanitizer = inject(DomSanitizer);
20
+ platformId = inject(PLATFORM_ID);
21
+ iconProvider = inject(ICON_PROVIDER);
22
+ abortController;
23
+ svgContent = signal('', ...(ngDevMode ? [{ debugName: "svgContent" }] : []));
24
+ isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
25
+ isVisible = signal(false, ...(ngDevMode ? [{ debugName: "isVisible" }] : []));
26
+ size = '1em';
27
+ color = 'currentColor';
28
+ ngOnDestroy() {
29
+ this.abortController?.abort();
30
+ }
31
+ // Usa el nombre del icono con el provider configurado
32
+ set name(iconName) {
33
+ if (!iconName) {
34
+ this.isVisible.set(false);
35
+ return;
36
+ }
37
+ const path = this.iconProvider.getPath(iconName);
38
+ // Cancela la petición anterior si existe
39
+ this.abortController?.abort();
40
+ // Si el path es el fallback por defecto (icons/), no muestra nada
41
+ if (!path || path.startsWith('icons/')) {
42
+ this.isVisible.set(false);
43
+ return;
44
+ }
45
+ this.loadSvg(path);
46
+ }
47
+ // Usa el path directo del icono
48
+ set src(path) {
49
+ if (!path) {
50
+ this.isVisible.set(false);
51
+ return;
52
+ }
53
+ // Cancela la petición anterior si existe
54
+ this.abortController?.abort();
55
+ this.loadSvg(path);
56
+ }
57
+ loadSvg(path) {
58
+ // En SSR, no muestra nada
59
+ if (!isPlatformBrowser(this.platformId)) {
60
+ this.isVisible.set(false);
61
+ return;
62
+ }
63
+ // Limpia el contenido y oculta el icono mientras carga
64
+ this.isLoading.set(true);
65
+ this.svgContent.set('');
66
+ this.isVisible.set(false);
67
+ // Crea un nuevo AbortController para esta petición
68
+ this.abortController = new AbortController();
69
+ fetch(path, {
70
+ signal: this.abortController.signal,
71
+ mode: 'cors',
72
+ cache: 'default'
73
+ })
74
+ .then(response => {
75
+ if (!response.ok) {
76
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
77
+ }
78
+ return response.text();
79
+ })
80
+ .then(svg => {
81
+ // Verifica que el contenido sea un SVG válido
82
+ if (!this.isValidSvg(svg)) {
83
+ console.error(`Invalid SVG received from ${path}. Response is not valid SVG.`);
84
+ this.isVisible.set(false);
85
+ return;
86
+ }
87
+ const processed = this.processSvg(svg);
88
+ if (processed) {
89
+ this.svgContent.set(this.sanitizer.bypassSecurityTrustHtml(processed));
90
+ this.isVisible.set(true);
91
+ }
92
+ else {
93
+ this.isVisible.set(false);
94
+ }
95
+ })
96
+ .catch((error) => {
97
+ // Ignora el error de abort
98
+ if (error.name === 'AbortError') {
99
+ return;
100
+ }
101
+ console.error(`Error loading icon from ${path}:`, error.message);
102
+ this.isVisible.set(false);
103
+ })
104
+ .finally(() => {
105
+ this.isLoading.set(false);
106
+ });
107
+ }
108
+ isValidSvg(content) {
109
+ // Realiza validaciones estrictas para asegurar que sea SVG
110
+ const trimmed = content.trim();
111
+ // 1. Verifica que comience con <svg (ignorando espacios y declaraciones XML)
112
+ const svgRegex = /^\s*(<\?xml[^>]*>\s*)?<\s*svg\b/i;
113
+ if (!svgRegex.test(trimmed)) {
114
+ return false;
115
+ }
116
+ // 2. Verifica que termine con </svg>
117
+ if (!trimmed.includes('</svg>')) {
118
+ return false;
119
+ }
120
+ // 3. Verifica que no contenga <html>, <head>, <body> (indicaría HTML completo)
121
+ const htmlTags = ['<html', '<head', '<body', '<!DOCTYPE html'];
122
+ for (const tag of htmlTags) {
123
+ if (trimmed.toLowerCase().includes(tag.toLowerCase())) {
124
+ return false;
125
+ }
126
+ }
127
+ // 4. Verifica que tenga un tamaño razonable para un icono (máximo 100KB)
128
+ if (content.length > 100 * 1024) {
129
+ console.warn('SVG file is too large for an icon:', content.length, 'bytes');
130
+ return false;
131
+ }
132
+ return true;
133
+ }
134
+ processSvg(svg) {
135
+ // Valida el SVG antes de procesarlo
136
+ if (!this.isValidSvg(svg)) {
137
+ return null;
138
+ }
139
+ // En SSR, usa procesamiento simple con regex (no hay DOMParser)
140
+ if (!isPlatformBrowser(this.platformId)) {
141
+ return this.processSvgWithRegex(svg);
142
+ }
143
+ // En Browser, usa DOMParser para procesamiento robusto
144
+ try {
145
+ const parser = new DOMParser();
146
+ const doc = parser.parseFromString(svg, 'image/svg+xml');
147
+ // Verifica que no haya errores de parseo
148
+ const parserError = doc.querySelector('parsererror');
149
+ if (parserError) {
150
+ console.error('SVG parsing error:', parserError.textContent);
151
+ return null;
152
+ }
153
+ const svgElement = doc.querySelector('svg');
154
+ if (!svgElement) {
155
+ return null;
156
+ }
157
+ // Verifica que sea realmente un elemento SVG
158
+ if (svgElement.tagName.toLowerCase() !== 'svg') {
159
+ return null;
160
+ }
161
+ // Modifica solo el elemento <svg> raíz
162
+ svgElement.removeAttribute('width');
163
+ svgElement.removeAttribute('height');
164
+ // Cambia fill y stroke solo si no son "none"
165
+ const currentFill = svgElement.getAttribute('fill');
166
+ if (currentFill && currentFill !== 'none') {
167
+ svgElement.setAttribute('fill', 'currentColor');
168
+ }
169
+ const currentStroke = svgElement.getAttribute('stroke');
170
+ if (currentStroke && currentStroke !== 'none') {
171
+ svgElement.setAttribute('stroke', 'currentColor');
172
+ }
173
+ // Asegura el viewBox (requerido para escalado)
174
+ if (!svgElement.hasAttribute('viewBox')) {
175
+ svgElement.setAttribute('viewBox', '0 0 24 24');
176
+ }
177
+ // Serializa el SVG de vuelta a string
178
+ return new XMLSerializer().serializeToString(svgElement);
179
+ }
180
+ catch (error) {
181
+ console.error('Error processing SVG:', error);
182
+ return null;
183
+ }
184
+ }
185
+ processSvgWithRegex(svg) {
186
+ // Realiza procesamiento simple con regex para SSR (donde no hay DOMParser)
187
+ let processed = svg;
188
+ // Remueve width y height solo del tag <svg> de apertura
189
+ processed = processed.replace(/(<svg[^>]*?)\s+width="[^"]*"/i, '$1');
190
+ processed = processed.replace(/(<svg[^>]*?)\s+height="[^"]*"/i, '$1');
191
+ // Cambia fill a currentColor si existe y no es "none"
192
+ processed = processed.replace(/(<svg[^>]*?\s+fill=")(?!none)([^"]*)(")/i, '$1currentColor$3');
193
+ // Cambia stroke a currentColor si existe y no es "none"
194
+ processed = processed.replace(/(<svg[^>]*?\s+stroke=")(?!none)([^"]*)(")/i, '$1currentColor$3');
195
+ // Asegura el viewBox si no existe
196
+ if (!/viewBox=/i.test(processed)) {
197
+ processed = processed.replace(/(<svg[^>]*?)>/i, '$1 viewBox="0 0 24 24">');
198
+ }
199
+ return processed;
200
+ }
201
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Icon, deps: [], target: i0.ɵɵFactoryTarget.Component });
202
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: Icon, isStandalone: true, selector: "cat-icon", inputs: { size: "size", color: "color", name: "name", src: "src" }, ngImport: i0, template: "@if (isVisible()) {\n <span [innerHTML]=\"svgContent()\" [style.width]=\"size\" [style.height]=\"size\" [style.display]=\"'inline-flex'\"\n [style.color]=\"color\" class=\"cat-icon\">\n </span>\n}", styles: [":host{display:inline-flex;align-items:center;justify-content:center}.cat-icon{width:100%;height:100%;line-height:0}.cat-icon :deep(svg){width:100%;height:100%;display:block}\n"] });
203
+ }
204
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Icon, decorators: [{
205
+ type: Component,
206
+ args: [{ selector: 'cat-icon', imports: [], template: "@if (isVisible()) {\n <span [innerHTML]=\"svgContent()\" [style.width]=\"size\" [style.height]=\"size\" [style.display]=\"'inline-flex'\"\n [style.color]=\"color\" class=\"cat-icon\">\n </span>\n}", styles: [":host{display:inline-flex;align-items:center;justify-content:center}.cat-icon{width:100%;height:100%;line-height:0}.cat-icon :deep(svg){width:100%;height:100%;display:block}\n"] }]
207
+ }], propDecorators: { size: [{
208
+ type: Input
209
+ }], color: [{
210
+ type: Input
211
+ }], name: [{
212
+ type: Input
213
+ }], src: [{
214
+ type: Input
215
+ }] } });
216
+
217
+ class Button {
218
+ variant = 'primary';
219
+ size = 'md';
220
+ disabled = false;
221
+ type = 'button';
222
+ iconLeft;
223
+ iconCenter;
224
+ iconRight;
225
+ customClass = '';
226
+ clicked = new EventEmitter();
227
+ get buttonClasses() {
228
+ return `cat-button ${this.variant} ${this.size} ${this.customClass}`;
229
+ }
230
+ get iconSize() {
231
+ const sizes = { sm: '16px', md: '20px', lg: '24px' };
232
+ return sizes[this.size];
233
+ }
234
+ get dataCustomClass() {
235
+ return this.customClass;
236
+ }
237
+ handleClick(event) {
238
+ if (!this.disabled) {
239
+ this.clicked.emit(event);
240
+ }
241
+ }
242
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Button, deps: [], target: i0.ɵɵFactoryTarget.Component });
243
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: Button, isStandalone: true, selector: "cat-button", inputs: { variant: "variant", size: "size", disabled: "disabled", type: "type", iconLeft: "iconLeft", iconCenter: "iconCenter", iconRight: "iconRight", customClass: "customClass" }, outputs: { clicked: "clicked" }, host: { properties: { "attr.data-button-class": "this.dataCustomClass" } }, ngImport: i0, template: "<button [class]=\"buttonClasses\" [disabled]=\"disabled\" [type]=\"type\" (click)=\"handleClick($event)\">\n @if (iconLeft) {\n <cat-icon [name]=\"iconLeft\" [size]=\"iconSize\" class=\"icon-left\"> </cat-icon>\n }\n\n <span class=\"button-content\">\n @if (iconCenter) {\n <cat-icon [name]=\"iconCenter\" [size]=\"iconSize\" class=\"icon-center\"> </cat-icon>\n }\n <ng-content></ng-content>\n </span>\n\n @if (iconRight) {\n <cat-icon [name]=\"iconRight\" [size]=\"iconSize\" class=\"icon-right\"> </cat-icon>\n }\n</button>\n", styles: [".cat-button.primary{background-color:var(--primary-color-0);color:#fff}.cat-button.primary:hover:not(:disabled){background-color:var(--primary-color-1)}.cat-button.primary:active:not(:disabled){background-color:var(--primary-color-2)}.cat-button.secondary{background-color:var(--neutral-color-0);color:var(--neutral-color-9)}.cat-button.secondary:hover:not(:disabled){background-color:var(--neutral-color-1)}.cat-button.secondary:active:not(:disabled){background-color:var(--neutral-color-2)}.cat-button.contrast{background-color:var(--neutral-color-9);color:var(--neutral-color-0)}.cat-button.contrast:hover:not(:disabled){background-color:var(--neutral-color-8)}.cat-button.contrast:active:not(:disabled){background-color:var(--neutral-color-2);color:var(--neutral-color-9)}.cat-button.ghost{background-color:transparent;color:var(--primary-color-0)}.cat-button.ghost:hover:not(:disabled){background-color:color-mix(in srgb,var(--primary-color-0) 10%,transparent)}.cat-button.ghost:active:not(:disabled){background-color:color-mix(in srgb,var(--primary-color-0) 30%,transparent)}.cat-button.outline{background-color:transparent;color:var(--primary-color-0);border:2px solid var(--primary-color-1)}.cat-button.outline:hover:not(:disabled){background-color:var(--primary-color-0);color:#fff}.cat-button.outline:active:not(:disabled){border:2px solid var(--primary-color-2);background-color:var(--primary-color-1)}.cat-button.success{background-color:var(--success-color-default);color:var(--neutral-color-0)}.cat-button.success:hover:not(:disabled){background-color:var(--success-color-hover)}.cat-button.success:active:not(:disabled){background-color:var(--success-color-active)}.cat-button.danger{background-color:var(--danger-color-default);color:var(--neutral-color-0)}.cat-button.danger:hover:not(:disabled){background-color:var(--danger-color-hover)}.cat-button.danger:active:not(:disabled){background-color:var(--danger-color-active)}.cat-button.warn{background-color:var(--warn-color-default);color:var(--neutral-color-0)}.cat-button.warn:hover:not(:disabled){background-color:var(--warn-color-hover)}.cat-button.warn:active:not(:disabled){background-color:var(--warn-color-active)}.cat-button.info{background-color:var(--info-color-default);color:var(--neutral-color-0)}.cat-button.info:hover:not(:disabled){background-color:var(--info-color-hover)}.cat-button.info:active:not(:disabled){background-color:var(--info-color-active)}.cat-button{display:inline-flex;align-items:center;gap:.5rem;padding:8px 16px;border:none;border-radius:18px;font-family:inherit;font-size:1rem;font-weight:500;cursor:pointer;transition:all .2s;white-space:nowrap;box-sizing:border-box}.cat-button:disabled{opacity:.5;cursor:not-allowed}.cat-button.sm{padding:.25rem .75rem;font-size:.875rem}.cat-button.md{padding:.5rem 1rem;font-size:1rem}.cat-button.lg{padding:.75rem 1.5rem;font-size:1.125rem}.cat-button .icon-left,.cat-button .icon-right,.cat-button .icon-center{display:inline-flex}.cat-button .icon-center{margin:auto}.cat-button .icon-right{margin-left:auto}.cat-button .button-content{display:inline-flex;align-items:center;width:100%}\n"], dependencies: [{ kind: "component", type: Icon, selector: "cat-icon", inputs: ["size", "color", "name", "src"] }] });
244
+ }
245
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Button, decorators: [{
246
+ type: Component,
247
+ args: [{ selector: 'cat-button', imports: [Icon], template: "<button [class]=\"buttonClasses\" [disabled]=\"disabled\" [type]=\"type\" (click)=\"handleClick($event)\">\n @if (iconLeft) {\n <cat-icon [name]=\"iconLeft\" [size]=\"iconSize\" class=\"icon-left\"> </cat-icon>\n }\n\n <span class=\"button-content\">\n @if (iconCenter) {\n <cat-icon [name]=\"iconCenter\" [size]=\"iconSize\" class=\"icon-center\"> </cat-icon>\n }\n <ng-content></ng-content>\n </span>\n\n @if (iconRight) {\n <cat-icon [name]=\"iconRight\" [size]=\"iconSize\" class=\"icon-right\"> </cat-icon>\n }\n</button>\n", styles: [".cat-button.primary{background-color:var(--primary-color-0);color:#fff}.cat-button.primary:hover:not(:disabled){background-color:var(--primary-color-1)}.cat-button.primary:active:not(:disabled){background-color:var(--primary-color-2)}.cat-button.secondary{background-color:var(--neutral-color-0);color:var(--neutral-color-9)}.cat-button.secondary:hover:not(:disabled){background-color:var(--neutral-color-1)}.cat-button.secondary:active:not(:disabled){background-color:var(--neutral-color-2)}.cat-button.contrast{background-color:var(--neutral-color-9);color:var(--neutral-color-0)}.cat-button.contrast:hover:not(:disabled){background-color:var(--neutral-color-8)}.cat-button.contrast:active:not(:disabled){background-color:var(--neutral-color-2);color:var(--neutral-color-9)}.cat-button.ghost{background-color:transparent;color:var(--primary-color-0)}.cat-button.ghost:hover:not(:disabled){background-color:color-mix(in srgb,var(--primary-color-0) 10%,transparent)}.cat-button.ghost:active:not(:disabled){background-color:color-mix(in srgb,var(--primary-color-0) 30%,transparent)}.cat-button.outline{background-color:transparent;color:var(--primary-color-0);border:2px solid var(--primary-color-1)}.cat-button.outline:hover:not(:disabled){background-color:var(--primary-color-0);color:#fff}.cat-button.outline:active:not(:disabled){border:2px solid var(--primary-color-2);background-color:var(--primary-color-1)}.cat-button.success{background-color:var(--success-color-default);color:var(--neutral-color-0)}.cat-button.success:hover:not(:disabled){background-color:var(--success-color-hover)}.cat-button.success:active:not(:disabled){background-color:var(--success-color-active)}.cat-button.danger{background-color:var(--danger-color-default);color:var(--neutral-color-0)}.cat-button.danger:hover:not(:disabled){background-color:var(--danger-color-hover)}.cat-button.danger:active:not(:disabled){background-color:var(--danger-color-active)}.cat-button.warn{background-color:var(--warn-color-default);color:var(--neutral-color-0)}.cat-button.warn:hover:not(:disabled){background-color:var(--warn-color-hover)}.cat-button.warn:active:not(:disabled){background-color:var(--warn-color-active)}.cat-button.info{background-color:var(--info-color-default);color:var(--neutral-color-0)}.cat-button.info:hover:not(:disabled){background-color:var(--info-color-hover)}.cat-button.info:active:not(:disabled){background-color:var(--info-color-active)}.cat-button{display:inline-flex;align-items:center;gap:.5rem;padding:8px 16px;border:none;border-radius:18px;font-family:inherit;font-size:1rem;font-weight:500;cursor:pointer;transition:all .2s;white-space:nowrap;box-sizing:border-box}.cat-button:disabled{opacity:.5;cursor:not-allowed}.cat-button.sm{padding:.25rem .75rem;font-size:.875rem}.cat-button.md{padding:.5rem 1rem;font-size:1rem}.cat-button.lg{padding:.75rem 1.5rem;font-size:1.125rem}.cat-button .icon-left,.cat-button .icon-right,.cat-button .icon-center{display:inline-flex}.cat-button .icon-center{margin:auto}.cat-button .icon-right{margin-left:auto}.cat-button .button-content{display:inline-flex;align-items:center;width:100%}\n"] }]
248
+ }], propDecorators: { variant: [{
249
+ type: Input
250
+ }], size: [{
251
+ type: Input
252
+ }], disabled: [{
253
+ type: Input
254
+ }], type: [{
255
+ type: Input
256
+ }], iconLeft: [{
257
+ type: Input
258
+ }], iconCenter: [{
259
+ type: Input
260
+ }], iconRight: [{
261
+ type: Input
262
+ }], customClass: [{
263
+ type: Input
264
+ }], clicked: [{
265
+ type: Output
266
+ }], dataCustomClass: [{
267
+ type: HostBinding,
268
+ args: ['attr.data-button-class']
269
+ }] } });
270
+
271
+ class Card {
272
+ variant = 'surface';
273
+ size = 'md';
274
+ width = 'auto';
275
+ customClass = '';
276
+ // Expone las clases como atributos de datos
277
+ get dataVariant() {
278
+ return this.variant;
279
+ }
280
+ get dataSize() {
281
+ return this.size;
282
+ }
283
+ get dataCustomClass() {
284
+ return this.customClass;
285
+ }
286
+ /*// También exponer como CSS Custom Properties
287
+ @HostBinding('style.--card-variant') get cssVariant() {
288
+ return this.variant;
289
+ }
290
+
291
+ @HostBinding('style.--card-custom-class') get cssCustomClass() {
292
+ return this.customClass;
293
+ }
294
+ */
295
+ get cardClasses() {
296
+ return `cat-card ${this.variant} ${this.size} ${this.customClass}`;
297
+ }
298
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Card, deps: [], target: i0.ɵɵFactoryTarget.Component });
299
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: Card, isStandalone: true, selector: "cat-card", inputs: { variant: "variant", size: "size", width: "width", customClass: "customClass" }, host: { properties: { "attr.data-card-variant": "this.dataVariant", "attr.data-card-size": "this.dataSize", "attr.data-card-class": "this.dataCustomClass" } }, ngImport: i0, template: "<section [class]=\"cardClasses\" [attr.data-class]=\"customClass\" [style]=\"`width: ${width};`\">\n <ng-content></ng-content>\n</section>", styles: [".cat-card.surface{background-color:var(--element-color-4)}.cat-card.elevated{background-color:var(--neutral-color-0)}.cat-card.outlined{background-color:var(--element-color-3);border:1px solid var(--neutral-color-6)}.cat-card{min-width:7em;min-height:3em;height:auto;padding:8px;box-sizing:border-box;gap:.5rem;display:flex;flex-direction:column;border:none;border-radius:18px;font-family:inherit;font-size:1rem;font-weight:500;transition:all .2s}.cat-card.sm{padding:.25rem .75rem;font-size:.875rem}.cat-card.md{padding:.5rem 1rem;font-size:1rem}.cat-card.lg{padding:.75rem 1.5rem;font-size:1.125rem}\n"] });
300
+ }
301
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Card, decorators: [{
302
+ type: Component,
303
+ args: [{ selector: 'cat-card', template: "<section [class]=\"cardClasses\" [attr.data-class]=\"customClass\" [style]=\"`width: ${width};`\">\n <ng-content></ng-content>\n</section>", styles: [".cat-card.surface{background-color:var(--element-color-4)}.cat-card.elevated{background-color:var(--neutral-color-0)}.cat-card.outlined{background-color:var(--element-color-3);border:1px solid var(--neutral-color-6)}.cat-card{min-width:7em;min-height:3em;height:auto;padding:8px;box-sizing:border-box;gap:.5rem;display:flex;flex-direction:column;border:none;border-radius:18px;font-family:inherit;font-size:1rem;font-weight:500;transition:all .2s}.cat-card.sm{padding:.25rem .75rem;font-size:.875rem}.cat-card.md{padding:.5rem 1rem;font-size:1rem}.cat-card.lg{padding:.75rem 1.5rem;font-size:1.125rem}\n"] }]
304
+ }], propDecorators: { variant: [{
305
+ type: Input
306
+ }], size: [{
307
+ type: Input
308
+ }], width: [{
309
+ type: Input
310
+ }], customClass: [{
311
+ type: Input
312
+ }], dataVariant: [{
313
+ type: HostBinding,
314
+ args: ['attr.data-card-variant']
315
+ }], dataSize: [{
316
+ type: HostBinding,
317
+ args: ['attr.data-card-size']
318
+ }], dataCustomClass: [{
319
+ type: HostBinding,
320
+ args: ['attr.data-card-class']
321
+ }] } });
322
+
323
+ class Accordion {
324
+ accordionId;
325
+ status = false; //false = unactive
326
+ label = 'Accordion Name';
327
+ disabled = false;
328
+ customClass = '';
329
+ // Propiedades del botón
330
+ buttonVariant = 'secondary';
331
+ buttonSize = 'md';
332
+ iconLeft = false;
333
+ iconCenter = false;
334
+ iconRight = true;
335
+ // Propiedades del panel
336
+ scrolleable = false;
337
+ variant = 'surface';
338
+ updateAccordionGroupStatusOutput = new EventEmitter();
339
+ buttonRef;
340
+ buttonWidth = 0;
341
+ ngAfterViewInit() {
342
+ // Obtiene el ancho del botón después de renderizar
343
+ setTimeout(() => {
344
+ if (this.buttonRef) {
345
+ const button = this.buttonRef.nativeElement.querySelector('button');
346
+ if (button) {
347
+ this.buttonWidth = button.offsetWidth;
348
+ }
349
+ }
350
+ });
351
+ }
352
+ // Actualiza cuando cambia el label o otros inputs que afectan el tamaño
353
+ ngOnChanges() {
354
+ if (this.buttonRef) {
355
+ const button = this.buttonRef.nativeElement.querySelector('button');
356
+ if (button) {
357
+ this.buttonWidth = button.offsetWidth;
358
+ }
359
+ }
360
+ }
361
+ updateAccordionGroupStatus() {
362
+ this.status = !this.status;
363
+ this.updateAccordionGroupStatusOutput.emit(this.accordionId);
364
+ }
365
+ forceStatus(newStatus) {
366
+ this.status = newStatus;
367
+ }
368
+ ;
369
+ get dataCustomClass() {
370
+ return this.customClass;
371
+ }
372
+ get panelClasses() {
373
+ return `${this.variant} ${this.customClass} ${this.scrolleable ? 'scrolleable' : undefined}`;
374
+ }
375
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Accordion, deps: [], target: i0.ɵɵFactoryTarget.Component });
376
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: Accordion, isStandalone: true, selector: "cat-accordion", inputs: { accordionId: "accordionId", status: "status", label: "label", disabled: "disabled", customClass: "customClass", buttonVariant: "buttonVariant", buttonSize: "buttonSize", iconLeft: "iconLeft", iconCenter: "iconCenter", iconRight: "iconRight", scrolleable: "scrolleable", variant: "variant" }, outputs: { updateAccordionGroupStatusOutput: "updateAccordionGroupStatusOutput" }, host: { properties: { "attr.data-accordion-class": "this.dataCustomClass" } }, viewQueries: [{ propertyName: "buttonRef", first: true, predicate: ["buttonRef"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<section class=\"accordion\">\n <div>\n <cat-button [iconLeft]=\"iconLeft ? (status ? 'minus' : 'plus') : undefined\"\n [iconCenter]=\"iconCenter ? (status ? 'minus' : 'plus') : undefined\"\n [iconRight]=\"iconRight && status ? 'minus' : 'plus'\" (clicked)=\"updateAccordionGroupStatus()\"\n [variant]=\"buttonVariant\" [size]=\"buttonSize\" customClass=\"accordion-button\" [disabled]=\"disabled\">\n {{label}}\n </cat-button>\n </div>\n <div [class]=\"panelClasses\" [ngClass]=\"status ? 'accordion-panel-active': 'accordion-panel-unactive'\">\n <ng-content *ngIf=\"status\"></ng-content>\n </div>\n</section>", styles: [":host{display:inline-block;max-width:100%}.accordion{margin:0;padding:0;width:100%;box-sizing:border-box;border-radius:8px}.accordion-panel-active{box-sizing:border-box;padding:.5em;min-height:5em;background-color:var(--neutral-color-0);width:100%;transition:.25s;border-radius:18px}.accordion-panel-unactive{display:none;transition:.15s}cat-button[data-button-class=accordion-button]{width:100%;display:block}cat-button[data-button-class=accordion-button] ::ng-deep button{width:100%;justify-content:space-between}.scrolleable{height:7em;overflow-y:auto}.scrolleable::-webkit-scrollbar{width:8px;height:8px}.scrolleable::-webkit-scrollbar-track{background:transparent}.scrolleable::-webkit-scrollbar-thumb{background:#888;border-radius:4px}.scrolleable::-webkit-scrollbar-thumb:hover{background:#555}.surface{background-color:var(--element-color-4)}.elevated{background-color:var(--neutral-color-0)}.outlined{background-color:var(--element-color-3);border:1px solid var(--neutral-color-6)}\n"], dependencies: [{ kind: "component", type: Button, selector: "cat-button", inputs: ["variant", "size", "disabled", "type", "iconLeft", "iconCenter", "iconRight", "customClass"], outputs: ["clicked"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
377
+ }
378
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Accordion, decorators: [{
379
+ type: Component,
380
+ args: [{ selector: 'cat-accordion', imports: [Button, NgClass, NgIf], template: "<section class=\"accordion\">\n <div>\n <cat-button [iconLeft]=\"iconLeft ? (status ? 'minus' : 'plus') : undefined\"\n [iconCenter]=\"iconCenter ? (status ? 'minus' : 'plus') : undefined\"\n [iconRight]=\"iconRight && status ? 'minus' : 'plus'\" (clicked)=\"updateAccordionGroupStatus()\"\n [variant]=\"buttonVariant\" [size]=\"buttonSize\" customClass=\"accordion-button\" [disabled]=\"disabled\">\n {{label}}\n </cat-button>\n </div>\n <div [class]=\"panelClasses\" [ngClass]=\"status ? 'accordion-panel-active': 'accordion-panel-unactive'\">\n <ng-content *ngIf=\"status\"></ng-content>\n </div>\n</section>", styles: [":host{display:inline-block;max-width:100%}.accordion{margin:0;padding:0;width:100%;box-sizing:border-box;border-radius:8px}.accordion-panel-active{box-sizing:border-box;padding:.5em;min-height:5em;background-color:var(--neutral-color-0);width:100%;transition:.25s;border-radius:18px}.accordion-panel-unactive{display:none;transition:.15s}cat-button[data-button-class=accordion-button]{width:100%;display:block}cat-button[data-button-class=accordion-button] ::ng-deep button{width:100%;justify-content:space-between}.scrolleable{height:7em;overflow-y:auto}.scrolleable::-webkit-scrollbar{width:8px;height:8px}.scrolleable::-webkit-scrollbar-track{background:transparent}.scrolleable::-webkit-scrollbar-thumb{background:#888;border-radius:4px}.scrolleable::-webkit-scrollbar-thumb:hover{background:#555}.surface{background-color:var(--element-color-4)}.elevated{background-color:var(--neutral-color-0)}.outlined{background-color:var(--element-color-3);border:1px solid var(--neutral-color-6)}\n"] }]
381
+ }], propDecorators: { accordionId: [{
382
+ type: Input
383
+ }], status: [{
384
+ type: Input
385
+ }], label: [{
386
+ type: Input
387
+ }], disabled: [{
388
+ type: Input
389
+ }], customClass: [{
390
+ type: Input
391
+ }], buttonVariant: [{
392
+ type: Input
393
+ }], buttonSize: [{
394
+ type: Input
395
+ }], iconLeft: [{
396
+ type: Input
397
+ }], iconCenter: [{
398
+ type: Input
399
+ }], iconRight: [{
400
+ type: Input
401
+ }], scrolleable: [{
402
+ type: Input
403
+ }], variant: [{
404
+ type: Input
405
+ }], updateAccordionGroupStatusOutput: [{
406
+ type: Output
407
+ }], buttonRef: [{
408
+ type: ViewChild,
409
+ args: ['buttonRef', { static: false }]
410
+ }], dataCustomClass: [{
411
+ type: HostBinding,
412
+ args: ['attr.data-accordion-class']
413
+ }] } });
414
+
415
+ class AccordionGroup {
416
+ singleExpand = true;
417
+ customClass = '';
418
+ accordions;
419
+ accordionActiveId;
420
+ sub;
421
+ ngAfterContentInit() {
422
+ if (this.singleExpand) {
423
+ this.accordions.forEach(acc => {
424
+ this.sub = acc.updateAccordionGroupStatusOutput.subscribe(id => {
425
+ this.handleOpen(id);
426
+ });
427
+ });
428
+ }
429
+ }
430
+ handleOpen(id) {
431
+ this.accordions.forEach(acc => acc.forceStatus(false));
432
+ const target = this.accordions.find(acc => acc.accordionId === id);
433
+ if (this.accordionActiveId === id) {
434
+ target?.forceStatus(false);
435
+ this.accordionActiveId = undefined;
436
+ }
437
+ else {
438
+ target?.forceStatus(true);
439
+ this.accordionActiveId = id;
440
+ }
441
+ }
442
+ get dataCustomClass() {
443
+ return this.customClass;
444
+ }
445
+ get accordionGroupClasses() {
446
+ return `${this.customClass}`;
447
+ }
448
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AccordionGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
449
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: AccordionGroup, isStandalone: true, selector: "cat-accordion-group", inputs: { singleExpand: "singleExpand", customClass: "customClass" }, host: { properties: { "attr.data-accordion-group-class": "this.dataCustomClass" } }, queries: [{ propertyName: "accordions", predicate: Accordion }], ngImport: i0, template: "<section [class]=\"accordionGroupClasses\">\n <ng-content></ng-content>\n</section>", styles: [":host{min-width:3em;width:8em}section{width:100%;display:flex;flex-direction:column}\n"] });
450
+ }
451
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AccordionGroup, decorators: [{
452
+ type: Component,
453
+ args: [{ selector: 'cat-accordion-group', imports: [], template: "<section [class]=\"accordionGroupClasses\">\n <ng-content></ng-content>\n</section>", styles: [":host{min-width:3em;width:8em}section{width:100%;display:flex;flex-direction:column}\n"] }]
454
+ }], propDecorators: { singleExpand: [{
455
+ type: Input
456
+ }], customClass: [{
457
+ type: Input
458
+ }], accordions: [{
459
+ type: ContentChildren,
460
+ args: [Accordion]
461
+ }], dataCustomClass: [{
462
+ type: HostBinding,
463
+ args: ['attr.data-accordion-group-class']
464
+ }] } });
465
+
466
+ class CatInput {
467
+ el = inject(ElementRef);
468
+ platformId = inject(PLATFORM_ID);
469
+ control = inject(NgControl, { optional: true, self: true });
470
+ static stylesInjected = false;
471
+ ngOnInit() {
472
+ if (this.el.nativeElement.tagName.toLowerCase() !== 'input') {
473
+ console.warn('catInput directive can only be used on <input> elements');
474
+ return;
475
+ }
476
+ // Inyecta los estilos solo una vez
477
+ if (!CatInput.stylesInjected && isPlatformBrowser(this.platformId)) {
478
+ this.injectStyles();
479
+ CatInput.stylesInjected = true;
480
+ }
481
+ }
482
+ injectStyles() {
483
+ const style = document.createElement('style');
484
+ style.textContent = `
485
+ .cat-input {
486
+ border: 1px solid var(--neutral-color-3);
487
+ background-color: var(--neutral-color-0);
488
+ color: var(--neutral-color-9);
489
+ border-radius: 18px;
490
+ outline: none;
491
+ transition: all 0.2s;
492
+ max-width: 100%;
493
+ box-sizing: border-box;
494
+ }
495
+
496
+ .cat-input:disabled {
497
+ opacity: 0.5;
498
+ cursor: not-allowed;
499
+ }
500
+
501
+ .cat-input::placeholder {
502
+ color: var(--neutral-color-6);
503
+ transition: font-size 0.2s;
504
+ }
505
+
506
+ .cat-input:focus::placeholder {
507
+ font-size: 0.7em;
508
+ }
509
+
510
+ .cat-input:focus {
511
+ border: 1px solid var(--neutral-color-9);
512
+ color: var(--neutral-color-9);
513
+ -webkit-text-fill-color: var(--neutral-color-9);
514
+ }
515
+
516
+ .cat-input.invalid,
517
+ .cat-input.ng-invalid.ng-touched {
518
+ border: 1px solid red;
519
+ }
520
+
521
+ .cat-input.ng-valid.ng-touched {
522
+ border: 1px solid green;
523
+ }
524
+
525
+ .cat-input:-webkit-autofill,
526
+ .cat-input:-webkit-autofill:hover,
527
+ .cat-input:-webkit-autofill:focus,
528
+ .cat-input:-webkit-autofill:active {
529
+ -webkit-box-shadow: 0 0 0 1000px var(--neutral-color-1) inset;
530
+ box-shadow: 0 0 0 1000px var(--neutral-color-1) inset;
531
+ -webkit-text-fill-color: var(--neutral-color-9);
532
+ }
533
+
534
+
535
+ .cat-input.md {
536
+ padding: 0.5rem 1rem;
537
+ font-size: 1rem;
538
+ }
539
+
540
+ .cat-input.sm {
541
+ padding: 0.25rem 0.75rem;
542
+ font-size: 0.875rem;
543
+ }
544
+
545
+ .cat-input.lg {
546
+ padding: 0.75rem 1.5rem;
547
+ font-size: 1.125rem;
548
+ }
549
+ `;
550
+ document.head.appendChild(style);
551
+ }
552
+ get isInvalid() {
553
+ return !!(this.control && this.control.invalid && this.control.touched);
554
+ }
555
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CatInput, deps: [], target: i0.ɵɵFactoryTarget.Directive });
556
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.15", type: CatInput, isStandalone: true, selector: "[catInput]", host: { properties: { "class.cat-input": "true", "class.md": "true", "class.invalid": "isInvalid" } }, ngImport: i0 });
557
+ }
558
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CatInput, decorators: [{
559
+ type: Directive,
560
+ args: [{
561
+ selector: '[catInput]',
562
+ standalone: true,
563
+ host: {
564
+ '[class.cat-input]': 'true',
565
+ '[class.md]': 'true',
566
+ '[class.invalid]': 'isInvalid'
567
+ }
568
+ }]
569
+ }], propDecorators: { control: [{
570
+ type: Optional
571
+ }, {
572
+ type: Self
573
+ }] } });
574
+
575
+ class ColorInput {
576
+ value = '#000000';
577
+ icon = false;
578
+ size = '2em';
579
+ onChange = (value) => { };
580
+ onTouched = () => { };
581
+ onInput(event) {
582
+ const newValue = event.target.value;
583
+ this.value = newValue;
584
+ this.onChange(newValue); // Informa al componente padre del cambio de valor
585
+ }
586
+ // Métodos requeridos por ControlValueAccessor
587
+ writeValue(value) {
588
+ this.value = value || '#000000';
589
+ }
590
+ registerOnChange(fn) {
591
+ this.onChange = fn;
592
+ }
593
+ registerOnTouched(fn) {
594
+ this.onTouched = fn;
595
+ }
596
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ColorInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
597
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: ColorInput, isStandalone: true, selector: "cat-color-input", inputs: { icon: "icon", size: "size" }, providers: [{
598
+ provide: NG_VALUE_ACCESSOR,
599
+ useExisting: forwardRef(() => ColorInput),
600
+ multi: true
601
+ }], ngImport: i0, template: "<style>\n div {\n position: relative;\n aspect-ratio: 1/1;\n }\n\n div:hover {\n cursor: grab;\n }\n input {\n width: 100%;\n aspect-ratio: 1/1;\n top: 0;\n left: 0;\n }\n cat-icon {\n position: absolute;\n top: 0;\n left: 0;\n pointer-events: none;\n }\n</style>\n<!-- input-color.html -->\n<div [style.height]=\"size\">\n <input type=\"color\" [style]=\"icon ? 'opacity: 0;' : 'opacity: 100%;'\" [value]=\"value\" (input)=\"onInput($event)\" (blur)=\"onTouched()\">\n @if (icon) {\n <cat-icon [style.height]=\"size\" size=\"100%\" name=\"palette\"></cat-icon> \n }\n</div>", styles: ["", "div{position:relative;aspect-ratio:1/1}div:hover{cursor:grab}input{width:100%;aspect-ratio:1/1;top:0;left:0}cat-icon{position:absolute;top:0;left:0;pointer-events:none}\n"], dependencies: [{ kind: "component", type: Icon, selector: "cat-icon", inputs: ["size", "color", "name", "src"] }] });
602
+ }
603
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ColorInput, decorators: [{
604
+ type: Component,
605
+ args: [{ selector: 'cat-color-input', imports: [Icon], providers: [{
606
+ provide: NG_VALUE_ACCESSOR,
607
+ useExisting: forwardRef(() => ColorInput),
608
+ multi: true
609
+ }], template: "<style>\n div {\n position: relative;\n aspect-ratio: 1/1;\n }\n\n div:hover {\n cursor: grab;\n }\n input {\n width: 100%;\n aspect-ratio: 1/1;\n top: 0;\n left: 0;\n }\n cat-icon {\n position: absolute;\n top: 0;\n left: 0;\n pointer-events: none;\n }\n</style>\n<!-- input-color.html -->\n<div [style.height]=\"size\">\n <input type=\"color\" [style]=\"icon ? 'opacity: 0;' : 'opacity: 100%;'\" [value]=\"value\" (input)=\"onInput($event)\" (blur)=\"onTouched()\">\n @if (icon) {\n <cat-icon [style.height]=\"size\" size=\"100%\" name=\"palette\"></cat-icon> \n }\n</div>", styles: ["div{position:relative;aspect-ratio:1/1}div:hover{cursor:grab}input{width:100%;aspect-ratio:1/1;top:0;left:0}cat-icon{position:absolute;top:0;left:0;pointer-events:none}\n"] }]
610
+ }], propDecorators: { icon: [{
611
+ type: Input
612
+ }], size: [{
613
+ type: Input
614
+ }] } });
615
+
616
+ class SelectInput {
617
+ el;
618
+ inputEl;
619
+ optionsContainer;
620
+ transform; //This option basicly allow to the consumer put the options at the side where he wants
621
+ options;
622
+ placeholder = '';
623
+ type = 'string';
624
+ value = '';
625
+ active = false;
626
+ isInsideMenu = false;
627
+ variant = 'surface';
628
+ scrolleable = false;
629
+ customClass = '';
630
+ //@Output() selected = new EventEmitter<string>();
631
+ // Accesibilidad
632
+ outerClick(event) {
633
+ if (!this.el.nativeElement.contains(event.target)) {
634
+ this.active = false;
635
+ }
636
+ }
637
+ ;
638
+ toggleActive() {
639
+ this.active = !this.active;
640
+ }
641
+ constructor(el) {
642
+ this.el = el;
643
+ }
644
+ onChange = (value) => { };
645
+ onTouched = () => { };
646
+ // Aquí comienzan los eventos de ControlValueAccessor
647
+ writeValue(value) {
648
+ this.value = value;
649
+ }
650
+ ;
651
+ registerOnChange(fn) {
652
+ this.onChange = fn;
653
+ }
654
+ registerOnTouched(fn) {
655
+ this.onTouched = fn;
656
+ }
657
+ // Aquí terminan los eventos de ControlValueAccessor
658
+ choseValue(option) {
659
+ this.value = option;
660
+ this.onChange(option);
661
+ this.onTouched();
662
+ this.active = false;
663
+ //this.selected.emit(option);
664
+ }
665
+ ;
666
+ get dataCustomClass() {
667
+ return this.customClass;
668
+ }
669
+ get selectInputClass() {
670
+ return `${this.variant} ${this.scrolleable ? 'scrolleable' : ''}`;
671
+ }
672
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SelectInput, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
673
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: SelectInput, isStandalone: true, selector: "cat-select-input", inputs: { transform: "transform", options: "options", placeholder: "placeholder", type: "type", variant: "variant", scrolleable: "scrolleable", customClass: "customClass" }, host: { listeners: { "document:click": "outerClick($event)" }, properties: { "attr.data-select-input-class": "this.dataCustomClass" } }, providers: [{
674
+ provide: NG_VALUE_ACCESSOR,
675
+ useExisting: forwardRef(() => SelectInput),
676
+ multi: true
677
+ }], viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["input"], descendants: true }, { propertyName: "optionsContainer", first: true, predicate: ["optionsContainer"], descendants: true }], ngImport: i0, template: "<section class=\"select-input-container\">\n <input catInput #input [value]=\"value\" [type]=\"type\" readonly id=\"select\" (mousedown)=\"toggleActive()\"\n [placeholder]=\"placeholder\" class=\"select-input\">\n<section #optionsContainer role=\"listbox\" [class]=\"selectInputClass\" class=\"options\"\n [ngClass]=\"active ? 'options-active' : 'options-unactive'\" [style.transform]=\"transform\">\n @if (active) {\n @for (option of options; track $index) {\n <cat-button customClass=\"select-input-option\" (clicked)=\"choseValue(option)\" variant=\"ghost\">{{ option }}</cat-button>\n }\n<!-- <div role=\"option\" *ngFor=\"let option of options\" (mousedown)=\"choseValue(option)\">\n {{ option }}\n </div> -->\n }\n</section>\n</section>", styles: [":host{position:relative;display:inline-block;z-index:auto;max-width:100%;width:13em}.select-input{width:100%}.options-active{z-index:3;border-radius:18px;padding:8px;box-sizing:border-box;width:100%;position:absolute;display:flex;flex-direction:column;transition:.25s;isolation:isolate}.options-unactive{display:none;transition:.15s}.options>cat-button[data-button-class=select-input-option] ::ng-deep button{color:var(--neutral-color-9)}.scrolleable{height:7em;overflow-y:auto}.scrolleable::-webkit-scrollbar{width:8px;height:8px}.scrolleable::-webkit-scrollbar-track{background:transparent}.scrolleable::-webkit-scrollbar-thumb{background:#888;border-radius:4px}.scrolleable::-webkit-scrollbar-thumb:hover{background:#555}.surface{background-color:var(--element-color-4)}.elevated{background-color:var(--neutral-color-0)}.outlined{background-color:var(--element-color-3);border:1px solid var(--neutral-color-6)}\n"], dependencies: [{ kind: "directive", type: CatInput, selector: "[catInput]" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: Button, selector: "cat-button", inputs: ["variant", "size", "disabled", "type", "iconLeft", "iconCenter", "iconRight", "customClass"], outputs: ["clicked"] }] });
678
+ }
679
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SelectInput, decorators: [{
680
+ type: Component,
681
+ args: [{ selector: 'cat-select-input', imports: [
682
+ CatInput,
683
+ NgClass,
684
+ Button
685
+ ], providers: [{
686
+ provide: NG_VALUE_ACCESSOR,
687
+ useExisting: forwardRef(() => SelectInput),
688
+ multi: true
689
+ }], template: "<section class=\"select-input-container\">\n <input catInput #input [value]=\"value\" [type]=\"type\" readonly id=\"select\" (mousedown)=\"toggleActive()\"\n [placeholder]=\"placeholder\" class=\"select-input\">\n<section #optionsContainer role=\"listbox\" [class]=\"selectInputClass\" class=\"options\"\n [ngClass]=\"active ? 'options-active' : 'options-unactive'\" [style.transform]=\"transform\">\n @if (active) {\n @for (option of options; track $index) {\n <cat-button customClass=\"select-input-option\" (clicked)=\"choseValue(option)\" variant=\"ghost\">{{ option }}</cat-button>\n }\n<!-- <div role=\"option\" *ngFor=\"let option of options\" (mousedown)=\"choseValue(option)\">\n {{ option }}\n </div> -->\n }\n</section>\n</section>", styles: [":host{position:relative;display:inline-block;z-index:auto;max-width:100%;width:13em}.select-input{width:100%}.options-active{z-index:3;border-radius:18px;padding:8px;box-sizing:border-box;width:100%;position:absolute;display:flex;flex-direction:column;transition:.25s;isolation:isolate}.options-unactive{display:none;transition:.15s}.options>cat-button[data-button-class=select-input-option] ::ng-deep button{color:var(--neutral-color-9)}.scrolleable{height:7em;overflow-y:auto}.scrolleable::-webkit-scrollbar{width:8px;height:8px}.scrolleable::-webkit-scrollbar-track{background:transparent}.scrolleable::-webkit-scrollbar-thumb{background:#888;border-radius:4px}.scrolleable::-webkit-scrollbar-thumb:hover{background:#555}.surface{background-color:var(--element-color-4)}.elevated{background-color:var(--neutral-color-0)}.outlined{background-color:var(--element-color-3);border:1px solid var(--neutral-color-6)}\n"] }]
690
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { inputEl: [{
691
+ type: ViewChild,
692
+ args: ['input']
693
+ }], optionsContainer: [{
694
+ type: ViewChild,
695
+ args: ['optionsContainer', { static: false }]
696
+ }], transform: [{
697
+ type: Input
698
+ }], options: [{
699
+ type: Input
700
+ }], placeholder: [{
701
+ type: Input
702
+ }], type: [{
703
+ type: Input
704
+ }], variant: [{
705
+ type: Input
706
+ }], scrolleable: [{
707
+ type: Input
708
+ }], customClass: [{
709
+ type: Input
710
+ }], outerClick: [{
711
+ type: HostListener,
712
+ args: ['document:click', ['$event']]
713
+ }], dataCustomClass: [{
714
+ type: HostBinding,
715
+ args: ['attr.data-select-input-class']
716
+ }] } });
717
+
718
+ class Drag {
719
+ el;
720
+ renderer;
721
+ document;
722
+ offsetX = 0;
723
+ offsetY = 0;
724
+ dragging = false;
725
+ constructor(el, renderer, document) {
726
+ this.el = el;
727
+ this.renderer = renderer;
728
+ this.document = document;
729
+ }
730
+ ngAfterViewInit() {
731
+ const el = this.el.nativeElement;
732
+ // Si el elemento no tiene position seteado, establece absolute
733
+ if (typeof window !== 'undefined') {
734
+ const computedStyle = window.getComputedStyle(el);
735
+ if (computedStyle.position === 'static') {
736
+ this.renderer.setStyle(el, 'position', 'absolute');
737
+ }
738
+ }
739
+ el.addEventListener('mousedown', (e) => {
740
+ this.dragging = true;
741
+ this.offsetX = e.clientX - el.offsetLeft;
742
+ this.offsetY = e.clientY - el.offsetTop;
743
+ el.style.cursor = 'grabbing';
744
+ });
745
+ this.document.addEventListener('mousemove', (e) => {
746
+ if (this.dragging) {
747
+ el.style.left = e.clientX - this.offsetX + 'px';
748
+ el.style.top = e.clientY - this.offsetY + 'px';
749
+ }
750
+ });
751
+ this.document.addEventListener('mouseup', () => {
752
+ this.dragging = false;
753
+ el.style.cursor = 'grab';
754
+ });
755
+ }
756
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Drag, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Directive });
757
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.15", type: Drag, isStandalone: true, selector: "[CDrag]", ngImport: i0 });
758
+ }
759
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Drag, decorators: [{
760
+ type: Directive,
761
+ args: [{
762
+ selector: '[CDrag]'
763
+ }]
764
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: Document, decorators: [{
765
+ type: Inject,
766
+ args: [DOCUMENT]
767
+ }] }] });
768
+
769
+ class Dialog {
770
+ // Inyecta el servicio Overlay del CDK
771
+ overlay = inject(Overlay);
772
+ // ViewContainerRef necesario para crear el TemplatePortal
773
+ viewContainerRef = inject(ViewContainerRef);
774
+ // Referencia al overlay creado
775
+ overlayRef;
776
+ variant = 'surface';
777
+ size = 'md';
778
+ customClass = '';
779
+ closs = new EventEmitter();
780
+ // Referencia al template que contiene el ng-content
781
+ dialogTemplate;
782
+ createOverlayConfig() {
783
+ const positionStrategy = this.overlay.position()
784
+ .global()
785
+ .centerHorizontally()
786
+ .centerVertically();
787
+ return {
788
+ positionStrategy,
789
+ scrollStrategy: this.overlay.scrollStrategies.block(),
790
+ hasBackdrop: true,
791
+ backdropClass: 'cdk-overlay-dark-backdrop',
792
+ panelClass: ['cat-dialog-overlay-panel', this.variant, this.size, this.customClass],
793
+ };
794
+ }
795
+ openDialog() {
796
+ const config = this.createOverlayConfig();
797
+ this.overlayRef = this.overlay.create(config);
798
+ // TemplatePortal permite renderizar un template (con ng-content) dentro del overlay
799
+ const portal = new TemplatePortal(this.dialogTemplate, this.viewContainerRef);
800
+ this.overlayRef.attach(portal);
801
+ // Escucha cuando se hace clic en el backdrop y cierra el dialog
802
+ this.overlayRef.backdropClick().subscribe(() => {
803
+ this.closeDialog();
804
+ });
805
+ // Escucha la tecla Escape para cerrar
806
+ this.overlayRef.keydownEvents().subscribe(event => {
807
+ if (event.key === 'Escape') {
808
+ this.closeDialog();
809
+ }
810
+ });
811
+ }
812
+ closeDialog() {
813
+ if (this.overlayRef) {
814
+ this.overlayRef.detach();
815
+ this.overlayRef.dispose();
816
+ this.overlayRef = undefined;
817
+ this.closs.emit(false);
818
+ }
819
+ }
820
+ get dialogClasses() {
821
+ return `${this.variant} ${this.size} ${this.customClass}`;
822
+ }
823
+ ngOnInit() {
824
+ this.openDialog();
825
+ }
826
+ ngOnDestroy() {
827
+ this.closeDialog();
828
+ }
829
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Dialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
830
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: Dialog, isStandalone: true, selector: "cat-dialog", inputs: { variant: "variant", size: "size", customClass: "customClass" }, outputs: { closs: "closs" }, viewQueries: [{ propertyName: "dialogTemplate", first: true, predicate: ["dialogTemplate"], descendants: true, static: true }], ngImport: i0, template: "<!-- Template que se renderiza dentro del overlay del CDK -->\n<ng-template #dialogTemplate>\n <section CDrag [class]=\"dialogClasses\">\n <ng-content></ng-content>\n </section>\n</ng-template>", styles: ["section{position:relative;width:80vw;height:80vh;border-radius:18px;overflow:auto;padding:8px;box-sizing:border-box;min-width:7em;min-height:7em;cursor:grab;-webkit-user-select:none;user-select:none}.surface{background-color:var(--element-color-4)}.elevated{background-color:var(--neutral-color-0)}.outlined{background-color:var(--element-color-3);border:2px solid var(--neutral-color-9)}.sm{padding:.25rem .75rem;font-size:.875rem}.md{padding:.5rem 1rem;font-size:1rem}.lg{padding:.75rem 1.5rem;font-size:1.125rem}\n"], dependencies: [{ kind: "directive", type: Drag, selector: "[CDrag]" }] });
831
+ }
832
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Dialog, decorators: [{
833
+ type: Component,
834
+ args: [{ selector: 'cat-dialog', imports: [Drag], template: "<!-- Template que se renderiza dentro del overlay del CDK -->\n<ng-template #dialogTemplate>\n <section CDrag [class]=\"dialogClasses\">\n <ng-content></ng-content>\n </section>\n</ng-template>", styles: ["section{position:relative;width:80vw;height:80vh;border-radius:18px;overflow:auto;padding:8px;box-sizing:border-box;min-width:7em;min-height:7em;cursor:grab;-webkit-user-select:none;user-select:none}.surface{background-color:var(--element-color-4)}.elevated{background-color:var(--neutral-color-0)}.outlined{background-color:var(--element-color-3);border:2px solid var(--neutral-color-9)}.sm{padding:.25rem .75rem;font-size:.875rem}.md{padding:.5rem 1rem;font-size:1rem}.lg{padding:.75rem 1.5rem;font-size:1.125rem}\n"] }]
835
+ }], propDecorators: { variant: [{
836
+ type: Input
837
+ }], size: [{
838
+ type: Input
839
+ }], customClass: [{
840
+ type: Input
841
+ }], closs: [{
842
+ type: Output
843
+ }], dialogTemplate: [{
844
+ type: ViewChild,
845
+ args: ['dialogTemplate', { static: true }]
846
+ }] } });
847
+
848
+ class Drawer {
849
+ // Inyecta el servicio Overlay del CDK
850
+ overlay = inject(Overlay);
851
+ // ViewContainerRef necesario para crear el TemplatePortal
852
+ viewContainerRef = inject(ViewContainerRef);
853
+ // Referencia al overlay creado
854
+ overlayRef;
855
+ side = 'left';
856
+ variant = 'surface';
857
+ customClass = '';
858
+ closs = new EventEmitter();
859
+ // Referencia al template que contiene el ng-content
860
+ drawerTemplate;
861
+ createOverlayConfig() {
862
+ // Crea estrategia de posicionamiento global
863
+ const positionStrategy = this.overlay.position().global();
864
+ switch (this.side) {
865
+ case 'left':
866
+ positionStrategy.left('0');
867
+ break;
868
+ case 'right':
869
+ positionStrategy.right('0');
870
+ break;
871
+ case 'top':
872
+ positionStrategy.top('0');
873
+ break;
874
+ case 'bottom':
875
+ positionStrategy.bottom('0');
876
+ break;
877
+ }
878
+ return {
879
+ positionStrategy,
880
+ scrollStrategy: this.overlay.scrollStrategies.block(),
881
+ hasBackdrop: true,
882
+ backdropClass: 'cdk-overlay-dark-backdrop',
883
+ panelClass: ['cat-drawer-overlay-panel', this.side, this.variant, this.customClass],
884
+ };
885
+ }
886
+ openDrawer() {
887
+ const config = this.createOverlayConfig();
888
+ this.overlayRef = this.overlay.create(config);
889
+ // Crea un portal con el template del drawer
890
+ // TemplatePortal permite renderizar un template (con ng-content) dentro del overlay
891
+ const portal = new TemplatePortal(this.drawerTemplate, this.viewContainerRef);
892
+ // Adjunta el portal al overlay, esto renderiza el template dentro del overlay
893
+ this.overlayRef.attach(portal);
894
+ // Escucha cuando se hace clic en el backdrop y cierra el drawer
895
+ this.overlayRef.backdropClick().subscribe(() => {
896
+ this.closeDrawer();
897
+ });
898
+ // Escucha la tecla Escape para cerrar
899
+ this.overlayRef.keydownEvents().subscribe(event => {
900
+ if (event.key === 'Escape') {
901
+ this.closeDrawer();
902
+ }
903
+ });
904
+ }
905
+ closeDrawer() {
906
+ if (this.overlayRef) {
907
+ // Desconecta el portal del overlay
908
+ this.overlayRef.detach();
909
+ // Limpia todos los recursos del overlay
910
+ this.overlayRef.dispose();
911
+ this.overlayRef = undefined;
912
+ // Emite el evento de cierre
913
+ this.closs.emit(false);
914
+ }
915
+ }
916
+ get drawerClasses() {
917
+ return `${this.variant} ${this.side} ${this.customClass}`;
918
+ }
919
+ ngOnInit() {
920
+ this.openDrawer();
921
+ }
922
+ ngOnDestroy() {
923
+ this.closeDrawer();
924
+ }
925
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Drawer, deps: [], target: i0.ɵɵFactoryTarget.Component });
926
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: Drawer, isStandalone: true, selector: "cat-drawer", inputs: { side: "side", variant: "variant", customClass: "customClass" }, outputs: { closs: "closs" }, viewQueries: [{ propertyName: "drawerTemplate", first: true, predicate: ["drawerTemplate"], descendants: true, static: true }], ngImport: i0, template: "<!-- Template que se renderiza dentro del overlay del CDK -->\n<ng-template #drawerTemplate>\n <section [class]=\"drawerClasses\">\n <cat-button iconCenter=\"x-mark\" variant=\"contrast\" class=\"close-button\" (clicked)=\"closeDrawer()\"></cat-button>\n <ng-content></ng-content>\n </section>\n </ng-template>", styles: ["section{position:relative;overflow:auto;box-sizing:border-box;padding:.25rem .75rem;transition:.25s;-webkit-user-select:none;user-select:none}.surface{background-color:var(--element-color-4)}.elevated{background-color:var(--neutral-color-0)}.outlined{background-color:var(--element-color-3);border:2px solid var(--neutral-color-9)}.close-button{position:absolute}.left,.right{width:30vw;height:100vh}.left .close-button,.right .close-button{right:.25rem}.top,.bottom{width:100vw;min-height:10em}.top .close-button,.bottom .close-button{right:.25rem}@media screen and (max-width: 1024px){.left,.right{width:50vw}.top,.bottom{height:50vh}}@media screen and (orientation: portrait) and (max-width: 600px){.left,.right{width:80vw}.top,.bottom{height:70vh}}\n"], dependencies: [{ kind: "component", type: Button, selector: "cat-button", inputs: ["variant", "size", "disabled", "type", "iconLeft", "iconCenter", "iconRight", "customClass"], outputs: ["clicked"] }] });
927
+ }
928
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Drawer, decorators: [{
929
+ type: Component,
930
+ args: [{ selector: 'cat-drawer', imports: [Button], template: "<!-- Template que se renderiza dentro del overlay del CDK -->\n<ng-template #drawerTemplate>\n <section [class]=\"drawerClasses\">\n <cat-button iconCenter=\"x-mark\" variant=\"contrast\" class=\"close-button\" (clicked)=\"closeDrawer()\"></cat-button>\n <ng-content></ng-content>\n </section>\n </ng-template>", styles: ["section{position:relative;overflow:auto;box-sizing:border-box;padding:.25rem .75rem;transition:.25s;-webkit-user-select:none;user-select:none}.surface{background-color:var(--element-color-4)}.elevated{background-color:var(--neutral-color-0)}.outlined{background-color:var(--element-color-3);border:2px solid var(--neutral-color-9)}.close-button{position:absolute}.left,.right{width:30vw;height:100vh}.left .close-button,.right .close-button{right:.25rem}.top,.bottom{width:100vw;min-height:10em}.top .close-button,.bottom .close-button{right:.25rem}@media screen and (max-width: 1024px){.left,.right{width:50vw}.top,.bottom{height:50vh}}@media screen and (orientation: portrait) and (max-width: 600px){.left,.right{width:80vw}.top,.bottom{height:70vh}}\n"] }]
931
+ }], propDecorators: { side: [{
932
+ type: Input
933
+ }], variant: [{
934
+ type: Input
935
+ }], customClass: [{
936
+ type: Input
937
+ }], closs: [{
938
+ type: Output
939
+ }], drawerTemplate: [{
940
+ type: ViewChild,
941
+ args: ['drawerTemplate', { static: true }]
942
+ }] } });
943
+
944
+ class Menu {
945
+ /* @Input() variant: 'surface' | 'elevated' | 'outlined' = 'surface';
946
+ @Input() customClass: string = '';
947
+
948
+ @HostBinding('attr.data-menu-class') get dataCustomClass() {
949
+ return this.customClass;
950
+ }
951
+
952
+ get menuClasses(): string {
953
+ return `${this.variant} ${this.customClass}`;
954
+ } */
955
+ menuContainer;
956
+ menuContent;
957
+ dropdown;
958
+ platformId = inject(PLATFORM_ID);
959
+ resizeObserver;
960
+ mutationObserver;
961
+ showMoreButton = signal(false, ...(ngDevMode ? [{ debugName: "showMoreButton" }] : []));
962
+ isDropdownOpen = signal(false, ...(ngDevMode ? [{ debugName: "isDropdownOpen" }] : []));
963
+ overflowItems = signal([], ...(ngDevMode ? [{ debugName: "overflowItems" }] : []));
964
+ ngAfterViewInit() {
965
+ if (!isPlatformBrowser(this.platformId))
966
+ return;
967
+ setTimeout(() => {
968
+ this.checkOverflow();
969
+ this.setupObservers();
970
+ }, 0);
971
+ }
972
+ ngOnDestroy() {
973
+ this.resizeObserver?.disconnect();
974
+ this.mutationObserver?.disconnect();
975
+ if (isPlatformBrowser(this.platformId)) {
976
+ document.removeEventListener('click', this.handleOutsideClick);
977
+ }
978
+ }
979
+ setupObservers() {
980
+ if (!isPlatformBrowser(this.platformId))
981
+ return;
982
+ this.resizeObserver = new ResizeObserver(() => {
983
+ this.checkOverflow();
984
+ });
985
+ this.resizeObserver.observe(this.menuContent.nativeElement);
986
+ document.addEventListener('click', this.handleOutsideClick);
987
+ }
988
+ handleOutsideClick = (event) => {
989
+ if (!this.isDropdownOpen())
990
+ return;
991
+ const target = event.target;
992
+ const clickedInside = this.menuContainer.nativeElement.contains(target) ||
993
+ this.dropdown?.nativeElement.contains(target);
994
+ if (!clickedInside) {
995
+ this.isDropdownOpen.set(false);
996
+ }
997
+ };
998
+ checkOverflow() {
999
+ // Si el dropdown está abierto, no recalcula el overflow
1000
+ if (this.isDropdownOpen()) {
1001
+ const overflowItems = this.overflowItems();
1002
+ if (overflowItems.length > 0) {
1003
+ this.showMoreButton.set(true);
1004
+ setTimeout(() => {
1005
+ //this.waitForDropdownAndUpdate();
1006
+ this.updateDropdownContent();
1007
+ }, 0);
1008
+ }
1009
+ return;
1010
+ }
1011
+ const container = this.menuContent.nativeElement;
1012
+ // Restaura todos los elementos que puedan estar en el dropdown
1013
+ this.restoreOverflowItems();
1014
+ const items = Array.from(container.children);
1015
+ if (items.length === 0) {
1016
+ this.showMoreButton.set(false);
1017
+ this.overflowItems.set([]);
1018
+ return;
1019
+ }
1020
+ const menuItems = items.filter(item => !item.classList.contains('more-button'));
1021
+ if (menuItems.length === 0) {
1022
+ this.showMoreButton.set(false);
1023
+ this.overflowItems.set([]);
1024
+ return;
1025
+ }
1026
+ // Restaura todos los elementos a su estado visible antes de calcular
1027
+ menuItems.forEach(item => {
1028
+ item.style.display = '';
1029
+ });
1030
+ // Fuerza un reflow para obtener posiciones correctas
1031
+ container.offsetHeight;
1032
+ // Detecta elementos en la primera fila vs elementos en filas adicionales
1033
+ const firstItemTop = menuItems[0]?.getBoundingClientRect().top;
1034
+ const firstRowItems = [];
1035
+ const overflowItems = [];
1036
+ menuItems.forEach(item => {
1037
+ const itemTop = item.getBoundingClientRect().top;
1038
+ // Usa tolerancia de 1px para manejar diferencias de redondeo
1039
+ if (Math.abs(itemTop - firstItemTop) <= 1) {
1040
+ firstRowItems.push(item);
1041
+ }
1042
+ else {
1043
+ overflowItems.push(item);
1044
+ }
1045
+ });
1046
+ // Si hay elementos en overflow, muestra el botón More y oculta los elementos overflow
1047
+ const needsMoreButton = overflowItems.length > 0;
1048
+ this.showMoreButton.set(needsMoreButton);
1049
+ // Oculta elementos que están en la segunda fila o más
1050
+ overflowItems.forEach(item => {
1051
+ item.style.display = 'none';
1052
+ });
1053
+ // Mantiene visibles solo los elementos de la primera fila
1054
+ firstRowItems.forEach(item => {
1055
+ item.style.display = '';
1056
+ });
1057
+ if (needsMoreButton) {
1058
+ this.overflowItems.set(overflowItems);
1059
+ }
1060
+ else {
1061
+ this.overflowItems.set([]);
1062
+ }
1063
+ }
1064
+ updateDropdownContent() {
1065
+ const menuWrapper = this.menuContainer.nativeElement.closest('.menu-wrapper');
1066
+ if (!menuWrapper) {
1067
+ return;
1068
+ }
1069
+ const dropdown = menuWrapper.querySelector('.dropdown');
1070
+ if (!dropdown) {
1071
+ return;
1072
+ }
1073
+ const dropdownContent = dropdown.querySelector('.dropdown-content');
1074
+ if (!dropdownContent) {
1075
+ return;
1076
+ }
1077
+ // Limpia el contenido previo del dropdown (por si hay algún elemento)
1078
+ this.restoreOverflowItems();
1079
+ const overflowItems = this.overflowItems();
1080
+ if (overflowItems.length === 0) {
1081
+ return;
1082
+ }
1083
+ //const menuContent = this.menuContent.nativeElement; //No se usa porque los elementos ya están en el dropdown
1084
+ overflowItems.forEach(item => {
1085
+ // Mueve el elemento real al dropdown
1086
+ // El elemento ya está oculto (display: none), así que lo hace visible y lo mueve al dropdown
1087
+ item.style.display = '';
1088
+ item.style.visibility = 'visible';
1089
+ // Mueve el elemento al dropdown
1090
+ dropdownContent.appendChild(item);
1091
+ });
1092
+ }
1093
+ // Esta función sirve para mover los elementos del dropdown al menu-content
1094
+ // NO los elimina del signal overflowItems, ni del DOM, (por lo que genera sobrecarga de memoria)
1095
+ restoreOverflowItems() {
1096
+ const overflowItems = this.overflowItems();
1097
+ const menuContent = this.menuContent.nativeElement;
1098
+ overflowItems.forEach(item => {
1099
+ // Si el elemento está en el dropdown, lo mueve de vuelta al menu-content
1100
+ const dropdownContent = item.closest('.dropdown-content');
1101
+ if (dropdownContent && item.parentElement === dropdownContent) {
1102
+ // Oculta el elemento y lo mueve de vuelta al menu-content
1103
+ item.style.display = 'none';
1104
+ menuContent.appendChild(item);
1105
+ }
1106
+ });
1107
+ }
1108
+ toggleDropdown() {
1109
+ const newState = !this.isDropdownOpen();
1110
+ if (!newState) {
1111
+ // Si se está cerrando, restaura los elementos a su posición original
1112
+ this.restoreOverflowItems();
1113
+ }
1114
+ this.isDropdownOpen.set(newState);
1115
+ if (newState) {
1116
+ // Recalcula el overflow antes de abrir el dropdown
1117
+ setTimeout(() => {
1118
+ this.checkOverflow();
1119
+ // Esperar a que el dropdown esté en el DOM antes de actualizar
1120
+ //this.waitForDropdownAndUpdate();
1121
+ this.updateDropdownContent();
1122
+ }, 0);
1123
+ }
1124
+ }
1125
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Menu, deps: [], target: i0.ɵɵFactoryTarget.Component });
1126
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: Menu, isStandalone: true, selector: "cat-menu", viewQueries: [{ propertyName: "menuContainer", first: true, predicate: ["menuContainer"], descendants: true }, { propertyName: "menuContent", first: true, predicate: ["menuContent"], descendants: true }, { propertyName: "dropdown", first: true, predicate: ["dropdown"], descendants: true }], ngImport: i0, template: "<div class=\"menu-wrapper\">\n <div class=\"menu\" #menuContainer>\n <div class=\"menu-content\" #menuContent>\n <ng-content></ng-content>\n </div>\n\n @if (showMoreButton()) {\n <button class=\"more-button\" (click)=\"toggleDropdown()\" [attr.aria-expanded]=\"isDropdownOpen()\" type=\"button\">\n <span>More</span>\n @if(isDropdownOpen()){\n <cat-icon size=\"16px\" name=\"chevron-up\"></cat-icon>\n } @else {\n <cat-icon size=\"16px\" name=\"chevron-down\"></cat-icon>\n }\n<!-- <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"currentColor\"\n [style.transform]=\"isDropdownOpen() ? 'rotate(180deg)' : 'rotate(0deg)'\">\n <path d=\"M4 6l4 4 4-4z\" />\n </svg> -->\n </button>\n }\n </div>\n\n @if (showMoreButton() && isDropdownOpen()) {\n <div class=\"dropdown\" #dropdown>\n <div class=\"dropdown-content\">\n <!-- Aqu\u00ED se mover\u00E1n los elementos overflow -->\n </div>\n </div>\n }\n</div>", styles: [".menu-wrapper{position:relative;width:100%;padding-top:.75rem;padding-bottom:.75rem;box-sizing:border-box}.menu{height:auto;background-color:rgb(var(--element-color-4) / .7);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);padding:1.75rem 2.5rem;margin:auto;border-radius:52px;border:1px var(--neutral-color-7) solid;display:flex;gap:1em;align-items:center;position:relative;width:100%;box-sizing:border-box}.menu-content{display:flex;gap:1em;align-items:center;flex:1;flex-wrap:wrap;min-width:0}.more-button{display:flex;align-items:center;gap:.5rem;padding:.5rem 1rem;border:none;border-radius:18px;background-color:var(--neutral-color-9);color:var(--neutral-color-0);cursor:pointer;font-size:1rem;font-weight:500;transition:all .2s;white-space:nowrap;flex-shrink:0;margin-left:auto}.more-button:hover{background-color:var(--neutral-color-8)}.more-button svg{transition:transform .2s}.dropdown{position:absolute;top:calc(100% - .75rem);right:.75rem;background-color:rgb(var(--element-color-4) / .95);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border-radius:24px;border:1px var(--neutral-color-7) solid;padding:1rem;min-width:200px;box-shadow:0 8px 24px #00000026;z-index:2;animation:dropdownSlide .2s ease-out}@keyframes dropdownSlide{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.dropdown-content{display:flex;flex-direction:column;gap:.5rem}.dropdown-content ::ng-deep>cat-button,.dropdown-content ::ng-deep>button{width:100%}@media (max-width: 600px){:host{max-width:100vw}.menu-wrapper{max-width:100vw;padding:.5rem}.menu{padding:1rem 1.5rem;max-width:calc(100vw - 1rem);width:calc(100% - 1rem)}.dropdown{right:.5rem;left:.5rem;max-width:none}}:host{display:block;width:100%;box-sizing:border-box}@media (min-width: 601px){:host{max-width:100%}.menu-wrapper{max-width:100%}.menu{max-width:calc(100% - 1.5rem)}}\n"], dependencies: [{ kind: "component", type: Icon, selector: "cat-icon", inputs: ["size", "color", "name", "src"] }] });
1127
+ }
1128
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Menu, decorators: [{
1129
+ type: Component,
1130
+ args: [{ selector: 'cat-menu', imports: [Icon], template: "<div class=\"menu-wrapper\">\n <div class=\"menu\" #menuContainer>\n <div class=\"menu-content\" #menuContent>\n <ng-content></ng-content>\n </div>\n\n @if (showMoreButton()) {\n <button class=\"more-button\" (click)=\"toggleDropdown()\" [attr.aria-expanded]=\"isDropdownOpen()\" type=\"button\">\n <span>More</span>\n @if(isDropdownOpen()){\n <cat-icon size=\"16px\" name=\"chevron-up\"></cat-icon>\n } @else {\n <cat-icon size=\"16px\" name=\"chevron-down\"></cat-icon>\n }\n<!-- <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"currentColor\"\n [style.transform]=\"isDropdownOpen() ? 'rotate(180deg)' : 'rotate(0deg)'\">\n <path d=\"M4 6l4 4 4-4z\" />\n </svg> -->\n </button>\n }\n </div>\n\n @if (showMoreButton() && isDropdownOpen()) {\n <div class=\"dropdown\" #dropdown>\n <div class=\"dropdown-content\">\n <!-- Aqu\u00ED se mover\u00E1n los elementos overflow -->\n </div>\n </div>\n }\n</div>", styles: [".menu-wrapper{position:relative;width:100%;padding-top:.75rem;padding-bottom:.75rem;box-sizing:border-box}.menu{height:auto;background-color:rgb(var(--element-color-4) / .7);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);padding:1.75rem 2.5rem;margin:auto;border-radius:52px;border:1px var(--neutral-color-7) solid;display:flex;gap:1em;align-items:center;position:relative;width:100%;box-sizing:border-box}.menu-content{display:flex;gap:1em;align-items:center;flex:1;flex-wrap:wrap;min-width:0}.more-button{display:flex;align-items:center;gap:.5rem;padding:.5rem 1rem;border:none;border-radius:18px;background-color:var(--neutral-color-9);color:var(--neutral-color-0);cursor:pointer;font-size:1rem;font-weight:500;transition:all .2s;white-space:nowrap;flex-shrink:0;margin-left:auto}.more-button:hover{background-color:var(--neutral-color-8)}.more-button svg{transition:transform .2s}.dropdown{position:absolute;top:calc(100% - .75rem);right:.75rem;background-color:rgb(var(--element-color-4) / .95);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border-radius:24px;border:1px var(--neutral-color-7) solid;padding:1rem;min-width:200px;box-shadow:0 8px 24px #00000026;z-index:2;animation:dropdownSlide .2s ease-out}@keyframes dropdownSlide{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.dropdown-content{display:flex;flex-direction:column;gap:.5rem}.dropdown-content ::ng-deep>cat-button,.dropdown-content ::ng-deep>button{width:100%}@media (max-width: 600px){:host{max-width:100vw}.menu-wrapper{max-width:100vw;padding:.5rem}.menu{padding:1rem 1.5rem;max-width:calc(100vw - 1rem);width:calc(100% - 1rem)}.dropdown{right:.5rem;left:.5rem;max-width:none}}:host{display:block;width:100%;box-sizing:border-box}@media (min-width: 601px){:host{max-width:100%}.menu-wrapper{max-width:100%}.menu{max-width:calc(100% - 1.5rem)}}\n"] }]
1131
+ }], propDecorators: { menuContainer: [{
1132
+ type: ViewChild,
1133
+ args: ['menuContainer', { static: false }]
1134
+ }], menuContent: [{
1135
+ type: ViewChild,
1136
+ args: ['menuContent', { static: false }]
1137
+ }], dropdown: [{
1138
+ type: ViewChild,
1139
+ args: ['dropdown', { static: false }]
1140
+ }] } });
1141
+
1142
+ class Theming {
1143
+ //Light Theme = False
1144
+ activeThemeSubject = new BehaviorSubject(false);
1145
+ activeTheme$ = this.activeThemeSubject.asObservable();
1146
+ //Palettes
1147
+ allPalettesSubject = new BehaviorSubject([]);
1148
+ allPalettes$ = this.allPalettesSubject.asObservable();
1149
+ generatePalettes(color, dark) {
1150
+ this.activeThemeSubject.next(dark);
1151
+ const primaryColors = this.calculatePrimaryColor(color);
1152
+ const dynamicPalettes = this.calculateDynamicPalettes(dark);
1153
+ // Asigna todas las paletas a variables locales
1154
+ let allPalettes = [primaryColors];
1155
+ allPalettes = allPalettes.concat([dynamicPalettes.neutral]);
1156
+ allPalettes = allPalettes.concat([dynamicPalettes.elements]);
1157
+ this.allPalettesSubject.next(allPalettes);
1158
+ // Aplica el tema
1159
+ this.applyTheme(allPalettes);
1160
+ return this.allPalettesSubject.value;
1161
+ }
1162
+ calculatePrimaryColor(color) {
1163
+ // Paso 1: Calcula el color
1164
+ const colors = this.hexToRgb(color);
1165
+ // Paso 2: Obtiene la paleta primaria (estática, no cambia con el tema)
1166
+ const primaryColors = this.palette(colors, false, 4); // Always use light theme
1167
+ const allPalettes = [
1168
+ primaryColors, // Keep primary (static)
1169
+ this.allPalettesSubject.value[1],
1170
+ this.allPalettesSubject.value[2]
1171
+ ];
1172
+ this.allPalettesSubject.next(allPalettes);
1173
+ this.applyTheme(allPalettes);
1174
+ return primaryColors;
1175
+ }
1176
+ calculateDynamicPalettes(dark) {
1177
+ const theme = dark;
1178
+ const contrastTheme = !dark;
1179
+ this.activeThemeSubject.next(dark);
1180
+ // Calcula los colores neutrales (cambian con el tema)
1181
+ const neutralColors = contrastTheme
1182
+ ? this.palette({ red: 255, green: 255, blue: 255 }, false, 9)
1183
+ : this.palette({ red: 0, green: 0, blue: 0 }, true, 9);
1184
+ // Calcula los colores de elementos (cambian con el tema)
1185
+ const elementsColors = this.elementsColors(theme, 3, 40);
1186
+ // Actualiza el array de paletas con valores dinámicos
1187
+ const allPalettes = [
1188
+ this.allPalettesSubject.value[0], // Keep primary (static)
1189
+ neutralColors,
1190
+ elementsColors
1191
+ ];
1192
+ this.allPalettesSubject.next(allPalettes);
1193
+ // Aplica el tema a las variables CSS
1194
+ this.applyTheme(allPalettes);
1195
+ return {
1196
+ neutral: neutralColors,
1197
+ elements: elementsColors
1198
+ };
1199
+ }
1200
+ palette(colors, dark, steps) {
1201
+ //Palette
1202
+ const colorsReturn = [];
1203
+ const contrastTheme = !dark;
1204
+ const target = contrastTheme ? 0 : 255;
1205
+ const umbralR = (target - colors.red) / steps;
1206
+ const umbralG = (target - colors.green) / steps;
1207
+ const umbralB = (target - colors.blue) / steps;
1208
+ for (let i = 0; i <= steps; i++) {
1209
+ const r = Math.round(colors.red + umbralR * i);
1210
+ const g = Math.round(colors.green + umbralG * i);
1211
+ const b = Math.round(colors.blue + umbralB * i);
1212
+ colorsReturn.push(`rgb(${r}, ${g}, ${b})`);
1213
+ }
1214
+ return colorsReturn;
1215
+ }
1216
+ ;
1217
+ elementsColors(theme, iteration, amplitude) {
1218
+ amplitude = amplitude / iteration;
1219
+ const colorsReturn = [];
1220
+ for (let i = 0; i < 5; i++) {
1221
+ let r = theme ? 0 + ((85 - 0) / (5 - 1) * i) : 0 + ((255 - 0) / (5 - 1) * i);
1222
+ let g = theme ? 0 + ((85 - 0) / (5 - 1) * i) : 0 + ((255 - 0) / (5 - 1) * i);
1223
+ let b = theme ? 0 + ((85 - 0) / (5 - 1) * i) : 0 + ((255 - 0) / (5 - 1) * i);
1224
+ if (i <= iteration && theme === false) {
1225
+ r = r + amplitude;
1226
+ g = g + amplitude;
1227
+ b = b + amplitude;
1228
+ }
1229
+ else if (theme === false) {
1230
+ r = r - amplitude;
1231
+ g = g - amplitude;
1232
+ b = b - amplitude;
1233
+ }
1234
+ colorsReturn.push(`rgb(${r}, ${g},${b})`);
1235
+ }
1236
+ ;
1237
+ return colorsReturn;
1238
+ }
1239
+ ;
1240
+ applyTheme(palettes) {
1241
+ if (typeof document === 'undefined')
1242
+ return;
1243
+ const root = document.documentElement;
1244
+ const cssVars = [
1245
+ { prefix: '--primary-color-', index: 0 },
1246
+ { prefix: '--neutral-color-', index: 1 },
1247
+ { prefix: '--element-color-', index: 2 }
1248
+ ];
1249
+ cssVars.forEach(({ prefix, index }) => {
1250
+ palettes[index]?.forEach((color, i) => {
1251
+ root.style.setProperty(`${prefix}${i}`, color);
1252
+ });
1253
+ });
1254
+ }
1255
+ hexToRgb(hex) {
1256
+ const value = parseInt(hex.replace('#', ''), 16);
1257
+ return {
1258
+ red: (value >> 16) & 255,
1259
+ green: (value >> 8) & 255,
1260
+ blue: value & 255,
1261
+ };
1262
+ }
1263
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Theming, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1264
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Theming, providedIn: 'root' });
1265
+ }
1266
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Theming, decorators: [{
1267
+ type: Injectable,
1268
+ args: [{
1269
+ providedIn: 'root'
1270
+ }]
1271
+ }] });
1272
+
1273
+ const ICON_BASE_PATH = 'safirial-icons';
1274
+ const iconList = [
1275
+ 'academic-cap',
1276
+ 'adjustments-horizontal',
1277
+ 'adjustments-vertical',
1278
+ 'archive-box',
1279
+ 'archive-box-arrow-down',
1280
+ 'archive-box-x-mark',
1281
+ 'arrow-down',
1282
+ 'arrow-down-circle',
1283
+ 'arrow-down-left',
1284
+ 'arrow-down-on-square',
1285
+ 'arrow-down-on-square-stack',
1286
+ 'arrow-down-right',
1287
+ 'arrow-down-tray',
1288
+ 'arrow-left',
1289
+ 'arrow-left-circle',
1290
+ 'arrow-left-end-on-rectangle',
1291
+ 'arrow-left-start-on-rectangle',
1292
+ 'arrow-long-down',
1293
+ 'arrow-long-left',
1294
+ 'arrow-long-right',
1295
+ 'arrow-long-up',
1296
+ 'arrow-path',
1297
+ 'arrow-path-rounded-square',
1298
+ 'arrow-right',
1299
+ 'arrow-right-circle',
1300
+ 'arrow-right-end-on-rectangle',
1301
+ 'arrow-right-start-on-rectangle',
1302
+ 'arrow-top-right-on-square',
1303
+ 'arrow-trending-down',
1304
+ 'arrow-trending-up',
1305
+ 'arrow-turn-down-left',
1306
+ 'arrow-turn-down-right',
1307
+ 'arrow-turn-left-down',
1308
+ 'arrow-turn-left-up',
1309
+ 'arrow-turn-right-down',
1310
+ 'arrow-turn-right-up',
1311
+ 'arrow-turn-up-left',
1312
+ 'arrow-turn-up-right',
1313
+ 'arrow-up',
1314
+ 'arrow-up-circle',
1315
+ 'arrow-up-left',
1316
+ 'arrow-up-on-square',
1317
+ 'arrow-up-on-square-stack',
1318
+ 'arrow-up-right',
1319
+ 'arrow-up-tray',
1320
+ 'arrow-uturn-down',
1321
+ 'arrow-uturn-left',
1322
+ 'arrow-uturn-right',
1323
+ 'arrow-uturn-up',
1324
+ 'arrows-pointing-in',
1325
+ 'arrows-pointing-out',
1326
+ 'arrows-right-left',
1327
+ 'arrows-up-down',
1328
+ 'at-symbol',
1329
+ 'backspace',
1330
+ 'backward',
1331
+ 'banknotes',
1332
+ 'bars-2',
1333
+ 'bars-3',
1334
+ 'bars-3-bottom-left',
1335
+ 'bars-3-bottom-right',
1336
+ 'bars-3-center-left',
1337
+ 'bars-4',
1338
+ 'bars-arrow-down',
1339
+ 'bars-arrow-up',
1340
+ 'battery-0',
1341
+ 'battery-100',
1342
+ 'battery-50',
1343
+ 'beaker',
1344
+ 'bell',
1345
+ 'bell-alert',
1346
+ 'bell-slash',
1347
+ 'bell-snooze',
1348
+ 'bold',
1349
+ 'bolt',
1350
+ 'bolt-slash',
1351
+ 'book-open',
1352
+ 'bookmark',
1353
+ 'bookmark-slash',
1354
+ 'bookmark-square',
1355
+ 'briefcase',
1356
+ 'bug-ant',
1357
+ 'building-library',
1358
+ 'building-office',
1359
+ 'building-office-2',
1360
+ 'building-storefront',
1361
+ 'cake',
1362
+ 'calculator',
1363
+ 'calendar',
1364
+ 'calendar-date-range',
1365
+ 'calendar-days',
1366
+ 'camera',
1367
+ 'chart-bar',
1368
+ 'chart-bar-square',
1369
+ 'chart-pie',
1370
+ 'chat-bubble-bottom-center',
1371
+ 'chat-bubble-bottom-center-text',
1372
+ 'chat-bubble-left',
1373
+ 'chat-bubble-left-ellipsis',
1374
+ 'chat-bubble-left-right',
1375
+ 'chat-bubble-oval-left',
1376
+ 'chat-bubble-oval-left-ellipsis',
1377
+ 'check',
1378
+ 'check-badge',
1379
+ 'check-circle',
1380
+ 'chevron-double-down',
1381
+ 'chevron-double-left',
1382
+ 'chevron-double-right',
1383
+ 'chevron-double-up',
1384
+ 'chevron-down',
1385
+ 'chevron-left',
1386
+ 'chevron-right',
1387
+ 'chevron-up',
1388
+ 'chevron-up-down',
1389
+ 'circle-stack',
1390
+ 'clipboard',
1391
+ 'clipboard-document',
1392
+ 'clipboard-document-check',
1393
+ 'clipboard-document-list',
1394
+ 'clock',
1395
+ 'cloud',
1396
+ 'cloud-arrow-down',
1397
+ 'cloud-arrow-up',
1398
+ 'code-bracket',
1399
+ 'code-bracket-square',
1400
+ 'cog',
1401
+ 'cog-6-tooth',
1402
+ 'cog-8-tooth',
1403
+ 'command-line',
1404
+ 'computer-desktop',
1405
+ 'cpu-chip',
1406
+ 'credit-card',
1407
+ 'cube',
1408
+ 'cube-transparent',
1409
+ 'currency-bangladeshi',
1410
+ 'currency-dollar',
1411
+ 'currency-euro',
1412
+ 'currency-pound',
1413
+ 'currency-rupee',
1414
+ 'currency-yen',
1415
+ 'cursor-arrow-rays',
1416
+ 'cursor-arrow-ripple',
1417
+ 'device-phone-mobile',
1418
+ 'device-tablet',
1419
+ 'divide',
1420
+ 'document',
1421
+ 'document-arrow-down',
1422
+ 'document-arrow-up',
1423
+ 'document-chart-bar',
1424
+ 'document-check',
1425
+ 'document-currency-bangladeshi',
1426
+ 'document-currency-dollar',
1427
+ 'document-currency-euro',
1428
+ 'document-currency-pound',
1429
+ 'document-currency-rupee',
1430
+ 'document-currency-yen',
1431
+ 'document-duplicate',
1432
+ 'document-magnifying-glass',
1433
+ 'document-minus',
1434
+ 'document-plus',
1435
+ 'document-text',
1436
+ 'ellipsis-horizontal',
1437
+ 'ellipsis-horizontal-circle',
1438
+ 'ellipsis-vertical',
1439
+ 'email',
1440
+ 'envelope',
1441
+ 'envelope-open',
1442
+ 'equals',
1443
+ 'exclamation-circle',
1444
+ 'exclamation-triangle',
1445
+ 'eye',
1446
+ 'eye-dropper',
1447
+ 'eye-slash',
1448
+ 'face-frown',
1449
+ 'face-smile',
1450
+ 'film',
1451
+ 'finger-print',
1452
+ 'fire',
1453
+ 'flag',
1454
+ 'folder',
1455
+ 'folder-arrow-down',
1456
+ 'folder-minus',
1457
+ 'folder-open',
1458
+ 'folder-plus',
1459
+ 'forward',
1460
+ 'funnel',
1461
+ 'gif',
1462
+ 'gift',
1463
+ 'gift-top',
1464
+ 'github',
1465
+ 'globe-alt',
1466
+ 'globe-americas',
1467
+ 'globe-asia-australia',
1468
+ 'globe-europe-africa',
1469
+ 'h1',
1470
+ 'h2',
1471
+ 'h3',
1472
+ 'hand-raised',
1473
+ 'hand-thumb-down',
1474
+ 'hand-thumb-up',
1475
+ 'hashtag',
1476
+ 'heart',
1477
+ 'home',
1478
+ 'home-modern',
1479
+ 'identification',
1480
+ 'inbox',
1481
+ 'inbox-arrow-down',
1482
+ 'inbox-stack',
1483
+ 'information-circle',
1484
+ 'italic',
1485
+ 'key',
1486
+ 'language',
1487
+ 'lifebuoy',
1488
+ 'light-bulb',
1489
+ 'link',
1490
+ 'link-slash',
1491
+ 'linkedin',
1492
+ 'list-bullet',
1493
+ 'lock-closed',
1494
+ 'lock-open',
1495
+ 'magnifying-glass',
1496
+ 'magnifying-glass-circle',
1497
+ 'magnifying-glass-minus',
1498
+ 'magnifying-glass-plus',
1499
+ 'map',
1500
+ 'map-pin',
1501
+ 'megaphone',
1502
+ 'microphone',
1503
+ 'minus',
1504
+ 'minus-circle',
1505
+ 'moon',
1506
+ 'musical-note',
1507
+ 'newspaper',
1508
+ 'no-symbol',
1509
+ 'numbered-list',
1510
+ 'paint-brush',
1511
+ 'palette',
1512
+ 'paper-airplane',
1513
+ 'paper-clip',
1514
+ 'pause',
1515
+ 'pause-circle',
1516
+ 'pencil',
1517
+ 'pencil-square',
1518
+ 'percent-badge',
1519
+ 'phone',
1520
+ 'phone-arrow-down-left',
1521
+ 'phone-arrow-up-right',
1522
+ 'phone-x-mark',
1523
+ 'photo',
1524
+ 'play',
1525
+ 'play-circle',
1526
+ 'play-pause',
1527
+ 'plus',
1528
+ 'plus-circle',
1529
+ 'power',
1530
+ 'presentation-chart-bar',
1531
+ 'presentation-chart-line',
1532
+ 'printer',
1533
+ 'puzzle-piece',
1534
+ 'qr-code',
1535
+ 'question-mark-circle',
1536
+ 'queue-list',
1537
+ 'radio',
1538
+ 'receipt-percent',
1539
+ 'receipt-refund',
1540
+ 'rectangle-group',
1541
+ 'rectangle-stack',
1542
+ 'rocket-launch',
1543
+ 'rss',
1544
+ 'scale',
1545
+ 'scissors',
1546
+ 'server',
1547
+ 'server-stack',
1548
+ 'share',
1549
+ 'shield-check',
1550
+ 'shield-exclamation',
1551
+ 'shopping-bag',
1552
+ 'shopping-cart',
1553
+ 'signal',
1554
+ 'signal-slash',
1555
+ 'slash',
1556
+ 'sparkles',
1557
+ 'speaker-wave',
1558
+ 'speaker-x-mark',
1559
+ 'square-2-stack',
1560
+ 'square-3-stack-3d',
1561
+ 'squares-2x2',
1562
+ 'squares-plus',
1563
+ 'star',
1564
+ 'stop',
1565
+ 'stop-circle',
1566
+ 'strikethrough',
1567
+ 'sun',
1568
+ 'swatch',
1569
+ 'table-cells',
1570
+ 'tag',
1571
+ 'ticket',
1572
+ 'trash',
1573
+ 'trophy',
1574
+ 'truck',
1575
+ 'tv',
1576
+ 'underline',
1577
+ 'user',
1578
+ 'user-circle',
1579
+ 'user-group',
1580
+ 'user-minus',
1581
+ 'user-plus',
1582
+ 'users',
1583
+ 'variable',
1584
+ 'video-camera',
1585
+ 'video-camera-slash',
1586
+ 'view-columns',
1587
+ 'viewfinder-circle',
1588
+ 'wallet',
1589
+ 'wifi',
1590
+ 'window',
1591
+ 'wrench',
1592
+ 'wrench-screwdriver',
1593
+ 'x-circle',
1594
+ 'x-mark',
1595
+ ];
1596
+ function getIconPath(name) {
1597
+ return `${ICON_BASE_PATH}/${name}.svg`;
1598
+ }
1599
+
1600
+ /*
1601
+ * Public API Surface of catarina
1602
+ */
1603
+ // design-system
1604
+
1605
+ /**
1606
+ * Generated bundle index. Do not edit.
1607
+ */
1608
+
1609
+ export { Accordion, AccordionGroup, Button, Card, CatInput, ColorInput, Dialog, Drag, Drawer, ICON_BASE_PATH, ICON_PROVIDER, Icon, Menu, SelectInput, Theming, getIconPath, iconList };
1610
+ //# sourceMappingURL=catarina-ds-angular.mjs.map