@catarina-ds/angular 0.1.0 → 0.1.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.
@@ -1,218 +1,19 @@
1
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';
2
+ import { Component, EventEmitter, TemplateRef, HostBinding, Output, Input, ViewChild, ContentChildren, inject, ElementRef, PLATFORM_ID, Optional, Self, Directive, forwardRef, HostListener, DOCUMENT, Inject, ViewContainerRef, ChangeDetectorRef, Injectable, input, effect } from '@angular/core';
3
+ import { NgComponentOutlet, NgTemplateOutlet, NgClass, NgIf, isPlatformBrowser } from '@angular/common';
5
4
  import { NgControl, NG_VALUE_ACCESSOR } from '@angular/forms';
6
5
  import { Overlay } from '@angular/cdk/overlay';
7
6
  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
- });
7
+ import { BehaviorSubject, Subject, Subscription } from 'rxjs';
17
8
 
18
9
  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
10
  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"] });
11
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: Icon, isStandalone: true, selector: "cat-icon", ngImport: i0, template: "<ng-content></ng-content>\n", styles: [":host{display:inline-flex;align-items:center;justify-content:center;width:1em;height:1em;font-size:24px;overflow:hidden}:host :deep(svg),:host :deep(img){width:100%;height:100%;object-fit:contain}\n"] });
203
12
  }
204
13
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Icon, decorators: [{
205
14
  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
- }] } });
15
+ args: [{ selector: 'cat-icon', imports: [], template: "<ng-content></ng-content>\n", styles: [":host{display:inline-flex;align-items:center;justify-content:center;width:1em;height:1em;font-size:24px;overflow:hidden}:host :deep(svg),:host :deep(img){width:100%;height:100%;object-fit:contain}\n"] }]
16
+ }] });
216
17
 
217
18
  class Button {
218
19
  variant = 'primary';
@@ -231,6 +32,9 @@ class Button {
231
32
  const sizes = { sm: '16px', md: '20px', lg: '24px' };
232
33
  return sizes[this.size];
233
34
  }
35
+ isTemplateRef(content) {
36
+ return content instanceof TemplateRef;
37
+ }
234
38
  get dataCustomClass() {
235
39
  return this.customClass;
236
40
  }
@@ -240,11 +44,11 @@ class Button {
240
44
  }
241
45
  }
242
46
  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"] }] });
47
+ 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 class=\"icon-left\">\n @if (isTemplateRef(iconLeft)) {\n <ng-container [ngTemplateOutlet]=\"iconLeft\"></ng-container>\n } @else {\n <ng-container *ngComponentOutlet=\"iconLeft\"></ng-container>\n }\n </cat-icon>\n }\n\n <span class=\"button-content\">\n @if (iconCenter) {\n <cat-icon class=\"icon-center\">\n @if (isTemplateRef(iconCenter)) {\n <ng-container [ngTemplateOutlet]=\"iconCenter\"></ng-container>\n } @else {\n <ng-container *ngComponentOutlet=\"iconCenter\"></ng-container>\n }\n </cat-icon>\n }\n <ng-content></ng-content>\n </span>\n\n @if (iconRight) {\n <cat-icon class=\"icon-right\">\n @if (isTemplateRef(iconRight)) {\n <ng-container [ngTemplateOutlet]=\"iconRight\"></ng-container>\n } @else {\n <ng-container *ngComponentOutlet=\"iconRight\"></ng-container>\n }\n </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" }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
244
48
  }
