@catarina-ds/angular 0.1.1 → 0.1.3

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,7 +584,8 @@ class Dialog {
774
584
  // Referencia al overlay creado
775
585
  overlayRef;
776
586
  variant = 'surface';
777
- size = { width: '300px', height: '200px' };
587
+ width = '300px';
588
+ height = '200px';
778
589
  customClass = '';
779
590
  closs = new EventEmitter();
780
591
  // Referencia al template que contiene el ng-content
@@ -828,14 +639,16 @@ class Dialog {
828
639
  this.closeDialog();
829
640
  }
830
641
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Dialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
831
- 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\n [style]=\"`height: ${size.height} !important; width: ${size.width} !important;`\"\n CDrag\n [class]=\"dialogClasses\"\n >\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]" }] });
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]" }] });
832
643
  }
833
644
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Dialog, decorators: [{
834
645
  type: Component,
835
- args: [{ selector: 'cat-dialog', imports: [Drag], template: "<!-- Template que se renderiza dentro del overlay del CDK -->\n<ng-template #dialogTemplate>\n <section\n [style]=\"`height: ${size.height} !important; width: ${size.width} !important;`\"\n CDrag\n [class]=\"dialogClasses\"\n >\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"] }]
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"] }]
836
647
  }], propDecorators: { variant: [{
837
648
  type: Input
838
- }], size: [{
649
+ }], width: [{
650
+ type: Input
651
+ }], height: [{
839
652
  type: Input
840
653
  }], customClass: [{
841
654
  type: Input
@@ -924,11 +737,11 @@ class Drawer {
924
737
  this.closeDrawer();
925
738
  }
926
739
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Drawer, deps: [], target: i0.ɵɵFactoryTarget.Component });
927
- 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"] }] });
928
741
  }
929
742
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Drawer, decorators: [{
930
743
  type: Component,
931
- 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"] }]
932
745
  }], propDecorators: { side: [{
933
746
  type: Input
934
747
  }], variant: [{
@@ -942,202 +755,133 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
942
755
  args: ['drawerTemplate', { static: true }]
943
756
  }] } });
944
757
 
