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