245
49
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Button, decorators: [{
246
50
  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"] }]
51
+ args: [{ selector: 'cat-button', imports: [Icon, NgComponentOutlet, NgTemplateOutlet], template: "<button [class]=\"buttonClasses\" [disabled]=\"disabled\" [type]=\"type\" (click)=\"handleClick($event)\">\n @if (iconLeft) {\n <cat-icon class=\"icon-left\">\n @if (isTemplateRef(iconLeft)) {\n <ng-container [ngTemplateOutlet]=\"iconLeft\"></ng-container>\n } @else {\n <ng-container *ngComponentOutlet=\"iconLeft\"></ng-container>\n }\n </cat-icon>\n }\n\n <span class=\"button-content\">\n @if (iconCenter) {\n <cat-icon class=\"icon-center\">\n @if (isTemplateRef(iconCenter)) {\n <ng-container [ngTemplateOutlet]=\"iconCenter\"></ng-container>\n } @else {\n <ng-container *ngComponentOutlet=\"iconCenter\"></ng-container>\n }\n </cat-icon>\n }\n <ng-content></ng-content>\n </span>\n\n @if (iconRight) {\n <cat-icon class=\"icon-right\">\n @if (isTemplateRef(iconRight)) {\n <ng-container [ngTemplateOutlet]=\"iconRight\"></ng-container>\n } @else {\n <ng-container *ngComponentOutlet=\"iconRight\"></ng-container>\n }\n </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
52
  }], propDecorators: { variant: [{
249
53
  type: Input
250
54
  }], size: [{
@@ -365,7 +169,6 @@ class Accordion {
365
169
  forceStatus(newStatus) {
366
170
  this.status = newStatus;
367
171
  }
368
- ;
369
172
  get dataCustomClass() {
370
173
  return this.customClass;
371
174
  }
@@ -373,11 +176,11 @@ class Accordion {
373
176
  return `${this.variant} ${this.customClass} ${this.scrolleable ? 'scrolleable' : undefined}`;
374
177
  }
375
178
  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"] }] });
179
+ 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: "<ng-template #collapsedIcon>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"M12 5v14M5 12h14\"></path>\n </svg>\n</ng-template>\n<ng-template #expandedIcon>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"M5 12h14\"></path>\n </svg>\n</ng-template>\n\n<section class=\"accordion\">\n <div>\n <cat-button\n [iconLeft]=\"\n iconLeft === true ? (status ? expandedIcon : collapsedIcon) : iconLeft || undefined\n \"\n [iconCenter]=\"\n iconCenter === true ? (status ? expandedIcon : collapsedIcon) : iconCenter || undefined\n \"\n [iconRight]=\"\n iconRight === true ? (status ? expandedIcon : collapsedIcon) : iconRight || undefined\n \"\n (clicked)=\"updateAccordionGroupStatus()\"\n [variant]=\"buttonVariant\"\n [size]=\"buttonSize\"\n customClass=\"accordion-button\"\n [disabled]=\"disabled\"\n >\n {{ label }}\n </cat-button>\n </div>\n <div\n [class]=\"panelClasses\"\n [ngClass]=\"status ? 'accordion-panel-active' : 'accordion-panel-unactive'\"\n >\n <ng-content *ngIf=\"status\"></ng-content>\n </div>\n</section>\n", 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
180
  }
378
181
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Accordion, decorators: [{
379
182
  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"] }]
183
+ args: [{ selector: 'cat-accordion', imports: [Button, NgClass, NgIf], template: "<ng-template #collapsedIcon>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"M12 5v14M5 12h14\"></path>\n </svg>\n</ng-template>\n<ng-template #expandedIcon>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"M5 12h14\"></path>\n </svg>\n</ng-template>\n\n<section class=\"accordion\">\n <div>\n <cat-button\n [iconLeft]=\"\n iconLeft === true ? (status ? expandedIcon : collapsedIcon) : iconLeft || undefined\n \"\n [iconCenter]=\"\n iconCenter === true ? (status ? expandedIcon : collapsedIcon) : iconCenter || undefined\n \"\n [iconRight]=\"\n iconRight === true ? (status ? expandedIcon : collapsedIcon) : iconRight || undefined\n \"\n (clicked)=\"updateAccordionGroupStatus()\"\n [variant]=\"buttonVariant\"\n [size]=\"buttonSize\"\n customClass=\"accordion-button\"\n [disabled]=\"disabled\"\n >\n {{ label }}\n </cat-button>\n </div>\n <div\n [class]=\"panelClasses\"\n [ngClass]=\"status ? 'accordion-panel-active' : 'accordion-panel-unactive'\"\n >\n <ng-content *ngIf=\"status\"></ng-content>\n </div>\n</section>\n", 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
184
  }], propDecorators: { accordionId: [{
382
185
  type: Input
383
186
  }], status: [{
@@ -578,6 +381,9 @@ class ColorInput {
578
381
  size = '2em';
579
382
  onChange = (value) => { };
580
383
  onTouched = () => { };
384
+ isTemplateRef(content) {
385
+ return content instanceof TemplateRef;
386
+ }
581
387
  onInput(event) {
582
388
  const newValue = event.target.value;
583
389
  this.value = newValue;
@@ -594,19 +400,23 @@ class ColorInput {
594
400
  this.onTouched = fn;
595
401
  }
596
402
  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: [{
403
+ 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: [
404
+ {
598
405
  provide: NG_VALUE_ACCESSOR,
599
406
  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"] }] });
407
+ multi: true,
408
+ },
409
+ ], ngImport: i0, template: "<style>\n div {\n position: relative;\n aspect-ratio: 1/1;\n }\n\n div:hover {\n cursor: grab;\n }\n\n input {\n width: 100%;\n aspect-ratio: 1/1;\n top: 0;\n left: 0;\n }\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)\"\n (blur)=\"onTouched()\" />\n @if (icon) {\n <cat-icon style=\"width: 100%; height: 100%;\">\n @if (icon === true) {\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n <g id=\"SVGRepo_iconCarrier\">\n <path d=\"M10.5 10.5c.002 2.762-2.237 5-5 5s-5.002-2.238-5-5c-.002-2.76 2.237-5 5-5s5.002 2.24 5 5z\"\n color=\"#000000\" fill=\"#ff15a1\" stroke=\"#373737\" stroke-width=\".49999682600000006\"></path>\n <path\n d=\"M8 1.401a4.998 4.998 0 0 0-2.488 9.334c-.004-.078-.012-.155-.012-.234a4.998 4.998 0 0 1 7.488-4.334A4.994 4.994 0 0 0 8 1.4z\"\n fill=\"#1583ff\"></path>\n <path\n d=\"M10.5 5.5a4.998 4.998 0 0 0-5 5c0 .08.008.157.012.235A4.998 4.998 0 0 0 13 6.401c0-.079-.008-.156-.012-.234A4.975 4.975 0 0 0 10.5 5.5z\"\n fill=\"#00cf2d\"></path>\n <path\n d=\"M12.988 6.167c.004.078.012.155.012.234a4.998 4.998 0 0 1-7.489 4.334 4.994 4.994 0 0 0 4.989 4.766 4.998 4.998 0 0 0 2.488-9.334z\"\n fill=\"#f8ff15\"></path>\n <path\n d=\"M5.512 10.735a4.996 4.996 0 0 0 2.486 4.093 4.987 4.987 0 0 0 2.49-4.091A4.978 4.978 0 0 1 8 11.4a4.975 4.975 0 0 1-2.488-.666z\"\n fill=\"#ef0000\"></path>\n <path\n d=\"M7.998 6.173A4.991 4.991 0 0 0 5.5 10.5c0 .079.008.156.012.234a4.978 4.978 0 0 0 4.977.002c.003-.079.011-.157.011-.236a4.99 4.99 0 0 0-2.502-4.328z\"\n fill=\"#383027\"></path>\n <path\n d=\"M5.5 5.5c-.91 0-1.76.247-2.494.67a4.99 4.99 0 0 0 2.506 4.564c-.004-.077-.012-.154-.012-.233a4.991 4.991 0 0 1 2.498-4.328A4.975 4.975 0 0 0 5.5 5.5z\"\n fill=\"#5100cc\"></path>\n <path\n d=\"M8 1.401a4.998 4.998 0 0 0-4.994 4.77 4.998 4.998 0 1 0 4.992 8.658 4.998 4.998 0 1 0 4.99-8.662A4.994 4.994 0 0 0 8 1.4z\"\n fill=\"none\" stroke=\"#373737\" stroke-width=\".9999936520000001\"></path>\n </g>\n </svg>\n } @else if (isTemplateRef(icon)) {\n <ng-container [ngTemplateOutlet]=\"icon\"></ng-container>\n } @else {\n <ng-container *ngComponentOutlet=\"icon\"></ng-container>\n }\n </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" }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
602
410
  }
603
411
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ColorInput, decorators: [{
604
412
  type: Component,
605
- args: [{ selector: 'cat-color-input', imports: [Icon], providers: [{
413
+ args: [{ selector: 'cat-color-input', imports: [Icon, NgComponentOutlet, NgTemplateOutlet], providers: [
414
+ {
606
415
  provide: NG_VALUE_ACCESSOR,
607
416
  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"] }]
417
+ multi: true,
418
+ },
419
+ ], template: "<style>\n div {\n position: relative;\n aspect-ratio: 1/1;\n }\n\n div:hover {\n cursor: grab;\n }\n\n input {\n width: 100%;\n aspect-ratio: 1/1;\n top: 0;\n left: 0;\n }\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)\"\n (blur)=\"onTouched()\" />\n @if (icon) {\n <cat-icon style=\"width: 100%; height: 100%;\">\n @if (icon === true) {\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n <g id=\"SVGRepo_iconCarrier\">\n <path d=\"M10.5 10.5c.002 2.762-2.237 5-5 5s-5.002-2.238-5-5c-.002-2.76 2.237-5 5-5s5.002 2.24 5 5z\"\n color=\"#000000\" fill=\"#ff15a1\" stroke=\"#373737\" stroke-width=\".49999682600000006\"></path>\n <path\n d=\"M8 1.401a4.998 4.998 0 0 0-2.488 9.334c-.004-.078-.012-.155-.012-.234a4.998 4.998 0 0 1 7.488-4.334A4.994 4.994 0 0 0 8 1.4z\"\n fill=\"#1583ff\"></path>\n <path\n d=\"M10.5 5.5a4.998 4.998 0 0 0-5 5c0 .08.008.157.012.235A4.998 4.998 0 0 0 13 6.401c0-.079-.008-.156-.012-.234A4.975 4.975 0 0 0 10.5 5.5z\"\n fill=\"#00cf2d\"></path>\n <path\n d=\"M12.988 6.167c.004.078.012.155.012.234a4.998 4.998 0 0 1-7.489 4.334 4.994 4.994 0 0 0 4.989 4.766 4.998 4.998 0 0 0 2.488-9.334z\"\n fill=\"#f8ff15\"></path>\n <path\n d=\"M5.512 10.735a4.996 4.996 0 0 0 2.486 4.093 4.987 4.987 0 0 0 2.49-4.091A4.978 4.978 0 0 1 8 11.4a4.975 4.975 0 0 1-2.488-.666z\"\n fill=\"#ef0000\"></path>\n <path\n d=\"M7.998 6.173A4.991 4.991 0 0 0 5.5 10.5c0 .079.008.156.012.234a4.978 4.978 0 0 0 4.977.002c.003-.079.011-.157.011-.236a4.99 4.99 0 0 0-2.502-4.328z\"\n fill=\"#383027\"></path>\n <path\n d=\"M5.5 5.5c-.91 0-1.76.247-2.494.67a4.99 4.99 0 0 0 2.506 4.564c-.004-.077-.012-.154-.012-.233a4.991 4.991 0 0 1 2.498-4.328A4.975 4.975 0 0 0 5.5 5.5z\"\n fill=\"#5100cc\"></path>\n <path\n d=\"M8 1.401a4.998 4.998 0 0 0-4.994 4.77 4.998 4.998 0 1 0 4.992 8.658 4.998 4.998 0 1 0 4.99-8.662A4.994 4.994 0 0 0 8 1.4z\"\n fill=\"none\" stroke=\"#373737\" stroke-width=\".9999936520000001\"></path>\n </g>\n </svg>\n } @else if (isTemplateRef(icon)) {\n <ng-container [ngTemplateOutlet]=\"icon\"></ng-container>\n } @else {\n <ng-container *ngComponentOutlet=\"icon\"></ng-container>\n }\n </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
420
  }], propDecorators: { icon: [{
611
421
  type: Input
612
422
  }], size: [{
@@ -774,13 +584,15 @@ class Dialog {
774
584
  // Referencia al overlay creado
775
585
  overlayRef;
776
586
  variant = 'surface';
777
- size = 'md';
587
+ width = '300px';
588
+ height = '200px';
778
589
  customClass = '';
779
590
  closs = new EventEmitter();
780
591
  // Referencia al template que contiene el ng-content
781
592
  dialogTemplate;
782
593
  createOverlayConfig() {
783
- const positionStrategy = this.overlay.position()
594
+ const positionStrategy = this.overlay
595
+ .position()
784
596
  .global()
785
597
  .centerHorizontally()
786
598
  .centerVertically();
@@ -789,7 +601,7 @@ class Dialog {
789
601
  scrollStrategy: this.overlay.scrollStrategies.block(),
790
602
  hasBackdrop: true,
791
603
  backdropClass: 'cdk-overlay-dark-backdrop',
792
- panelClass: ['cat-dialog-overlay-panel', this.variant, this.size, this.customClass],
604
+ panelClass: ['cat-dialog-overlay-panel', this.variant, this.customClass],
793
605
  };
794
606
  }
795
607
  openDialog() {
@@ -803,7 +615,7 @@ class Dialog {
803
615
  this.closeDialog();
804
616
  });
805
617
  // Escucha la tecla Escape para cerrar
806
- this.overlayRef.keydownEvents().subscribe(event => {
618
+ this.overlayRef.keydownEvents().subscribe((event) => {
807
619
  if (event.key === 'Escape') {
808
620
  this.closeDialog();
809
621
  }
@@ -818,7 +630,7 @@ class Dialog {
818
630
  }
819
631
  }
820
632
  get dialogClasses() {
821
- return `${this.variant} ${this.size} ${this.customClass}`;
633
+ return `${this.variant} {this.customClass}`;
822
634
  }
823
635
  ngOnInit() {
824
636
  this.openDialog();
@@ -827,14 +639,16 @@ class Dialog {
827
639
  this.closeDialog();
828
640
  }
829
641
  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]" }] });
642
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: Dialog, isStandalone: true, selector: "cat-dialog", inputs: { variant: "variant", width: "width", height: "height", 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 [style]=\"`height: ${height}; width: ${width};`\" CDrag [class]=\"dialogClasses\">\n <ng-content></ng-content>\n </section>\n</ng-template>\n", styles: ["section{position:relative;border-radius:18px;overflow:auto;padding:.75rem 1.5rem;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)}\n"], dependencies: [{ kind: "directive", type: Drag, selector: "[CDrag]" }] });
831
643
  }
832
644
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Dialog, decorators: [{
833
645
  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"] }]
646
+ args: [{ selector: 'cat-dialog', imports: [Drag], template: "<!-- Template que se renderiza dentro del overlay del CDK -->\n<ng-template #dialogTemplate>\n <section [style]=\"`height: ${height}; width: ${width};`\" CDrag [class]=\"dialogClasses\">\n <ng-content></ng-content>\n </section>\n</ng-template>\n", styles: ["section{position:relative;border-radius:18px;overflow:auto;padding:.75rem 1.5rem;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)}\n"] }]
835
647
  }], propDecorators: { variant: [{
836
648
  type: Input
837
- }], size: [{
649
+ }], width: [{
650
+ type: Input
651
+ }], height: [{
838
652
  type: Input
839
653
  }], customClass: [{
840
654
  type: Input
@@ -923,11 +737,11 @@ class Drawer {
923
737
  this.closeDrawer();
924
738
  }
925
739
  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"] }] });
740
+ 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 <ng-template #closeIcon>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"m6 6 12 12M18 6 6 18\"></path>\n </svg>\n </ng-template>\n <section [class]=\"drawerClasses\">\n <cat-button\n [iconCenter]=\"closeIcon\"\n variant=\"contrast\"\n class=\"close-button\"\n (clicked)=\"closeDrawer()\"\n ></cat-button>\n <ng-content></ng-content>\n </section>\n</ng-template>\n", 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
741
  }
928
742
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Drawer, decorators: [{
929
743
  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"] }]
744
+ args: [{ selector: 'cat-drawer', imports: [Button], template: "<!-- Template que se renderiza dentro del overlay del CDK -->\n<ng-template #drawerTemplate>\n <ng-template #closeIcon>\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\">\n <path d=\"m6 6 12 12M18 6 6 18\"></path>\n </svg>\n </ng-template>\n <section [class]=\"drawerClasses\">\n <cat-button\n [iconCenter]=\"closeIcon\"\n variant=\"contrast\"\n class=\"close-button\"\n (clicked)=\"closeDrawer()\"\n ></cat-button>\n <ng-content></ng-content>\n </section>\n</ng-template>\n", 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
745
  }], propDecorators: { side: [{
932
746
  type: Input
933
747
  }], variant: [{
@@ -941,202 +755,132 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
941
755
  args: ['drawerTemplate', { static: true }]
942
756
  }] } });
943
757
 
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();
758
+ class MenuDropdown {
759
+ items = [];
760
+ panelContainer;
761
+ activeIndex = 0;
762
+ get isSingle() {
763
+ return this.items.length === 1;
764
+ }
765
+ isTemplateRef(value) {
766
+ return value instanceof TemplateRef;
767
+ }
768
+ setActive(index) {
769
+ // Oculta el panel activo actual
770
+ this.items[this.activeIndex]?.element.style.setProperty('display', 'none');
771
+ this.activeIndex = index;
772
+ // Muestra el nuevo panel activo
773
+ this.items[this.activeIndex]?.element.style.removeProperty('display');
774
+ }
775
+ showActivePanel() {
776
+ this.items.forEach((item, i) => {
777
+ item.element.style.setProperty('display', i === this.activeIndex ? '' : 'none');
984
778
  });
985
- this.resizeObserver.observe(this.menuContent.nativeElement);
986
- document.addEventListener('click', this.handleOutsideClick);
987
779
  }
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([]);
780
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: MenuDropdown, deps: [], target: i0.ɵɵFactoryTarget.Component });
781
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: MenuDropdown, isStandalone: true, selector: "cat-menu-dropdown", inputs: { items: "items" }, viewQueries: [{ propertyName: "panelContainer", first: true, predicate: ["panelContainer"], descendants: true, static: true }], ngImport: i0, template: "@if (!isSingle) {\n <!-- Tabs: solo cuando hay m\u00FAltiples paneles -->\n <div class=\"dropdown-tabs\">\n @for (item of items; track $index) {\n @if (isTemplateRef(item.label)) {\n <cat-button\n variant=\"secondary\"\n [iconCenter]=\"item.label\"\n [customClass]=\"activeIndex === $index ? 'tab-active' : ''\"\n (clicked)=\"setActive($index)\"\n ></cat-button>\n } @else {\n <cat-button\n variant=\"secondary\"\n [customClass]=\"activeIndex === $index ? 'tab-active' : ''\"\n (clicked)=\"setActive($index)\"\n >{{ item.label }}</cat-button>\n }\n }\n </div>\n}\n\n<!-- Contenedor donde el Menu mueve los nodos DOM de cat-menu-panel -->\n<div class=\"dropdown-content\" #panelContainer></div>\n", styles: [":host{display:block;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;animation:dropdownSlide .2s ease-out}@keyframes dropdownSlide{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.dropdown-tabs{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:.75rem;padding-bottom:.75rem;border-bottom:1px solid var(--neutral-color-7)}.dropdown-tabs ::ng-deep cat-button.tab-active button{background-color:var(--neutral-color-7)}.dropdown-content{display:flex;flex-direction:column;gap:.5rem}.dropdown-content ::ng-deep>cat-button,.dropdown-content ::ng-deep>button{width:100%}\n"], dependencies: [{ kind: "component", type: Button, selector: "cat-button", inputs: ["variant", "size", "disabled", "type", "iconLeft", "iconCenter", "iconRight", "customClass"], outputs: ["clicked"] }] });
782
+ }
783
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: MenuDropdown, decorators: [{
784
+ type: Component,
785
+ args: [{ selector: 'cat-menu-dropdown', imports: [NgTemplateOutlet, Button], template: "@if (!isSingle) {\n <!-- Tabs: solo cuando hay m\u00FAltiples paneles -->\n <div class=\"dropdown-tabs\">\n @for (item of items; track $index) {\n @if (isTemplateRef(item.label)) {\n <cat-button\n variant=\"secondary\"\n [iconCenter]=\"item.label\"\n [customClass]=\"activeIndex === $index ? 'tab-active' : ''\"\n (clicked)=\"setActive($index)\"\n ></cat-button>\n } @else {\n <cat-button\n variant=\"secondary\"\n [customClass]=\"activeIndex === $index ? 'tab-active' : ''\"\n (clicked)=\"setActive($index)\"\n >{{ item.label }}</cat-button>\n }\n }\n </div>\n}\n\n<!-- Contenedor donde el Menu mueve los nodos DOM de cat-menu-panel -->\n<div class=\"dropdown-content\" #panelContainer></div>\n", styles: [":host{display:block;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;animation:dropdownSlide .2s ease-out}@keyframes dropdownSlide{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.dropdown-tabs{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:.75rem;padding-bottom:.75rem;border-bottom:1px solid var(--neutral-color-7)}.dropdown-tabs ::ng-deep cat-button.tab-active button{background-color:var(--neutral-color-7)}.dropdown-content{display:flex;flex-direction:column;gap:.5rem}.dropdown-content ::ng-deep>cat-button,.dropdown-content ::ng-deep>button{width:100%}\n"] }]
786
+ }], propDecorators: { items: [{
787
+ type: Input
788
+ }], panelContainer: [{
789
+ type: ViewChild,
790
+ args: ['panelContainer', { static: true }]
791
+ }] } });
792
+
793
+ class MenuPanel {
794
+ elementRef;
795
+ label;
796
+ constructor(elementRef) {
797
+ this.elementRef = elementRef;
798
+ }
799
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: MenuPanel, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
800
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: MenuPanel, isStandalone: true, selector: "cat-menu-panel", inputs: { label: "label" }, ngImport: i0, template: "<ng-content></ng-content>\n" });
801
+ }
802
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: MenuPanel, decorators: [{
803
+ type: Component,
804
+ args: [{ selector: 'cat-menu-panel', template: "<ng-content></ng-content>\n" }]
805
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { label: [{
806
+ type: Input
807
+ }] } });
808
+
809
+ class Menu {
810
+ panels;
811
+ panelsHost;
812
+ dropdownRef;
813
+ cdr = inject(ChangeDetectorRef);
814
+ // Controla si los cat-menu-panel están colapsados hacia el dropdown
815
+ isDropdownActive = false;
816
+ // Controla si el panel del dropdown está visible
817
+ isPanelOpen = false;
818
+ // Flag para ejecutar el move de paneles en el próximo AfterViewChecked
819
+ pendingPanelMove = false;
820
+ ngAfterContentInit() { }
821
+ ngAfterViewChecked() {
822
+ // Ejecuta el move cuando el dropdownRef ya está disponible en el DOM
823
+ if (this.pendingPanelMove && this.dropdownRef) {
824
+ this.pendingPanelMove = false;
825
+ this.executePanelMove();
1062
826
  }
1063
827
  }
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;
828
+ // Llamado por el consumidor via referencia de template
829
+ toggleContent() {
830
+ this.isDropdownActive = !this.isDropdownActive;
831
+ if (!this.isDropdownActive) {
832
+ this.restorePanels();
1076
833
  }
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;
834
+ }
835
+ // Llamado por el botón chevron
836
+ togglePanel() {
837
+ this.isPanelOpen = !this.isPanelOpen;
838
+ if (this.isPanelOpen) {
839
+ // Marca el move pendiente — se ejecutará cuando dropdownRef esté disponible
840
+ this.pendingPanelMove = true;
1082
841
  }
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
842
  }
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
- }
843
+ executePanelMove() {
844
+ if (!this.dropdownRef)
845
+ return;
846
+ const container = this.dropdownRef.panelContainer.nativeElement;
847
+ const items = this.panels.map(panel => ({
848
+ label: panel.label,
849
+ element: panel.elementRef.nativeElement,
850
+ }));
851
+ items.forEach((item, i) => {
852
+ item.element.style.display = i === 0 ? '' : 'none';
853
+ container.appendChild(item.element);
1106
854
  });
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);
855
+ this.dropdownRef.items = items;
856
+ this.dropdownRef.activeIndex = 0;
857
+ this.cdr.detectChanges();
858
+ }
859
+ restorePanels() {
860
+ this.isPanelOpen = false;
861
+ if (this.panelsHost) {
862
+ this.panels.forEach(panel => {
863
+ const el = panel.elementRef.nativeElement;
864
+ el.style.display = '';
865
+ this.panelsHost.nativeElement.appendChild(el);
866
+ });
1123
867
  }
1124
868
  }
1125
869
  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"] }] });
870
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: Menu, isStandalone: true, selector: "cat-menu", queries: [{ propertyName: "panels", predicate: MenuPanel }], viewQueries: [{ propertyName: "panelsHost", first: true, predicate: ["panelsHost"], descendants: true }, { propertyName: "dropdownRef", first: true, predicate: ["dropdownRef"], descendants: true }], ngImport: i0, template: "<div class=\"menu-wrapper\">\n <div class=\"menu\">\n\n <!-- Contenido est\u00E1tico: todo lo que NO sea cat-menu-panel -->\n <div class=\"menu-static\">\n <ng-content select=\":not(cat-menu-panel)\"></ng-content>\n </div>\n\n <!-- Host de los cat-menu-panel: visible en estado inicial, oculto cuando el dropdown est\u00E1 activo -->\n <div #panelsHost class=\"menu-panels-host\" [style.display]=\"isDropdownActive ? 'none' : 'contents'\">\n <ng-content select=\"cat-menu-panel\"></ng-content>\n </div>\n\n <!-- Bot\u00F3n chevron: visible cuando isDropdownActive es true -->\n @if (isDropdownActive) {\n <div class=\"menu-toggle\">\n <cat-button variant=\"secondary\" (clicked)=\"togglePanel()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" style=\"width: 20px; height: 20px;\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m19.5 8.25-7.5 7.5-7.5-7.5\" />\n </svg>\n </cat-button>\n </div>\n }\n\n <!-- Dropdown: siempre en el DOM cuando isDropdownActive, visible solo cuando isPanelOpen -->\n @if (isDropdownActive) {\n <cat-menu-dropdown\n #dropdownRef\n [style.display]=\"isPanelOpen ? 'block' : 'none'\"\n ></cat-menu-dropdown>\n }\n\n </div>\n</div>\n", styles: [":host{display:block;width:100%;box-sizing:border-box}.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-static{display:flex;gap:1em;align-items:center;flex:1;flex-wrap:wrap;min-width:0}.menu-toggle{flex-shrink:0;margin-left:auto}cat-menu-dropdown{position:absolute;top:calc(100% - .75rem);right:.75rem;z-index:2}@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)}cat-menu-dropdown{right:.5rem;left:.5rem}}@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: Button, selector: "cat-button", inputs: ["variant", "size", "disabled", "type", "iconLeft", "iconCenter", "iconRight", "customClass"], outputs: ["clicked"] }, { kind: "component", type: MenuDropdown, selector: "cat-menu-dropdown", inputs: ["items"] }] });
1127
871
  }
1128
872
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Menu, decorators: [{
1129
873
  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: [{
874
+ args: [{ selector: 'cat-menu', imports: [Button, MenuDropdown], template: "<div class=\"menu-wrapper\">\n <div class=\"menu\">\n\n <!-- Contenido est\u00E1tico: todo lo que NO sea cat-menu-panel -->\n <div class=\"menu-static\">\n <ng-content select=\":not(cat-menu-panel)\"></ng-content>\n </div>\n\n <!-- Host de los cat-menu-panel: visible en estado inicial, oculto cuando el dropdown est\u00E1 activo -->\n <div #panelsHost class=\"menu-panels-host\" [style.display]=\"isDropdownActive ? 'none' : 'contents'\">\n <ng-content select=\"cat-menu-panel\"></ng-content>\n </div>\n\n <!-- Bot\u00F3n chevron: visible cuando isDropdownActive es true -->\n @if (isDropdownActive) {\n <div class=\"menu-toggle\">\n <cat-button variant=\"secondary\" (clicked)=\"togglePanel()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" style=\"width: 20px; height: 20px;\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m19.5 8.25-7.5 7.5-7.5-7.5\" />\n </svg>\n </cat-button>\n </div>\n }\n\n <!-- Dropdown: siempre en el DOM cuando isDropdownActive, visible solo cuando isPanelOpen -->\n @if (isDropdownActive) {\n <cat-menu-dropdown\n #dropdownRef\n [style.display]=\"isPanelOpen ? 'block' : 'none'\"\n ></cat-menu-dropdown>\n }\n\n </div>\n</div>\n", styles: [":host{display:block;width:100%;box-sizing:border-box}.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-static{display:flex;gap:1em;align-items:center;flex:1;flex-wrap:wrap;min-width:0}.menu-toggle{flex-shrink:0;margin-left:auto}cat-menu-dropdown{position:absolute;top:calc(100% - .75rem);right:.75rem;z-index:2}@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)}cat-menu-dropdown{right:.5rem;left:.5rem}}@media (min-width: 601px){:host{max-width:100%}.menu-wrapper{max-width:100%}.menu{max-width:calc(100% - 1.5rem)}}\n"] }]
875
+ }], propDecorators: { panels: [{
876
+ type: ContentChildren,
877
+ args: [MenuPanel]
878
+ }], panelsHost: [{
1135
879
  type: ViewChild,
1136
- args: ['menuContent', { static: false }]
1137
- }], dropdown: [{
880
+ args: ['panelsHost']
881
+ }], dropdownRef: [{
1138
882
  type: ViewChild,
1139
- args: ['dropdown', { static: false }]
883
+ args: ['dropdownRef']
1140
884
  }] } });
1141
885
 
1142
886
  class Theming {
@@ -1270,332 +1014,102 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
1270
1014
  }]
1271
1015
  }] });
1272
1016
 
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`;
1017
+ class DynamicBackgroundService {
1018
+ setImages$ = new Subject();
1019
+ setBackgroundImage$ = new Subject();
1020
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DynamicBackgroundService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1021
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DynamicBackgroundService });
1022
+ }
1023
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DynamicBackgroundService, decorators: [{
1024
+ type: Injectable
1025
+ }] });
1026
+
1027
+ class DynamicBackground {
1028
+ el;
1029
+ renderer;
1030
+ bgService;
1031
+ showControls = input(true, ...(ngDevMode ? [{ debugName: "showControls" }] : []));
1032
+ images = input(...(ngDevMode ? [undefined, { debugName: "images" }] : []));
1033
+ /** Label shown in the navigation controls next to the image counter. */
1034
+ controlsLabel = input('Background Image', ...(ngDevMode ? [{ debugName: "controlsLabel" }] : []));
1035
+ /** Slideshow interval in milliseconds. 0 = disabled. */
1036
+ slideshowInterval = input(0, ...(ngDevMode ? [{ debugName: "slideshowInterval" }] : []));
1037
+ backgroundElement;
1038
+ resolvedImages = [];
1039
+ imageIndex = 0;
1040
+ slideshowTimer;
1041
+ subscriptions = new Subscription();
1042
+ constructor(el, renderer, bgService) {
1043
+ this.el = el;
1044
+ this.renderer = renderer;
1045
+ this.bgService = bgService;
1046
+ effect(() => {
1047
+ this.startSlideshow(this.slideshowInterval());
1048
+ });
1049
+ if (this.bgService) {
1050
+ this.subscriptions.add(this.bgService.setImages$.subscribe((urls) => {
1051
+ this.resolvedImages = urls;
1052
+ this.applyBackground();
1053
+ this.startSlideshow(this.slideshowInterval());
1054
+ }));
1055
+ this.subscriptions.add(this.bgService.setBackgroundImage$.subscribe((index) => {
1056
+ this.imageIndex = Math.max(0, Math.min(index, this.resolvedImages.length - 1));
1057
+ this.applyBackground();
1058
+ }));
1059
+ }
1060
+ }
1061
+ ngAfterViewInit() {
1062
+ this.backgroundElement = this.el.nativeElement.querySelector('.generalBackground');
1063
+ this.resolvedImages = this.images() ?? [];
1064
+ this.applyBackground();
1065
+ this.startSlideshow(this.slideshowInterval());
1066
+ }
1067
+ ngOnDestroy() {
1068
+ this.subscriptions.unsubscribe();
1069
+ this.stopSlideshow();
1070
+ }
1071
+ applyBackground() {
1072
+ if (!this.backgroundElement || !this.resolvedImages.length)
1073
+ return;
1074
+ this.renderer.setAttribute(this.backgroundElement, 'style', `background-image: url(${this.resolvedImages[this.imageIndex]});`);
1075
+ }
1076
+ startSlideshow(interval) {
1077
+ this.stopSlideshow();
1078
+ if (interval <= 0 || !this.resolvedImages.length)
1079
+ return;
1080
+ this.slideshowTimer = setInterval(() => this.changeImageIndex(true), interval);
1081
+ }
1082
+ stopSlideshow() {
1083
+ if (this.slideshowTimer) {
1084
+ clearInterval(this.slideshowTimer);
1085
+ this.slideshowTimer = undefined;
1086
+ }
1087
+ }
1088
+ changeImageIndex(increment) {
1089
+ if (!this.resolvedImages.length)
1090
+ return;
1091
+ this.imageIndex += increment ? 1 : -1;
1092
+ if (this.imageIndex < 0)
1093
+ this.imageIndex = this.resolvedImages.length - 1;
1094
+ if (this.imageIndex >= this.resolvedImages.length)
1095
+ this.imageIndex = 0;
1096
+ this.applyBackground();
1097
+ }
1098
+ get currentIndex() {
1099
+ return this.imageIndex;
1100
+ }
1101
+ get totalImages() {
1102
+ return this.resolvedImages.length;
1103
+ }
1104
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DynamicBackground, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: DynamicBackgroundService, optional: true }], target: i0.ɵɵFactoryTarget.Component });
1105
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DynamicBackground, isStandalone: true, selector: "cat-dynamic-background", inputs: { showControls: { classPropertyName: "showControls", publicName: "showControls", isSignal: true, isRequired: false, transformFunction: null }, images: { classPropertyName: "images", publicName: "images", isSignal: true, isRequired: false, transformFunction: null }, controlsLabel: { classPropertyName: "controlsLabel", publicName: "controlsLabel", isSignal: true, isRequired: false, transformFunction: null }, slideshowInterval: { classPropertyName: "slideshowInterval", publicName: "slideshowInterval", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-template #chevronRight>\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-6\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m8.25 4.5 7.5 7.5-7.5 7.5\" />\n</svg>\n</ng-template>\n<ng-template #chevronLeft>\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-6\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15.75 19.5 8.25 12l7.5-7.5\" />\n</svg>\n</ng-template>\n\n<section class=\"generalBackground\"></section>\n\n@if (showControls()) {\n<div class=\"multimedia-themes-controler\">\n <div>\n <cat-button\n variant=\"secondary\"\n (clicked)=\"changeImageIndex(false)\"\n [iconCenter]=\"chevronLeft\"\n >\n </cat-button>\n </div>\n <div>\n <p>\n <b>{{ controlsLabel() }} {{ currentIndex + 1 }} / {{ totalImages }}</b>\n </p>\n </div>\n <div>\n <cat-button\n variant=\"secondary\"\n (clicked)=\"changeImageIndex(true)\"\n [iconCenter]=\"chevronRight\"\n ></cat-button>\n </div>\n</div>\n}\n", styles: [".generalBackground{position:fixed;top:0;left:0;z-index:-1;background-size:cover;background-position:center 70%;background-repeat:no-repeat;min-height:100vh;height:100%;width:100%;padding-top:7em}.multimedia-themes-controler{position:fixed;z-index:10;bottom:1em;left:1em;width:auto;max-width:33%;min-width:23%;height:auto;min-height:3em;background-color:var(--neutral-color-0);border-radius:16px;display:flex;justify-content:space-between;align-items:center;gap:1em}.multimedia-themes-controler>div{width:auto;height:100%}@media screen and (orientation: portrait) and (max-width: 600px){.multimedia-themes-controler{max-width:100%;width:80%;left:50%;transform:translate(-50%)}}\n"], dependencies: [{ kind: "component", type: Button, selector: "cat-button", inputs: ["variant", "size", "disabled", "type", "iconLeft", "iconCenter", "iconRight", "customClass"], outputs: ["clicked"] }] });
1598
1106
  }
1107
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DynamicBackground, decorators: [{
1108
+ type: Component,
1109
+ args: [{ selector: 'cat-dynamic-background', imports: [Button], template: "<ng-template #chevronRight>\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-6\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m8.25 4.5 7.5 7.5-7.5 7.5\" />\n</svg>\n</ng-template>\n<ng-template #chevronLeft>\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-6\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15.75 19.5 8.25 12l7.5-7.5\" />\n</svg>\n</ng-template>\n\n<section class=\"generalBackground\"></section>\n\n@if (showControls()) {\n<div class=\"multimedia-themes-controler\">\n <div>\n <cat-button\n variant=\"secondary\"\n (clicked)=\"changeImageIndex(false)\"\n [iconCenter]=\"chevronLeft\"\n >\n </cat-button>\n </div>\n <div>\n <p>\n <b>{{ controlsLabel() }} {{ currentIndex + 1 }} / {{ totalImages }}</b>\n </p>\n </div>\n <div>\n <cat-button\n variant=\"secondary\"\n (clicked)=\"changeImageIndex(true)\"\n [iconCenter]=\"chevronRight\"\n ></cat-button>\n </div>\n</div>\n}\n", styles: [".generalBackground{position:fixed;top:0;left:0;z-index:-1;background-size:cover;background-position:center 70%;background-repeat:no-repeat;min-height:100vh;height:100%;width:100%;padding-top:7em}.multimedia-themes-controler{position:fixed;z-index:10;bottom:1em;left:1em;width:auto;max-width:33%;min-width:23%;height:auto;min-height:3em;background-color:var(--neutral-color-0);border-radius:16px;display:flex;justify-content:space-between;align-items:center;gap:1em}.multimedia-themes-controler>div{width:auto;height:100%}@media screen and (orientation: portrait) and (max-width: 600px){.multimedia-themes-controler{max-width:100%;width:80%;left:50%;transform:translate(-50%)}}\n"] }]
1110
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: DynamicBackgroundService, decorators: [{
1111
+ type: Optional
1112
+ }] }], propDecorators: { showControls: [{ type: i0.Input, args: [{ isSignal: true, alias: "showControls", required: false }] }], images: [{ type: i0.Input, args: [{ isSignal: true, alias: "images", required: false }] }], controlsLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlsLabel", required: false }] }], slideshowInterval: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideshowInterval", required: false }] }] } });
1599
1113
 
1600
1114
  /*
1601
1115
  * Public API Surface of catarina
@@ -1606,5 +1120,5 @@ function getIconPath(name) {
1606
1120
  * Generated bundle index. Do not edit.
1607
1121
  */
1608
1122
 
1609
- export { Accordion, AccordionGroup, Button, Card, CatInput, ColorInput, Dialog, Drag, Drawer, ICON_BASE_PATH, ICON_PROVIDER, Icon, Menu, SelectInput, Theming, getIconPath, iconList };
1123
+ export { Accordion, AccordionGroup, Button, Card, CatInput, ColorInput, Dialog, Drag, Drawer, DynamicBackground, DynamicBackgroundService, Icon, Menu, MenuDropdown, MenuPanel, SelectInput, Theming };
1610
1124
  //# sourceMappingURL=catarina-ds-angular.mjs.map