945
- class Menu {
946
- /* @Input() variant: 'surface' | 'elevated' | 'outlined' = 'surface';
947
- @Input() customClass: string = '';
948
-
949
- @HostBinding('attr.data-menu-class') get dataCustomClass() {
950
- return this.customClass;
951
- }
952
-
953
- get menuClasses(): string {
954
- return `${this.variant} ${this.customClass}`;
955
- } */
956
- menuContainer;
957
- menuContent;
958
- dropdown;
959
- platformId = inject(PLATFORM_ID);
960
- resizeObserver;
961
- mutationObserver;
962
- showMoreButton = signal(false, ...(ngDevMode ? [{ debugName: "showMoreButton" }] : []));
963
- isDropdownOpen = signal(false, ...(ngDevMode ? [{ debugName: "isDropdownOpen" }] : []));
964
- overflowItems = signal([], ...(ngDevMode ? [{ debugName: "overflowItems" }] : []));
965
- ngAfterViewInit() {
966
- if (!isPlatformBrowser(this.platformId))
967
- return;
968
- setTimeout(() => {
969
- this.checkOverflow();
970
- this.setupObservers();
971
- }, 0);
972
- }
973
- ngOnDestroy() {
974
- this.resizeObserver?.disconnect();
975
- this.mutationObserver?.disconnect();
976
- if (isPlatformBrowser(this.platformId)) {
977
- document.removeEventListener('click', this.handleOutsideClick);
978
- }
979
- }
980
- setupObservers() {
981
- if (!isPlatformBrowser(this.platformId))
982
- return;
983
- this.resizeObserver = new ResizeObserver(() => {
984
- 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');
985
778
  });
986
- this.resizeObserver.observe(this.menuContent.nativeElement);
987
- document.addEventListener('click', this.handleOutsideClick);
988
779
  }
989
- handleOutsideClick = (event) => {
990
- if (!this.isDropdownOpen())
991
- return;
992
- const target = event.target;
993
- const clickedInside = this.menuContainer.nativeElement.contains(target) ||
994
- this.dropdown?.nativeElement.contains(target);
995
- if (!clickedInside) {
996
- this.isDropdownOpen.set(false);
997
- }
998
- };
999
- checkOverflow() {
1000
- // Si el dropdown está abierto, no recalcula el overflow
1001
- if (this.isDropdownOpen()) {
1002
- const overflowItems = this.overflowItems();
1003
- if (overflowItems.length > 0) {
1004
- this.showMoreButton.set(true);
1005
- setTimeout(() => {
1006
- //this.waitForDropdownAndUpdate();
1007
- this.updateDropdownContent();
1008
- }, 0);
1009
- }
1010
- return;
1011
- }
1012
- const container = this.menuContent.nativeElement;
1013
- // Restaura todos los elementos que puedan estar en el dropdown
1014
- this.restoreOverflowItems();
1015
- const items = Array.from(container.children);
1016
- if (items.length === 0) {
1017
- this.showMoreButton.set(false);
1018
- this.overflowItems.set([]);
1019
- return;
1020
- }
1021
- const menuItems = items.filter(item => !item.classList.contains('more-button'));
1022
- if (menuItems.length === 0) {
1023
- this.showMoreButton.set(false);
1024
- this.overflowItems.set([]);
1025
- return;
1026
- }
1027
- // Restaura todos los elementos a su estado visible antes de calcular
1028
- menuItems.forEach(item => {
1029
- item.style.display = '';
1030
- });
1031
- // Fuerza un reflow para obtener posiciones correctas
1032
- container.offsetHeight;
1033
- // Detecta elementos en la primera fila vs elementos en filas adicionales
1034
- const firstItemTop = menuItems[0]?.getBoundingClientRect().top;
1035
- const firstRowItems = [];
1036
- const overflowItems = [];
1037
- menuItems.forEach(item => {
1038
- const itemTop = item.getBoundingClientRect().top;
1039
- // Usa tolerancia de 1px para manejar diferencias de redondeo
1040
- if (Math.abs(itemTop - firstItemTop) <= 1) {
1041
- firstRowItems.push(item);
1042
- }
1043
- else {
1044
- overflowItems.push(item);
1045
- }
1046
- });
1047
- // Si hay elementos en overflow, muestra el botón More y oculta los elementos overflow
1048
- const needsMoreButton = overflowItems.length > 0;
1049
- this.showMoreButton.set(needsMoreButton);
1050
- // Oculta elementos que están en la segunda fila o más
1051
- overflowItems.forEach(item => {
1052
- item.style.display = 'none';
1053
- });
1054
- // Mantiene visibles solo los elementos de la primera fila
1055
- firstRowItems.forEach(item => {
1056
- item.style.display = '';
1057
- });
1058
- if (needsMoreButton) {
1059
- this.overflowItems.set(overflowItems);
1060
- }
1061
- else {
1062
- 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();
1063
826
  }
1064
827
  }
1065
- updateDropdownContent() {
1066
- const menuWrapper = this.menuContainer.nativeElement.closest('.menu-wrapper');
1067
- if (!menuWrapper) {
1068
- return;
1069
- }
1070
- const dropdown = menuWrapper.querySelector('.dropdown');
1071
- if (!dropdown) {
1072
- return;
1073
- }
1074
- const dropdownContent = dropdown.querySelector('.dropdown-content');
1075
- if (!dropdownContent) {
1076
- return;
828
+ // Llamado por el consumidor via referencia de template
829
+ toggleContent() {
830
+ this.isDropdownActive = !this.isDropdownActive;
831
+ if (!this.isDropdownActive) {
832
+ this.restorePanels();
1077
833
  }
1078
- // Limpia el contenido previo del dropdown (por si hay algún elemento)
1079
- this.restoreOverflowItems();
1080
- const overflowItems = this.overflowItems();
1081
- if (overflowItems.length === 0) {
1082
- return;
834
+ this.cdr.markForCheck();
835
+ }
836
+ // Llamado por el botón chevron
837
+ togglePanel() {
838
+ this.isPanelOpen = !this.isPanelOpen;
839
+ if (this.isPanelOpen) {
840
+ // Marca el move pendiente — se ejecutará cuando dropdownRef esté disponible
841
+ this.pendingPanelMove = true;
1083
842
  }
1084
- //const menuContent = this.menuContent.nativeElement; //No se usa porque los elementos ya están en el dropdown
1085
- overflowItems.forEach(item => {
1086
- // Mueve el elemento real al dropdown
1087
- // El elemento ya está oculto (display: none), así que lo hace visible y lo mueve al dropdown
1088
- item.style.display = '';
1089
- item.style.visibility = 'visible';
1090
- // Mueve el elemento al dropdown
1091
- dropdownContent.appendChild(item);
1092
- });
1093
843
  }
1094
- // Esta función sirve para mover los elementos del dropdown al menu-content
1095
- // NO los elimina del signal overflowItems, ni del DOM, (por lo que genera sobrecarga de memoria)
1096
- restoreOverflowItems() {
1097
- const overflowItems = this.overflowItems();
1098
- const menuContent = this.menuContent.nativeElement;
1099
- overflowItems.forEach(item => {
1100
- // Si el elemento está en el dropdown, lo mueve de vuelta al menu-content
1101
- const dropdownContent = item.closest('.dropdown-content');
1102
- if (dropdownContent && item.parentElement === dropdownContent) {
1103
- // Oculta el elemento y lo mueve de vuelta al menu-content
1104
- item.style.display = 'none';
1105
- menuContent.appendChild(item);
1106
- }
844
+ executePanelMove() {
845
+ if (!this.dropdownRef)
846
+ return;
847
+ const container = this.dropdownRef.panelContainer.nativeElement;
848
+ const items = this.panels.map((panel) => ({
849
+ label: panel.label,
850
+ element: panel.elementRef.nativeElement,
851
+ }));
852
+ items.forEach((item, i) => {
853
+ item.element.style.display = i === 0 ? '' : 'none';
854
+ container.appendChild(item.element);
1107
855
  });
1108
- }
1109
- toggleDropdown() {
1110
- const newState = !this.isDropdownOpen();
1111
- if (!newState) {
1112
- // Si se está cerrando, restaura los elementos a su posición original
1113
- this.restoreOverflowItems();
1114
- }
1115
- this.isDropdownOpen.set(newState);
1116
- if (newState) {
1117
- // Recalcula el overflow antes de abrir el dropdown
1118
- setTimeout(() => {
1119
- this.checkOverflow();
1120
- // Esperar a que el dropdown esté en el DOM antes de actualizar
1121
- //this.waitForDropdownAndUpdate();
1122
- this.updateDropdownContent();
1123
- }, 0);
856
+ this.dropdownRef.items = items;
857
+ this.dropdownRef.activeIndex = 0;
858
+ this.cdr.detectChanges();
859
+ }
860
+ restorePanels() {
861
+ this.isPanelOpen = false;
862
+ if (this.panelsHost) {
863
+ this.panels.forEach((panel) => {
864
+ const el = panel.elementRef.nativeElement;
865
+ el.style.display = '';
866
+ this.panelsHost.nativeElement.appendChild(el);
867
+ });
1124
868
  }
1125
869
  }
1126
870
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Menu, deps: [], target: i0.ɵɵFactoryTarget.Component });
1127
- 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"] }] });
871
+ 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 <!-- 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\n #panelsHost\n class=\"menu-panels-host\"\n [style.display]=\"isDropdownActive ? 'none' : 'contents'\"\n >\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 @if (isPanelOpen) {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n style=\"width: 20px; height: 20px\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m4.5 15.75 7.5-7.5 7.5 7.5\" />\n </svg>\n } @else {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n style=\"width: 20px; height: 20px\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m19.5 8.25-7.5 7.5-7.5-7.5\" />\n </svg>\n }\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 </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"] }] });
1128
872
  }
1129
873
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Menu, decorators: [{
1130
874
  type: Component,
1131
- 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"] }]
1132
- }], propDecorators: { menuContainer: [{
1133
- type: ViewChild,
1134
- args: ['menuContainer', { static: false }]
1135
- }], menuContent: [{
875
+ args: [{ selector: 'cat-menu', imports: [Button, MenuDropdown], template: "<div class=\"menu-wrapper\">\n <div class=\"menu\">\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\n #panelsHost\n class=\"menu-panels-host\"\n [style.display]=\"isDropdownActive ? 'none' : 'contents'\"\n >\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 @if (isPanelOpen) {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n style=\"width: 20px; height: 20px\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m4.5 15.75 7.5-7.5 7.5 7.5\" />\n </svg>\n } @else {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n style=\"width: 20px; height: 20px\"\n >\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m19.5 8.25-7.5 7.5-7.5-7.5\" />\n </svg>\n }\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 </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"] }]
876
+ }], propDecorators: { panels: [{
877
+ type: ContentChildren,
878
+ args: [MenuPanel]
879
+ }], panelsHost: [{
1136
880
  type: ViewChild,
1137
- args: ['menuContent', { static: false }]
1138
- }], dropdown: [{
881
+ args: ['panelsHost']
882
+ }], dropdownRef: [{
1139
883
  type: ViewChild,
1140
- args: ['dropdown', { static: false }]
884
+ args: ['dropdownRef']
1141
885
  }] } });
1142
886
 
1143
887
  class Theming {
@@ -1271,332 +1015,102 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
1271
1015
  }]
1272
1016
  }] });
