catarina 1.0.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 +63 -0
- package/fesm2022/catarina.mjs +998 -0
- package/fesm2022/catarina.mjs.map +1 -0
- package/index.d.ts +235 -0
- package/package.json +23 -0
|
@@ -0,0 +1,998 @@
|
|
|
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, Injectable } from '@angular/core';
|
|
3
|
+
import { DomSanitizer } from '@angular/platform-browser';
|
|
4
|
+
import { isPlatformBrowser, NgClass, NgIf, NgFor } from '@angular/common';
|
|
5
|
+
import { NgControl, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
6
|
+
import { BehaviorSubject } from 'rxjs';
|
|
7
|
+
|
|
8
|
+
const ICON_PROVIDER = new InjectionToken('ICON_PROVIDER', {
|
|
9
|
+
providedIn: 'root',
|
|
10
|
+
factory: () => ({
|
|
11
|
+
// Fallback por defecto si no se configura
|
|
12
|
+
getPath: (name) => `icons/${name}.svg`
|
|
13
|
+
})
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const ICON_NOT_FOUND_SVG = `
|
|
17
|
+
<svg viewBox="0 0 24 24" role="img" xmlns="http://www.w3.org/2000/svg"
|
|
18
|
+
aria-labelledby="placeholderIconTitle" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none">
|
|
19
|
+
<title id="placeholderIconTitle">Icon not found</title>
|
|
20
|
+
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
|
21
|
+
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
|
|
22
|
+
<g id="SVGRepo_iconCarrier">
|
|
23
|
+
<rect width="18" height="18" x="3" y="3"></rect>
|
|
24
|
+
<path stroke-linecap="round" d="M21 21L3 3 21 21zM21 3L3 21 21 3z"></path>
|
|
25
|
+
</g>
|
|
26
|
+
</svg>
|
|
27
|
+
`;
|
|
28
|
+
class Icon {
|
|
29
|
+
sanitizer = inject(DomSanitizer);
|
|
30
|
+
platformId = inject(PLATFORM_ID);
|
|
31
|
+
iconProvider = inject(ICON_PROVIDER);
|
|
32
|
+
abortController;
|
|
33
|
+
svgContent = signal('', ...(ngDevMode ? [{ debugName: "svgContent" }] : []));
|
|
34
|
+
isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
|
|
35
|
+
size = '24px';
|
|
36
|
+
color = 'currentColor';
|
|
37
|
+
ngOnDestroy() {
|
|
38
|
+
this.abortController?.abort();
|
|
39
|
+
}
|
|
40
|
+
// Usar nombre (con provider)
|
|
41
|
+
set name(iconName) {
|
|
42
|
+
if (!iconName)
|
|
43
|
+
return;
|
|
44
|
+
const path = this.iconProvider.getPath(iconName);
|
|
45
|
+
// Cancelar petición anterior si existe
|
|
46
|
+
this.abortController?.abort();
|
|
47
|
+
// Si el path es el fallback por defecto (icons/), no intentes cargarlo
|
|
48
|
+
if (!path || path.startsWith('icons/')) {
|
|
49
|
+
this.showPlaceholder();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this.loadSvg(path);
|
|
53
|
+
}
|
|
54
|
+
// Usar path directo
|
|
55
|
+
set src(path) {
|
|
56
|
+
if (!path)
|
|
57
|
+
return;
|
|
58
|
+
// Cancelar petición anterior si existe
|
|
59
|
+
this.abortController?.abort();
|
|
60
|
+
this.loadSvg(path);
|
|
61
|
+
}
|
|
62
|
+
loadSvg(path) {
|
|
63
|
+
// En SSR, mostrar placeholder inmediatamente
|
|
64
|
+
if (!isPlatformBrowser(this.platformId)) {
|
|
65
|
+
this.showPlaceholder();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Limpiar contenido y mostrar estado de carga
|
|
69
|
+
this.isLoading.set(true);
|
|
70
|
+
this.svgContent.set('');
|
|
71
|
+
// Crear nuevo AbortController para esta petición
|
|
72
|
+
this.abortController = new AbortController();
|
|
73
|
+
fetch(path, {
|
|
74
|
+
signal: this.abortController.signal,
|
|
75
|
+
mode: 'cors',
|
|
76
|
+
cache: 'default'
|
|
77
|
+
})
|
|
78
|
+
.then(response => {
|
|
79
|
+
if (!response.ok) {
|
|
80
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
81
|
+
}
|
|
82
|
+
return response.text();
|
|
83
|
+
})
|
|
84
|
+
.then(svg => {
|
|
85
|
+
// VALIDACIÓN CRÍTICA: Verificar que sea un SVG
|
|
86
|
+
if (!this.isValidSvg(svg)) {
|
|
87
|
+
console.error(`Invalid SVG received from ${path}. Response is not valid SVG.`);
|
|
88
|
+
this.showPlaceholder();
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const processed = this.processSvg(svg);
|
|
92
|
+
if (processed) {
|
|
93
|
+
this.svgContent.set(this.sanitizer.bypassSecurityTrustHtml(processed));
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
this.showPlaceholder();
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
.catch((error) => {
|
|
100
|
+
// Ignorar errores de abort (son esperados)
|
|
101
|
+
if (error.name === 'AbortError') {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
console.error(`Error loading icon from ${path}:`, error.message);
|
|
105
|
+
this.showPlaceholder();
|
|
106
|
+
})
|
|
107
|
+
.finally(() => {
|
|
108
|
+
this.isLoading.set(false);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
showPlaceholder() {
|
|
112
|
+
this.isLoading.set(false);
|
|
113
|
+
const processed = this.processSvg(ICON_NOT_FOUND_SVG);
|
|
114
|
+
if (processed) {
|
|
115
|
+
this.svgContent.set(this.sanitizer.bypassSecurityTrustHtml(processed));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
isValidSvg(content) {
|
|
119
|
+
// Validaciones estrictas para asegurar que sea SVG
|
|
120
|
+
const trimmed = content.trim();
|
|
121
|
+
// 1. Debe comenzar con <svg (ignorando espacios y declaraciones XML)
|
|
122
|
+
const svgRegex = /^\s*(<\?xml[^>]*>\s*)?<\s*svg\b/i;
|
|
123
|
+
if (!svgRegex.test(trimmed)) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
// 2. Debe terminar con </svg>
|
|
127
|
+
if (!trimmed.includes('</svg>')) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
// 3. No debe contener <html>, <head>, <body> (indicaría HTML completo)
|
|
131
|
+
const htmlTags = ['<html', '<head', '<body', '<!DOCTYPE html'];
|
|
132
|
+
for (const tag of htmlTags) {
|
|
133
|
+
if (trimmed.toLowerCase().includes(tag.toLowerCase())) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// 4. Tamaño razonable para un icono (máximo 100KB)
|
|
138
|
+
if (content.length > 100 * 1024) {
|
|
139
|
+
console.warn('SVG file is too large for an icon:', content.length, 'bytes');
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
processSvg(svg) {
|
|
145
|
+
// Validar antes de procesar
|
|
146
|
+
if (!this.isValidSvg(svg)) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
// En SSR, usar procesamiento simple con regex (no hay DOMParser)
|
|
150
|
+
if (!isPlatformBrowser(this.platformId)) {
|
|
151
|
+
return this.processSvgWithRegex(svg);
|
|
152
|
+
}
|
|
153
|
+
// En Browser, usar DOMParser para procesamiento robusto
|
|
154
|
+
try {
|
|
155
|
+
const parser = new DOMParser();
|
|
156
|
+
const doc = parser.parseFromString(svg, 'image/svg+xml');
|
|
157
|
+
// Verificar que no haya errores de parseo
|
|
158
|
+
const parserError = doc.querySelector('parsererror');
|
|
159
|
+
if (parserError) {
|
|
160
|
+
console.error('SVG parsing error:', parserError.textContent);
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
const svgElement = doc.querySelector('svg');
|
|
164
|
+
if (!svgElement) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
// Verificar que sea realmente un elemento SVG
|
|
168
|
+
if (svgElement.tagName.toLowerCase() !== 'svg') {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
// Modificar solo el elemento <svg> raíz
|
|
172
|
+
svgElement.removeAttribute('width');
|
|
173
|
+
svgElement.removeAttribute('height');
|
|
174
|
+
// Cambiar fill y stroke solo si no son "none"
|
|
175
|
+
const currentFill = svgElement.getAttribute('fill');
|
|
176
|
+
if (currentFill && currentFill !== 'none') {
|
|
177
|
+
svgElement.setAttribute('fill', 'currentColor');
|
|
178
|
+
}
|
|
179
|
+
const currentStroke = svgElement.getAttribute('stroke');
|
|
180
|
+
if (currentStroke && currentStroke !== 'none') {
|
|
181
|
+
svgElement.setAttribute('stroke', 'currentColor');
|
|
182
|
+
}
|
|
183
|
+
// Asegurar viewBox (requerido para escalado)
|
|
184
|
+
if (!svgElement.hasAttribute('viewBox')) {
|
|
185
|
+
svgElement.setAttribute('viewBox', '0 0 24 24');
|
|
186
|
+
}
|
|
187
|
+
// Serializar de vuelta a string
|
|
188
|
+
return new XMLSerializer().serializeToString(svgElement);
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
console.error('Error processing SVG:', error);
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
processSvgWithRegex(svg) {
|
|
196
|
+
// Procesamiento simple con regex para SSR (donde no hay DOMParser)
|
|
197
|
+
let processed = svg;
|
|
198
|
+
// Remover width y height solo del tag <svg> de apertura
|
|
199
|
+
processed = processed.replace(/(<svg[^>]*?)\s+width="[^"]*"/i, '$1');
|
|
200
|
+
processed = processed.replace(/(<svg[^>]*?)\s+height="[^"]*"/i, '$1');
|
|
201
|
+
// Cambiar fill a currentColor si existe y no es "none"
|
|
202
|
+
processed = processed.replace(/(<svg[^>]*?\s+fill=")(?!none)([^"]*)(")/i, '$1currentColor$3');
|
|
203
|
+
// Cambiar stroke a currentColor si existe y no es "none"
|
|
204
|
+
processed = processed.replace(/(<svg[^>]*?\s+stroke=")(?!none)([^"]*)(")/i, '$1currentColor$3');
|
|
205
|
+
// Asegurar viewBox si no existe
|
|
206
|
+
if (!/viewBox=/i.test(processed)) {
|
|
207
|
+
processed = processed.replace(/(<svg[^>]*?)>/i, '$1 viewBox="0 0 24 24">');
|
|
208
|
+
}
|
|
209
|
+
return processed;
|
|
210
|
+
}
|
|
211
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Icon, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
212
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.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: "<span [innerHTML]=\"svgContent()\" [style.width]=\"size\" [style.height]=\"size\" [style.display]=\"'inline-flex'\"\n [style.color]=\"color\" class=\"cat-icon\">\n</span>", 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"] });
|
|
213
|
+
}
|
|
214
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Icon, decorators: [{
|
|
215
|
+
type: Component,
|
|
216
|
+
args: [{ selector: 'cat-icon', imports: [], template: "<span [innerHTML]=\"svgContent()\" [style.width]=\"size\" [style.height]=\"size\" [style.display]=\"'inline-flex'\"\n [style.color]=\"color\" class=\"cat-icon\">\n</span>", 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"] }]
|
|
217
|
+
}], propDecorators: { size: [{
|
|
218
|
+
type: Input
|
|
219
|
+
}], color: [{
|
|
220
|
+
type: Input
|
|
221
|
+
}], name: [{
|
|
222
|
+
type: Input
|
|
223
|
+
}], src: [{
|
|
224
|
+
type: Input
|
|
225
|
+
}] } });
|
|
226
|
+
|
|
227
|
+
class Button {
|
|
228
|
+
variant = 'primary';
|
|
229
|
+
size = 'md';
|
|
230
|
+
disabled = false;
|
|
231
|
+
type = 'button';
|
|
232
|
+
iconLeft;
|
|
233
|
+
iconCenter;
|
|
234
|
+
iconRight;
|
|
235
|
+
customClass = '';
|
|
236
|
+
clicked = new EventEmitter();
|
|
237
|
+
get buttonClasses() {
|
|
238
|
+
return `${this.variant} ${this.size} ${this.customClass}`;
|
|
239
|
+
}
|
|
240
|
+
get iconSize() {
|
|
241
|
+
const sizes = { sm: '16px', md: '20px', lg: '24px' };
|
|
242
|
+
return sizes[this.size];
|
|
243
|
+
}
|
|
244
|
+
get dataCustomClass() {
|
|
245
|
+
return this.customClass;
|
|
246
|
+
}
|
|
247
|
+
handleClick(event) {
|
|
248
|
+
if (!this.disabled) {
|
|
249
|
+
this.clicked.emit(event);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Button, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
253
|
+
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\n @if (iconLeft) {\n <cat-icon [name]=\"iconLeft\" [size]=\"iconSize\" class=\"icon-left\">\n </cat-icon>\n }\n\n <span class=\"button-content\">\n @if (iconCenter) {\n <cat-icon [name]=\"iconCenter\" [size]=\"iconSize\" class=\"icon-left\">\n </cat-icon>\n }\n <ng-content></ng-content>\n </span>\n\n @if (iconRight) {\n <cat-icon [name]=\"iconRight\" [size]=\"iconSize\" class=\"icon-right\">\n </cat-icon>\n }\n</button>", styles: ["button{display:inline-flex;align-items:center;gap:.5rem;padding:.5rem 1rem;border:none;border-radius:18px;font-family:inherit;font-size:1rem;font-weight:500;cursor:pointer;transition:all .2s;white-space:nowrap}button:disabled{opacity:.5;cursor:not-allowed}.primary{background-color:var(--primary-color-0);color:#fff}.primary:hover:not(:disabled){background-color:#8a0000;background-color:var(--primary-color-1)}.secondary{background-color:var(--neutral-color-3);color:#fff}.secondary:hover:not(:disabled){background-color:var(--neutral-color-4)}.contrast{background-color:var(--neutral-color-9);color:var(--neutral-color-0)}.contrast:hover:not(:disabled){background-color:var(--neutral-color-8)}.outline{background-color:transparent;color:#a40000;border:2px solid #A40000}.outline:hover:not(:disabled){background-color:#a40000;color:#fff}.ghost{background-color:transparent;color:#a40000}.ghost:hover:not(:disabled){background-color:#a400001a}.sm{padding:.25rem .75rem;font-size:.875rem}.md{padding:.5rem 1rem;font-size:1rem}.lg{padding:.75rem 1.5rem;font-size:1.125rem}.icon-left,.icon-right,.icon-center{display:inline-flex}.button-content{display:inline-flex;align-items:center}\n"], dependencies: [{ kind: "component", type: Icon, selector: "cat-icon", inputs: ["size", "color", "name", "src"] }] });
|
|
254
|
+
}
|
|
255
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Button, decorators: [{
|
|
256
|
+
type: Component,
|
|
257
|
+
args: [{ selector: 'cat-button', imports: [Icon], template: "<button [class]=\"buttonClasses\" [disabled]=\"disabled\" [type]=\"type\" (click)=\"handleClick($event)\">\n\n @if (iconLeft) {\n <cat-icon [name]=\"iconLeft\" [size]=\"iconSize\" class=\"icon-left\">\n </cat-icon>\n }\n\n <span class=\"button-content\">\n @if (iconCenter) {\n <cat-icon [name]=\"iconCenter\" [size]=\"iconSize\" class=\"icon-left\">\n </cat-icon>\n }\n <ng-content></ng-content>\n </span>\n\n @if (iconRight) {\n <cat-icon [name]=\"iconRight\" [size]=\"iconSize\" class=\"icon-right\">\n </cat-icon>\n }\n</button>", styles: ["button{display:inline-flex;align-items:center;gap:.5rem;padding:.5rem 1rem;border:none;border-radius:18px;font-family:inherit;font-size:1rem;font-weight:500;cursor:pointer;transition:all .2s;white-space:nowrap}button:disabled{opacity:.5;cursor:not-allowed}.primary{background-color:var(--primary-color-0);color:#fff}.primary:hover:not(:disabled){background-color:#8a0000;background-color:var(--primary-color-1)}.secondary{background-color:var(--neutral-color-3);color:#fff}.secondary:hover:not(:disabled){background-color:var(--neutral-color-4)}.contrast{background-color:var(--neutral-color-9);color:var(--neutral-color-0)}.contrast:hover:not(:disabled){background-color:var(--neutral-color-8)}.outline{background-color:transparent;color:#a40000;border:2px solid #A40000}.outline:hover:not(:disabled){background-color:#a40000;color:#fff}.ghost{background-color:transparent;color:#a40000}.ghost:hover:not(:disabled){background-color:#a400001a}.sm{padding:.25rem .75rem;font-size:.875rem}.md{padding:.5rem 1rem;font-size:1rem}.lg{padding:.75rem 1.5rem;font-size:1.125rem}.icon-left,.icon-right,.icon-center{display:inline-flex}.button-content{display:inline-flex;align-items:center}\n"] }]
|
|
258
|
+
}], propDecorators: { variant: [{
|
|
259
|
+
type: Input
|
|
260
|
+
}], size: [{
|
|
261
|
+
type: Input
|
|
262
|
+
}], disabled: [{
|
|
263
|
+
type: Input
|
|
264
|
+
}], type: [{
|
|
265
|
+
type: Input
|
|
266
|
+
}], iconLeft: [{
|
|
267
|
+
type: Input
|
|
268
|
+
}], iconCenter: [{
|
|
269
|
+
type: Input
|
|
270
|
+
}], iconRight: [{
|
|
271
|
+
type: Input
|
|
272
|
+
}], customClass: [{
|
|
273
|
+
type: Input
|
|
274
|
+
}], clicked: [{
|
|
275
|
+
type: Output
|
|
276
|
+
}], dataCustomClass: [{
|
|
277
|
+
type: HostBinding,
|
|
278
|
+
args: ['attr.data-button-class']
|
|
279
|
+
}] } });
|
|
280
|
+
|
|
281
|
+
class Card {
|
|
282
|
+
variant = 'surface';
|
|
283
|
+
size = 'md';
|
|
284
|
+
width = 'auto';
|
|
285
|
+
customClass = '';
|
|
286
|
+
// Exponer las clases como atributos de datos
|
|
287
|
+
get dataVariant() {
|
|
288
|
+
return this.variant;
|
|
289
|
+
}
|
|
290
|
+
get dataSize() {
|
|
291
|
+
return this.size;
|
|
292
|
+
}
|
|
293
|
+
get dataCustomClass() {
|
|
294
|
+
return this.customClass;
|
|
295
|
+
}
|
|
296
|
+
/*// También exponer como CSS Custom Properties
|
|
297
|
+
@HostBinding('style.--card-variant') get cssVariant() {
|
|
298
|
+
return this.variant;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
@HostBinding('style.--card-custom-class') get cssCustomClass() {
|
|
302
|
+
return this.customClass;
|
|
303
|
+
}
|
|
304
|
+
*/
|
|
305
|
+
get cardClasses() {
|
|
306
|
+
return `${this.variant} ${this.size} ${this.customClass}`;
|
|
307
|
+
}
|
|
308
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Card, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
309
|
+
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: ["section{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}.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)}.sm{padding:.25rem .75rem;font-size:.875rem}.md{padding:.5rem 1rem;font-size:1rem}.lg{padding:.75rem 1.5rem;font-size:1.125rem}\n"] });
|
|
310
|
+
}
|
|
311
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Card, decorators: [{
|
|
312
|
+
type: Component,
|
|
313
|
+
args: [{ selector: 'cat-card', template: "<section [class]=\"cardClasses\" [attr.data-class]=\"customClass\" [style]=\"`width: ${width};`\">\n <ng-content></ng-content>\n</section>", styles: ["section{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}.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)}.sm{padding:.25rem .75rem;font-size:.875rem}.md{padding:.5rem 1rem;font-size:1rem}.lg{padding:.75rem 1.5rem;font-size:1.125rem}\n"] }]
|
|
314
|
+
}], propDecorators: { variant: [{
|
|
315
|
+
type: Input
|
|
316
|
+
}], size: [{
|
|
317
|
+
type: Input
|
|
318
|
+
}], width: [{
|
|
319
|
+
type: Input
|
|
320
|
+
}], customClass: [{
|
|
321
|
+
type: Input
|
|
322
|
+
}], dataVariant: [{
|
|
323
|
+
type: HostBinding,
|
|
324
|
+
args: ['attr.data-card-variant']
|
|
325
|
+
}], dataSize: [{
|
|
326
|
+
type: HostBinding,
|
|
327
|
+
args: ['attr.data-card-size']
|
|
328
|
+
}], dataCustomClass: [{
|
|
329
|
+
type: HostBinding,
|
|
330
|
+
args: ['attr.data-card-class']
|
|
331
|
+
}] } });
|
|
332
|
+
|
|
333
|
+
class Accordion {
|
|
334
|
+
accordionId;
|
|
335
|
+
status = false; //false = unactive
|
|
336
|
+
label = 'Accordion Name';
|
|
337
|
+
disabled = false;
|
|
338
|
+
customClass = '';
|
|
339
|
+
width = 'auto';
|
|
340
|
+
//Button Properties
|
|
341
|
+
buttonVariant = 'secondary';
|
|
342
|
+
buttonSize = 'md';
|
|
343
|
+
iconLeft = false;
|
|
344
|
+
iconCenter = false;
|
|
345
|
+
iconRight = true;
|
|
346
|
+
//Panel Properties
|
|
347
|
+
scrolleable = false;
|
|
348
|
+
variant = 'surface';
|
|
349
|
+
updateAccordionGroupStatusOutput = new EventEmitter();
|
|
350
|
+
buttonRef;
|
|
351
|
+
buttonWidth = 0;
|
|
352
|
+
ngAfterViewInit() {
|
|
353
|
+
// Obtener el ancho del botón después de renderizar
|
|
354
|
+
setTimeout(() => {
|
|
355
|
+
if (this.buttonRef) {
|
|
356
|
+
const button = this.buttonRef.nativeElement.querySelector('button');
|
|
357
|
+
if (button) {
|
|
358
|
+
this.buttonWidth = button.offsetWidth;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
// Actualizar cuando cambie el label o otros inputs que afecten tamaño
|
|
364
|
+
ngOnChanges() {
|
|
365
|
+
if (this.buttonRef) {
|
|
366
|
+
const button = this.buttonRef.nativeElement.querySelector('button');
|
|
367
|
+
if (button) {
|
|
368
|
+
this.buttonWidth = button.offsetWidth;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
updateAccordionGroupStatus() {
|
|
373
|
+
this.status = !this.status;
|
|
374
|
+
this.updateAccordionGroupStatusOutput.emit(this.accordionId);
|
|
375
|
+
}
|
|
376
|
+
forceStatus(newStatus) {
|
|
377
|
+
this.status = newStatus;
|
|
378
|
+
}
|
|
379
|
+
;
|
|
380
|
+
get dataCustomClass() {
|
|
381
|
+
return this.customClass;
|
|
382
|
+
}
|
|
383
|
+
get panelClasses() {
|
|
384
|
+
return `${this.variant} ${this.customClass} ${this.scrolleable ? 'scrolleable' : undefined}`;
|
|
385
|
+
}
|
|
386
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Accordion, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
387
|
+
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", width: "width", 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\" [style]=\"`width: ${width};`\">\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: [".accordion{margin:0;padding:0;min-width:5em;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"] }] });
|
|
388
|
+
}
|
|
389
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Accordion, decorators: [{
|
|
390
|
+
type: Component,
|
|
391
|
+
args: [{ selector: 'cat-accordion', imports: [Button, NgClass, NgIf], template: "<section class=\"accordion\" [style]=\"`width: ${width};`\">\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: [".accordion{margin:0;padding:0;min-width:5em;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"] }]
|
|
392
|
+
}], propDecorators: { accordionId: [{
|
|
393
|
+
type: Input
|
|
394
|
+
}], status: [{
|
|
395
|
+
type: Input
|
|
396
|
+
}], label: [{
|
|
397
|
+
type: Input
|
|
398
|
+
}], disabled: [{
|
|
399
|
+
type: Input
|
|
400
|
+
}], customClass: [{
|
|
401
|
+
type: Input
|
|
402
|
+
}], width: [{
|
|
403
|
+
type: Input
|
|
404
|
+
}], buttonVariant: [{
|
|
405
|
+
type: Input
|
|
406
|
+
}], buttonSize: [{
|
|
407
|
+
type: Input
|
|
408
|
+
}], iconLeft: [{
|
|
409
|
+
type: Input
|
|
410
|
+
}], iconCenter: [{
|
|
411
|
+
type: Input
|
|
412
|
+
}], iconRight: [{
|
|
413
|
+
type: Input
|
|
414
|
+
}], scrolleable: [{
|
|
415
|
+
type: Input
|
|
416
|
+
}], variant: [{
|
|
417
|
+
type: Input
|
|
418
|
+
}], updateAccordionGroupStatusOutput: [{
|
|
419
|
+
type: Output
|
|
420
|
+
}], buttonRef: [{
|
|
421
|
+
type: ViewChild,
|
|
422
|
+
args: ['buttonRef', { static: false }]
|
|
423
|
+
}], dataCustomClass: [{
|
|
424
|
+
type: HostBinding,
|
|
425
|
+
args: ['attr.data-accordion-class']
|
|
426
|
+
}] } });
|
|
427
|
+
|
|
428
|
+
class AccordionGroup {
|
|
429
|
+
singleExpand = true;
|
|
430
|
+
customClass = '';
|
|
431
|
+
accordions;
|
|
432
|
+
accordionActiveId;
|
|
433
|
+
sub;
|
|
434
|
+
ngAfterContentInit() {
|
|
435
|
+
if (this.singleExpand) {
|
|
436
|
+
this.accordions.forEach(acc => {
|
|
437
|
+
this.sub = acc.updateAccordionGroupStatusOutput.subscribe(id => {
|
|
438
|
+
this.handleOpen(id);
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
handleOpen(id) {
|
|
444
|
+
this.accordions.forEach(acc => acc.forceStatus(false));
|
|
445
|
+
const target = this.accordions.find(acc => acc.accordionId === id);
|
|
446
|
+
if (this.accordionActiveId === id) {
|
|
447
|
+
target?.forceStatus(false);
|
|
448
|
+
this.accordionActiveId = undefined;
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
target?.forceStatus(true);
|
|
452
|
+
this.accordionActiveId = id;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
get dataCustomClass() {
|
|
456
|
+
return this.customClass;
|
|
457
|
+
}
|
|
458
|
+
get accordionGroupClasses() {
|
|
459
|
+
return `${this.customClass}`;
|
|
460
|
+
}
|
|
461
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AccordionGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
462
|
+
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: "<style>\n section {\n width: 100%;\n }\n</style>\n<section [class]=\"accordionGroupClasses\">\n <ng-content></ng-content>\n</section>", styles: ["", "section{width:100%}\n"] });
|
|
463
|
+
}
|
|
464
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AccordionGroup, decorators: [{
|
|
465
|
+
type: Component,
|
|
466
|
+
args: [{ selector: 'cat-accordion-group', imports: [], template: "<style>\n section {\n width: 100%;\n }\n</style>\n<section [class]=\"accordionGroupClasses\">\n <ng-content></ng-content>\n</section>", styles: ["section{width:100%}\n"] }]
|
|
467
|
+
}], propDecorators: { singleExpand: [{
|
|
468
|
+
type: Input
|
|
469
|
+
}], customClass: [{
|
|
470
|
+
type: Input
|
|
471
|
+
}], accordions: [{
|
|
472
|
+
type: ContentChildren,
|
|
473
|
+
args: [Accordion]
|
|
474
|
+
}], dataCustomClass: [{
|
|
475
|
+
type: HostBinding,
|
|
476
|
+
args: ['attr.data-accordion-group-class']
|
|
477
|
+
}] } });
|
|
478
|
+
|
|
479
|
+
class CatInput {
|
|
480
|
+
el = inject(ElementRef);
|
|
481
|
+
platformId = inject(PLATFORM_ID);
|
|
482
|
+
control = inject(NgControl, { optional: true, self: true });
|
|
483
|
+
static stylesInjected = false;
|
|
484
|
+
ngOnInit() {
|
|
485
|
+
if (this.el.nativeElement.tagName.toLowerCase() !== 'input') {
|
|
486
|
+
console.warn('catInput directive can only be used on <input> elements');
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
// Inyectar estilos solo una vez
|
|
490
|
+
if (!CatInput.stylesInjected && isPlatformBrowser(this.platformId)) {
|
|
491
|
+
this.injectStyles();
|
|
492
|
+
CatInput.stylesInjected = true;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
injectStyles() {
|
|
496
|
+
const style = document.createElement('style');
|
|
497
|
+
style.textContent = `
|
|
498
|
+
.cat-input {
|
|
499
|
+
border: 1px solid var(--neutral-color-3);
|
|
500
|
+
background-color: var(--neutral-color-0);
|
|
501
|
+
color: var(--neutral-color-9);
|
|
502
|
+
border-radius: 18px;
|
|
503
|
+
outline: none;
|
|
504
|
+
transition: all 0.2s;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
.cat-input:disabled {
|
|
508
|
+
opacity: 0.5;
|
|
509
|
+
cursor: not-allowed;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
.cat-input::placeholder {
|
|
513
|
+
color: var(--neutral-color-6);
|
|
514
|
+
transition: font-size 0.2s;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
.cat-input:focus::placeholder {
|
|
518
|
+
font-size: 0.7em;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
.cat-input:focus {
|
|
522
|
+
border: 1px solid var(--neutral-color-9);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
.cat-input.invalid,
|
|
526
|
+
.cat-input.ng-invalid.ng-touched {
|
|
527
|
+
border: 1px solid red;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
.cat-input.ng-valid.ng-touched {
|
|
531
|
+
border: 1px solid green;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
.cat-input.md {
|
|
535
|
+
padding: 0.5rem 1rem;
|
|
536
|
+
font-size: 1rem;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
.cat-input.sm {
|
|
540
|
+
padding: 0.25rem 0.75rem;
|
|
541
|
+
font-size: 0.875rem;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
.cat-input.lg {
|
|
545
|
+
padding: 0.75rem 1.5rem;
|
|
546
|
+
font-size: 1.125rem;
|
|
547
|
+
}
|
|
548
|
+
`;
|
|
549
|
+
document.head.appendChild(style);
|
|
550
|
+
}
|
|
551
|
+
get isInvalid() {
|
|
552
|
+
return !!(this.control && this.control.invalid && this.control.touched);
|
|
553
|
+
}
|
|
554
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CatInput, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
555
|
+
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 });
|
|
556
|
+
}
|
|
557
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CatInput, decorators: [{
|
|
558
|
+
type: Directive,
|
|
559
|
+
args: [{
|
|
560
|
+
selector: '[catInput]',
|
|
561
|
+
standalone: true,
|
|
562
|
+
host: {
|
|
563
|
+
'[class.cat-input]': 'true',
|
|
564
|
+
'[class.md]': 'true',
|
|
565
|
+
'[class.invalid]': 'isInvalid'
|
|
566
|
+
}
|
|
567
|
+
}]
|
|
568
|
+
}], propDecorators: { control: [{
|
|
569
|
+
type: Optional
|
|
570
|
+
}, {
|
|
571
|
+
type: Self
|
|
572
|
+
}] } });
|
|
573
|
+
|
|
574
|
+
class ColorInput {
|
|
575
|
+
value = '#000000';
|
|
576
|
+
icon = false;
|
|
577
|
+
size = '2em';
|
|
578
|
+
onChange = (value) => { };
|
|
579
|
+
onTouched = () => { };
|
|
580
|
+
onInput(event) {
|
|
581
|
+
const newValue = event.target.value;
|
|
582
|
+
this.value = newValue;
|
|
583
|
+
this.onChange(newValue); // informa al padre
|
|
584
|
+
}
|
|
585
|
+
// Métodos requeridos por ControlValueAccessor
|
|
586
|
+
writeValue(value) {
|
|
587
|
+
this.value = value || '#000000';
|
|
588
|
+
}
|
|
589
|
+
registerOnChange(fn) {
|
|
590
|
+
this.onChange = fn;
|
|
591
|
+
}
|
|
592
|
+
registerOnTouched(fn) {
|
|
593
|
+
this.onTouched = fn;
|
|
594
|
+
}
|
|
595
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ColorInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
596
|
+
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: [{
|
|
597
|
+
provide: NG_VALUE_ACCESSOR,
|
|
598
|
+
useExisting: forwardRef(() => ColorInput),
|
|
599
|
+
multi: true
|
|
600
|
+
}], 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]=\"`width: ${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"] }] });
|
|
601
|
+
}
|
|
602
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ColorInput, decorators: [{
|
|
603
|
+
type: Component,
|
|
604
|
+
args: [{ selector: 'cat-color-input', imports: [Icon], providers: [{
|
|
605
|
+
provide: NG_VALUE_ACCESSOR,
|
|
606
|
+
useExisting: forwardRef(() => ColorInput),
|
|
607
|
+
multi: true
|
|
608
|
+
}], 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]=\"`width: ${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"] }]
|
|
609
|
+
}], propDecorators: { icon: [{
|
|
610
|
+
type: Input
|
|
611
|
+
}], size: [{
|
|
612
|
+
type: Input
|
|
613
|
+
}] } });
|
|
614
|
+
|
|
615
|
+
class SelectInput {
|
|
616
|
+
el;
|
|
617
|
+
inputEl;
|
|
618
|
+
transform; //This option basicly allow to the consumer put the options at the side where he wants
|
|
619
|
+
options;
|
|
620
|
+
placeholder = '';
|
|
621
|
+
type = 'string';
|
|
622
|
+
value = '';
|
|
623
|
+
active = false;
|
|
624
|
+
variant = 'surface';
|
|
625
|
+
scrolleable = false;
|
|
626
|
+
customClass = '';
|
|
627
|
+
//@Output() selected = new EventEmitter<string>();
|
|
628
|
+
//Accesibility
|
|
629
|
+
outerClick(event) {
|
|
630
|
+
if (!this.el.nativeElement.contains(event.target)) {
|
|
631
|
+
this.active = false;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
;
|
|
635
|
+
constructor(el) {
|
|
636
|
+
this.el = el;
|
|
637
|
+
}
|
|
638
|
+
onChange = (value) => { };
|
|
639
|
+
onTouched = () => { };
|
|
640
|
+
//Here starts the events from ControlValueAccesor
|
|
641
|
+
writeValue(value) {
|
|
642
|
+
this.value = value;
|
|
643
|
+
}
|
|
644
|
+
;
|
|
645
|
+
registerOnChange(fn) {
|
|
646
|
+
this.onChange = fn;
|
|
647
|
+
}
|
|
648
|
+
registerOnTouched(fn) {
|
|
649
|
+
this.onTouched = fn;
|
|
650
|
+
}
|
|
651
|
+
//Here ends The events from ControlValueAccesor
|
|
652
|
+
choseValue(option) {
|
|
653
|
+
this.value = option;
|
|
654
|
+
this.onChange(option);
|
|
655
|
+
this.onTouched();
|
|
656
|
+
this.active = false;
|
|
657
|
+
//this.selected.emit(option);
|
|
658
|
+
}
|
|
659
|
+
;
|
|
660
|
+
get dataCustomClass() {
|
|
661
|
+
return this.customClass;
|
|
662
|
+
}
|
|
663
|
+
get selectInputClass() {
|
|
664
|
+
return `${this.variant} ${this.scrolleable ? 'scrolleable' : ''}`;
|
|
665
|
+
}
|
|
666
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SelectInput, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
667
|
+
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: [{
|
|
668
|
+
provide: NG_VALUE_ACCESSOR,
|
|
669
|
+
useExisting: forwardRef(() => SelectInput),
|
|
670
|
+
multi: true
|
|
671
|
+
}], viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["input"], descendants: true }], ngImport: i0, template: "<div>\n <input catInput [value]=\"value\" [type]=\"type\" readonly id=\"select\" (mousedown)=\"active =! active\" [placeholder]=\"placeholder\">\n <section role=\"listbox\" [class]=\"selectInputClass\" class=\"options\" [ngClass]=\"active ? 'options-active' : 'options.unactive'\" [style.transform]=\"transform\">\n @if (active) {\n <div role=\"option\"*ngFor=\"let option of options\" (mousedown)=\"choseValue(option)\">\n {{ option }}\n </div>\n }\n </section>\n</div>", styles: ["div{position:relative;display:inline-block}.options-active{background-color:var(--neutral-color-0);z-index:1;border-radius:18px;padding:8px;box-sizing:border-box;width:100%;position:absolute;display:flex;flex-direction:column;transition:.25s}.options-unactive{display:none;transition:.15s}.options>div{background-color:transparent;min-height:1em;padding-top:.5em;padding-left:.5em;padding-right:.8em;color:var(--neutral-color-9);box-sizing:border-box}.options>div:hover{background-color:var(--neutral-color-1)}.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: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: CatInput, selector: "[catInput]" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
|
|
672
|
+
}
|
|
673
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SelectInput, decorators: [{
|
|
674
|
+
type: Component,
|
|
675
|
+
args: [{ selector: 'cat-select-input', imports: [
|
|
676
|
+
NgFor,
|
|
677
|
+
CatInput,
|
|
678
|
+
NgClass
|
|
679
|
+
], providers: [{
|
|
680
|
+
provide: NG_VALUE_ACCESSOR,
|
|
681
|
+
useExisting: forwardRef(() => SelectInput),
|
|
682
|
+
multi: true
|
|
683
|
+
}], template: "<div>\n <input catInput [value]=\"value\" [type]=\"type\" readonly id=\"select\" (mousedown)=\"active =! active\" [placeholder]=\"placeholder\">\n <section role=\"listbox\" [class]=\"selectInputClass\" class=\"options\" [ngClass]=\"active ? 'options-active' : 'options.unactive'\" [style.transform]=\"transform\">\n @if (active) {\n <div role=\"option\"*ngFor=\"let option of options\" (mousedown)=\"choseValue(option)\">\n {{ option }}\n </div>\n }\n </section>\n</div>", styles: ["div{position:relative;display:inline-block}.options-active{background-color:var(--neutral-color-0);z-index:1;border-radius:18px;padding:8px;box-sizing:border-box;width:100%;position:absolute;display:flex;flex-direction:column;transition:.25s}.options-unactive{display:none;transition:.15s}.options>div{background-color:transparent;min-height:1em;padding-top:.5em;padding-left:.5em;padding-right:.8em;color:var(--neutral-color-9);box-sizing:border-box}.options>div:hover{background-color:var(--neutral-color-1)}.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"] }]
|
|
684
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { inputEl: [{
|
|
685
|
+
type: ViewChild,
|
|
686
|
+
args: ['input']
|
|
687
|
+
}], transform: [{
|
|
688
|
+
type: Input
|
|
689
|
+
}], options: [{
|
|
690
|
+
type: Input
|
|
691
|
+
}], placeholder: [{
|
|
692
|
+
type: Input
|
|
693
|
+
}], type: [{
|
|
694
|
+
type: Input
|
|
695
|
+
}], variant: [{
|
|
696
|
+
type: Input
|
|
697
|
+
}], scrolleable: [{
|
|
698
|
+
type: Input
|
|
699
|
+
}], customClass: [{
|
|
700
|
+
type: Input
|
|
701
|
+
}], outerClick: [{
|
|
702
|
+
type: HostListener,
|
|
703
|
+
args: ['document:click', ['$event']]
|
|
704
|
+
}], dataCustomClass: [{
|
|
705
|
+
type: HostBinding,
|
|
706
|
+
args: ['attr.data-select-input-class']
|
|
707
|
+
}] } });
|
|
708
|
+
|
|
709
|
+
class DateInput {
|
|
710
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DateInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
711
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: DateInput, isStandalone: true, selector: "lib-date-input", ngImport: i0, template: "<p>date-input works!</p>\n", styles: [""] });
|
|
712
|
+
}
|
|
713
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DateInput, decorators: [{
|
|
714
|
+
type: Component,
|
|
715
|
+
args: [{ selector: 'lib-date-input', imports: [], template: "<p>date-input works!</p>\n" }]
|
|
716
|
+
}] });
|
|
717
|
+
|
|
718
|
+
class FileInput {
|
|
719
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FileInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
720
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: FileInput, isStandalone: true, selector: "lib-file-input", ngImport: i0, template: "<p>file-input works!</p>\n", styles: [""] });
|
|
721
|
+
}
|
|
722
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FileInput, decorators: [{
|
|
723
|
+
type: Component,
|
|
724
|
+
args: [{ selector: 'lib-file-input', imports: [], template: "<p>file-input works!</p>\n" }]
|
|
725
|
+
}] });
|
|
726
|
+
|
|
727
|
+
class PasswordInput {
|
|
728
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PasswordInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
729
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: PasswordInput, isStandalone: true, selector: "lib-password-input", ngImport: i0, template: "<p>password-input works!</p>\n", styles: [""] });
|
|
730
|
+
}
|
|
731
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PasswordInput, decorators: [{
|
|
732
|
+
type: Component,
|
|
733
|
+
args: [{ selector: 'lib-password-input', imports: [], template: "<p>password-input works!</p>\n" }]
|
|
734
|
+
}] });
|
|
735
|
+
|
|
736
|
+
class RangeInput {
|
|
737
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: RangeInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
738
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: RangeInput, isStandalone: true, selector: "lib-range-input", ngImport: i0, template: "<p>range-input works!</p>\n", styles: [""] });
|
|
739
|
+
}
|
|
740
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: RangeInput, decorators: [{
|
|
741
|
+
type: Component,
|
|
742
|
+
args: [{ selector: 'lib-range-input', imports: [], template: "<p>range-input works!</p>\n" }]
|
|
743
|
+
}] });
|
|
744
|
+
|
|
745
|
+
class TextAreaInput {
|
|
746
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TextAreaInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
747
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: TextAreaInput, isStandalone: true, selector: "lib-text-area-input", ngImport: i0, template: "<p>text-area-input works!</p>\n", styles: [""] });
|
|
748
|
+
}
|
|
749
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TextAreaInput, decorators: [{
|
|
750
|
+
type: Component,
|
|
751
|
+
args: [{ selector: 'lib-text-area-input', imports: [], template: "<p>text-area-input works!</p>\n" }]
|
|
752
|
+
}] });
|
|
753
|
+
|
|
754
|
+
class TimeInput {
|
|
755
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TimeInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
756
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: TimeInput, isStandalone: true, selector: "lib-time-input", ngImport: i0, template: "<p>time-input works!</p>\n", styles: [""] });
|
|
757
|
+
}
|
|
758
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TimeInput, decorators: [{
|
|
759
|
+
type: Component,
|
|
760
|
+
args: [{ selector: 'lib-time-input', imports: [], template: "<p>time-input works!</p>\n" }]
|
|
761
|
+
}] });
|
|
762
|
+
|
|
763
|
+
class Drag {
|
|
764
|
+
el;
|
|
765
|
+
renderer;
|
|
766
|
+
document;
|
|
767
|
+
offsetX = 0;
|
|
768
|
+
offsetY = 0;
|
|
769
|
+
dragging = false;
|
|
770
|
+
constructor(el, renderer, document) {
|
|
771
|
+
this.el = el;
|
|
772
|
+
this.renderer = renderer;
|
|
773
|
+
this.document = document;
|
|
774
|
+
}
|
|
775
|
+
ngAfterViewInit() {
|
|
776
|
+
const el = this.el.nativeElement;
|
|
777
|
+
// Si el elemento no tiene position seteado, le ponemos absolute
|
|
778
|
+
if (typeof window !== 'undefined') {
|
|
779
|
+
const computedStyle = window.getComputedStyle(el);
|
|
780
|
+
if (computedStyle.position === 'static') {
|
|
781
|
+
this.renderer.setStyle(el, 'position', 'absolute');
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
el.addEventListener('mousedown', (e) => {
|
|
785
|
+
this.dragging = true;
|
|
786
|
+
this.offsetX = e.clientX - el.offsetLeft;
|
|
787
|
+
this.offsetY = e.clientY - el.offsetTop;
|
|
788
|
+
el.style.cursor = 'grabbing';
|
|
789
|
+
});
|
|
790
|
+
this.document.addEventListener('mousemove', (e) => {
|
|
791
|
+
if (this.dragging) {
|
|
792
|
+
el.style.left = e.clientX - this.offsetX + 'px';
|
|
793
|
+
el.style.top = e.clientY - this.offsetY + 'px';
|
|
794
|
+
}
|
|
795
|
+
});
|
|
796
|
+
this.document.addEventListener('mouseup', () => {
|
|
797
|
+
this.dragging = false;
|
|
798
|
+
el.style.cursor = 'grab';
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
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 });
|
|
802
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.15", type: Drag, isStandalone: true, selector: "[CDrag]", ngImport: i0 });
|
|
803
|
+
}
|
|
804
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Drag, decorators: [{
|
|
805
|
+
type: Directive,
|
|
806
|
+
args: [{
|
|
807
|
+
selector: '[CDrag]'
|
|
808
|
+
}]
|
|
809
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: Document, decorators: [{
|
|
810
|
+
type: Inject,
|
|
811
|
+
args: [DOCUMENT]
|
|
812
|
+
}] }] });
|
|
813
|
+
|
|
814
|
+
class Dialog {
|
|
815
|
+
closs = new EventEmitter();
|
|
816
|
+
handleKeyDown(event) {
|
|
817
|
+
this.clossOverlay();
|
|
818
|
+
}
|
|
819
|
+
variant = 'surface';
|
|
820
|
+
size = 'md';
|
|
821
|
+
customClass = '';
|
|
822
|
+
// Exponer las clases como atributos de datos
|
|
823
|
+
get dataVariant() {
|
|
824
|
+
return this.variant;
|
|
825
|
+
}
|
|
826
|
+
get dataSize() {
|
|
827
|
+
return this.size;
|
|
828
|
+
}
|
|
829
|
+
get dataCustomClass() {
|
|
830
|
+
return this.customClass;
|
|
831
|
+
}
|
|
832
|
+
get dialogClasses() {
|
|
833
|
+
return `${this.variant} ${this.size} ${this.customClass}`;
|
|
834
|
+
}
|
|
835
|
+
clossOverlay() {
|
|
836
|
+
this.closs.emit(false);
|
|
837
|
+
}
|
|
838
|
+
;
|
|
839
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Dialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
840
|
+
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" }, host: { listeners: { "window:keydown.escape": "handleKeyDown($event)" }, properties: { "attr.data-card-variant": "this.dataVariant", "attr.data-card-size": "this.dataSize", "attr.data-card-class": "this.dataCustomClass" } }, ngImport: i0, template: "<div class=\"dialog-shadow\" (click)=\"clossOverlay()\">\n</div>\n<section CDrag [class]=\"dialogClasses\">\n <ng-content></ng-content>\n</section>", styles: [".dialog-shadow{position:fixed;top:0;left:0;width:100%;height:100%;background:#000000b3;z-index:999}section{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:80vw;height:80vh;border-radius:18px;overflow:auto;padding:8px;box-sizing:border-box;z-index:1000;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]" }] });
|
|
841
|
+
}
|
|
842
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Dialog, decorators: [{
|
|
843
|
+
type: Component,
|
|
844
|
+
args: [{ selector: 'cat-dialog', imports: [Drag], template: "<div class=\"dialog-shadow\" (click)=\"clossOverlay()\">\n</div>\n<section CDrag [class]=\"dialogClasses\">\n <ng-content></ng-content>\n</section>", styles: [".dialog-shadow{position:fixed;top:0;left:0;width:100%;height:100%;background:#000000b3;z-index:999}section{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:80vw;height:80vh;border-radius:18px;overflow:auto;padding:8px;box-sizing:border-box;z-index:1000;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"] }]
|
|
845
|
+
}], propDecorators: { closs: [{
|
|
846
|
+
type: Output
|
|
847
|
+
}], handleKeyDown: [{
|
|
848
|
+
type: HostListener,
|
|
849
|
+
args: ['window:keydown.escape', ['$event']]
|
|
850
|
+
}], variant: [{
|
|
851
|
+
type: Input
|
|
852
|
+
}], size: [{
|
|
853
|
+
type: Input
|
|
854
|
+
}], customClass: [{
|
|
855
|
+
type: Input
|
|
856
|
+
}], dataVariant: [{
|
|
857
|
+
type: HostBinding,
|
|
858
|
+
args: ['attr.data-card-variant']
|
|
859
|
+
}], dataSize: [{
|
|
860
|
+
type: HostBinding,
|
|
861
|
+
args: ['attr.data-card-size']
|
|
862
|
+
}], dataCustomClass: [{
|
|
863
|
+
type: HostBinding,
|
|
864
|
+
args: ['attr.data-card-class']
|
|
865
|
+
}] } });
|
|
866
|
+
|
|
867
|
+
class Theming {
|
|
868
|
+
//Light Theme = False
|
|
869
|
+
activeThemeSubject = new BehaviorSubject(false);
|
|
870
|
+
activeTheme$ = this.activeThemeSubject.asObservable();
|
|
871
|
+
//Palettes
|
|
872
|
+
allPalettesSubject = new BehaviorSubject([]);
|
|
873
|
+
allPalettes$ = this.allPalettesSubject.asObservable();
|
|
874
|
+
generatePalettes(color, dark) {
|
|
875
|
+
this.activeThemeSubject.next(dark);
|
|
876
|
+
//Step 1: Calculate the Color
|
|
877
|
+
const colors = this.hexToRgb(color);
|
|
878
|
+
//Step 2: Get the Primary Palette (static, doesn't change with theme)
|
|
879
|
+
const primaryColors = this.palette(colors, false, 4); // Always use light theme
|
|
880
|
+
//Step 3: Calculate dynamic palettes (neutral and elements)
|
|
881
|
+
const dynamicPalettes = this.calculateDynamicPalettes(dark);
|
|
882
|
+
//Step 4: Assign All Palettes to Local Variables
|
|
883
|
+
let allPalettes = [primaryColors];
|
|
884
|
+
allPalettes = allPalettes.concat([dynamicPalettes.neutral]);
|
|
885
|
+
allPalettes = allPalettes.concat([dynamicPalettes.elements]);
|
|
886
|
+
this.allPalettesSubject.next(allPalettes);
|
|
887
|
+
//Apply theme
|
|
888
|
+
this.applyTheme(allPalettes);
|
|
889
|
+
return this.allPalettesSubject.value;
|
|
890
|
+
}
|
|
891
|
+
calculateDynamicPalettes(dark) {
|
|
892
|
+
const theme = dark;
|
|
893
|
+
const contrastTheme = !dark;
|
|
894
|
+
this.activeThemeSubject.next(dark);
|
|
895
|
+
// Calculate neutral colors (changes with theme)
|
|
896
|
+
const neutralColors = contrastTheme
|
|
897
|
+
? this.palette({ red: 255, green: 255, blue: 255 }, false, 9)
|
|
898
|
+
: this.palette({ red: 0, green: 0, blue: 0 }, true, 9);
|
|
899
|
+
// Calculate element colors (changes with theme)
|
|
900
|
+
const elementsColors = this.elementsColors(theme, 3, 40);
|
|
901
|
+
// Update palettes array with dynamic values
|
|
902
|
+
const allPalettes = [
|
|
903
|
+
this.allPalettesSubject.value[0], // Keep primary (static)
|
|
904
|
+
neutralColors,
|
|
905
|
+
elementsColors
|
|
906
|
+
];
|
|
907
|
+
this.allPalettesSubject.next(allPalettes);
|
|
908
|
+
// Apply theme to CSS variables
|
|
909
|
+
this.applyTheme(allPalettes);
|
|
910
|
+
return {
|
|
911
|
+
neutral: neutralColors,
|
|
912
|
+
elements: elementsColors
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
palette(colors, dark, steps) {
|
|
916
|
+
//Palette
|
|
917
|
+
const colorsReturn = [];
|
|
918
|
+
const contrastTheme = !dark;
|
|
919
|
+
const target = contrastTheme ? 0 : 255;
|
|
920
|
+
const umbralR = (target - colors.red) / steps;
|
|
921
|
+
const umbralG = (target - colors.green) / steps;
|
|
922
|
+
const umbralB = (target - colors.blue) / steps;
|
|
923
|
+
for (let i = 0; i <= steps; i++) {
|
|
924
|
+
const r = Math.round(colors.red + umbralR * i);
|
|
925
|
+
const g = Math.round(colors.green + umbralG * i);
|
|
926
|
+
const b = Math.round(colors.blue + umbralB * i);
|
|
927
|
+
colorsReturn.push(`rgb(${r}, ${g}, ${b})`);
|
|
928
|
+
}
|
|
929
|
+
return colorsReturn;
|
|
930
|
+
}
|
|
931
|
+
;
|
|
932
|
+
elementsColors(theme, iteration, amplitude) {
|
|
933
|
+
amplitude = amplitude / iteration;
|
|
934
|
+
const colorsReturn = [];
|
|
935
|
+
for (let i = 0; i < 5; i++) {
|
|
936
|
+
let r = theme ? 0 + ((85 - 0) / (5 - 1) * i) : 0 + ((255 - 0) / (5 - 1) * i);
|
|
937
|
+
let g = theme ? 0 + ((85 - 0) / (5 - 1) * i) : 0 + ((255 - 0) / (5 - 1) * i);
|
|
938
|
+
let b = theme ? 0 + ((85 - 0) / (5 - 1) * i) : 0 + ((255 - 0) / (5 - 1) * i);
|
|
939
|
+
if (i <= iteration && theme === false) {
|
|
940
|
+
r = r + amplitude;
|
|
941
|
+
g = g + amplitude;
|
|
942
|
+
b = b + amplitude;
|
|
943
|
+
}
|
|
944
|
+
else if (theme === false) {
|
|
945
|
+
r = r - amplitude;
|
|
946
|
+
g = g - amplitude;
|
|
947
|
+
b = b - amplitude;
|
|
948
|
+
}
|
|
949
|
+
colorsReturn.push(`rgb(${r}, ${g},${b})`);
|
|
950
|
+
}
|
|
951
|
+
;
|
|
952
|
+
return colorsReturn;
|
|
953
|
+
}
|
|
954
|
+
;
|
|
955
|
+
applyTheme(palettes) {
|
|
956
|
+
if (typeof document === 'undefined')
|
|
957
|
+
return;
|
|
958
|
+
const root = document.documentElement;
|
|
959
|
+
const cssVars = [
|
|
960
|
+
{ prefix: '--primary-color-', index: 0 },
|
|
961
|
+
{ prefix: '--neutral-color-', index: 1 },
|
|
962
|
+
{ prefix: '--element-color-', index: 2 }
|
|
963
|
+
];
|
|
964
|
+
cssVars.forEach(({ prefix, index }) => {
|
|
965
|
+
palettes[index]?.forEach((color, i) => {
|
|
966
|
+
root.style.setProperty(`${prefix}${i}`, color);
|
|
967
|
+
});
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
hexToRgb(hex) {
|
|
971
|
+
const value = parseInt(hex.replace('#', ''), 16);
|
|
972
|
+
return {
|
|
973
|
+
red: (value >> 16) & 255,
|
|
974
|
+
green: (value >> 8) & 255,
|
|
975
|
+
blue: value & 255,
|
|
976
|
+
};
|
|
977
|
+
}
|
|
978
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Theming, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
979
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Theming, providedIn: 'root' });
|
|
980
|
+
}
|
|
981
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: Theming, decorators: [{
|
|
982
|
+
type: Injectable,
|
|
983
|
+
args: [{
|
|
984
|
+
providedIn: 'root'
|
|
985
|
+
}]
|
|
986
|
+
}] });
|
|
987
|
+
|
|
988
|
+
/*
|
|
989
|
+
* Public API Surface of catarina
|
|
990
|
+
*/
|
|
991
|
+
// design-system
|
|
992
|
+
|
|
993
|
+
/**
|
|
994
|
+
* Generated bundle index. Do not edit.
|
|
995
|
+
*/
|
|
996
|
+
|
|
997
|
+
export { Accordion, AccordionGroup, Button, Card, CatInput, ColorInput, DateInput, Dialog, Drag, FileInput, ICON_PROVIDER, Icon, PasswordInput, RangeInput, SelectInput, TextAreaInput, Theming, TimeInput };
|
|
998
|
+
//# sourceMappingURL=catarina.mjs.map
|