1273
1017
 
1274
- const ICON_BASE_PATH = 'safirial-icons';
1275
- const iconList = [
1276
- 'academic-cap',
1277
- 'adjustments-horizontal',
1278
- 'adjustments-vertical',
1279
- 'archive-box',
1280
- 'archive-box-arrow-down',
1281
- 'archive-box-x-mark',
1282
- 'arrow-down',
1283
- 'arrow-down-circle',
1284
- 'arrow-down-left',
1285
- 'arrow-down-on-square',
1286
- 'arrow-down-on-square-stack',
1287
- 'arrow-down-right',
1288
- 'arrow-down-tray',
1289
- 'arrow-left',
1290
- 'arrow-left-circle',
1291
- 'arrow-left-end-on-rectangle',
1292
- 'arrow-left-start-on-rectangle',
1293
- 'arrow-long-down',
1294
- 'arrow-long-left',
1295
- 'arrow-long-right',
1296
- 'arrow-long-up',
1297
- 'arrow-path',
1298
- 'arrow-path-rounded-square',
1299
- 'arrow-right',
1300
- 'arrow-right-circle',
1301
- 'arrow-right-end-on-rectangle',
1302
- 'arrow-right-start-on-rectangle',
1303
- 'arrow-top-right-on-square',
1304
- 'arrow-trending-down',
1305
- 'arrow-trending-up',
1306
- 'arrow-turn-down-left',
1307
- 'arrow-turn-down-right',
1308
- 'arrow-turn-left-down',
1309
- 'arrow-turn-left-up',
1310
- 'arrow-turn-right-down',
1311
- 'arrow-turn-right-up',
1312
- 'arrow-turn-up-left',
1313
- 'arrow-turn-up-right',
1314
- 'arrow-up',
1315
- 'arrow-up-circle',
1316
- 'arrow-up-left',
1317
- 'arrow-up-on-square',
1318
- 'arrow-up-on-square-stack',
1319
- 'arrow-up-right',
1320
- 'arrow-up-tray',
1321
- 'arrow-uturn-down',
1322
- 'arrow-uturn-left',
1323
- 'arrow-uturn-right',
1324
- 'arrow-uturn-up',
1325
- 'arrows-pointing-in',
1326
- 'arrows-pointing-out',
1327
- 'arrows-right-left',
1328
- 'arrows-up-down',
1329
- 'at-symbol',
1330
- 'backspace',
1331
- 'backward',
1332
- 'banknotes',
1333
- 'bars-2',
1334
- 'bars-3',
1335
- 'bars-3-bottom-left',
1336
- 'bars-3-bottom-right',
1337
- 'bars-3-center-left',
1338
- 'bars-4',
1339
- 'bars-arrow-down',
1340
- 'bars-arrow-up',
1341
- 'battery-0',
1342
- 'battery-100',
1343
- 'battery-50',
1344
- 'beaker',
1345
- 'bell',
1346
- 'bell-alert',
1347
- 'bell-slash',
1348
- 'bell-snooze',
1349
- 'bold',
1350
- 'bolt',
1351
- 'bolt-slash',
1352
- 'book-open',
1353
- 'bookmark',
1354
- 'bookmark-slash',
1355
- 'bookmark-square',
1356
- 'briefcase',
1357
- 'bug-ant',
1358
- 'building-library',
1359
- 'building-office',
1360
- 'building-office-2',
1361
- 'building-storefront',
1362
- 'cake',
1363
- 'calculator',
1364
- 'calendar',
1365
- 'calendar-date-range',
1366
- 'calendar-days',
1367
- 'camera',
1368
- 'chart-bar',
1369
- 'chart-bar-square',
1370
- 'chart-pie',
1371
- 'chat-bubble-bottom-center',
1372
- 'chat-bubble-bottom-center-text',
1373
- 'chat-bubble-left',
1374
- 'chat-bubble-left-ellipsis',
1375
- 'chat-bubble-left-right',
1376
- 'chat-bubble-oval-left',
1377
- 'chat-bubble-oval-left-ellipsis',
1378
- 'check',
1379
- 'check-badge',
1380
- 'check-circle',
1381
- 'chevron-double-down',
1382
- 'chevron-double-left',
1383
- 'chevron-double-right',
1384
- 'chevron-double-up',
1385
- 'chevron-down',
1386
- 'chevron-left',
1387
- 'chevron-right',
1388
- 'chevron-up',
1389
- 'chevron-up-down',
1390
- 'circle-stack',
1391
- 'clipboard',
1392
- 'clipboard-document',
1393
- 'clipboard-document-check',
1394
- 'clipboard-document-list',
1395
- 'clock',
1396
- 'cloud',
1397
- 'cloud-arrow-down',
1398
- 'cloud-arrow-up',
1399
- 'code-bracket',
1400
- 'code-bracket-square',
1401
- 'cog',
1402
- 'cog-6-tooth',
1403
- 'cog-8-tooth',
1404
- 'command-line',
1405
- 'computer-desktop',
1406
- 'cpu-chip',
1407
- 'credit-card',
1408
- 'cube',
1409
- 'cube-transparent',
1410
- 'currency-bangladeshi',
1411
- 'currency-dollar',
1412
- 'currency-euro',
1413
- 'currency-pound',
1414
- 'currency-rupee',
1415
- 'currency-yen',
1416
- 'cursor-arrow-rays',
1417
- 'cursor-arrow-ripple',
1418
- 'device-phone-mobile',
1419
- 'device-tablet',
1420
- 'divide',
1421
- 'document',
1422
- 'document-arrow-down',
1423
- 'document-arrow-up',
1424
- 'document-chart-bar',
1425
- 'document-check',
1426
- 'document-currency-bangladeshi',
1427
- 'document-currency-dollar',
1428
- 'document-currency-euro',
1429
- 'document-currency-pound',
1430
- 'document-currency-rupee',
1431
- 'document-currency-yen',
1432
- 'document-duplicate',
1433
- 'document-magnifying-glass',
1434
- 'document-minus',
1435
- 'document-plus',
1436
- 'document-text',
1437
- 'ellipsis-horizontal',
1438
- 'ellipsis-horizontal-circle',
1439
- 'ellipsis-vertical',
1440
- 'email',
1441
- 'envelope',
1442
- 'envelope-open',
1443
- 'equals',
1444
- 'exclamation-circle',
1445
- 'exclamation-triangle',
1446
- 'eye',
1447
- 'eye-dropper',
1448
- 'eye-slash',
1449
- 'face-frown',
1450
- 'face-smile',
1451
- 'film',
1452
- 'finger-print',
1453
- 'fire',
1454
- 'flag',
1455
- 'folder',
1456
- 'folder-arrow-down',
1457
- 'folder-minus',
1458
- 'folder-open',
1459
- 'folder-plus',
1460
- 'forward',
1461
- 'funnel',
1462
- 'gif',
1463
- 'gift',
1464
- 'gift-top',
1465
- 'github',
1466
- 'globe-alt',
1467
- 'globe-americas',
1468
- 'globe-asia-australia',
1469
- 'globe-europe-africa',
1470
- 'h1',
1471
- 'h2',
1472
- 'h3',
1473
- 'hand-raised',
1474
- 'hand-thumb-down',
1475
- 'hand-thumb-up',
1476
- 'hashtag',
1477
- 'heart',
1478
- 'home',
1479
- 'home-modern',
1480
- 'identification',
1481
- 'inbox',
1482
- 'inbox-arrow-down',
1483
- 'inbox-stack',
1484
- 'information-circle',
1485
- 'italic',
1486
- 'key',
1487
- 'language',
1488
- 'lifebuoy',
1489
- 'light-bulb',
1490
- 'link',
1491
- 'link-slash',
1492
- 'linkedin',
1493
- 'list-bullet',
1494
- 'lock-closed',
1495
- 'lock-open',
1496
- 'magnifying-glass',
1497
- 'magnifying-glass-circle',
1498
- 'magnifying-glass-minus',
1499
- 'magnifying-glass-plus',
1500
- 'map',
1501
- 'map-pin',
1502
- 'megaphone',
1503
- 'microphone',
1504
- 'minus',
1505
- 'minus-circle',
1506
- 'moon',
1507
- 'musical-note',
1508
- 'newspaper',
1509
- 'no-symbol',
1510
- 'numbered-list',
1511
- 'paint-brush',
1512
- 'palette',
1513
- 'paper-airplane',
1514
- 'paper-clip',
1515
- 'pause',
1516
- 'pause-circle',
1517
- 'pencil',
1518
- 'pencil-square',
1519
- 'percent-badge',
1520
- 'phone',
1521
- 'phone-arrow-down-left',
1522
- 'phone-arrow-up-right',
1523
- 'phone-x-mark',
1524
- 'photo',
1525
- 'play',
1526
- 'play-circle',
1527
- 'play-pause',
1528
- 'plus',
1529
- 'plus-circle',
1530
- 'power',
1531
- 'presentation-chart-bar',
1532
- 'presentation-chart-line',
1533
- 'printer',
1534
- 'puzzle-piece',
1535
- 'qr-code',
1536
- 'question-mark-circle',
1537
- 'queue-list',
1538
- 'radio',
1539
- 'receipt-percent',
1540
- 'receipt-refund',
1541
- 'rectangle-group',
1542
- 'rectangle-stack',
1543
- 'rocket-launch',
1544
- 'rss',
1545
- 'scale',
1546
- 'scissors',
1547
- 'server',
1548
- 'server-stack',
1549
- 'share',
1550
- 'shield-check',
1551
- 'shield-exclamation',
1552
- 'shopping-bag',
1553
- 'shopping-cart',
1554
- 'signal',
1555
- 'signal-slash',
1556
- 'slash',
1557
- 'sparkles',
1558
- 'speaker-wave',
1559
- 'speaker-x-mark',
1560
- 'square-2-stack',
1561
- 'square-3-stack-3d',
1562
- 'squares-2x2',
1563
- 'squares-plus',
1564
- 'star',
1565
- 'stop',
1566
- 'stop-circle',
1567
- 'strikethrough',
1568
- 'sun',
1569
- 'swatch',
1570
- 'table-cells',
1571
- 'tag',
1572
- 'ticket',
1573
- 'trash',
1574
- 'trophy',
1575
- 'truck',
1576
- 'tv',
1577
- 'underline',
1578
- 'user',
1579
- 'user-circle',
1580
- 'user-group',
1581
- 'user-minus',
1582
- 'user-plus',
1583
- 'users',
1584
- 'variable',
1585
- 'video-camera',
1586
- 'video-camera-slash',
1587
- 'view-columns',
1588
- 'viewfinder-circle',
1589
- 'wallet',
1590
- 'wifi',
1591
- 'window',
1592
- 'wrench',
1593
- 'wrench-screwdriver',
1594
- 'x-circle',
1595
- 'x-mark',
1596
- ];
1597
- function getIconPath(name) {
1598
- return `${ICON_BASE_PATH}/${name}.svg`;
1018
+ class DynamicBackgroundService {
1019
+ setImages$ = new Subject();
1020
+ setBackgroundImage$ = new Subject();
1021
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DynamicBackgroundService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1022
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DynamicBackgroundService });
1599
1023
  }
1024
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DynamicBackgroundService, decorators: [{
1025
+ type: Injectable
1026
+ }] });
1027
+
1028
+ class DynamicBackground {
1029
+ el;
1030
+ renderer;
1031
+ bgService;
1032
+ showControls = input(true, ...(ngDevMode ? [{ debugName: "showControls" }] : []));
1033
+ images = input(...(ngDevMode ? [undefined, { debugName: "images" }] : []));
1034
+ /** Label shown in the navigation controls next to the image counter. */
1035
+ controlsLabel = input('Background Image', ...(ngDevMode ? [{ debugName: "controlsLabel" }] : []));
1036
+ /** Slideshow interval in milliseconds. 0 = disabled. */
1037
+ slideshowInterval = input(0, ...(ngDevMode ? [{ debugName: "slideshowInterval" }] : []));
1038
+ backgroundElement;
1039
+ resolvedImages = [];
1040
+ imageIndex = 0;
1041
+ slideshowTimer;
1042
+ subscriptions = new Subscription();
1043
+ constructor(el, renderer, bgService) {
1044
+ this.el = el;
1045
+ this.renderer = renderer;
1046
+ this.bgService = bgService;
1047
+ effect(() => {
1048
+ this.startSlideshow(this.slideshowInterval());
1049
+ });
1050
+ if (this.bgService) {
1051
+ this.subscriptions.add(this.bgService.setImages$.subscribe((urls) => {
1052
+ this.resolvedImages = urls;
1053
+ this.applyBackground();
1054
+ this.startSlideshow(this.slideshowInterval());
1055
+ }));
1056
+ this.subscriptions.add(this.bgService.setBackgroundImage$.subscribe((index) => {
1057
+ this.imageIndex = Math.max(0, Math.min(index, this.resolvedImages.length - 1));
1058
+ this.applyBackground();
1059
+ }));
1060
+ }
1061
+ }
1062
+ ngAfterViewInit() {
1063
+ this.backgroundElement = this.el.nativeElement.querySelector('.generalBackground');
1064
+ this.resolvedImages = this.images() ?? [];
1065
+ this.applyBackground();
1066
+ this.startSlideshow(this.slideshowInterval());
1067
+ }
1068
+ ngOnDestroy() {
1069
+ this.subscriptions.unsubscribe();
1070
+ this.stopSlideshow();
1071
+ }
1072
+ applyBackground() {
1073
+ if (!this.backgroundElement || !this.resolvedImages.length)
1074
+ return;
1075
+ this.renderer.setAttribute(this.backgroundElement, 'style', `background-image: url(${this.resolvedImages[this.imageIndex]});`);
1076
+ }
1077
+ startSlideshow(interval) {
1078
+ this.stopSlideshow();
1079
+ if (interval <= 0 || !this.resolvedImages.length)
1080
+ return;
1081
+ this.slideshowTimer = setInterval(() => this.changeImageIndex(true), interval);
1082
+ }
1083
+ stopSlideshow() {
1084
+ if (this.slideshowTimer) {
1085
+ clearInterval(this.slideshowTimer);
1086
+ this.slideshowTimer = undefined;
1087
+ }
1088
+ }
1089
+ changeImageIndex(increment) {
1090
+ if (!this.resolvedImages.length)
1091
+ return;
1092
+ this.imageIndex += increment ? 1 : -1;
1093
+ if (this.imageIndex < 0)
1094
+ this.imageIndex = this.resolvedImages.length - 1;
1095
+ if (this.imageIndex >= this.resolvedImages.length)
1096
+ this.imageIndex = 0;
1097
+ this.applyBackground();
1098
+ }
1099
+ get currentIndex() {
1100
+ return this.imageIndex;
1101
+ }
1102
+ get totalImages() {
1103
+ return this.resolvedImages.length;
1104
+ }
1105
+ 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 });
1106
+ 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"] }] });
1107
+ }
1108
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DynamicBackground, decorators: [{
1109
+ type: Component,
1110
+ 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"] }]
1111
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: DynamicBackgroundService, decorators: [{
1112
+ type: Optional
1113
+ }] }], 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 }] }] } });
1600
1114
 
1601
1115
  /*
1602
1116
  * Public API Surface of catarina
@@ -1607,5 +1121,5 @@ function getIconPath(name) {
1607
1121
  * Generated bundle index. Do not edit.
1608
1122
  */
1609
1123
 
1610
- export { Accordion, AccordionGroup, Button, Card, CatInput, ColorInput, Dialog, Drag, Drawer, ICON_BASE_PATH, ICON_PROVIDER, Icon, Menu, SelectInput, Theming, getIconPath, iconList };
1124
+ export { Accordion, AccordionGroup, Button, Card, CatInput, ColorInput, Dialog, Drag, Drawer, DynamicBackground, DynamicBackgroundService, Icon, Menu, MenuDropdown, MenuPanel, SelectInput, Theming };
1611
1125
  //# sourceMappingURL=catarina-ds-angular.mjs.map