codexly-ui 0.1.21 → 0.1.22

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.
@@ -7,7 +7,7 @@ import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
7
7
  import { startWith, map, debounceTime, distinctUntilChanged, switchMap, of, catchError } from 'rxjs';
8
8
  import * as i1$1 from '@angular/cdk/overlay';
9
9
  import { ScrollStrategyOptions, OverlayModule } from '@angular/cdk/overlay';
10
- import { ScrollingModule } from '@angular/cdk/scrolling';
10
+ import { ScrollingModule, CdkScrollable } from '@angular/cdk/scrolling';
11
11
  import { Chart, LineController, BarController, PieController, DoughnutController, RadarController, PolarAreaController, CategoryScale, LinearScale, RadialLinearScale, BarElement, LineElement, PointElement, ArcElement, Filler, Tooltip, Legend } from 'chart.js';
12
12
  import { RouterLink, RouterLinkActive } from '@angular/router';
13
13
 
@@ -165,163 +165,6 @@ const BADGE_SHAPE_FIXED = {
165
165
  circle: 'rounded-full',
166
166
  };
167
167
 
168
- const CLX_FONT_CATALOG = [
169
- {
170
- label: 'Roboto',
171
- value: 'Roboto',
172
- googleUrl: 'https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap',
173
- },
174
- {
175
- label: 'Inter',
176
- value: 'Inter',
177
- googleUrl: 'https://fonts.googleapis.com/css2?family=Inter:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap',
178
- },
179
- {
180
- label: 'Poppins',
181
- value: 'Poppins',
182
- googleUrl: 'https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap',
183
- },
184
- {
185
- label: 'Plus Jakarta Sans',
186
- value: 'Plus Jakarta Sans',
187
- googleUrl: 'https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap',
188
- },
189
- {
190
- label: 'Nunito',
191
- value: 'Nunito',
192
- googleUrl: 'https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap',
193
- },
194
- {
195
- label: 'DM Sans',
196
- value: 'DM Sans',
197
- googleUrl: 'https://fonts.googleapis.com/css2?family=DM+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap',
198
- },
199
- {
200
- label: 'Geist',
201
- value: 'Geist',
202
- googleUrl: 'https://fonts.googleapis.com/css2?family=Geist:wght@300;400;500;600;700&display=swap',
203
- },
204
- {
205
- label: 'Lato',
206
- value: 'Lato',
207
- googleUrl: 'https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,300;0,400;0,700;1,300;1,400;1,700&display=swap',
208
- },
209
- {
210
- label: 'Montserrat',
211
- value: 'Montserrat',
212
- googleUrl: 'https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap',
213
- },
214
- {
215
- label: 'Open Sans',
216
- value: 'Open Sans',
217
- googleUrl: 'https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap',
218
- },
219
- {
220
- label: 'Work Sans',
221
- value: 'Work Sans',
222
- googleUrl: 'https://fonts.googleapis.com/css2?family=Work+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap',
223
- },
224
- {
225
- label: 'Manrope',
226
- value: 'Manrope',
227
- googleUrl: 'https://fonts.googleapis.com/css2?family=Manrope:wght@300;400;500;600;700&display=swap',
228
- },
229
- {
230
- label: 'Sora',
231
- value: 'Sora',
232
- googleUrl: 'https://fonts.googleapis.com/css2?family=Sora:wght@300;400;500;600;700&display=swap',
233
- },
234
- {
235
- label: 'Outfit',
236
- value: 'Outfit',
237
- googleUrl: 'https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap',
238
- },
239
- {
240
- label: 'Rubik',
241
- value: 'Rubik',
242
- googleUrl: 'https://fonts.googleapis.com/css2?family=Rubik:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap',
243
- },
244
- {
245
- label: 'Source Sans 3',
246
- value: 'Source Sans 3',
247
- googleUrl: 'https://fonts.googleapis.com/css2?family=Source+Sans+3:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap',
248
- },
249
- {
250
- label: 'Space Grotesk',
251
- value: 'Space Grotesk',
252
- googleUrl: 'https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap',
253
- },
254
- {
255
- label: 'Merriweather',
256
- value: 'Merriweather',
257
- googleUrl: 'https://fonts.googleapis.com/css2?family=Merriweather:ital,wght@0,300;0,400;0,700;0,900;1,300;1,400;1,700;1,900&display=swap',
258
- },
259
- {
260
- label: 'Playfair Display',
261
- value: 'Playfair Display',
262
- googleUrl: 'https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,500;0,600;0,700;0,800;0,900;1,400;1,500;1,600;1,700;1,800;1,900&display=swap',
263
- },
264
- {
265
- label: 'Lora',
266
- value: 'Lora',
267
- googleUrl: 'https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700&display=swap',
268
- },
269
- {
270
- label: 'PT Serif',
271
- value: 'PT Serif',
272
- googleUrl: 'https://fonts.googleapis.com/css2?family=PT+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap',
273
- },
274
- {
275
- label: 'Caveat',
276
- value: 'Caveat',
277
- googleUrl: 'https://fonts.googleapis.com/css2?family=Caveat:wght@400;500;600;700&display=swap',
278
- },
279
- {
280
- label: 'Dancing Script',
281
- value: 'Dancing Script',
282
- googleUrl: 'https://fonts.googleapis.com/css2?family=Dancing+Script:wght@400;500;600;700&display=swap',
283
- },
284
- {
285
- label: 'Cinzel',
286
- value: 'Cinzel',
287
- googleUrl: 'https://fonts.googleapis.com/css2?family=Cinzel:wght@400;500;600;700;800;900&display=swap',
288
- },
289
- {
290
- label: 'Berkshire Swash',
291
- value: 'Berkshire Swash',
292
- googleUrl: 'https://fonts.googleapis.com/css2?family=Berkshire+Swash&display=swap',
293
- },
294
- {
295
- label: 'JetBrains Mono',
296
- value: 'JetBrains Mono',
297
- googleUrl: 'https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700&display=swap',
298
- },
299
- {
300
- label: 'Orbitron',
301
- value: 'Orbitron',
302
- googleUrl: 'https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;600;700;800;900&display=swap',
303
- },
304
- {
305
- label: 'UnifrakturMaguntia',
306
- value: 'UnifrakturMaguntia',
307
- googleUrl: 'https://fonts.googleapis.com/css2?family=UnifrakturMaguntia&display=swap',
308
- },
309
- {
310
- label: 'Pirata One',
311
- value: 'Pirata One',
312
- googleUrl: 'https://fonts.googleapis.com/css2?family=Pirata+One&display=swap',
313
- },
314
- {
315
- label: 'Press Start 2P',
316
- value: 'Press Start 2P',
317
- googleUrl: 'https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap',
318
- },
319
- {
320
- label: 'Bungee',
321
- value: 'Bungee',
322
- googleUrl: 'https://fonts.googleapis.com/css2?family=Bungee&display=swap',
323
- },
324
- ];
325
168
  // ── Tailwind rounded classes per borderRadius token ───────────────────────────
326
169
  const CLX_RADIUS_MAP = {
327
170
  none: 'rounded-none',
@@ -351,16 +194,13 @@ function resolveContainerRadius(r) {
351
194
  // ── Default theme ─────────────────────────────────────────────────────────────
352
195
  const CLX_THEME_DEFAULTS = {
353
196
  primaryColor: 'indigo',
354
- secondaryColor: 'slate',
355
197
  dangerColor: 'red',
356
198
  successColor: 'green',
357
199
  warningColor: 'amber',
358
200
  neutralColor: 'slate',
359
- textColor: 'slate',
360
201
  borderRadius: 'md',
361
202
  defaultSize: 'md',
362
203
  defaultShape: 'rounded',
363
- fontFamily: 'Roboto',
364
204
  };
365
205
  // ── Injection token ───────────────────────────────────────────────────────────
366
206
  const CLX_THEME_CONFIG = new InjectionToken('CLX_THEME_CONFIG', { factory: () => CLX_THEME_DEFAULTS });
@@ -372,107 +212,7 @@ function provideCodexlyTheme(config) {
372
212
  };
373
213
  }
374
214
 
375
- // ── Full Tailwind v4 palette (hex), all colors × all shades ──────────────────
376
- // Source of truth: official Tailwind CSS v4 color values.
377
- const CLX_COLOR_PALETTE = {
378
- red: {
379
- 50: '#fef2f2', 100: '#fee2e2', 200: '#fecaca', 300: '#fca5a5', 400: '#f87171',
380
- 500: '#ef4444', 600: '#dc2626', 700: '#b91c1c', 800: '#991b1b', 900: '#7f1d1d', 950: '#450a0a',
381
- },
382
- orange: {
383
- 50: '#fff7ed', 100: '#ffedd5', 200: '#fed7aa', 300: '#fdba74', 400: '#fb923c',
384
- 500: '#f97316', 600: '#ea580c', 700: '#c2410c', 800: '#9a3412', 900: '#7c2d12', 950: '#431407',
385
- },
386
- amber: {
387
- 50: '#fffbeb', 100: '#fef3c7', 200: '#fde68a', 300: '#fcd34d', 400: '#fbbf24',
388
- 500: '#f59e0b', 600: '#d97706', 700: '#b45309', 800: '#92400e', 900: '#78350f', 950: '#451a03',
389
- },
390
- yellow: {
391
- 50: '#fefce8', 100: '#fef9c3', 200: '#fef08a', 300: '#fde047', 400: '#facc15',
392
- 500: '#eab308', 600: '#ca8a04', 700: '#a16207', 800: '#854d0e', 900: '#713f12', 950: '#422006',
393
- },
394
- lime: {
395
- 50: '#f7fee7', 100: '#ecfccb', 200: '#d9f99d', 300: '#bef264', 400: '#a3e635',
396
- 500: '#84cc16', 600: '#65a30d', 700: '#4d7c0f', 800: '#3f6212', 900: '#365314', 950: '#1a2e05',
397
- },
398
- green: {
399
- 50: '#f0fdf4', 100: '#dcfce7', 200: '#bbf7d0', 300: '#86efac', 400: '#4ade80',
400
- 500: '#22c55e', 600: '#16a34a', 700: '#15803d', 800: '#166534', 900: '#14532d', 950: '#052e16',
401
- },
402
- emerald: {
403
- 50: '#ecfdf5', 100: '#d1fae5', 200: '#a7f3d0', 300: '#6ee7b7', 400: '#34d399',
404
- 500: '#10b981', 600: '#059669', 700: '#047857', 800: '#065f46', 900: '#064e3b', 950: '#022c22',
405
- },
406
- teal: {
407
- 50: '#f0fdfa', 100: '#ccfbf1', 200: '#99f6e4', 300: '#5eead4', 400: '#2dd4bf',
408
- 500: '#14b8a6', 600: '#0d9488', 700: '#0f766e', 800: '#115e59', 900: '#134e4a', 950: '#042f2e',
409
- },
410
- cyan: {
411
- 50: '#ecfeff', 100: '#cffafe', 200: '#a5f3fc', 300: '#67e8f9', 400: '#22d3ee',
412
- 500: '#06b6d4', 600: '#0891b2', 700: '#0e7490', 800: '#155e75', 900: '#164e63', 950: '#083344',
413
- },
414
- sky: {
415
- 50: '#f0f9ff', 100: '#e0f2fe', 200: '#bae6fd', 300: '#7dd3fc', 400: '#38bdf8',
416
- 500: '#0ea5e9', 600: '#0284c7', 700: '#0369a1', 800: '#075985', 900: '#0c4a6e', 950: '#082f49',
417
- },
418
- blue: {
419
- 50: '#eff6ff', 100: '#dbeafe', 200: '#bfdbfe', 300: '#93c5fd', 400: '#60a5fa',
420
- 500: '#3b82f6', 600: '#2563eb', 700: '#1d4ed8', 800: '#1e40af', 900: '#1e3a8a', 950: '#172554',
421
- },
422
- indigo: {
423
- 50: '#eef2ff', 100: '#e0e7ff', 200: '#c7d2fe', 300: '#a5b4fc', 400: '#818cf8',
424
- 500: '#6366f1', 600: '#4f46e5', 700: '#4338ca', 800: '#3730a3', 900: '#312e81', 950: '#1e1b4b',
425
- },
426
- violet: {
427
- 50: '#f5f3ff', 100: '#ede9fe', 200: '#ddd6fe', 300: '#c4b5fd', 400: '#a78bfa',
428
- 500: '#8b5cf6', 600: '#7c3aed', 700: '#6d28d9', 800: '#5b21b6', 900: '#4c1d95', 950: '#2e1065',
429
- },
430
- purple: {
431
- 50: '#faf5ff', 100: '#f3e8ff', 200: '#e9d5ff', 300: '#d8b4fe', 400: '#c084fc',
432
- 500: '#a855f7', 600: '#9333ea', 700: '#7e22ce', 800: '#6b21a8', 900: '#581c87', 950: '#3b0764',
433
- },
434
- fuchsia: {
435
- 50: '#fdf4ff', 100: '#fae8ff', 200: '#f5d0fe', 300: '#f0abfc', 400: '#e879f9',
436
- 500: '#d946ef', 600: '#c026d3', 700: '#a21caf', 800: '#86198f', 900: '#701a75', 950: '#4a044e',
437
- },
438
- pink: {
439
- 50: '#fdf2f8', 100: '#fce7f3', 200: '#fbcfe8', 300: '#f9a8d4', 400: '#f472b6',
440
- 500: '#ec4899', 600: '#db2777', 700: '#be185d', 800: '#9d174d', 900: '#831843', 950: '#500724',
441
- },
442
- rose: {
443
- 50: '#fff1f2', 100: '#ffe4e6', 200: '#fecdd3', 300: '#fda4af', 400: '#fb7185',
444
- 500: '#f43f5e', 600: '#e11d48', 700: '#be123c', 800: '#9f1239', 900: '#881337', 950: '#4c0519',
445
- },
446
- slate: {
447
- 50: '#f8fafc', 100: '#f1f5f9', 200: '#e2e8f0', 300: '#cbd5e1', 400: '#94a3b8',
448
- 500: '#64748b', 600: '#475569', 700: '#334155', 800: '#1e293b', 900: '#0f172a', 950: '#020617',
449
- },
450
- gray: {
451
- 50: '#f9fafb', 100: '#f3f4f6', 200: '#e5e7eb', 300: '#d1d5db', 400: '#9ca3af',
452
- 500: '#6b7280', 600: '#4b5563', 700: '#374151', 800: '#1f2937', 900: '#111827', 950: '#030712',
453
- },
454
- zinc: {
455
- 50: '#fafafa', 100: '#f4f4f5', 200: '#e4e4e7', 300: '#d4d4d8', 400: '#a1a1aa',
456
- 500: '#71717a', 600: '#52525b', 700: '#3f3f46', 800: '#27272a', 900: '#18181b', 950: '#09090b',
457
- },
458
- neutral: {
459
- 50: '#fafafa', 100: '#f5f5f5', 200: '#e5e5e5', 300: '#d4d4d4', 400: '#a3a3a3',
460
- 500: '#737373', 600: '#525252', 700: '#404040', 800: '#262626', 900: '#171717', 950: '#0a0a0a',
461
- },
462
- stone: {
463
- 50: '#fafaf9', 100: '#f5f5f4', 200: '#e7e5e4', 300: '#d6d3d1', 400: '#a8a29e',
464
- 500: '#78716c', 600: '#57534e', 700: '#44403c', 800: '#292524', 900: '#1c1917', 950: '#0c0a09',
465
- },
466
- white: { 500: '#ffffff' },
467
- };
468
- /** Resolve a hex value for any Tailwind color + shade, with a safe fallback. */
469
- function resolvePaletteHex(color, shade) {
470
- const entry = CLX_COLOR_PALETTE[color] ?? CLX_COLOR_PALETTE.indigo;
471
- return entry[shade] ?? entry[500] ?? CLX_COLOR_PALETTE.indigo[500];
472
- }
473
-
474
215
  const STORAGE_KEY = 'clx-theme-mode';
475
- const FONT_LINK_ID = 'clx-google-font';
476
216
  class ClxThemeService {
477
217
  _isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
478
218
  _initial = inject(CLX_THEME_CONFIG);
@@ -489,12 +229,6 @@ class ClxThemeService {
489
229
  return false;
490
230
  return this._sysDark();
491
231
  }, ...(ngDevMode ? [{ debugName: "isDark" }] : /* istanbul ignore next */ []));
492
- /** Color to apply to clx-nav-group labels — falls back to neutralColor */
493
- sidebarGroupColor = computed(() => this._config().sidebarGroupColor ?? this._config().neutralColor, ...(ngDevMode ? [{ debugName: "sidebarGroupColor" }] : /* istanbul ignore next */ []));
494
- /** Color to apply to top-level clx-menu — falls back to primaryColor */
495
- sidebarMenuColor = computed(() => this._config().sidebarMenuColor ?? this._config().primaryColor, ...(ngDevMode ? [{ debugName: "sidebarMenuColor" }] : /* istanbul ignore next */ []));
496
- /** Color to apply to clx-menu-item — falls back to primaryColor */
497
- sidebarItemColor = computed(() => this._config().sidebarItemColor ?? this._config().primaryColor, ...(ngDevMode ? [{ debugName: "sidebarItemColor" }] : /* istanbul ignore next */ []));
498
232
  constructor() {
499
233
  effect(() => {
500
234
  if (!this._isBrowser)
@@ -504,15 +238,14 @@ class ClxThemeService {
504
238
  effect(() => {
505
239
  if (!this._isBrowser)
506
240
  return;
507
- const cfg = this._config();
508
- this._applyColorVar('--clx-primary', '--clx-primary-light', cfg.primaryColor);
509
- this._applyColorVar('--clx-secondary', '--clx-secondary-light', cfg.secondaryColor);
510
- this._applyTextColor(cfg.textColor, this.isDark());
511
- });
512
- effect(() => {
513
- if (!this._isBrowser)
241
+ const primaryColor = this._config().primaryColor;
242
+ if (!primaryColor)
514
243
  return;
515
- this._applyFont(this._config().fontFamily ?? 'Roboto');
244
+ const { color } = parseColorInput(primaryColor);
245
+ const hex500 = CLX_COLOR_HEX[color] ?? CLX_COLOR_HEX.indigo;
246
+ const hex100 = CLX_COLOR_HEX_100[color] ?? CLX_COLOR_HEX_100.indigo;
247
+ document.documentElement.style.setProperty('--clx-primary', hex500);
248
+ document.documentElement.style.setProperty('--clx-primary-light', hex100);
516
249
  });
517
250
  if (this._isBrowser) {
518
251
  const mq = window.matchMedia('(prefers-color-scheme: dark)');
@@ -530,42 +263,6 @@ class ClxThemeService {
530
263
  toggle() {
531
264
  this.setMode(this.isDark() ? 'light' : 'dark');
532
265
  }
533
- _applyColorVar(varName, lightVarName, input) {
534
- if (!input)
535
- return;
536
- const { color, shade } = parseColorInput(input);
537
- document.documentElement.style.setProperty(varName, resolvePaletteHex(color, shade));
538
- if (lightVarName) {
539
- document.documentElement.style.setProperty(lightVarName, resolvePaletteHex(color, 100));
540
- }
541
- }
542
- _applyTextColor(input, dark) {
543
- if (!input)
544
- return;
545
- const { color } = parseColorInput(input);
546
- const shades = dark
547
- ? { text: 100, label: 300, muted: 400, subtle: 500, faint: 600 }
548
- : { text: 900, label: 600, muted: 500, subtle: 400, faint: 300 };
549
- document.documentElement.style.setProperty('--clx-text', resolvePaletteHex(color, shades.text));
550
- document.documentElement.style.setProperty('--clx-text-label', resolvePaletteHex(color, shades.label));
551
- document.documentElement.style.setProperty('--clx-text-muted', resolvePaletteHex(color, shades.muted));
552
- document.documentElement.style.setProperty('--clx-text-subtle', resolvePaletteHex(color, shades.subtle));
553
- document.documentElement.style.setProperty('--clx-text-faint', resolvePaletteHex(color, shades.faint));
554
- }
555
- _applyFont(family) {
556
- const option = CLX_FONT_CATALOG.find(f => f.value === family);
557
- if (!option)
558
- return;
559
- let link = document.getElementById(FONT_LINK_ID);
560
- if (!link) {
561
- link = document.createElement('link');
562
- link.id = FONT_LINK_ID;
563
- link.rel = 'stylesheet';
564
- document.head.appendChild(link);
565
- }
566
- link.href = option.googleUrl;
567
- document.documentElement.style.setProperty('--clx-font-body', `'${family}', ui-sans-serif, system-ui, sans-serif`);
568
- }
569
266
  _loadMode() {
570
267
  if (!this._isBrowser)
571
268
  return 'system';
@@ -2938,7 +2635,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
2938
2635
  const CLX_LIST_CONTEXT = new InjectionToken('CLX_LIST_CONTEXT');
2939
2636
  // ── Variant maps ──────────────────────────────────────────────────────────────
2940
2637
  const LIST_VARIANT_SHAPE = {
2941
- bordered: 'bg-clx-surface rounded-2xl overflow-hidden border border-clx-border',
2638
+ bordered: 'bg-white rounded-2xl overflow-hidden',
2942
2639
  flat: 'bg-transparent',
2943
2640
  flush: 'bg-transparent',
2944
2641
  };
@@ -4144,7 +3841,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
4144
3841
 
4145
3842
  const INPUT_STATUS_MAP = {
4146
3843
  default: {
4147
- border: 'border-clx-border',
3844
+ border: 'border-slate-200',
4148
3845
  ring: '',
4149
3846
  msgCls: '',
4150
3847
  iconName: '',
@@ -4557,18 +4254,11 @@ class ClxSelectComponent {
4557
4254
  _activeColor = computed(() => this.activeColor() ?? this._themeSvc.config().primaryColor, ...(ngDevMode ? [{ debugName: "_activeColor" }] : /* istanbul ignore next */ []));
4558
4255
  _el = inject((ElementRef));
4559
4256
  _sso = inject(ScrollStrategyOptions);
4560
- _isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
4561
- _loadedFonts = new Set();
4562
4257
  _scrollStrategy = this._sso.reposition();
4563
4258
  constructor() {
4564
4259
  this._searchQuery = toSignal(this._searchControl.valueChanges.pipe(startWith(''), map(v => v ?? '')), { initialValue: '' });
4565
4260
  if (this._ngControl)
4566
4261
  this._ngControl.valueAccessor = this;
4567
- effect(() => {
4568
- const family = this._displayFontFamily();
4569
- if (family)
4570
- this._loadPreviewFont(family);
4571
- });
4572
4262
  // Async autocomplete: debounce + switchMap sobre el search control
4573
4263
  this._searchControl.valueChanges.pipe(debounceTime(this.debounceMs()), distinctUntilChanged(), switchMap(query => {
4574
4264
  const q = query ?? '';
@@ -4616,10 +4306,6 @@ class ClxSelectComponent {
4616
4306
  const sel = this._selectedOptions();
4617
4307
  return sel.length ? sel[0].label : this.placeholder();
4618
4308
  }, ...(ngDevMode ? [{ debugName: "_displayValue" }] : /* istanbul ignore next */ []));
4619
- _displayFontFamily = computed(() => {
4620
- const sel = this._selectedOptions();
4621
- return sel.length ? sel[0].previewFontFamily ?? null : null;
4622
- }, ...(ngDevMode ? [{ debugName: "_displayFontFamily" }] : /* istanbul ignore next */ []));
4623
4309
  _overlayWidth = computed(() => this._overlayWidthPx(), ...(ngDevMode ? [{ debugName: "_overlayWidth" }] : /* istanbul ignore next */ []));
4624
4310
  _labelClass = computed(() => `${this._sizeConfig().label} ${CLX_TEXT_LABEL} leading-none`, ...(ngDevMode ? [{ debugName: "_labelClass" }] : /* istanbul ignore next */ []));
4625
4311
  _hintClass = computed(() => `${this._sizeConfig().hint} ${CLX_TEXT_HINT}`, ...(ngDevMode ? [{ debugName: "_hintClass" }] : /* istanbul ignore next */ []));
@@ -4670,26 +4356,6 @@ class ClxSelectComponent {
4670
4356
  if (!this.async())
4671
4357
  this._searchControl.setValue('', { emitEvent: false });
4672
4358
  this._isOpen.set(true);
4673
- for (const opt of this.options()) {
4674
- if (opt.previewFontFamily)
4675
- this._loadPreviewFont(opt.previewFontFamily);
4676
- }
4677
- }
4678
- _loadPreviewFont(family) {
4679
- if (!this._isBrowser || this._loadedFonts.has(family))
4680
- return;
4681
- const option = CLX_FONT_CATALOG.find(f => f.value === family);
4682
- if (!option)
4683
- return;
4684
- this._loadedFonts.add(family);
4685
- const id = `clx-preview-font-${family.replace(/\s+/g, '-').toLowerCase()}`;
4686
- if (document.getElementById(id))
4687
- return;
4688
- const link = document.createElement('link');
4689
- link.id = id;
4690
- link.rel = 'stylesheet';
4691
- link.href = option.googleUrl;
4692
- document.head.appendChild(link);
4693
4359
  }
4694
4360
  _closePanel() {
4695
4361
  this._isOpen.set(false);
@@ -4761,145 +4427,145 @@ class ClxSelectComponent {
4761
4427
  this._cvaDisabled.set(disabled);
4762
4428
  }
4763
4429
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4764
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxSelectComponent, isStandalone: true, selector: "clx-select", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, activeColor: { classPropertyName: "activeColor", publicName: "activeColor", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, async: { classPropertyName: "async", publicName: "async", isSignal: true, isRequired: false, transformFunction: null }, loadOptions: { classPropertyName: "loadOptions", publicName: "loadOptions", isSignal: true, isRequired: false, transformFunction: null }, debounceMs: { classPropertyName: "debounceMs", publicName: "debounceMs", isSignal: true, isRequired: false, transformFunction: null }, minChars: { classPropertyName: "minChars", publicName: "minChars", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "keydown.escape": "onEscape()" }, classAttribute: "flex flex-col gap-1.5 w-full" }, ngImport: i0, template: `
4765
- @if (label()) {
4766
- <span [id]="_labelId" [class]="_labelClass()">{{ label() }}</span>
4767
- }
4768
-
4769
- <!-- ── Trigger ─────────────────────────────────────────────────────────── -->
4770
- <div
4771
- #origin="cdkOverlayOrigin"
4772
- cdkOverlayOrigin
4773
- [class]="_triggerClass()"
4774
- [attr.tabindex]="_disabled() ? null : '0'"
4775
- role="combobox"
4776
- [attr.aria-labelledby]="label() ? _labelId : null"
4777
- [attr.aria-expanded]="_isOpen()"
4778
- aria-haspopup="listbox"
4779
- (click)="!_disabled() && _togglePanel()"
4780
- (keydown)="_onTriggerKeydown($event)">
4781
-
4782
- <!-- Multi mode: tag chips -->
4783
- @if (multiple()) {
4784
- <div [class]="_tagContainerClass()">
4785
- @for (opt of _selectedOptions(); track opt.value) {
4786
- <span
4787
- clx-tag
4788
- variant="soft"
4789
- [color]="_activeColor()"
4790
- [size]="_sizeConfig().tagSize"
4791
- (onRemove)="_deselect(opt.value)">
4792
- {{ opt.label }}
4793
- </span>
4794
- }
4795
- @if (!_selectedOptions().length) {
4796
- <span [class]="_placeholderClass()">{{ placeholder() }}</span>
4797
- }
4798
- </div>
4799
-
4800
- <!-- Single mode: display value -->
4801
- } @else {
4802
- <span [class]="_singleDisplayClass()" [style.font-family]="_displayFontFamily()">{{ _displayValue() }}</span>
4803
- }
4804
-
4805
- <!-- Right controls: clear + chevron -->
4806
- <div class="absolute right-2 top-1/2 -translate-y-1/2 flex items-center gap-0.5">
4807
- @if (_hasValue() && !_disabled() && multiple()) {
4808
- <button
4809
- clx-button
4810
- variant="ghost"
4811
- [color]="_activeColor()"
4812
- shape="circle"
4813
- [size]="_sizeConfig().btnSize"
4814
- icon="close"
4815
- [iconOnly]="true"
4816
- (mousedown)="$event.preventDefault()"
4817
- (click)="$event.stopPropagation(); _clearAll()">
4818
- </button>
4819
- }
4820
- <button
4821
- clx-button
4822
- variant="ghost"
4823
- [color]="_activeColor()"
4824
- shape="circle"
4825
- [size]="_sizeConfig().btnSize"
4826
- icon="keyboard_arrow_down"
4827
- [iconOnly]="true"
4828
- [class]="_chevronBtnClass()"
4829
- (mousedown)="$event.preventDefault()">
4830
- </button>
4831
- </div>
4832
- </div>
4833
-
4834
- <!-- ── Overlay panel ───────────────────────────────────────────────────── -->
4835
- <ng-template
4836
- cdkConnectedOverlay
4837
- [cdkConnectedOverlayOrigin]="origin"
4838
- [cdkConnectedOverlayOpen]="_isOpen()"
4839
- [cdkConnectedOverlayPositions]="_positions"
4840
- [cdkConnectedOverlayScrollStrategy]="_scrollStrategy"
4841
- [cdkConnectedOverlayWidth]="_overlayWidth()"
4842
- [cdkConnectedOverlayPush]="true"
4843
- (overlayOutsideClick)="_closePanel()"
4844
- (overlayKeydown)="_onOverlayKeydown($event)">
4845
-
4846
- <div [class]="_panelClass()" role="listbox">
4847
-
4848
- <!-- Search / Autocomplete input -->
4849
- @if (searchable() || async()) {
4850
- <div class="p-2 border-b border-clx-border-soft" (click)="$event.stopPropagation()">
4851
- <clx-input
4852
- [formControl]="_searchControl"
4853
- [placeholder]="async() ? 'Buscar...' : searchPlaceholder()"
4854
- [color]="_activeColor()"
4855
- [suffixIcon]="async() && _asyncLoading() ? '' : 'search'"
4856
- size="sm">
4857
- </clx-input>
4858
- </div>
4859
- }
4860
-
4861
- <!-- Options list -->
4862
- <div class="overflow-y-auto max-h-60 p-1 space-y-0.5">
4863
- @if (async() && _asyncLoading()) {
4864
- <div class="flex items-center justify-center py-6 gap-2 text-sm text-clx-text-subtle">
4865
- <clx-spinner size="sm" [color]="_activeColor()" />
4866
- Buscando...
4867
- </div>
4868
- } @else if (_showAsyncPlaceholder()) {
4869
- <div class="px-3 py-4 text-center text-sm text-clx-text-subtle">
4870
- Escribe {{ minChars() === 1 ? 'al menos 1 carácter' : 'al menos ' + minChars() + ' caracteres' }}
4871
- </div>
4872
- } @else if (_filteredOptions().length === 0) {
4873
- <div class="px-3 py-4 text-center text-sm text-clx-text-subtle">Sin resultados</div>
4874
- } @else {
4875
- @for (opt of _filteredOptions(); track opt.value) {
4876
- <button
4877
- type="button"
4878
- [class]="_optionClass(opt)"
4879
- [disabled]="opt.disabled ?? false"
4880
- (mousedown)="$event.preventDefault()"
4881
- (click)="_selectOption(opt)">
4882
- <span class="flex-1 text-left truncate" [style.font-family]="opt.previewFontFamily ?? null">{{ opt.label }}</span>
4883
- @if (_isSelected(opt.value)) {
4884
- <span clx-icon name="check" size="xs" class="shrink-0"></span>
4885
- }
4886
- </button>
4887
- }
4888
- }
4889
- </div>
4890
-
4891
- </div>
4892
- </ng-template>
4893
-
4894
- <!-- ── Bottom message ─────────────────────────────────────────────────── -->
4895
- @if (_isInvalid()) {
4896
- <p class="text-xs text-red-500 flex items-center gap-1">
4897
- <span clx-icon name="error" size="xs"></span>
4898
- {{ errorMessage() }}
4899
- </p>
4900
- } @else if (hint()) {
4901
- <p [class]="_hintClass()">{{ hint() }}</p>
4902
- }
4430
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxSelectComponent, isStandalone: true, selector: "clx-select", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, activeColor: { classPropertyName: "activeColor", publicName: "activeColor", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, async: { classPropertyName: "async", publicName: "async", isSignal: true, isRequired: false, transformFunction: null }, loadOptions: { classPropertyName: "loadOptions", publicName: "loadOptions", isSignal: true, isRequired: false, transformFunction: null }, debounceMs: { classPropertyName: "debounceMs", publicName: "debounceMs", isSignal: true, isRequired: false, transformFunction: null }, minChars: { classPropertyName: "minChars", publicName: "minChars", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "keydown.escape": "onEscape()" }, classAttribute: "flex flex-col gap-1.5 w-full" }, ngImport: i0, template: `
4431
+ @if (label()) {
4432
+ <span [id]="_labelId" [class]="_labelClass()">{{ label() }}</span>
4433
+ }
4434
+
4435
+ <!-- ── Trigger ─────────────────────────────────────────────────────────── -->
4436
+ <div
4437
+ #origin="cdkOverlayOrigin"
4438
+ cdkOverlayOrigin
4439
+ [class]="_triggerClass()"
4440
+ [attr.tabindex]="_disabled() ? null : '0'"
4441
+ role="combobox"
4442
+ [attr.aria-labelledby]="label() ? _labelId : null"
4443
+ [attr.aria-expanded]="_isOpen()"
4444
+ aria-haspopup="listbox"
4445
+ (click)="!_disabled() && _togglePanel()"
4446
+ (keydown)="_onTriggerKeydown($event)">
4447
+
4448
+ <!-- Multi mode: tag chips -->
4449
+ @if (multiple()) {
4450
+ <div [class]="_tagContainerClass()">
4451
+ @for (opt of _selectedOptions(); track opt.value) {
4452
+ <span
4453
+ clx-tag
4454
+ variant="soft"
4455
+ [color]="_activeColor()"
4456
+ [size]="_sizeConfig().tagSize"
4457
+ (onRemove)="_deselect(opt.value)">
4458
+ {{ opt.label }}
4459
+ </span>
4460
+ }
4461
+ @if (!_selectedOptions().length) {
4462
+ <span [class]="_placeholderClass()">{{ placeholder() }}</span>
4463
+ }
4464
+ </div>
4465
+
4466
+ <!-- Single mode: display value -->
4467
+ } @else {
4468
+ <span [class]="_singleDisplayClass()">{{ _displayValue() }}</span>
4469
+ }
4470
+
4471
+ <!-- Right controls: clear + chevron -->
4472
+ <div class="absolute right-2 top-1/2 -translate-y-1/2 flex items-center gap-0.5">
4473
+ @if (_hasValue() && !_disabled() && multiple()) {
4474
+ <button
4475
+ clx-button
4476
+ variant="ghost"
4477
+ [color]="_activeColor()"
4478
+ shape="circle"
4479
+ [size]="_sizeConfig().btnSize"
4480
+ icon="close"
4481
+ [iconOnly]="true"
4482
+ (mousedown)="$event.preventDefault()"
4483
+ (click)="$event.stopPropagation(); _clearAll()">
4484
+ </button>
4485
+ }
4486
+ <button
4487
+ clx-button
4488
+ variant="ghost"
4489
+ [color]="_activeColor()"
4490
+ shape="circle"
4491
+ [size]="_sizeConfig().btnSize"
4492
+ icon="keyboard_arrow_down"
4493
+ [iconOnly]="true"
4494
+ [class]="_chevronBtnClass()"
4495
+ (mousedown)="$event.preventDefault()">
4496
+ </button>
4497
+ </div>
4498
+ </div>
4499
+
4500
+ <!-- ── Overlay panel ───────────────────────────────────────────────────── -->
4501
+ <ng-template
4502
+ cdkConnectedOverlay
4503
+ [cdkConnectedOverlayOrigin]="origin"
4504
+ [cdkConnectedOverlayOpen]="_isOpen()"
4505
+ [cdkConnectedOverlayPositions]="_positions"
4506
+ [cdkConnectedOverlayScrollStrategy]="_scrollStrategy"
4507
+ [cdkConnectedOverlayWidth]="_overlayWidth()"
4508
+ [cdkConnectedOverlayPush]="true"
4509
+ (overlayOutsideClick)="_closePanel()"
4510
+ (overlayKeydown)="_onOverlayKeydown($event)">
4511
+
4512
+ <div [class]="_panelClass()" role="listbox">
4513
+
4514
+ <!-- Search / Autocomplete input -->
4515
+ @if (searchable() || async()) {
4516
+ <div class="p-2 border-b border-clx-border-soft" (click)="$event.stopPropagation()">
4517
+ <clx-input
4518
+ [formControl]="_searchControl"
4519
+ [placeholder]="async() ? 'Buscar...' : searchPlaceholder()"
4520
+ [color]="_activeColor()"
4521
+ [suffixIcon]="async() && _asyncLoading() ? '' : 'search'"
4522
+ size="sm">
4523
+ </clx-input>
4524
+ </div>
4525
+ }
4526
+
4527
+ <!-- Options list -->
4528
+ <div class="overflow-y-auto max-h-60 p-1 space-y-0.5">
4529
+ @if (async() && _asyncLoading()) {
4530
+ <div class="flex items-center justify-center py-6 gap-2 text-sm text-clx-text-subtle">
4531
+ <clx-spinner size="sm" [color]="_activeColor()" />
4532
+ Buscando...
4533
+ </div>
4534
+ } @else if (_showAsyncPlaceholder()) {
4535
+ <div class="px-3 py-4 text-center text-sm text-clx-text-subtle">
4536
+ Escribe {{ minChars() === 1 ? 'al menos 1 carácter' : 'al menos ' + minChars() + ' caracteres' }}
4537
+ </div>
4538
+ } @else if (_filteredOptions().length === 0) {
4539
+ <div class="px-3 py-4 text-center text-sm text-clx-text-subtle">Sin resultados</div>
4540
+ } @else {
4541
+ @for (opt of _filteredOptions(); track opt.value) {
4542
+ <button
4543
+ type="button"
4544
+ [class]="_optionClass(opt)"
4545
+ [disabled]="opt.disabled ?? false"
4546
+ (mousedown)="$event.preventDefault()"
4547
+ (click)="_selectOption(opt)">
4548
+ <span class="flex-1 text-left truncate">{{ opt.label }}</span>
4549
+ @if (_isSelected(opt.value)) {
4550
+ <span clx-icon name="check" size="xs" class="shrink-0"></span>
4551
+ }
4552
+ </button>
4553
+ }
4554
+ }
4555
+ </div>
4556
+
4557
+ </div>
4558
+ </ng-template>
4559
+
4560
+ <!-- ── Bottom message ─────────────────────────────────────────────────── -->
4561
+ @if (_isInvalid()) {
4562
+ <p class="text-xs text-red-500 flex items-center gap-1">
4563
+ <span clx-icon name="error" size="xs"></span>
4564
+ {{ errorMessage() }}
4565
+ </p>
4566
+ } @else if (hint()) {
4567
+ <p [class]="_hintClass()">{{ hint() }}</p>
4568
+ }
4903
4569
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: ClxTagComponent, selector: "span[clx-tag]", inputs: ["variant", "color", "size", "shape"], outputs: ["onRemove"] }, { kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "component", type: ClxButtonComponent, selector: "button[clx-button], a[clx-button]", inputs: ["variant", "color", "size", "shape", "loading", "disabled", "block", "icon", "iconPosition", "iconOnly", "badge", "badgeColor"] }, { kind: "component", type: ClxInputComponent, selector: "clx-input", inputs: ["label", "placeholder", "type", "color", "hint", "prefixIcon", "suffixIcon", "prefixText", "suffixText", "status", "statusMessage", "size", "value", "disabled", "autocomplete"] }, { kind: "component", type: ClxSpinnerComponent, selector: "clx-spinner", inputs: ["size", "color", "variant"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
4904
4570
  }
4905
4571
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxSelectComponent, decorators: [{
@@ -4908,145 +4574,145 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
4908
4574
  selector: 'clx-select',
4909
4575
  standalone: true,
4910
4576
  imports: [OverlayModule, ReactiveFormsModule, ClxTagComponent, ClxIconComponent, ClxButtonComponent, ClxInputComponent, ClxSpinnerComponent],
4911
- template: `
4912
- @if (label()) {
4913
- <span [id]="_labelId" [class]="_labelClass()">{{ label() }}</span>
4914
- }
4915
-
4916
- <!-- ── Trigger ─────────────────────────────────────────────────────────── -->
4917
- <div
4918
- #origin="cdkOverlayOrigin"
4919
- cdkOverlayOrigin
4920
- [class]="_triggerClass()"
4921
- [attr.tabindex]="_disabled() ? null : '0'"
4922
- role="combobox"
4923
- [attr.aria-labelledby]="label() ? _labelId : null"
4924
- [attr.aria-expanded]="_isOpen()"
4925
- aria-haspopup="listbox"
4926
- (click)="!_disabled() && _togglePanel()"
4927
- (keydown)="_onTriggerKeydown($event)">
4928
-
4929
- <!-- Multi mode: tag chips -->
4930
- @if (multiple()) {
4931
- <div [class]="_tagContainerClass()">
4932
- @for (opt of _selectedOptions(); track opt.value) {
4933
- <span
4934
- clx-tag
4935
- variant="soft"
4936
- [color]="_activeColor()"
4937
- [size]="_sizeConfig().tagSize"
4938
- (onRemove)="_deselect(opt.value)">
4939
- {{ opt.label }}
4940
- </span>
4941
- }
4942
- @if (!_selectedOptions().length) {
4943
- <span [class]="_placeholderClass()">{{ placeholder() }}</span>
4944
- }
4945
- </div>
4946
-
4947
- <!-- Single mode: display value -->
4948
- } @else {
4949
- <span [class]="_singleDisplayClass()" [style.font-family]="_displayFontFamily()">{{ _displayValue() }}</span>
4950
- }
4951
-
4952
- <!-- Right controls: clear + chevron -->
4953
- <div class="absolute right-2 top-1/2 -translate-y-1/2 flex items-center gap-0.5">
4954
- @if (_hasValue() && !_disabled() && multiple()) {
4955
- <button
4956
- clx-button
4957
- variant="ghost"
4958
- [color]="_activeColor()"
4959
- shape="circle"
4960
- [size]="_sizeConfig().btnSize"
4961
- icon="close"
4962
- [iconOnly]="true"
4963
- (mousedown)="$event.preventDefault()"
4964
- (click)="$event.stopPropagation(); _clearAll()">
4965
- </button>
4966
- }
4967
- <button
4968
- clx-button
4969
- variant="ghost"
4970
- [color]="_activeColor()"
4971
- shape="circle"
4972
- [size]="_sizeConfig().btnSize"
4973
- icon="keyboard_arrow_down"
4974
- [iconOnly]="true"
4975
- [class]="_chevronBtnClass()"
4976
- (mousedown)="$event.preventDefault()">
4977
- </button>
4978
- </div>
4979
- </div>
4980
-
4981
- <!-- ── Overlay panel ───────────────────────────────────────────────────── -->
4982
- <ng-template
4983
- cdkConnectedOverlay
4984
- [cdkConnectedOverlayOrigin]="origin"
4985
- [cdkConnectedOverlayOpen]="_isOpen()"
4986
- [cdkConnectedOverlayPositions]="_positions"
4987
- [cdkConnectedOverlayScrollStrategy]="_scrollStrategy"
4988
- [cdkConnectedOverlayWidth]="_overlayWidth()"
4989
- [cdkConnectedOverlayPush]="true"
4990
- (overlayOutsideClick)="_closePanel()"
4991
- (overlayKeydown)="_onOverlayKeydown($event)">
4992
-
4993
- <div [class]="_panelClass()" role="listbox">
4994
-
4995
- <!-- Search / Autocomplete input -->
4996
- @if (searchable() || async()) {
4997
- <div class="p-2 border-b border-clx-border-soft" (click)="$event.stopPropagation()">
4998
- <clx-input
4999
- [formControl]="_searchControl"
5000
- [placeholder]="async() ? 'Buscar...' : searchPlaceholder()"
5001
- [color]="_activeColor()"
5002
- [suffixIcon]="async() && _asyncLoading() ? '' : 'search'"
5003
- size="sm">
5004
- </clx-input>
5005
- </div>
5006
- }
5007
-
5008
- <!-- Options list -->
5009
- <div class="overflow-y-auto max-h-60 p-1 space-y-0.5">
5010
- @if (async() && _asyncLoading()) {
5011
- <div class="flex items-center justify-center py-6 gap-2 text-sm text-clx-text-subtle">
5012
- <clx-spinner size="sm" [color]="_activeColor()" />
5013
- Buscando...
5014
- </div>
5015
- } @else if (_showAsyncPlaceholder()) {
5016
- <div class="px-3 py-4 text-center text-sm text-clx-text-subtle">
5017
- Escribe {{ minChars() === 1 ? 'al menos 1 carácter' : 'al menos ' + minChars() + ' caracteres' }}
5018
- </div>
5019
- } @else if (_filteredOptions().length === 0) {
5020
- <div class="px-3 py-4 text-center text-sm text-clx-text-subtle">Sin resultados</div>
5021
- } @else {
5022
- @for (opt of _filteredOptions(); track opt.value) {
5023
- <button
5024
- type="button"
5025
- [class]="_optionClass(opt)"
5026
- [disabled]="opt.disabled ?? false"
5027
- (mousedown)="$event.preventDefault()"
5028
- (click)="_selectOption(opt)">
5029
- <span class="flex-1 text-left truncate" [style.font-family]="opt.previewFontFamily ?? null">{{ opt.label }}</span>
5030
- @if (_isSelected(opt.value)) {
5031
- <span clx-icon name="check" size="xs" class="shrink-0"></span>
5032
- }
5033
- </button>
5034
- }
5035
- }
5036
- </div>
5037
-
5038
- </div>
5039
- </ng-template>
5040
-
5041
- <!-- ── Bottom message ─────────────────────────────────────────────────── -->
5042
- @if (_isInvalid()) {
5043
- <p class="text-xs text-red-500 flex items-center gap-1">
5044
- <span clx-icon name="error" size="xs"></span>
5045
- {{ errorMessage() }}
5046
- </p>
5047
- } @else if (hint()) {
5048
- <p [class]="_hintClass()">{{ hint() }}</p>
5049
- }
4577
+ template: `
4578
+ @if (label()) {
4579
+ <span [id]="_labelId" [class]="_labelClass()">{{ label() }}</span>
4580
+ }
4581
+
4582
+ <!-- ── Trigger ─────────────────────────────────────────────────────────── -->
4583
+ <div
4584
+ #origin="cdkOverlayOrigin"
4585
+ cdkOverlayOrigin
4586
+ [class]="_triggerClass()"
4587
+ [attr.tabindex]="_disabled() ? null : '0'"
4588
+ role="combobox"
4589
+ [attr.aria-labelledby]="label() ? _labelId : null"
4590
+ [attr.aria-expanded]="_isOpen()"
4591
+ aria-haspopup="listbox"
4592
+ (click)="!_disabled() && _togglePanel()"
4593
+ (keydown)="_onTriggerKeydown($event)">
4594
+
4595
+ <!-- Multi mode: tag chips -->
4596
+ @if (multiple()) {
4597
+ <div [class]="_tagContainerClass()">
4598
+ @for (opt of _selectedOptions(); track opt.value) {
4599
+ <span
4600
+ clx-tag
4601
+ variant="soft"
4602
+ [color]="_activeColor()"
4603
+ [size]="_sizeConfig().tagSize"
4604
+ (onRemove)="_deselect(opt.value)">
4605
+ {{ opt.label }}
4606
+ </span>
4607
+ }
4608
+ @if (!_selectedOptions().length) {
4609
+ <span [class]="_placeholderClass()">{{ placeholder() }}</span>
4610
+ }
4611
+ </div>
4612
+
4613
+ <!-- Single mode: display value -->
4614
+ } @else {
4615
+ <span [class]="_singleDisplayClass()">{{ _displayValue() }}</span>
4616
+ }
4617
+
4618
+ <!-- Right controls: clear + chevron -->
4619
+ <div class="absolute right-2 top-1/2 -translate-y-1/2 flex items-center gap-0.5">
4620
+ @if (_hasValue() && !_disabled() && multiple()) {
4621
+ <button
4622
+ clx-button
4623
+ variant="ghost"
4624
+ [color]="_activeColor()"
4625
+ shape="circle"
4626
+ [size]="_sizeConfig().btnSize"
4627
+ icon="close"
4628
+ [iconOnly]="true"
4629
+ (mousedown)="$event.preventDefault()"
4630
+ (click)="$event.stopPropagation(); _clearAll()">
4631
+ </button>
4632
+ }
4633
+ <button
4634
+ clx-button
4635
+ variant="ghost"
4636
+ [color]="_activeColor()"
4637
+ shape="circle"
4638
+ [size]="_sizeConfig().btnSize"
4639
+ icon="keyboard_arrow_down"
4640
+ [iconOnly]="true"
4641
+ [class]="_chevronBtnClass()"
4642
+ (mousedown)="$event.preventDefault()">
4643
+ </button>
4644
+ </div>
4645
+ </div>
4646
+
4647
+ <!-- ── Overlay panel ───────────────────────────────────────────────────── -->
4648
+ <ng-template
4649
+ cdkConnectedOverlay
4650
+ [cdkConnectedOverlayOrigin]="origin"
4651
+ [cdkConnectedOverlayOpen]="_isOpen()"
4652
+ [cdkConnectedOverlayPositions]="_positions"
4653
+ [cdkConnectedOverlayScrollStrategy]="_scrollStrategy"
4654
+ [cdkConnectedOverlayWidth]="_overlayWidth()"
4655
+ [cdkConnectedOverlayPush]="true"
4656
+ (overlayOutsideClick)="_closePanel()"
4657
+ (overlayKeydown)="_onOverlayKeydown($event)">
4658
+
4659
+ <div [class]="_panelClass()" role="listbox">
4660
+
4661
+ <!-- Search / Autocomplete input -->
4662
+ @if (searchable() || async()) {
4663
+ <div class="p-2 border-b border-clx-border-soft" (click)="$event.stopPropagation()">
4664
+ <clx-input
4665
+ [formControl]="_searchControl"
4666
+ [placeholder]="async() ? 'Buscar...' : searchPlaceholder()"
4667
+ [color]="_activeColor()"
4668
+ [suffixIcon]="async() && _asyncLoading() ? '' : 'search'"
4669
+ size="sm">
4670
+ </clx-input>
4671
+ </div>
4672
+ }
4673
+
4674
+ <!-- Options list -->
4675
+ <div class="overflow-y-auto max-h-60 p-1 space-y-0.5">
4676
+ @if (async() && _asyncLoading()) {
4677
+ <div class="flex items-center justify-center py-6 gap-2 text-sm text-clx-text-subtle">
4678
+ <clx-spinner size="sm" [color]="_activeColor()" />
4679
+ Buscando...
4680
+ </div>
4681
+ } @else if (_showAsyncPlaceholder()) {
4682
+ <div class="px-3 py-4 text-center text-sm text-clx-text-subtle">
4683
+ Escribe {{ minChars() === 1 ? 'al menos 1 carácter' : 'al menos ' + minChars() + ' caracteres' }}
4684
+ </div>
4685
+ } @else if (_filteredOptions().length === 0) {
4686
+ <div class="px-3 py-4 text-center text-sm text-clx-text-subtle">Sin resultados</div>
4687
+ } @else {
4688
+ @for (opt of _filteredOptions(); track opt.value) {
4689
+ <button
4690
+ type="button"
4691
+ [class]="_optionClass(opt)"
4692
+ [disabled]="opt.disabled ?? false"
4693
+ (mousedown)="$event.preventDefault()"
4694
+ (click)="_selectOption(opt)">
4695
+ <span class="flex-1 text-left truncate">{{ opt.label }}</span>
4696
+ @if (_isSelected(opt.value)) {
4697
+ <span clx-icon name="check" size="xs" class="shrink-0"></span>
4698
+ }
4699
+ </button>
4700
+ }
4701
+ }
4702
+ </div>
4703
+
4704
+ </div>
4705
+ </ng-template>
4706
+
4707
+ <!-- ── Bottom message ─────────────────────────────────────────────────── -->
4708
+ @if (_isInvalid()) {
4709
+ <p class="text-xs text-red-500 flex items-center gap-1">
4710
+ <span clx-icon name="error" size="xs"></span>
4711
+ {{ errorMessage() }}
4712
+ </p>
4713
+ } @else if (hint()) {
4714
+ <p [class]="_hintClass()">{{ hint() }}</p>
4715
+ }
5050
4716
  `,
5051
4717
  encapsulation: ViewEncapsulation.None,
5052
4718
  changeDetection: ChangeDetectionStrategy.OnPush,
@@ -5471,7 +5137,6 @@ class ClxAlertComponent {
5471
5137
  _resolve = inject(CLX_ALERT_RESOLVE);
5472
5138
  _animate = inject(ClxAnimateService);
5473
5139
  _el = inject((ElementRef));
5474
- _themeSvc = inject(ClxThemeService);
5475
5140
  _zone;
5476
5141
  constructor() {
5477
5142
  const zone = inject(NgZone, { optional: true });
@@ -5479,36 +5144,17 @@ class ClxAlertComponent {
5479
5144
  }
5480
5145
  // ─── Resolved options ─────────────────────────────────────────────────────
5481
5146
  get _type() { return this._opts.type ?? 'info'; }
5482
- get _isConfirm() { return this._type === 'confirm'; }
5483
5147
  _icon = signal(ALERT_ICON_MAP[this._type], ...(ngDevMode ? [{ debugName: "_icon" }] : /* istanbul ignore next */ []));
5148
+ _iconBg = signal(ALERT_ICON_BG_MAP[this._type], ...(ngDevMode ? [{ debugName: "_iconBg" }] : /* istanbul ignore next */ []));
5149
+ _iconColor = signal(ALERT_ICON_COLOR_MAP[this._type], ...(ngDevMode ? [{ debugName: "_iconColor" }] : /* istanbul ignore next */ []));
5150
+ _progressColor = signal(ALERT_PROGRESS_COLOR_MAP[this._type], ...(ngDevMode ? [{ debugName: "_progressColor" }] : /* istanbul ignore next */ []));
5484
5151
  _title = signal(this._opts.title ?? '', ...(ngDevMode ? [{ debugName: "_title" }] : /* istanbul ignore next */ []));
5485
5152
  _message = signal(this._opts.message ?? '', ...(ngDevMode ? [{ debugName: "_message" }] : /* istanbul ignore next */ []));
5486
5153
  _showCancel = signal(this._opts.showCancelButton ?? this._opts.type === 'confirm', ...(ngDevMode ? [{ debugName: "_showCancel" }] : /* istanbul ignore next */ []));
5487
- _iconBg = computed(() => {
5488
- if (!this._isConfirm)
5489
- return ALERT_ICON_BG_MAP[this._type];
5490
- return resolveColor(this._themeSvc.config().primaryColor).bgSubtle;
5491
- }, ...(ngDevMode ? [{ debugName: "_iconBg" }] : /* istanbul ignore next */ []));
5492
- _iconColor = computed(() => {
5493
- if (!this._isConfirm)
5494
- return ALERT_ICON_COLOR_MAP[this._type];
5495
- return resolveColor(this._themeSvc.config().primaryColor).textSubtle;
5496
- }, ...(ngDevMode ? [{ debugName: "_iconColor" }] : /* istanbul ignore next */ []));
5497
- _progressColor = computed(() => {
5498
- if (!this._isConfirm)
5499
- return ALERT_PROGRESS_COLOR_MAP[this._type];
5500
- return resolveColor(this._themeSvc.config().primaryColor).bg;
5501
- }, ...(ngDevMode ? [{ debugName: "_progressColor" }] : /* istanbul ignore next */ []));
5502
5154
  _confirmText = signal(this._opts.confirmButton?.text ?? 'Aceptar', ...(ngDevMode ? [{ debugName: "_confirmText" }] : /* istanbul ignore next */ []));
5503
- _confirmColor = computed(() => {
5504
- if (this._opts.confirmButton?.color)
5505
- return this._opts.confirmButton.color;
5506
- if (this._isConfirm)
5507
- return this._themeSvc.config().primaryColor;
5508
- return ALERT_CONFIRM_COLOR_MAP[this._type];
5509
- }, ...(ngDevMode ? [{ debugName: "_confirmColor" }] : /* istanbul ignore next */ []));
5155
+ _confirmColor = signal(this._opts.confirmButton?.color ?? ALERT_CONFIRM_COLOR_MAP[this._type], ...(ngDevMode ? [{ debugName: "_confirmColor" }] : /* istanbul ignore next */ []));
5510
5156
  _cancelText = signal(this._opts.cancelButton?.text ?? 'Cancelar', ...(ngDevMode ? [{ debugName: "_cancelText" }] : /* istanbul ignore next */ []));
5511
- _cancelColor = computed(() => this._opts.cancelButton?.color ?? this._themeSvc.config().secondaryColor, ...(ngDevMode ? [{ debugName: "_cancelColor" }] : /* istanbul ignore next */ []));
5157
+ _cancelColor = signal(this._opts.cancelButton?.color ?? 'slate', ...(ngDevMode ? [{ debugName: "_cancelColor" }] : /* istanbul ignore next */ []));
5512
5158
  _cancelVariant = signal(this._opts.cancelButton?.variant ?? 'ghost', ...(ngDevMode ? [{ debugName: "_cancelVariant" }] : /* istanbul ignore next */ []));
5513
5159
  // ─── Timer state ─────────────────────────────────────────────────────────
5514
5160
  _timerTotal = signal(this._opts.timer ?? 0, ...(ngDevMode ? [{ debugName: "_timerTotal" }] : /* istanbul ignore next */ []));
@@ -5575,142 +5221,146 @@ class ClxAlertComponent {
5575
5221
  }
5576
5222
  }
5577
5223
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxAlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5578
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxAlertComponent, isStandalone: true, selector: "clx-alert", ngImport: i0, template: `
5579
- <!-- Dialog card -->
5580
- <div
5581
- #card
5582
- class="clx-alert-card relative w-full max-w-sm mx-auto bg-clx-surface rounded-3xl shadow-2xl overflow-hidden flex flex-col items-center text-center px-8 pt-8 pb-6 gap-4"
5583
- >
5584
- <!-- Icon circle -->
5585
- <div class="w-20 h-20 rounded-full flex items-center justify-center shrink-0"
5586
- [class]="_iconBg()">
5587
- <span clx-icon [name]="_icon()" size="xl" [class]="_iconColor()"></span>
5588
- </div>
5589
-
5590
- <!-- Title -->
5591
- @if (_title()) {
5592
- <h2
5593
- class="text-lg font-bold text-clx-text-label leading-snug"
5594
- [innerHTML]="_title()">
5595
- </h2>
5596
- }
5597
-
5598
- <!-- Message -->
5599
- @if (_message()) {
5600
- <p
5601
- class="text-sm text-clx-text-subtle leading-relaxed"
5602
- [innerHTML]="_message()">
5603
- </p>
5604
- }
5605
-
5606
- <!-- Buttons -->
5607
- <div class="flex items-center justify-center gap-3 w-full mt-1">
5608
-
5609
- @if (_showCancel()) {
5610
- <button
5611
- clx-button
5612
- [color]="_cancelColor()"
5613
- [variant]="_cancelVariant()"
5614
- size="md"
5615
- (click)="dismiss()"
5616
- >
5617
- {{ _cancelText() }}
5618
- </button>
5619
- }
5620
-
5621
- <button
5622
- clx-button
5623
- [color]="_confirmColor()"
5624
- variant="solid"
5625
- size="md"
5626
- (click)="confirm()"
5627
- >
5628
- {{ _confirmText() }}
5629
- </button>
5630
-
5631
- </div>
5632
-
5633
- <!-- Timer progress bar -->
5634
- @if (_timerTotal() > 0) {
5635
- <div class="absolute bottom-0 left-0 right-0 h-1 bg-clx-surface-2 rounded-b-3xl overflow-hidden">
5636
- <div
5637
- class="h-full transition-none rounded-b-3xl"
5638
- [class]="_progressColor()"
5639
- [ngStyle]="{ width: _progressPct() + '%' }">
5640
- </div>
5641
- </div>
5642
- }
5643
- </div>
5224
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxAlertComponent, isStandalone: true, selector: "clx-alert", ngImport: i0, template: `
5225
+ <!-- Dialog card -->
5226
+ <div
5227
+ #card
5228
+ class="clx-alert-card relative w-full max-w-sm mx-auto bg-clx-surface rounded-3xl shadow-2xl overflow-hidden flex flex-col items-center text-center px-8 pt-8 pb-6 gap-4"
5229
+ >
5230
+ <!-- Icon circle -->
5231
+ <div class="w-20 h-20 rounded-full flex items-center justify-center shrink-0"
5232
+ [class]="_iconBg()">
5233
+ <span clx-icon [name]="_icon()" size="xl" [class]="_iconColor()"></span>
5234
+ </div>
5235
+
5236
+ <!-- Title -->
5237
+ @if (_title()) {
5238
+ <h2
5239
+ class="text-lg font-bold text-clx-text-label leading-snug"
5240
+ [innerHTML]="_title()">
5241
+ </h2>
5242
+ }
5243
+
5244
+ <!-- Message -->
5245
+ @if (_message()) {
5246
+ <p
5247
+ class="text-sm text-clx-text-subtle leading-relaxed"
5248
+ [innerHTML]="_message()">
5249
+ </p>
5250
+ }
5251
+
5252
+ <!-- Buttons -->
5253
+ <div class="flex items-center justify-center gap-3 w-full mt-1">
5254
+
5255
+ @if (_showCancel()) {
5256
+ <button
5257
+ clx-button
5258
+ [color]="_cancelColor()"
5259
+ [variant]="_cancelVariant()"
5260
+ size="md"
5261
+ shape="pill"
5262
+ (click)="dismiss()"
5263
+ >
5264
+ {{ _cancelText() }}
5265
+ </button>
5266
+ }
5267
+
5268
+ <button
5269
+ clx-button
5270
+ [color]="_confirmColor()"
5271
+ variant="solid"
5272
+ size="md"
5273
+ shape="pill"
5274
+ (click)="confirm()"
5275
+ >
5276
+ {{ _confirmText() }}
5277
+ </button>
5278
+
5279
+ </div>
5280
+
5281
+ <!-- Timer progress bar -->
5282
+ @if (_timerTotal() > 0) {
5283
+ <div class="absolute bottom-0 left-0 right-0 h-1 bg-clx-surface-2 rounded-b-3xl overflow-hidden">
5284
+ <div
5285
+ class="h-full transition-none rounded-b-3xl"
5286
+ [class]="_progressColor()"
5287
+ [ngStyle]="{ width: _progressPct() + '%' }">
5288
+ </div>
5289
+ </div>
5290
+ }
5291
+ </div>
5644
5292
  `, isInline: true, styles: ["clx-alert{display:flex;align-items:center;justify-content:center;width:100%}.clx-alert-card{will-change:transform,opacity}\n"], dependencies: [{ kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "component", type: ClxButtonComponent, selector: "button[clx-button], a[clx-button]", inputs: ["variant", "color", "size", "shape", "loading", "disabled", "block", "icon", "iconPosition", "iconOnly", "badge", "badgeColor"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
5645
5293
  }
5646
5294
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxAlertComponent, decorators: [{
5647
5295
  type: Component,
5648
- args: [{ selector: 'clx-alert', standalone: true, imports: [ClxIconComponent, ClxButtonComponent, NgStyle], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: `
5649
- <!-- Dialog card -->
5650
- <div
5651
- #card
5652
- class="clx-alert-card relative w-full max-w-sm mx-auto bg-clx-surface rounded-3xl shadow-2xl overflow-hidden flex flex-col items-center text-center px-8 pt-8 pb-6 gap-4"
5653
- >
5654
- <!-- Icon circle -->
5655
- <div class="w-20 h-20 rounded-full flex items-center justify-center shrink-0"
5656
- [class]="_iconBg()">
5657
- <span clx-icon [name]="_icon()" size="xl" [class]="_iconColor()"></span>
5658
- </div>
5659
-
5660
- <!-- Title -->
5661
- @if (_title()) {
5662
- <h2
5663
- class="text-lg font-bold text-clx-text-label leading-snug"
5664
- [innerHTML]="_title()">
5665
- </h2>
5666
- }
5667
-
5668
- <!-- Message -->
5669
- @if (_message()) {
5670
- <p
5671
- class="text-sm text-clx-text-subtle leading-relaxed"
5672
- [innerHTML]="_message()">
5673
- </p>
5674
- }
5675
-
5676
- <!-- Buttons -->
5677
- <div class="flex items-center justify-center gap-3 w-full mt-1">
5678
-
5679
- @if (_showCancel()) {
5680
- <button
5681
- clx-button
5682
- [color]="_cancelColor()"
5683
- [variant]="_cancelVariant()"
5684
- size="md"
5685
- (click)="dismiss()"
5686
- >
5687
- {{ _cancelText() }}
5688
- </button>
5689
- }
5690
-
5691
- <button
5692
- clx-button
5693
- [color]="_confirmColor()"
5694
- variant="solid"
5695
- size="md"
5696
- (click)="confirm()"
5697
- >
5698
- {{ _confirmText() }}
5699
- </button>
5700
-
5701
- </div>
5702
-
5703
- <!-- Timer progress bar -->
5704
- @if (_timerTotal() > 0) {
5705
- <div class="absolute bottom-0 left-0 right-0 h-1 bg-clx-surface-2 rounded-b-3xl overflow-hidden">
5706
- <div
5707
- class="h-full transition-none rounded-b-3xl"
5708
- [class]="_progressColor()"
5709
- [ngStyle]="{ width: _progressPct() + '%' }">
5710
- </div>
5711
- </div>
5712
- }
5713
- </div>
5296
+ args: [{ selector: 'clx-alert', standalone: true, imports: [ClxIconComponent, ClxButtonComponent, NgStyle], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: `
5297
+ <!-- Dialog card -->
5298
+ <div
5299
+ #card
5300
+ class="clx-alert-card relative w-full max-w-sm mx-auto bg-clx-surface rounded-3xl shadow-2xl overflow-hidden flex flex-col items-center text-center px-8 pt-8 pb-6 gap-4"
5301
+ >
5302
+ <!-- Icon circle -->
5303
+ <div class="w-20 h-20 rounded-full flex items-center justify-center shrink-0"
5304
+ [class]="_iconBg()">
5305
+ <span clx-icon [name]="_icon()" size="xl" [class]="_iconColor()"></span>
5306
+ </div>
5307
+
5308
+ <!-- Title -->
5309
+ @if (_title()) {
5310
+ <h2
5311
+ class="text-lg font-bold text-clx-text-label leading-snug"
5312
+ [innerHTML]="_title()">
5313
+ </h2>
5314
+ }
5315
+
5316
+ <!-- Message -->
5317
+ @if (_message()) {
5318
+ <p
5319
+ class="text-sm text-clx-text-subtle leading-relaxed"
5320
+ [innerHTML]="_message()">
5321
+ </p>
5322
+ }
5323
+
5324
+ <!-- Buttons -->
5325
+ <div class="flex items-center justify-center gap-3 w-full mt-1">
5326
+
5327
+ @if (_showCancel()) {
5328
+ <button
5329
+ clx-button
5330
+ [color]="_cancelColor()"
5331
+ [variant]="_cancelVariant()"
5332
+ size="md"
5333
+ shape="pill"
5334
+ (click)="dismiss()"
5335
+ >
5336
+ {{ _cancelText() }}
5337
+ </button>
5338
+ }
5339
+
5340
+ <button
5341
+ clx-button
5342
+ [color]="_confirmColor()"
5343
+ variant="solid"
5344
+ size="md"
5345
+ shape="pill"
5346
+ (click)="confirm()"
5347
+ >
5348
+ {{ _confirmText() }}
5349
+ </button>
5350
+
5351
+ </div>
5352
+
5353
+ <!-- Timer progress bar -->
5354
+ @if (_timerTotal() > 0) {
5355
+ <div class="absolute bottom-0 left-0 right-0 h-1 bg-clx-surface-2 rounded-b-3xl overflow-hidden">
5356
+ <div
5357
+ class="h-full transition-none rounded-b-3xl"
5358
+ [class]="_progressColor()"
5359
+ [ngStyle]="{ width: _progressPct() + '%' }">
5360
+ </div>
5361
+ </div>
5362
+ }
5363
+ </div>
5714
5364
  `, styles: ["clx-alert{display:flex;align-items:center;justify-content:center;width:100%}.clx-alert-card{will-change:transform,opacity}\n"] }]
5715
5365
  }], ctorParameters: () => [] });
5716
5366
 
@@ -5721,7 +5371,7 @@ const MODAL_SIZE_MAP = {
5721
5371
  xl: 'w-full',
5722
5372
  full: 'w-full h-screen rounded-none',
5723
5373
  };
5724
- const MODAL_CONTAINER_CLASS = 'flex flex-col bg-clx-surface rounded-2xl shadow-2xl overflow-hidden';
5374
+ const MODAL_CONTAINER_CLASS = 'flex flex-col bg-white rounded-2xl shadow-2xl overflow-hidden';
5725
5375
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
5726
5376
  const CLX_MODAL_DATA = new InjectionToken('CLX_MODAL_DATA');
5727
5377
  const CLX_MODAL_SIZE = new InjectionToken('CLX_MODAL_SIZE');
@@ -5744,7 +5394,7 @@ const DRAWER_WIDTH_MAP = {
5744
5394
  md: '420px',
5745
5395
  lg: '560px',
5746
5396
  };
5747
- const DRAWER_CONTAINER_CLASS = 'flex flex-col bg-clx-surface shadow-2xl overflow-hidden h-screen';
5397
+ const DRAWER_CONTAINER_CLASS = 'flex flex-col bg-white shadow-2xl overflow-hidden h-screen';
5748
5398
  const CLX_DRAWER_SIZE = new InjectionToken('CLX_DRAWER_SIZE');
5749
5399
 
5750
5400
  class ClxDrawerComponent {
@@ -5771,57 +5421,59 @@ class ClxDrawerComponent {
5771
5421
  this._modalRef?.close();
5772
5422
  }
5773
5423
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxDrawerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5774
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxDrawerComponent, isStandalone: true, selector: "clx-drawer", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, showClose: { classPropertyName: "showClose", publicName: "showClose", isSignal: true, isRequired: false, transformFunction: null }, confirmButton: { classPropertyName: "confirmButton", publicName: "confirmButton", isSignal: true, isRequired: false, transformFunction: null }, cancelButton: { classPropertyName: "cancelButton", publicName: "cancelButton", isSignal: true, isRequired: false, transformFunction: null }, showCancelButton: { classPropertyName: "showCancelButton", publicName: "showCancelButton", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { confirmClick: "confirmClick", cancelClick: "cancelClick" }, host: { properties: { "class": "_hostClass()" } }, ngImport: i0, template: `
5775
- <!-- Header -->
5776
- <div class="flex items-center gap-3 px-6 py-4 border-b border-clx-border-soft shrink-0">
5777
- <div class="flex-1 min-w-0">
5778
- <ng-content select="[clx-drawer-title]" />
5779
- </div>
5780
- @if (showClose()) {
5781
- <button
5782
- clx-button
5783
- variant="ghost"
5784
- color="zinc"
5785
- shape="circle"
5786
- size="sm"
5787
- icon="close"
5788
- [iconOnly]="true"
5789
- class="shrink-0 -mr-1"
5790
- (click)="_close()">
5791
- </button>
5792
- }
5793
- </div>
5794
-
5795
- <!-- Body -->
5796
- <div class="flex-1 overflow-y-auto px-6 py-5">
5797
- <ng-content />
5798
- </div>
5799
-
5800
- <!-- Footer -->
5801
- <div class="flex items-center justify-end gap-3 px-6 py-4 border-t border-clx-border-soft shrink-0">
5802
- @if (_hasBuiltInButtons()) {
5803
- @if (showCancelButton()) {
5804
- <button
5805
- clx-button
5806
- [color]="_cancelColor()"
5807
- [variant]="_cancelVariant()"
5808
- size="md"
5809
- (click)="cancelClick.emit()">
5810
- {{ _cancelText() }}
5811
- </button>
5812
- }
5813
- <button
5814
- clx-button
5815
- [color]="_confirmColor()"
5816
- [variant]="_confirmVariant()"
5817
- size="md"
5818
- (click)="confirmClick.emit()">
5819
- {{ _confirmText() }}
5820
- </button>
5821
- } @else {
5822
- <ng-content select="[clx-drawer-footer]" />
5823
- }
5824
- </div>
5424
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxDrawerComponent, isStandalone: true, selector: "clx-drawer", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, showClose: { classPropertyName: "showClose", publicName: "showClose", isSignal: true, isRequired: false, transformFunction: null }, confirmButton: { classPropertyName: "confirmButton", publicName: "confirmButton", isSignal: true, isRequired: false, transformFunction: null }, cancelButton: { classPropertyName: "cancelButton", publicName: "cancelButton", isSignal: true, isRequired: false, transformFunction: null }, showCancelButton: { classPropertyName: "showCancelButton", publicName: "showCancelButton", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { confirmClick: "confirmClick", cancelClick: "cancelClick" }, host: { properties: { "class": "_hostClass()" } }, ngImport: i0, template: `
5425
+ <!-- Header -->
5426
+ <div class="flex items-center gap-3 px-6 py-4 border-b border-clx-border-soft shrink-0">
5427
+ <div class="flex-1 min-w-0">
5428
+ <ng-content select="[clx-drawer-title]" />
5429
+ </div>
5430
+ @if (showClose()) {
5431
+ <button
5432
+ clx-button
5433
+ variant="ghost"
5434
+ color="zinc"
5435
+ shape="circle"
5436
+ size="sm"
5437
+ icon="close"
5438
+ [iconOnly]="true"
5439
+ class="shrink-0 -mr-1"
5440
+ (click)="_close()">
5441
+ </button>
5442
+ }
5443
+ </div>
5444
+
5445
+ <!-- Body -->
5446
+ <div class="flex-1 overflow-y-auto px-6 py-5">
5447
+ <ng-content />
5448
+ </div>
5449
+
5450
+ <!-- Footer -->
5451
+ <div class="flex items-center justify-end gap-3 px-6 py-4 border-t border-clx-border-soft shrink-0 bg-clx-surface-2">
5452
+ @if (_hasBuiltInButtons()) {
5453
+ @if (showCancelButton()) {
5454
+ <button
5455
+ clx-button
5456
+ [color]="_cancelColor()"
5457
+ [variant]="_cancelVariant()"
5458
+ size="md"
5459
+ shape="pill"
5460
+ (click)="cancelClick.emit()">
5461
+ {{ _cancelText() }}
5462
+ </button>
5463
+ }
5464
+ <button
5465
+ clx-button
5466
+ [color]="_confirmColor()"
5467
+ [variant]="_confirmVariant()"
5468
+ size="md"
5469
+ shape="pill"
5470
+ (click)="confirmClick.emit()">
5471
+ {{ _confirmText() }}
5472
+ </button>
5473
+ } @else {
5474
+ <ng-content select="[clx-drawer-footer]" />
5475
+ }
5476
+ </div>
5825
5477
  `, isInline: true, dependencies: [{ kind: "component", type: ClxButtonComponent, selector: "button[clx-button], a[clx-button]", inputs: ["variant", "color", "size", "shape", "loading", "disabled", "block", "icon", "iconPosition", "iconOnly", "badge", "badgeColor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
5826
5478
  }
5827
5479
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxDrawerComponent, decorators: [{
@@ -5830,57 +5482,59 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
5830
5482
  selector: 'clx-drawer',
5831
5483
  standalone: true,
5832
5484
  imports: [ClxButtonComponent],
5833
- template: `
5834
- <!-- Header -->
5835
- <div class="flex items-center gap-3 px-6 py-4 border-b border-clx-border-soft shrink-0">
5836
- <div class="flex-1 min-w-0">
5837
- <ng-content select="[clx-drawer-title]" />
5838
- </div>
5839
- @if (showClose()) {
5840
- <button
5841
- clx-button
5842
- variant="ghost"
5843
- color="zinc"
5844
- shape="circle"
5845
- size="sm"
5846
- icon="close"
5847
- [iconOnly]="true"
5848
- class="shrink-0 -mr-1"
5849
- (click)="_close()">
5850
- </button>
5851
- }
5852
- </div>
5853
-
5854
- <!-- Body -->
5855
- <div class="flex-1 overflow-y-auto px-6 py-5">
5856
- <ng-content />
5857
- </div>
5858
-
5859
- <!-- Footer -->
5860
- <div class="flex items-center justify-end gap-3 px-6 py-4 border-t border-clx-border-soft shrink-0">
5861
- @if (_hasBuiltInButtons()) {
5862
- @if (showCancelButton()) {
5863
- <button
5864
- clx-button
5865
- [color]="_cancelColor()"
5866
- [variant]="_cancelVariant()"
5867
- size="md"
5868
- (click)="cancelClick.emit()">
5869
- {{ _cancelText() }}
5870
- </button>
5871
- }
5872
- <button
5873
- clx-button
5874
- [color]="_confirmColor()"
5875
- [variant]="_confirmVariant()"
5876
- size="md"
5877
- (click)="confirmClick.emit()">
5878
- {{ _confirmText() }}
5879
- </button>
5880
- } @else {
5881
- <ng-content select="[clx-drawer-footer]" />
5882
- }
5883
- </div>
5485
+ template: `
5486
+ <!-- Header -->
5487
+ <div class="flex items-center gap-3 px-6 py-4 border-b border-clx-border-soft shrink-0">
5488
+ <div class="flex-1 min-w-0">
5489
+ <ng-content select="[clx-drawer-title]" />
5490
+ </div>
5491
+ @if (showClose()) {
5492
+ <button
5493
+ clx-button
5494
+ variant="ghost"
5495
+ color="zinc"
5496
+ shape="circle"
5497
+ size="sm"
5498
+ icon="close"
5499
+ [iconOnly]="true"
5500
+ class="shrink-0 -mr-1"
5501
+ (click)="_close()">
5502
+ </button>
5503
+ }
5504
+ </div>
5505
+
5506
+ <!-- Body -->
5507
+ <div class="flex-1 overflow-y-auto px-6 py-5">
5508
+ <ng-content />
5509
+ </div>
5510
+
5511
+ <!-- Footer -->
5512
+ <div class="flex items-center justify-end gap-3 px-6 py-4 border-t border-clx-border-soft shrink-0 bg-clx-surface-2">
5513
+ @if (_hasBuiltInButtons()) {
5514
+ @if (showCancelButton()) {
5515
+ <button
5516
+ clx-button
5517
+ [color]="_cancelColor()"
5518
+ [variant]="_cancelVariant()"
5519
+ size="md"
5520
+ shape="pill"
5521
+ (click)="cancelClick.emit()">
5522
+ {{ _cancelText() }}
5523
+ </button>
5524
+ }
5525
+ <button
5526
+ clx-button
5527
+ [color]="_confirmColor()"
5528
+ [variant]="_confirmVariant()"
5529
+ size="md"
5530
+ shape="pill"
5531
+ (click)="confirmClick.emit()">
5532
+ {{ _confirmText() }}
5533
+ </button>
5534
+ } @else {
5535
+ <ng-content select="[clx-drawer-footer]" />
5536
+ }
5537
+ </div>
5884
5538
  `,
5885
5539
  encapsulation: ViewEncapsulation.None,
5886
5540
  changeDetection: ChangeDetectionStrategy.OnPush,
@@ -5912,57 +5566,59 @@ class ClxModalComponent {
5912
5566
  this._modalRef?.close();
5913
5567
  }
5914
5568
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5915
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxModalComponent, isStandalone: true, selector: "clx-modal", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, showClose: { classPropertyName: "showClose", publicName: "showClose", isSignal: true, isRequired: false, transformFunction: null }, confirmButton: { classPropertyName: "confirmButton", publicName: "confirmButton", isSignal: true, isRequired: false, transformFunction: null }, cancelButton: { classPropertyName: "cancelButton", publicName: "cancelButton", isSignal: true, isRequired: false, transformFunction: null }, showCancelButton: { classPropertyName: "showCancelButton", publicName: "showCancelButton", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { confirmClick: "confirmClick", cancelClick: "cancelClick" }, host: { properties: { "class": "_hostClass()" } }, ngImport: i0, template: `
5916
- <!-- Header -->
5917
- <div class="flex items-center gap-3 px-6 py-4 border-b border-clx-border-soft shrink-0">
5918
- <div class="flex-1 min-w-0 text-clx-text-label">
5919
- <ng-content select="[clx-modal-title]" />
5920
- </div>
5921
- @if (showClose()) {
5922
- <button
5923
- clx-button
5924
- variant="ghost"
5925
- color="zinc"
5926
- shape="circle"
5927
- size="md"
5928
- icon="close"
5929
- [iconOnly]="true"
5930
- class="shrink-0 -mr-1"
5931
- (click)="_close()">
5932
- </button>
5933
- }
5934
- </div>
5935
-
5936
- <!-- Body -->
5937
- <div cdkScrollable class="flex-1 min-h-0 overflow-y-auto px-6 py-5">
5938
- <ng-content />
5939
- </div>
5940
-
5941
- <!-- Footer -->
5942
- <div class="flex items-center justify-end gap-3 px-6 py-4 border-t border-clx-border-soft shrink-0">
5943
- @if (_hasBuiltInButtons()) {
5944
- @if (showCancelButton()) {
5945
- <button
5946
- clx-button
5947
- [color]="_cancelColor()"
5948
- [variant]="_cancelVariant()"
5949
- size="md"
5950
- (click)="cancelClick.emit()">
5951
- {{ _cancelText() }}
5952
- </button>
5953
- }
5954
- <button
5955
- clx-button
5956
- [color]="_confirmColor()"
5957
- [variant]="_confirmVariant()"
5958
- size="md"
5959
- (click)="confirmClick.emit()">
5960
- {{ _confirmText() }}
5961
- </button>
5962
- } @else {
5963
- <ng-content select="[clx-modal-footer]" />
5964
- }
5965
- </div>
5569
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxModalComponent, isStandalone: true, selector: "clx-modal", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, showClose: { classPropertyName: "showClose", publicName: "showClose", isSignal: true, isRequired: false, transformFunction: null }, confirmButton: { classPropertyName: "confirmButton", publicName: "confirmButton", isSignal: true, isRequired: false, transformFunction: null }, cancelButton: { classPropertyName: "cancelButton", publicName: "cancelButton", isSignal: true, isRequired: false, transformFunction: null }, showCancelButton: { classPropertyName: "showCancelButton", publicName: "showCancelButton", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { confirmClick: "confirmClick", cancelClick: "cancelClick" }, host: { properties: { "class": "_hostClass()" } }, ngImport: i0, template: `
5570
+ <!-- Header -->
5571
+ <div class="flex items-center gap-3 px-6 py-4 border-b border-clx-border-soft shrink-0">
5572
+ <div class="flex-1 min-w-0">
5573
+ <ng-content select="[clx-modal-title]" />
5574
+ </div>
5575
+ @if (showClose()) {
5576
+ <button
5577
+ clx-button
5578
+ variant="ghost"
5579
+ color="zinc"
5580
+ shape="circle"
5581
+ size="md"
5582
+ icon="close"
5583
+ [iconOnly]="true"
5584
+ class="shrink-0 -mr-1"
5585
+ (click)="_close()">
5586
+ </button>
5587
+ }
5588
+ </div>
5589
+
5590
+ <!-- Body -->
5591
+ <div cdkScrollable class="flex-1 min-h-0 overflow-y-auto px-6 py-5">
5592
+ <ng-content />
5593
+ </div>
5594
+
5595
+ <!-- Footer -->
5596
+ <div class="flex items-center justify-end gap-3 px-6 py-4 border-t border-clx-border-soft shrink-0 bg-clx-surface-2">
5597
+ @if (_hasBuiltInButtons()) {
5598
+ @if (showCancelButton()) {
5599
+ <button
5600
+ clx-button
5601
+ [color]="_cancelColor()"
5602
+ [variant]="_cancelVariant()"
5603
+ size="md"
5604
+ shape="pill"
5605
+ (click)="cancelClick.emit()">
5606
+ {{ _cancelText() }}
5607
+ </button>
5608
+ }
5609
+ <button
5610
+ clx-button
5611
+ [color]="_confirmColor()"
5612
+ [variant]="_confirmVariant()"
5613
+ size="md"
5614
+ shape="pill"
5615
+ (click)="confirmClick.emit()">
5616
+ {{ _confirmText() }}
5617
+ </button>
5618
+ } @else {
5619
+ <ng-content select="[clx-modal-footer]" />
5620
+ }
5621
+ </div>
5966
5622
  `, isInline: true, dependencies: [{ kind: "component", type: ClxButtonComponent, selector: "button[clx-button], a[clx-button]", inputs: ["variant", "color", "size", "shape", "loading", "disabled", "block", "icon", "iconPosition", "iconOnly", "badge", "badgeColor"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i1$1.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
5967
5623
  }
5968
5624
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxModalComponent, decorators: [{
@@ -5971,57 +5627,59 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
5971
5627
  selector: 'clx-modal',
5972
5628
  standalone: true,
5973
5629
  imports: [ClxButtonComponent, ScrollingModule],
5974
- template: `
5975
- <!-- Header -->
5976
- <div class="flex items-center gap-3 px-6 py-4 border-b border-clx-border-soft shrink-0">
5977
- <div class="flex-1 min-w-0 text-clx-text-label">
5978
- <ng-content select="[clx-modal-title]" />
5979
- </div>
5980
- @if (showClose()) {
5981
- <button
5982
- clx-button
5983
- variant="ghost"
5984
- color="zinc"
5985
- shape="circle"
5986
- size="md"
5987
- icon="close"
5988
- [iconOnly]="true"
5989
- class="shrink-0 -mr-1"
5990
- (click)="_close()">
5991
- </button>
5992
- }
5993
- </div>
5994
-
5995
- <!-- Body -->
5996
- <div cdkScrollable class="flex-1 min-h-0 overflow-y-auto px-6 py-5">
5997
- <ng-content />
5998
- </div>
5999
-
6000
- <!-- Footer -->
6001
- <div class="flex items-center justify-end gap-3 px-6 py-4 border-t border-clx-border-soft shrink-0">
6002
- @if (_hasBuiltInButtons()) {
6003
- @if (showCancelButton()) {
6004
- <button
6005
- clx-button
6006
- [color]="_cancelColor()"
6007
- [variant]="_cancelVariant()"
6008
- size="md"
6009
- (click)="cancelClick.emit()">
6010
- {{ _cancelText() }}
6011
- </button>
6012
- }
6013
- <button
6014
- clx-button
6015
- [color]="_confirmColor()"
6016
- [variant]="_confirmVariant()"
6017
- size="md"
6018
- (click)="confirmClick.emit()">
6019
- {{ _confirmText() }}
6020
- </button>
6021
- } @else {
6022
- <ng-content select="[clx-modal-footer]" />
6023
- }
6024
- </div>
5630
+ template: `
5631
+ <!-- Header -->
5632
+ <div class="flex items-center gap-3 px-6 py-4 border-b border-clx-border-soft shrink-0">
5633
+ <div class="flex-1 min-w-0">
5634
+ <ng-content select="[clx-modal-title]" />
5635
+ </div>
5636
+ @if (showClose()) {
5637
+ <button
5638
+ clx-button
5639
+ variant="ghost"
5640
+ color="zinc"
5641
+ shape="circle"
5642
+ size="md"
5643
+ icon="close"
5644
+ [iconOnly]="true"
5645
+ class="shrink-0 -mr-1"
5646
+ (click)="_close()">
5647
+ </button>
5648
+ }
5649
+ </div>
5650
+
5651
+ <!-- Body -->
5652
+ <div cdkScrollable class="flex-1 min-h-0 overflow-y-auto px-6 py-5">
5653
+ <ng-content />
5654
+ </div>
5655
+
5656
+ <!-- Footer -->
5657
+ <div class="flex items-center justify-end gap-3 px-6 py-4 border-t border-clx-border-soft shrink-0 bg-clx-surface-2">
5658
+ @if (_hasBuiltInButtons()) {
5659
+ @if (showCancelButton()) {
5660
+ <button
5661
+ clx-button
5662
+ [color]="_cancelColor()"
5663
+ [variant]="_cancelVariant()"
5664
+ size="md"
5665
+ shape="pill"
5666
+ (click)="cancelClick.emit()">
5667
+ {{ _cancelText() }}
5668
+ </button>
5669
+ }
5670
+ <button
5671
+ clx-button
5672
+ [color]="_confirmColor()"
5673
+ [variant]="_confirmVariant()"
5674
+ size="md"
5675
+ shape="pill"
5676
+ (click)="confirmClick.emit()">
5677
+ {{ _confirmText() }}
5678
+ </button>
5679
+ } @else {
5680
+ <ng-content select="[clx-modal-footer]" />
5681
+ }
5682
+ </div>
6025
5683
  `,
6026
5684
  encapsulation: ViewEncapsulation.None,
6027
5685
  changeDetection: ChangeDetectionStrategy.OnPush,
@@ -11778,9 +11436,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
11778
11436
  }] } });
11779
11437
 
11780
11438
  class ClxAppLayoutComponent {
11781
- _zone = inject(NgZone);
11782
- _document = inject(DOCUMENT);
11783
- _el = inject(ElementRef);
11439
+ _zone;
11440
+ _document;
11784
11441
  activeColor = input(undefined, ...(ngDevMode ? [{ debugName: "activeColor" }] : /* istanbul ignore next */ []));
11785
11442
  _sidebarOpen = signal(false, ...(ngDevMode ? [{ debugName: "_sidebarOpen" }] : /* istanbul ignore next */ []));
11786
11443
  collapsed = signal(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
@@ -11788,41 +11445,42 @@ class ClxAppLayoutComponent {
11788
11445
  _isMobile = signal(true, ...(ngDevMode ? [{ debugName: "_isMobile" }] : /* istanbul ignore next */ []));
11789
11446
  collapsedChange = output();
11790
11447
  expandedChange = output();
11448
+ constructor() {
11449
+ const zone = inject(NgZone, { optional: true });
11450
+ this._zone = zone ?? { run: (fn) => fn(), runOutsideAngular: (fn) => fn() };
11451
+ this._document = inject(DOCUMENT);
11452
+ }
11791
11453
  _showBackdrop = computed(() => this._sidebarOpen() && this._isMobile(), ...(ngDevMode ? [{ debugName: "_showBackdrop" }] : /* istanbul ignore next */ []));
11792
11454
  _isExpanded = computed(() => !this.collapsed() || this._hovered(), ...(ngDevMode ? [{ debugName: "_isExpanded" }] : /* istanbul ignore next */ []));
11793
11455
  _sidebarCls = computed(() => {
11794
- const mobile = this._isMobile();
11795
- const open = this._sidebarOpen();
11796
- const collapsed = this.collapsed();
11456
+ const isDesktopCollapsed = this.collapsed() && !this._isMobile();
11797
11457
  const hovered = this._hovered();
11798
- const base = 'flex flex-col bg-clx-surface border-r border-clx-border overflow-hidden shrink-0';
11799
- if (mobile) {
11800
- // Mobile: fixed overlay, slides in/out — no width transition needed
11801
- const visible = open ? 'translate-x-0' : '-translate-x-full';
11802
- return `fixed inset-y-0 left-0 z-30 w-72 ${base} transition-transform duration-300 ease-in-out ${visible}`;
11803
- }
11804
- // Desktop: in-flow (relative), width-only transition — no fixed, no transform
11805
- const width = collapsed && !hovered ? 'w-20' : 'w-72';
11806
- const shadow = collapsed && hovered ? 'shadow-2xl' : '';
11807
- return `relative z-30 ${width} ${base} transition-[width] duration-300 ease-in-out ${shadow}`;
11458
+ let width;
11459
+ if (isDesktopCollapsed && hovered) {
11460
+ width = 'w-72';
11461
+ }
11462
+ else if (isDesktopCollapsed) {
11463
+ width = 'w-20';
11464
+ }
11465
+ else {
11466
+ width = 'w-72';
11467
+ }
11468
+ const isOverlay = isDesktopCollapsed && hovered;
11469
+ return [
11470
+ `fixed inset-y-0 left-0 z-30 ${width} flex flex-col`,
11471
+ 'bg-clx-surface border-r border-clx-border overflow-hidden shrink-0',
11472
+ 'transition-[width,transform] duration-300 ease-in-out',
11473
+ isOverlay ? 'shadow-2xl' : '',
11474
+ 'lg:transition-[width] lg:relative lg:inset-auto lg:z-30 lg:translate-x-0',
11475
+ (!this._isMobile() || this._sidebarOpen()) ? 'translate-x-0' : '-translate-x-full',
11476
+ ].join(' ');
11808
11477
  }, ...(ngDevMode ? [{ debugName: "_sidebarCls" }] : /* istanbul ignore next */ []));
11809
- _nativeSetTimeout;
11810
- _nativeClearTimeout;
11811
11478
  _mql;
11812
11479
  _mqlListener;
11813
- _resizeTimer = null;
11814
- _resizeListener;
11815
- _mouseEnterFn;
11816
- _mouseLeaveFn;
11817
- _sidebarEl = null;
11818
11480
  ngOnInit() {
11819
11481
  const win = this._document.defaultView;
11820
11482
  if (!win)
11821
11483
  return;
11822
- // Use native (non-Zone-patched) timers so the resize debounce
11823
- // does not trigger Angular change detection cycles
11824
- this._nativeSetTimeout = win.__zone_symbol__setTimeout ?? win.setTimeout.bind(win);
11825
- this._nativeClearTimeout = win.__zone_symbol__clearTimeout ?? win.clearTimeout.bind(win);
11826
11484
  this._mql = win.matchMedia('(min-width: 1024px)');
11827
11485
  this._isMobile.set(!this._mql.matches);
11828
11486
  if (this._mql.matches)
@@ -11841,58 +11499,9 @@ class ClxAppLayoutComponent {
11841
11499
  });
11842
11500
  };
11843
11501
  this._mql.addEventListener('change', this._mqlListener);
11844
- this._zone.runOutsideAngular(() => {
11845
- // Suppress all transitions during resize using native (non-Zone-patched) timer
11846
- this._resizeListener = () => {
11847
- this._document.documentElement.classList.add('clx-resizing');
11848
- if (this._resizeTimer !== null)
11849
- this._nativeClearTimeout(this._resizeTimer);
11850
- this._resizeTimer = this._nativeSetTimeout(() => {
11851
- this._document.documentElement.classList.remove('clx-resizing');
11852
- this._resizeTimer = null;
11853
- }, 150);
11854
- };
11855
- win.addEventListener('resize', this._resizeListener, { passive: true });
11856
- // Sidebar hover outside NgZone — only enters zone when state actually changes
11857
- this._mouseEnterFn = () => {
11858
- if (!this.collapsed() || this._isMobile())
11859
- return;
11860
- if (!this._hovered()) {
11861
- this._zone.run(() => {
11862
- this._hovered.set(true);
11863
- this.expandedChange.emit(true);
11864
- });
11865
- }
11866
- };
11867
- this._mouseLeaveFn = () => {
11868
- if (this._hovered()) {
11869
- this._zone.run(() => {
11870
- this._hovered.set(false);
11871
- this.expandedChange.emit(false);
11872
- });
11873
- }
11874
- };
11875
- // Attach after a tick so the aside is rendered (native timer — no CD)
11876
- this._nativeSetTimeout(() => {
11877
- const host = this._el.nativeElement;
11878
- this._sidebarEl = host.querySelector('aside');
11879
- if (this._sidebarEl) {
11880
- this._sidebarEl.addEventListener('mouseenter', this._mouseEnterFn, { passive: true });
11881
- this._sidebarEl.addEventListener('mouseleave', this._mouseLeaveFn, { passive: true });
11882
- }
11883
- }, 0);
11884
- });
11885
11502
  }
11886
11503
  ngOnDestroy() {
11887
11504
  this._mql?.removeEventListener('change', this._mqlListener);
11888
- const win = this._document.defaultView;
11889
- win?.removeEventListener('resize', this._resizeListener);
11890
- if (this._resizeTimer !== null)
11891
- this._nativeClearTimeout?.(this._resizeTimer);
11892
- if (this._sidebarEl) {
11893
- this._sidebarEl.removeEventListener('mouseenter', this._mouseEnterFn);
11894
- this._sidebarEl.removeEventListener('mouseleave', this._mouseLeaveFn);
11895
- }
11896
11505
  }
11897
11506
  _toggleCollapsed() {
11898
11507
  const next = !this.collapsed();
@@ -11900,122 +11509,144 @@ class ClxAppLayoutComponent {
11900
11509
  this._hovered.set(false);
11901
11510
  this.collapsedChange.emit(next);
11902
11511
  }
11512
+ _onSidebarEnter() {
11513
+ if (this.collapsed() && !this._isMobile()) {
11514
+ this._hovered.set(true);
11515
+ this.expandedChange.emit(true);
11516
+ }
11517
+ }
11518
+ _onSidebarLeave() {
11519
+ if (this._hovered()) {
11520
+ this._hovered.set(false);
11521
+ this.expandedChange.emit(false);
11522
+ }
11523
+ }
11903
11524
  toggleSidebar() { this._sidebarOpen.update(v => !v); }
11904
11525
  openSidebar() { this._sidebarOpen.set(true); }
11905
11526
  closeSidebar() { this._sidebarOpen.set(false); }
11906
11527
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxAppLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
11907
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxAppLayoutComponent, isStandalone: true, selector: "clx-app-layout", inputs: { activeColor: { classPropertyName: "activeColor", publicName: "activeColor", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsedChange: "collapsedChange", expandedChange: "expandedChange" }, host: { classAttribute: "flex h-screen overflow-hidden" }, ngImport: i0, template: `
11908
- <!-- Mobile backdrop -->
11909
- @if (_showBackdrop()) {
11910
- <div
11911
- class="fixed inset-0 z-20 bg-slate-900/60"
11912
- aria-hidden="true"
11913
- (click)="closeSidebar()">
11914
- </div>
11915
- }
11916
-
11917
- <!-- Sidebar -->
11918
- <aside
11919
- [class]="_sidebarCls()"
11920
- aria-label="Navegación principal">
11921
-
11922
- <div class="border-b border-slate-700/50 shrink-0 overflow-hidden">
11923
- <ng-content select="clx-brand"></ng-content>
11924
- </div>
11925
-
11926
- <div class="flex flex-col flex-1 min-h-0 overflow-y-auto">
11927
- <ng-content select="[clx-sidebar]"></ng-content>
11928
- </div>
11929
- </aside>
11930
-
11931
- <!-- Right panel -->
11932
- <div class="flex-1 flex flex-col overflow-hidden min-w-0" style="contain:layout paint">
11933
-
11934
- <header class="h-16 shrink-0 bg-clx-surface border-b border-clx-border flex items-center z-10 px-4 gap-3">
11935
- <button
11936
- type="button"
11937
- class="hidden lg:flex items-center justify-center w-8 h-8 rounded-md text-clx-text-subtle hover:text-clx-text-label hover:bg-clx-surface-2 transition-colors shrink-0"
11938
- (click)="_toggleCollapsed()">
11939
- <span clx-icon [name]="collapsed() ? 'menu_open' : 'menu'" size="sm"></span>
11940
- </button>
11941
- <button
11942
- type="button"
11943
- class="flex lg:hidden items-center justify-center w-8 h-8 rounded-md text-clx-text-subtle hover:text-clx-text-label hover:bg-clx-surface-2 transition-colors shrink-0"
11944
- (click)="toggleSidebar()">
11945
- <span clx-icon name="menu" size="sm"></span>
11946
- </button>
11947
-
11948
- <ng-content select="[clx-header]"></ng-content>
11949
- </header>
11950
-
11951
- <main class="flex-1 overflow-y-auto bg-clx-bg" style="contain:layout paint">
11952
- <ng-content></ng-content>
11953
- </main>
11954
-
11955
- </div>
11956
- `, isInline: true, dependencies: [{ kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
11528
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxAppLayoutComponent, isStandalone: true, selector: "clx-app-layout", inputs: { activeColor: { classPropertyName: "activeColor", publicName: "activeColor", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsedChange: "collapsedChange", expandedChange: "expandedChange" }, host: { classAttribute: "flex h-screen overflow-hidden" }, ngImport: i0, template: `
11529
+ <!-- Mobile backdrop -->
11530
+ @if (_showBackdrop()) {
11531
+ <div
11532
+ class="fixed inset-0 z-20 bg-slate-900/60"
11533
+ aria-hidden="true"
11534
+ (click)="closeSidebar()">
11535
+ </div>
11536
+ }
11537
+
11538
+ <!-- Sidebar -->
11539
+ <aside
11540
+ [class]="_sidebarCls()"
11541
+ (mouseenter)="_onSidebarEnter()"
11542
+ (mouseleave)="_onSidebarLeave()"
11543
+ aria-label="Navegación principal">
11544
+
11545
+ <!-- Brand slot -->
11546
+ <div class="border-b border-slate-700/50 shrink-0 overflow-hidden">
11547
+ <ng-content select="clx-brand"></ng-content>
11548
+ </div>
11549
+
11550
+ <div class="flex flex-col flex-1 min-h-0">
11551
+ <ng-content select="[clx-sidebar]"></ng-content>
11552
+ </div>
11553
+ </aside>
11554
+
11555
+ <!-- Right panel -->
11556
+ <div class="flex-1 flex flex-col overflow-hidden min-w-0">
11557
+
11558
+ <header class="h-16 shrink-0 bg-clx-surface border-b border-clx-border flex items-center z-10 px-4 gap-3">
11559
+ <!-- Toggle button desktop -->
11560
+ <button
11561
+ type="button"
11562
+ class="hidden lg:flex items-center justify-center w-8 h-8 rounded-md text-clx-text-subtle hover:text-clx-text-label hover:bg-clx-surface-2 transition-colors shrink-0"
11563
+ (click)="_toggleCollapsed()">
11564
+ <span clx-icon [name]="collapsed() ? 'menu_open' : 'menu'" size="sm"></span>
11565
+ </button>
11566
+ <!-- Toggle button mobile -->
11567
+ <button
11568
+ type="button"
11569
+ class="flex lg:hidden items-center justify-center w-8 h-8 rounded-md text-clx-text-subtle hover:text-clx-text-label hover:bg-clx-surface-2 transition-colors shrink-0"
11570
+ (click)="toggleSidebar()">
11571
+ <span clx-icon name="menu" size="sm"></span>
11572
+ </button>
11573
+
11574
+ <ng-content select="[clx-header]"></ng-content>
11575
+ </header>
11576
+
11577
+ <main cdkScrollable class="flex-1 overflow-y-auto bg-clx-bg">
11578
+ <ng-content></ng-content>
11579
+ </main>
11580
+
11581
+ </div>
11582
+ `, isInline: true, dependencies: [{ kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "directive", type: CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
11957
11583
  }
11958
11584
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxAppLayoutComponent, decorators: [{
11959
11585
  type: Component,
11960
11586
  args: [{
11961
11587
  selector: 'clx-app-layout',
11962
11588
  standalone: true,
11963
- imports: [ClxIconComponent],
11964
- template: `
11965
- <!-- Mobile backdrop -->
11966
- @if (_showBackdrop()) {
11967
- <div
11968
- class="fixed inset-0 z-20 bg-slate-900/60"
11969
- aria-hidden="true"
11970
- (click)="closeSidebar()">
11971
- </div>
11972
- }
11973
-
11974
- <!-- Sidebar -->
11975
- <aside
11976
- [class]="_sidebarCls()"
11977
- aria-label="Navegación principal">
11978
-
11979
- <div class="border-b border-slate-700/50 shrink-0 overflow-hidden">
11980
- <ng-content select="clx-brand"></ng-content>
11981
- </div>
11982
-
11983
- <div class="flex flex-col flex-1 min-h-0 overflow-y-auto">
11984
- <ng-content select="[clx-sidebar]"></ng-content>
11985
- </div>
11986
- </aside>
11987
-
11988
- <!-- Right panel -->
11989
- <div class="flex-1 flex flex-col overflow-hidden min-w-0" style="contain:layout paint">
11990
-
11991
- <header class="h-16 shrink-0 bg-clx-surface border-b border-clx-border flex items-center z-10 px-4 gap-3">
11992
- <button
11993
- type="button"
11994
- class="hidden lg:flex items-center justify-center w-8 h-8 rounded-md text-clx-text-subtle hover:text-clx-text-label hover:bg-clx-surface-2 transition-colors shrink-0"
11995
- (click)="_toggleCollapsed()">
11996
- <span clx-icon [name]="collapsed() ? 'menu_open' : 'menu'" size="sm"></span>
11997
- </button>
11998
- <button
11999
- type="button"
12000
- class="flex lg:hidden items-center justify-center w-8 h-8 rounded-md text-clx-text-subtle hover:text-clx-text-label hover:bg-clx-surface-2 transition-colors shrink-0"
12001
- (click)="toggleSidebar()">
12002
- <span clx-icon name="menu" size="sm"></span>
12003
- </button>
12004
-
12005
- <ng-content select="[clx-header]"></ng-content>
12006
- </header>
12007
-
12008
- <main class="flex-1 overflow-y-auto bg-clx-bg" style="contain:layout paint">
12009
- <ng-content></ng-content>
12010
- </main>
12011
-
12012
- </div>
11589
+ imports: [ClxIconComponent, CdkScrollable],
11590
+ template: `
11591
+ <!-- Mobile backdrop -->
11592
+ @if (_showBackdrop()) {
11593
+ <div
11594
+ class="fixed inset-0 z-20 bg-slate-900/60"
11595
+ aria-hidden="true"
11596
+ (click)="closeSidebar()">
11597
+ </div>
11598
+ }
11599
+
11600
+ <!-- Sidebar -->
11601
+ <aside
11602
+ [class]="_sidebarCls()"
11603
+ (mouseenter)="_onSidebarEnter()"
11604
+ (mouseleave)="_onSidebarLeave()"
11605
+ aria-label="Navegación principal">
11606
+
11607
+ <!-- Brand slot -->
11608
+ <div class="border-b border-slate-700/50 shrink-0 overflow-hidden">
11609
+ <ng-content select="clx-brand"></ng-content>
11610
+ </div>
11611
+
11612
+ <div class="flex flex-col flex-1 min-h-0">
11613
+ <ng-content select="[clx-sidebar]"></ng-content>
11614
+ </div>
11615
+ </aside>
11616
+
11617
+ <!-- Right panel -->
11618
+ <div class="flex-1 flex flex-col overflow-hidden min-w-0">
11619
+
11620
+ <header class="h-16 shrink-0 bg-clx-surface border-b border-clx-border flex items-center z-10 px-4 gap-3">
11621
+ <!-- Toggle button desktop -->
11622
+ <button
11623
+ type="button"
11624
+ class="hidden lg:flex items-center justify-center w-8 h-8 rounded-md text-clx-text-subtle hover:text-clx-text-label hover:bg-clx-surface-2 transition-colors shrink-0"
11625
+ (click)="_toggleCollapsed()">
11626
+ <span clx-icon [name]="collapsed() ? 'menu_open' : 'menu'" size="sm"></span>
11627
+ </button>
11628
+ <!-- Toggle button mobile -->
11629
+ <button
11630
+ type="button"
11631
+ class="flex lg:hidden items-center justify-center w-8 h-8 rounded-md text-clx-text-subtle hover:text-clx-text-label hover:bg-clx-surface-2 transition-colors shrink-0"
11632
+ (click)="toggleSidebar()">
11633
+ <span clx-icon name="menu" size="sm"></span>
11634
+ </button>
11635
+
11636
+ <ng-content select="[clx-header]"></ng-content>
11637
+ </header>
11638
+
11639
+ <main cdkScrollable class="flex-1 overflow-y-auto bg-clx-bg">
11640
+ <ng-content></ng-content>
11641
+ </main>
11642
+
11643
+ </div>
12013
11644
  `,
12014
11645
  encapsulation: ViewEncapsulation.None,
12015
11646
  changeDetection: ChangeDetectionStrategy.OnPush,
12016
11647
  host: { class: 'flex h-screen overflow-hidden' },
12017
11648
  }]
12018
- }], propDecorators: { activeColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeColor", required: false }] }], collapsedChange: [{ type: i0.Output, args: ["collapsedChange"] }], expandedChange: [{ type: i0.Output, args: ["expandedChange"] }] } });
11649
+ }], ctorParameters: () => [], propDecorators: { activeColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeColor", required: false }] }], collapsedChange: [{ type: i0.Output, args: ["collapsedChange"] }], expandedChange: [{ type: i0.Output, args: ["expandedChange"] }] } });
12019
11650
 
12020
11651
  class ClxBrandComponent {
12021
11652
  logo = input.required(...(ngDevMode ? [{ debugName: "logo" }] : /* istanbul ignore next */ []));
@@ -12062,7 +11693,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
12062
11693
  }], propDecorators: { logo: [{ type: i0.Input, args: [{ isSignal: true, alias: "logo", required: true }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }] } });
12063
11694
 
12064
11695
  // ── Item geometry ──────────────────────────────────────────────────────────────
12065
- const NAV_ITEM_BASE = 'flex items-center gap-3 w-full text-sm font-medium cursor-pointer select-none';
11696
+ const NAV_ITEM_BASE = 'flex items-center gap-3 w-full text-sm font-medium transition-colors duration-150 cursor-pointer select-none';
12066
11697
  const NAV_ITEM_L1 = 'px-6 py-3';
12067
11698
  const NAV_ITEM_L2 = 'pl-4 pr-3 py-2';
12068
11699
  const NAV_ITEM_IDLE = 'text-clx-text-subtle';
@@ -12082,7 +11713,9 @@ class ClxMenuItemComponent {
12082
11713
  routerLink = input('', ...(ngDevMode ? [{ debugName: "routerLink" }] : /* istanbul ignore next */ []));
12083
11714
  routerLinkActiveOptions = input({ exact: false }, ...(ngDevMode ? [{ debugName: "routerLinkActiveOptions" }] : /* istanbul ignore next */ []));
12084
11715
  itemClick = output();
12085
- _resolvedColor = computed(() => this.color() ?? this._themeSvc.sidebarItemColor(), ...(ngDevMode ? [{ debugName: "_resolvedColor" }] : /* istanbul ignore next */ []));
11716
+ _inheritedColor = signal(null, ...(ngDevMode ? [{ debugName: "_inheritedColor" }] : /* istanbul ignore next */ []));
11717
+ _resolvedColor = computed(() => this._inheritedColor() ?? this.color() ?? this._themeSvc.config().primaryColor, ...(ngDevMode ? [{ debugName: "_resolvedColor" }] : /* istanbul ignore next */ []));
11718
+ inheritColor(c) { this._inheritedColor.set(c); }
12086
11719
  _geom = computed(() => {
12087
11720
  if (this.collapsed())
12088
11721
  return 'w-full py-3 px-0 justify-center';
@@ -12090,8 +11723,8 @@ class ClxMenuItemComponent {
12090
11723
  }, ...(ngDevMode ? [{ debugName: "_geom" }] : /* istanbul ignore next */ []));
12091
11724
  _iconCls = computed(() => resolveColor(this._resolvedColor()).textSubtle, ...(ngDevMode ? [{ debugName: "_iconCls" }] : /* istanbul ignore next */ []));
12092
11725
  _idleCls = computed(() => {
12093
- const hover = resolveColor(this._resolvedColor()).hoverBgMuted;
12094
- return `${NAV_ITEM_BASE} ${this._geom()} ${hover}`;
11726
+ const t = resolveColor(this._resolvedColor());
11727
+ return `${NAV_ITEM_BASE} ${this._geom()} ${NAV_ITEM_IDLE} ${t.hoverBgMuted}`;
12095
11728
  }, ...(ngDevMode ? [{ debugName: "_idleCls" }] : /* istanbul ignore next */ []));
12096
11729
  _activeCls = computed(() => {
12097
11730
  const t = resolveColor(this._resolvedColor());
@@ -12101,36 +11734,36 @@ class ClxMenuItemComponent {
12101
11734
  return `${NAV_ITEM_BASE} ${this._geom()} ${t.textSubtle} font-semibold border-l-2 ${t.borderLight} !pl-[22px] ${t.hoverBgMuted}`;
12102
11735
  }, ...(ngDevMode ? [{ debugName: "_activeCls" }] : /* istanbul ignore next */ []));
12103
11736
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxMenuItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
12104
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxMenuItemComponent, isStandalone: true, selector: "clx-menu-item", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, nested: { classPropertyName: "nested", publicName: "nested", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, routerLink: { classPropertyName: "routerLink", publicName: "routerLink", isSignal: true, isRequired: false, transformFunction: null }, routerLinkActiveOptions: { classPropertyName: "routerLinkActiveOptions", publicName: "routerLinkActiveOptions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick" }, host: { classAttribute: "block" }, ngImport: i0, template: `
12105
- @if (routerLink()) {
12106
- <a
12107
- [routerLink]="routerLink()"
12108
- routerLinkActive
12109
- #rla="routerLinkActive"
12110
- [routerLinkActiveOptions]="routerLinkActiveOptions()"
12111
- [class]="rla.isActive ? _activeCls() : _idleCls()"
12112
- [title]="collapsed() ? label() : ''">
12113
- @if (icon()) {
12114
- <span clx-icon [name]="icon()" size="sm" [class]="_iconCls()"></span>
12115
- }
12116
- @if (!collapsed()) {
12117
- <span class="flex-1 text-left truncate" [class]="rla.isActive ? '' : 'text-clx-text-subtle'">{{ label() }}</span>
12118
- }
12119
- </a>
12120
- } @else {
12121
- <button
12122
- type="button"
12123
- [class]="active() ? _activeCls() : _idleCls()"
12124
- [title]="collapsed() ? label() : ''"
12125
- (click)="itemClick.emit()">
12126
- @if (icon()) {
12127
- <span clx-icon [name]="icon()" size="sm" [class]="_iconCls()"></span>
12128
- }
12129
- @if (!collapsed()) {
12130
- <span class="flex-1 text-left truncate" [class]="active() ? '' : 'text-clx-text-subtle'">{{ label() }}</span>
12131
- }
12132
- </button>
12133
- }
11737
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxMenuItemComponent, isStandalone: true, selector: "clx-menu-item", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, nested: { classPropertyName: "nested", publicName: "nested", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, routerLink: { classPropertyName: "routerLink", publicName: "routerLink", isSignal: true, isRequired: false, transformFunction: null }, routerLinkActiveOptions: { classPropertyName: "routerLinkActiveOptions", publicName: "routerLinkActiveOptions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick" }, host: { classAttribute: "block" }, ngImport: i0, template: `
11738
+ @if (routerLink()) {
11739
+ <a
11740
+ [routerLink]="routerLink()"
11741
+ routerLinkActive
11742
+ #rla="routerLinkActive"
11743
+ [routerLinkActiveOptions]="routerLinkActiveOptions()"
11744
+ [class]="rla.isActive ? _activeCls() : _idleCls()"
11745
+ [title]="collapsed() ? label() : ''">
11746
+ @if (icon()) {
11747
+ <span clx-icon [name]="icon()" size="sm" [class]="rla.isActive ? _iconCls() : 'text-clx-text-subtle'"></span>
11748
+ }
11749
+ @if (!collapsed()) {
11750
+ <span class="flex-1 text-left truncate">{{ label() }}</span>
11751
+ }
11752
+ </a>
11753
+ } @else {
11754
+ <button
11755
+ type="button"
11756
+ [class]="active() ? _activeCls() : _idleCls()"
11757
+ [title]="collapsed() ? label() : ''"
11758
+ (click)="itemClick.emit()">
11759
+ @if (icon()) {
11760
+ <span clx-icon [name]="icon()" size="sm" [class]="active() ? _iconCls() : 'text-clx-text-subtle'"></span>
11761
+ }
11762
+ @if (!collapsed()) {
11763
+ <span class="flex-1 text-left truncate">{{ label() }}</span>
11764
+ }
11765
+ </button>
11766
+ }
12134
11767
  `, isInline: true, dependencies: [{ kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
12135
11768
  }
12136
11769
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxMenuItemComponent, decorators: [{
@@ -12139,36 +11772,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
12139
11772
  selector: 'clx-menu-item',
12140
11773
  standalone: true,
12141
11774
  imports: [ClxIconComponent, RouterLink, RouterLinkActive],
12142
- template: `
12143
- @if (routerLink()) {
12144
- <a
12145
- [routerLink]="routerLink()"
12146
- routerLinkActive
12147
- #rla="routerLinkActive"
12148
- [routerLinkActiveOptions]="routerLinkActiveOptions()"
12149
- [class]="rla.isActive ? _activeCls() : _idleCls()"
12150
- [title]="collapsed() ? label() : ''">
12151
- @if (icon()) {
12152
- <span clx-icon [name]="icon()" size="sm" [class]="_iconCls()"></span>
12153
- }
12154
- @if (!collapsed()) {
12155
- <span class="flex-1 text-left truncate" [class]="rla.isActive ? '' : 'text-clx-text-subtle'">{{ label() }}</span>
12156
- }
12157
- </a>
12158
- } @else {
12159
- <button
12160
- type="button"
12161
- [class]="active() ? _activeCls() : _idleCls()"
12162
- [title]="collapsed() ? label() : ''"
12163
- (click)="itemClick.emit()">
12164
- @if (icon()) {
12165
- <span clx-icon [name]="icon()" size="sm" [class]="_iconCls()"></span>
12166
- }
12167
- @if (!collapsed()) {
12168
- <span class="flex-1 text-left truncate" [class]="active() ? '' : 'text-clx-text-subtle'">{{ label() }}</span>
12169
- }
12170
- </button>
12171
- }
11775
+ template: `
11776
+ @if (routerLink()) {
11777
+ <a
11778
+ [routerLink]="routerLink()"
11779
+ routerLinkActive
11780
+ #rla="routerLinkActive"
11781
+ [routerLinkActiveOptions]="routerLinkActiveOptions()"
11782
+ [class]="rla.isActive ? _activeCls() : _idleCls()"
11783
+ [title]="collapsed() ? label() : ''">
11784
+ @if (icon()) {
11785
+ <span clx-icon [name]="icon()" size="sm" [class]="rla.isActive ? _iconCls() : 'text-clx-text-subtle'"></span>
11786
+ }
11787
+ @if (!collapsed()) {
11788
+ <span class="flex-1 text-left truncate">{{ label() }}</span>
11789
+ }
11790
+ </a>
11791
+ } @else {
11792
+ <button
11793
+ type="button"
11794
+ [class]="active() ? _activeCls() : _idleCls()"
11795
+ [title]="collapsed() ? label() : ''"
11796
+ (click)="itemClick.emit()">
11797
+ @if (icon()) {
11798
+ <span clx-icon [name]="icon()" size="sm" [class]="active() ? _iconCls() : 'text-clx-text-subtle'"></span>
11799
+ }
11800
+ @if (!collapsed()) {
11801
+ <span class="flex-1 text-left truncate">{{ label() }}</span>
11802
+ }
11803
+ </button>
11804
+ }
12172
11805
  `,
12173
11806
  encapsulation: ViewEncapsulation.None,
12174
11807
  changeDetection: ChangeDetectionStrategy.OnPush,
@@ -12181,13 +11814,14 @@ class ClxMenuComponent {
12181
11814
  label = input.required(...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
12182
11815
  icon = input('', ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
12183
11816
  color = input(undefined, ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
12184
- _color = computed(() => this.color() ?? this._themeSvc.sidebarMenuColor(), ...(ngDevMode ? [{ debugName: "_color" }] : /* istanbul ignore next */ []));
11817
+ _color = computed(() => this.color() ?? this._themeSvc.config().primaryColor, ...(ngDevMode ? [{ debugName: "_color" }] : /* istanbul ignore next */ []));
12185
11818
  collapsed = input(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
12186
11819
  active = input(false, ...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
12187
11820
  routerLink = input('', ...(ngDevMode ? [{ debugName: "routerLink" }] : /* istanbul ignore next */ []));
12188
11821
  routerLinkActiveOptions = input({ exact: false }, ...(ngDevMode ? [{ debugName: "routerLinkActiveOptions" }] : /* istanbul ignore next */ []));
12189
11822
  _isExpanded = signal(false, ...(ngDevMode ? [{ debugName: "_isExpanded" }] : /* istanbul ignore next */ []));
12190
11823
  _rla;
11824
+ _childItems;
12191
11825
  _destroyRef = inject(DestroyRef);
12192
11826
  constructor() {
12193
11827
  effect(() => { if (this.active())
@@ -12215,70 +11849,80 @@ class ClxMenuComponent {
12215
11849
  return `${base} ${t.textSubtle} font-semibold`;
12216
11850
  return `${base} ${t.textSubtle} font-semibold border-l-2 ${t.borderLight} !pl-[22px]`;
12217
11851
  }
12218
- return `${base} ${t.hoverBgMuted}`;
11852
+ return `${base} ${NAV_ITEM_IDLE} ${t.hoverBgMuted}`;
12219
11853
  }
12220
11854
  NAV_CHILDREN_WRAPPER = NAV_CHILDREN_WRAPPER;
12221
11855
  NAV_CHILDREN_INNER = NAV_CHILDREN_INNER;
12222
11856
  NAV_CHILDREN_LIST = NAV_CHILDREN_LIST;
11857
+ ngAfterContentInit() {
11858
+ this._syncChildren();
11859
+ this._childItems.changes
11860
+ .pipe(takeUntilDestroyed(this._destroyRef))
11861
+ .subscribe(() => this._syncChildren());
11862
+ }
11863
+ _syncChildren() {
11864
+ const color = this._color();
11865
+ this._childItems.forEach(c => c.inheritColor(color));
11866
+ }
12223
11867
  _toggle() {
12224
11868
  this._isExpanded.update(v => !v);
12225
11869
  }
12226
11870
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
12227
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxMenuComponent, isStandalone: true, selector: "clx-menu", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, routerLink: { classPropertyName: "routerLink", publicName: "routerLink", isSignal: true, isRequired: false, transformFunction: null }, routerLinkActiveOptions: { classPropertyName: "routerLinkActiveOptions", publicName: "routerLinkActiveOptions", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "block" }, viewQueries: [{ propertyName: "_rla", first: true, predicate: RouterLinkActive, descendants: true }], ngImport: i0, template: `
12228
- @if (routerLink()) {
12229
- <a
12230
- [routerLink]="routerLink()"
12231
- routerLinkActive
12232
- #rla="routerLinkActive"
12233
- [routerLinkActiveOptions]="routerLinkActiveOptions()"
12234
- [class]="_buttonCls(rla.isActive)"
12235
- [title]="collapsed() ? label() : ''"
12236
- (click)="$event.preventDefault(); !collapsed() && _toggle()">
12237
- @if (icon()) {
12238
- <span clx-icon [name]="icon()" size="sm" [class]="_iconCls()"></span>
12239
- }
12240
- @if (!collapsed()) {
12241
- <span class="flex-1 text-left truncate" [class]="rla.isActive ? '' : 'text-clx-text-subtle'">{{ label() }}</span>
12242
- <span
12243
- clx-icon
12244
- name="expand_more"
12245
- size="sm"
12246
- class="shrink-0 transition-transform duration-300"
12247
- [style.transform]="_isExpanded() ? 'rotate(180deg)' : 'rotate(0deg)'">
12248
- </span>
12249
- }
12250
- </a>
12251
- } @else {
12252
- <button
12253
- type="button"
12254
- [class]="_buttonCls(active())"
12255
- [title]="collapsed() ? label() : ''"
12256
- (click)="!collapsed() && _toggle()">
12257
- @if (icon()) {
12258
- <span clx-icon [name]="icon()" size="sm" [class]="_iconCls()"></span>
12259
- }
12260
- @if (!collapsed()) {
12261
- <span class="flex-1 text-left truncate" [class]="active() ? '' : 'text-clx-text-subtle'">{{ label() }}</span>
12262
- <span
12263
- clx-icon
12264
- name="expand_more"
12265
- size="sm"
12266
- class="shrink-0 transition-transform duration-300"
12267
- [style.transform]="_isExpanded() ? 'rotate(180deg)' : 'rotate(0deg)'">
12268
- </span>
12269
- }
12270
- </button>
12271
- }
12272
-
12273
- <div
12274
- [class]="NAV_CHILDREN_WRAPPER"
12275
- [style.grid-template-rows]="(!collapsed() && _isExpanded()) ? '1fr' : '0fr'">
12276
- <div [class]="NAV_CHILDREN_INNER">
12277
- <div [class]="NAV_CHILDREN_LIST">
12278
- <ng-content></ng-content>
12279
- </div>
12280
- </div>
12281
- </div>
11871
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxMenuComponent, isStandalone: true, selector: "clx-menu", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, routerLink: { classPropertyName: "routerLink", publicName: "routerLink", isSignal: true, isRequired: false, transformFunction: null }, routerLinkActiveOptions: { classPropertyName: "routerLinkActiveOptions", publicName: "routerLinkActiveOptions", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "block" }, queries: [{ propertyName: "_childItems", predicate: ClxMenuItemComponent, descendants: true }], viewQueries: [{ propertyName: "_rla", first: true, predicate: RouterLinkActive, descendants: true }], ngImport: i0, template: `
11872
+ @if (routerLink()) {
11873
+ <a
11874
+ [routerLink]="routerLink()"
11875
+ routerLinkActive
11876
+ #rla="routerLinkActive"
11877
+ [routerLinkActiveOptions]="routerLinkActiveOptions()"
11878
+ [class]="_buttonCls(rla.isActive)"
11879
+ [title]="collapsed() ? label() : ''"
11880
+ (click)="$event.preventDefault(); !collapsed() && _toggle()">
11881
+ @if (icon()) {
11882
+ <span clx-icon [name]="icon()" size="sm" [class]="_iconCls()"></span>
11883
+ }
11884
+ @if (!collapsed()) {
11885
+ <span class="flex-1 text-left truncate">{{ label() }}</span>
11886
+ <span
11887
+ clx-icon
11888
+ name="expand_more"
11889
+ size="sm"
11890
+ class="shrink-0 transition-transform duration-300"
11891
+ [style.transform]="_isExpanded() ? 'rotate(180deg)' : 'rotate(0deg)'">
11892
+ </span>
11893
+ }
11894
+ </a>
11895
+ } @else {
11896
+ <button
11897
+ type="button"
11898
+ [class]="_buttonCls(active())"
11899
+ [title]="collapsed() ? label() : ''"
11900
+ (click)="!collapsed() && _toggle()">
11901
+ @if (icon()) {
11902
+ <span clx-icon [name]="icon()" size="sm" [class]="_iconCls()"></span>
11903
+ }
11904
+ @if (!collapsed()) {
11905
+ <span class="flex-1 text-left truncate">{{ label() }}</span>
11906
+ <span
11907
+ clx-icon
11908
+ name="expand_more"
11909
+ size="sm"
11910
+ class="shrink-0 transition-transform duration-300"
11911
+ [style.transform]="_isExpanded() ? 'rotate(180deg)' : 'rotate(0deg)'">
11912
+ </span>
11913
+ }
11914
+ </button>
11915
+ }
11916
+
11917
+ <div
11918
+ [class]="NAV_CHILDREN_WRAPPER"
11919
+ [style.grid-template-rows]="(!collapsed() && _isExpanded()) ? '1fr' : '0fr'">
11920
+ <div [class]="NAV_CHILDREN_INNER">
11921
+ <div [class]="NAV_CHILDREN_LIST">
11922
+ <ng-content></ng-content>
11923
+ </div>
11924
+ </div>
11925
+ </div>
12282
11926
  `, isInline: true, dependencies: [{ kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
12283
11927
  }
12284
11928
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxMenuComponent, decorators: [{
@@ -12287,61 +11931,61 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
12287
11931
  selector: 'clx-menu',
12288
11932
  standalone: true,
12289
11933
  imports: [ClxIconComponent, RouterLink, RouterLinkActive],
12290
- template: `
12291
- @if (routerLink()) {
12292
- <a
12293
- [routerLink]="routerLink()"
12294
- routerLinkActive
12295
- #rla="routerLinkActive"
12296
- [routerLinkActiveOptions]="routerLinkActiveOptions()"
12297
- [class]="_buttonCls(rla.isActive)"
12298
- [title]="collapsed() ? label() : ''"
12299
- (click)="$event.preventDefault(); !collapsed() && _toggle()">
12300
- @if (icon()) {
12301
- <span clx-icon [name]="icon()" size="sm" [class]="_iconCls()"></span>
12302
- }
12303
- @if (!collapsed()) {
12304
- <span class="flex-1 text-left truncate" [class]="rla.isActive ? '' : 'text-clx-text-subtle'">{{ label() }}</span>
12305
- <span
12306
- clx-icon
12307
- name="expand_more"
12308
- size="sm"
12309
- class="shrink-0 transition-transform duration-300"
12310
- [style.transform]="_isExpanded() ? 'rotate(180deg)' : 'rotate(0deg)'">
12311
- </span>
12312
- }
12313
- </a>
12314
- } @else {
12315
- <button
12316
- type="button"
12317
- [class]="_buttonCls(active())"
12318
- [title]="collapsed() ? label() : ''"
12319
- (click)="!collapsed() && _toggle()">
12320
- @if (icon()) {
12321
- <span clx-icon [name]="icon()" size="sm" [class]="_iconCls()"></span>
12322
- }
12323
- @if (!collapsed()) {
12324
- <span class="flex-1 text-left truncate" [class]="active() ? '' : 'text-clx-text-subtle'">{{ label() }}</span>
12325
- <span
12326
- clx-icon
12327
- name="expand_more"
12328
- size="sm"
12329
- class="shrink-0 transition-transform duration-300"
12330
- [style.transform]="_isExpanded() ? 'rotate(180deg)' : 'rotate(0deg)'">
12331
- </span>
12332
- }
12333
- </button>
12334
- }
12335
-
12336
- <div
12337
- [class]="NAV_CHILDREN_WRAPPER"
12338
- [style.grid-template-rows]="(!collapsed() && _isExpanded()) ? '1fr' : '0fr'">
12339
- <div [class]="NAV_CHILDREN_INNER">
12340
- <div [class]="NAV_CHILDREN_LIST">
12341
- <ng-content></ng-content>
12342
- </div>
12343
- </div>
12344
- </div>
11934
+ template: `
11935
+ @if (routerLink()) {
11936
+ <a
11937
+ [routerLink]="routerLink()"
11938
+ routerLinkActive
11939
+ #rla="routerLinkActive"
11940
+ [routerLinkActiveOptions]="routerLinkActiveOptions()"
11941
+ [class]="_buttonCls(rla.isActive)"
11942
+ [title]="collapsed() ? label() : ''"
11943
+ (click)="$event.preventDefault(); !collapsed() && _toggle()">
11944
+ @if (icon()) {
11945
+ <span clx-icon [name]="icon()" size="sm" [class]="_iconCls()"></span>
11946
+ }
11947
+ @if (!collapsed()) {
11948
+ <span class="flex-1 text-left truncate">{{ label() }}</span>
11949
+ <span
11950
+ clx-icon
11951
+ name="expand_more"
11952
+ size="sm"
11953
+ class="shrink-0 transition-transform duration-300"
11954
+ [style.transform]="_isExpanded() ? 'rotate(180deg)' : 'rotate(0deg)'">
11955
+ </span>
11956
+ }
11957
+ </a>
11958
+ } @else {
11959
+ <button
11960
+ type="button"
11961
+ [class]="_buttonCls(active())"
11962
+ [title]="collapsed() ? label() : ''"
11963
+ (click)="!collapsed() && _toggle()">
11964
+ @if (icon()) {
11965
+ <span clx-icon [name]="icon()" size="sm" [class]="_iconCls()"></span>
11966
+ }
11967
+ @if (!collapsed()) {
11968
+ <span class="flex-1 text-left truncate">{{ label() }}</span>
11969
+ <span
11970
+ clx-icon
11971
+ name="expand_more"
11972
+ size="sm"
11973
+ class="shrink-0 transition-transform duration-300"
11974
+ [style.transform]="_isExpanded() ? 'rotate(180deg)' : 'rotate(0deg)'">
11975
+ </span>
11976
+ }
11977
+ </button>
11978
+ }
11979
+
11980
+ <div
11981
+ [class]="NAV_CHILDREN_WRAPPER"
11982
+ [style.grid-template-rows]="(!collapsed() && _isExpanded()) ? '1fr' : '0fr'">
11983
+ <div [class]="NAV_CHILDREN_INNER">
11984
+ <div [class]="NAV_CHILDREN_LIST">
11985
+ <ng-content></ng-content>
11986
+ </div>
11987
+ </div>
11988
+ </div>
12345
11989
  `,
12346
11990
  encapsulation: ViewEncapsulation.None,
12347
11991
  changeDetection: ChangeDetectionStrategy.OnPush,
@@ -12350,25 +11994,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
12350
11994
  }], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }], active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }], routerLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerLink", required: false }] }], routerLinkActiveOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerLinkActiveOptions", required: false }] }], _rla: [{
12351
11995
  type: ViewChild,
12352
11996
  args: [RouterLinkActive]
11997
+ }], _childItems: [{
11998
+ type: ContentChildren,
11999
+ args: [ClxMenuItemComponent, { descendants: true }]
12353
12000
  }] } });
12354
12001
 
12355
12002
  class ClxNavGroupComponent {
12356
12003
  label = input.required(...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
12357
12004
  collapsed = input(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
12358
- color = input(undefined, ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
12359
- labelClass = computed(() => {
12360
- const c = this.color();
12361
- return c ? resolveColor(c).textSubtle : 'text-clx-text-subtle';
12362
- }, ...(ngDevMode ? [{ debugName: "labelClass" }] : /* istanbul ignore next */ []));
12363
12005
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxNavGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
12364
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxNavGroupComponent, isStandalone: true, selector: "clx-nav-group", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "block" }, ngImport: i0, template: `
12365
- @if (!collapsed()) {
12366
- <span class="block px-6 pt-5 pb-1 text-[10px] font-bold uppercase tracking-widest select-none" [class]="labelClass()">{{ label() }}</span>
12367
- } @else {
12368
- <span class="flex items-center justify-center w-full py-3">
12369
- <span class="w-1.5 h-1.5 rounded-full bg-clx-border"></span>
12370
- </span>
12371
- }
12006
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxNavGroupComponent, isStandalone: true, selector: "clx-nav-group", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "block" }, ngImport: i0, template: `
12007
+ @if (!collapsed()) {
12008
+ <span class="block px-6 pt-5 pb-1 text-[10px] font-bold uppercase tracking-widest text-clx-text-subtle select-none">{{ label() }}</span>
12009
+ } @else {
12010
+ <span class="flex items-center justify-center w-full py-3">
12011
+ <span class="w-1.5 h-1.5 rounded-full bg-clx-border"></span>
12012
+ </span>
12013
+ }
12372
12014
  `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
12373
12015
  }
12374
12016
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxNavGroupComponent, decorators: [{
@@ -12376,20 +12018,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
12376
12018
  args: [{
12377
12019
  selector: 'clx-nav-group',
12378
12020
  standalone: true,
12379
- template: `
12380
- @if (!collapsed()) {
12381
- <span class="block px-6 pt-5 pb-1 text-[10px] font-bold uppercase tracking-widest select-none" [class]="labelClass()">{{ label() }}</span>
12382
- } @else {
12383
- <span class="flex items-center justify-center w-full py-3">
12384
- <span class="w-1.5 h-1.5 rounded-full bg-clx-border"></span>
12385
- </span>
12386
- }
12021
+ template: `
12022
+ @if (!collapsed()) {
12023
+ <span class="block px-6 pt-5 pb-1 text-[10px] font-bold uppercase tracking-widest text-clx-text-subtle select-none">{{ label() }}</span>
12024
+ } @else {
12025
+ <span class="flex items-center justify-center w-full py-3">
12026
+ <span class="w-1.5 h-1.5 rounded-full bg-clx-border"></span>
12027
+ </span>
12028
+ }
12387
12029
  `,
12388
12030
  encapsulation: ViewEncapsulation.None,
12389
12031
  changeDetection: ChangeDetectionStrategy.OnPush,
12390
12032
  host: { class: 'block' },
12391
12033
  }]
12392
- }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }] } });
12034
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }] } });
12393
12035
 
12394
12036
  class ClxProfileComponent {
12395
12037
  // ── Inputs ──────────────────────────────────────────────────────────────────
@@ -12610,7 +12252,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
12610
12252
  // ── Base classes ─────────────────────────────────────────────────────────────
12611
12253
  const TABLE_BASE_CLASS = 'w-full text-left border-collapse text-sm';
12612
12254
  const TABLE_HEADER_CELL_CLASS = 'px-4 py-3 font-semibold whitespace-nowrap';
12613
- const TABLE_CELL_CLASS = 'px-4 py-3 border-b border-clx-border-soft text-clx-text-label';
12255
+ const TABLE_CELL_CLASS = 'px-4 py-3 border-b border-slate-100 text-slate-700';
12614
12256
  const TABLE_ROW_CLASS = '';
12615
12257
  // ── Alignment ────────────────────────────────────────────────────────────────
12616
12258
  const TABLE_ALIGN_MAP = {
@@ -12870,25 +12512,20 @@ class ClxTableComponent {
12870
12512
  _isSelected(item) {
12871
12513
  return this.selectedItems().some(s => s === item);
12872
12514
  }
12873
- _headerCellClassMap = computed(() => {
12874
- const map = new Map();
12875
- for (const col of this.columns()) {
12876
- const align = TABLE_ALIGN_MAP[col.align || 'left'];
12877
- const cursor = col.sortable ? 'cursor-pointer select-none' : '';
12878
- const extra = col.headerClass || '';
12879
- map.set(col.key, `${TABLE_HEADER_CELL_CLASS} ${align} ${cursor} ${extra}`.trim());
12880
- }
12881
- return map;
12882
- }, ...(ngDevMode ? [{ debugName: "_headerCellClassMap" }] : /* istanbul ignore next */ []));
12883
- _dataCellClassMap = computed(() => {
12884
- const map = new Map();
12885
- for (const col of this.columns()) {
12886
- const align = TABLE_ALIGN_MAP[col.align || 'left'];
12887
- const extra = col.cellClass || '';
12888
- map.set(col.key, `${TABLE_CELL_CLASS} ${align} ${extra}`.trim());
12889
- }
12890
- return map;
12891
- }, ...(ngDevMode ? [{ debugName: "_dataCellClassMap" }] : /* istanbul ignore next */ []));
12515
+ _getAlignClass(align) {
12516
+ return TABLE_ALIGN_MAP[align];
12517
+ }
12518
+ _getHeaderCellClass(col) {
12519
+ const align = this._getAlignClass(col.align || 'left');
12520
+ const cursor = col.sortable ? 'cursor-pointer select-none' : '';
12521
+ const extra = col.headerClass || '';
12522
+ return `${TABLE_HEADER_CELL_CLASS} ${align} ${cursor} ${extra}`.trim();
12523
+ }
12524
+ _getDataCellClass(col) {
12525
+ const align = this._getAlignClass(col.align || 'left');
12526
+ const extra = col.cellClass || '';
12527
+ return `${TABLE_CELL_CLASS} ${align} ${extra}`.trim();
12528
+ }
12892
12529
  _getCellValue(item, key) {
12893
12530
  return item[key];
12894
12531
  }
@@ -12930,143 +12567,143 @@ class ClxTableComponent {
12930
12567
  this.selectionChange.emit({ selected: this.selectedItems(), allSelected: false });
12931
12568
  }
12932
12569
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
12933
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxTableComponent, isStandalone: true, selector: "clx-table", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, singleSelect: { classPropertyName: "singleSelect", publicName: "singleSelect", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, pagination: { classPropertyName: "pagination", publicName: "pagination", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, emptyIcon: { classPropertyName: "emptyIcon", publicName: "emptyIcon", isSignal: true, isRequired: false, transformFunction: null }, emptyTitle: { classPropertyName: "emptyTitle", publicName: "emptyTitle", isSignal: true, isRequired: false, transformFunction: null }, emptyDescription: { classPropertyName: "emptyDescription", publicName: "emptyDescription", isSignal: true, isRequired: false, transformFunction: null }, sortKey: { classPropertyName: "sortKey", publicName: "sortKey", isSignal: true, isRequired: false, transformFunction: null }, sortDir: { classPropertyName: "sortDir", publicName: "sortDir", isSignal: true, isRequired: false, transformFunction: null }, pageIndex: { classPropertyName: "pageIndex", publicName: "pageIndex", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, _currentPage: { classPropertyName: "_currentPage", publicName: "_currentPage", isSignal: true, isRequired: false, transformFunction: null }, searchQuery: { classPropertyName: "searchQuery", publicName: "searchQuery", isSignal: true, isRequired: false, transformFunction: null }, selectedItems: { classPropertyName: "selectedItems", publicName: "selectedItems", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortKey: "sortKeyChange", sortDir: "sortDirChange", pageIndex: "pageIndexChange", pageSize: "pageSizeChange", _currentPage: "_currentPageChange", searchQuery: "searchQueryChange", selectedItems: "selectedItemsChange", sortChange: "sortChange", pageChange: "pageChange", selectionChange: "selectionChange" }, host: { classAttribute: "block" }, queries: [{ propertyName: "_columnDefs", predicate: ClxColumnDefDirective, isSignal: true }], ngImport: i0, template: `
12934
- <!-- ── Toolbar: búsqueda ──────────────────────────────────────────────── -->
12935
- @if (searchable() && !loading() && _filteredData().length > 0) {
12936
- <div class="mb-3 max-w-80 min-w-40">
12937
- <clx-input
12938
- placeholder="Buscar..."
12939
- size="sm"
12940
- suffixIcon="search"
12941
- [color]="_color()"
12942
- [(ngModel)]="searchQuery">
12943
- </clx-input>
12944
- </div>
12945
- }
12946
-
12947
- @if (loading()) {
12948
- <!-- ── Loading State ───────────────────────────────────────────────── -->
12949
- <div class="space-y-3">
12950
- @for (row of [1, 2, 3, 4, 5]; track row) {
12951
- <div class="flex items-center gap-4">
12952
- @if (selectable()) {
12953
- <clx-skeleton variant="circular" size="xs"></clx-skeleton>
12954
- }
12955
- @for (col of columns(); track col.key) {
12956
- <clx-skeleton variant="text" size="md" [style.flex]="'1'"></clx-skeleton>
12957
- }
12958
- </div>
12959
- }
12960
- </div>
12961
- } @else if (_filteredData().length === 0) {
12962
- <!-- ── Empty State ─────────────────────────────────────────────────── -->
12963
- <div class="py-10">
12964
- <clx-page-empty
12965
- size="sm"
12966
- [icon]="emptyIcon()"
12967
- [title]="_emptyTitle()"
12968
- [description]="_emptyDescription()" />
12969
- </div>
12970
- } @else {
12971
- <!-- ── Tabla ───────────────────────────────────────────────────────── -->
12972
- <div class="overflow-x-auto">
12973
- <table [class]="_tableClass()">
12974
- <thead>
12975
- <tr [class]="_headerClass()">
12976
- @if (selectable()) {
12977
- <th [class]="_headerCellClass()"
12978
- [class.rounded-tl-lg]="true"
12979
- [class.rounded-bl-lg]="true"
12980
- class="w-10 text-center">
12981
- @if (!singleSelect()) {
12982
- <clx-checkbox
12983
- [color]="_color()"
12984
- [ngModel]="_allSelected()"
12985
- (ngModelChange)="_handleSelectAll($event)">
12986
- </clx-checkbox>
12987
- }
12988
- </th>
12989
- }
12990
-
12991
- @for (col of columns(); track col.key; let first = $first; let last = $last) {
12992
- <th
12993
- [class]="_headerCellClassMap().get(col.key)"
12994
- [class.rounded-tl-lg]="first && !selectable()"
12995
- [class.rounded-bl-lg]="first && !selectable()"
12996
- [class.rounded-tr-lg]="last"
12997
- [class.rounded-br-lg]="last"
12998
- [style.width]="col.width"
12999
- (click)="col.sortable && _handleSort(col.key)">
13000
- <div class="flex items-center gap-1.5"
13001
- [class.justify-end]="col.align === 'right'"
13002
- [class.justify-center]="col.align === 'center'">
13003
- @if (_getColumnDef(col.key)?.headerCell()?.templateRef; as tpl) {
13004
- <ng-container [ngTemplateOutlet]="tpl"></ng-container>
13005
- } @else {
13006
- <span>{{ col.header || col.key }}</span>
13007
- }
13008
- @if (col.sortable) {
13009
- <span class="opacity-50">
13010
- @if (sortKey() === col.key && sortDir() === 'asc') {
13011
- <span clx-icon name="arrow_upward" size="xs"></span>
13012
- } @else if (sortKey() === col.key && sortDir() === 'desc') {
13013
- <span clx-icon name="arrow_downward" size="xs"></span>
13014
- } @else {
13015
- <span clx-icon name="swap_vert" size="xs"></span>
13016
- }
13017
- </span>
13018
- }
13019
- </div>
13020
- </th>
13021
- }
13022
- </tr>
13023
- </thead>
13024
-
13025
- <tbody>
13026
- @for (item of _paginatedData(); track i; let i = $index) {
13027
- <tr [class]="_rowClass()">
13028
- @if (selectable()) {
13029
- <td [class]="_cellClass()" class="text-center">
13030
- <clx-checkbox
13031
- [color]="_color()"
13032
- [ngModel]="_isSelected(item)"
13033
- (ngModelChange)="_handleSelectItem(item, $event)">
13034
- </clx-checkbox>
13035
- </td>
13036
- }
13037
-
13038
- @for (col of columns(); track col.key) {
13039
- <td [class]="_dataCellClassMap().get(col.key)">
13040
- @if (_getColumnDef(col.key)?.cell()?.templateRef; as tpl) {
13041
- <ng-container
13042
- [ngTemplateOutlet]="tpl"
13043
- [ngTemplateOutletContext]="{ $implicit: item, index: i }">
13044
- </ng-container>
13045
- } @else {
13046
- {{ _getCellValue(item, col.key) }}
13047
- }
13048
- </td>
13049
- }
13050
- </tr>
13051
- }
13052
- </tbody>
13053
- </table>
13054
- </div>
13055
-
13056
- <!-- ── Footer: clx-pagination ────────────────────────────────────────── -->
13057
- @if (pagination()) {
13058
- <div class="border-t border-clx-border-soft pt-3">
13059
- <clx-pagination
13060
- size="sm"
13061
- [totalItems]="_totalItems()"
13062
- [color]="_color()"
13063
- [(currentPage)]="_currentPage"
13064
- [(pageSize)]="pageSize"
13065
- (pageChange)="_onPaginationPageChange($event.page)">
13066
- </clx-pagination>
13067
- </div>
13068
- }
13069
- }
12570
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxTableComponent, isStandalone: true, selector: "clx-table", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, singleSelect: { classPropertyName: "singleSelect", publicName: "singleSelect", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, pagination: { classPropertyName: "pagination", publicName: "pagination", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, emptyIcon: { classPropertyName: "emptyIcon", publicName: "emptyIcon", isSignal: true, isRequired: false, transformFunction: null }, emptyTitle: { classPropertyName: "emptyTitle", publicName: "emptyTitle", isSignal: true, isRequired: false, transformFunction: null }, emptyDescription: { classPropertyName: "emptyDescription", publicName: "emptyDescription", isSignal: true, isRequired: false, transformFunction: null }, sortKey: { classPropertyName: "sortKey", publicName: "sortKey", isSignal: true, isRequired: false, transformFunction: null }, sortDir: { classPropertyName: "sortDir", publicName: "sortDir", isSignal: true, isRequired: false, transformFunction: null }, pageIndex: { classPropertyName: "pageIndex", publicName: "pageIndex", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, _currentPage: { classPropertyName: "_currentPage", publicName: "_currentPage", isSignal: true, isRequired: false, transformFunction: null }, searchQuery: { classPropertyName: "searchQuery", publicName: "searchQuery", isSignal: true, isRequired: false, transformFunction: null }, selectedItems: { classPropertyName: "selectedItems", publicName: "selectedItems", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortKey: "sortKeyChange", sortDir: "sortDirChange", pageIndex: "pageIndexChange", pageSize: "pageSizeChange", _currentPage: "_currentPageChange", searchQuery: "searchQueryChange", selectedItems: "selectedItemsChange", sortChange: "sortChange", pageChange: "pageChange", selectionChange: "selectionChange" }, host: { classAttribute: "block" }, queries: [{ propertyName: "_columnDefs", predicate: ClxColumnDefDirective, isSignal: true }], ngImport: i0, template: `
12571
+ <!-- ── Toolbar: búsqueda ──────────────────────────────────────────────── -->
12572
+ @if (searchable() && !loading() && _filteredData().length > 0) {
12573
+ <div class="mb-3 max-w-80 min-w-40">
12574
+ <clx-input
12575
+ placeholder="Buscar..."
12576
+ size="sm"
12577
+ suffixIcon="search"
12578
+ [color]="_color()"
12579
+ [(ngModel)]="searchQuery">
12580
+ </clx-input>
12581
+ </div>
12582
+ }
12583
+
12584
+ @if (loading()) {
12585
+ <!-- ── Loading State ───────────────────────────────────────────────── -->
12586
+ <div class="space-y-3">
12587
+ @for (row of [1, 2, 3, 4, 5]; track row) {
12588
+ <div class="flex items-center gap-4">
12589
+ @if (selectable()) {
12590
+ <clx-skeleton variant="circular" size="xs"></clx-skeleton>
12591
+ }
12592
+ @for (col of columns(); track col.key) {
12593
+ <clx-skeleton variant="text" size="md" [style.flex]="'1'"></clx-skeleton>
12594
+ }
12595
+ </div>
12596
+ }
12597
+ </div>
12598
+ } @else if (_filteredData().length === 0) {
12599
+ <!-- ── Empty State ─────────────────────────────────────────────────── -->
12600
+ <div class="py-10">
12601
+ <clx-page-empty
12602
+ size="sm"
12603
+ [icon]="emptyIcon()"
12604
+ [title]="_emptyTitle()"
12605
+ [description]="_emptyDescription()" />
12606
+ </div>
12607
+ } @else {
12608
+ <!-- ── Tabla ───────────────────────────────────────────────────────── -->
12609
+ <div class="overflow-x-auto">
12610
+ <table [class]="_tableClass()">
12611
+ <thead>
12612
+ <tr [class]="_headerClass()">
12613
+ @if (selectable()) {
12614
+ <th [class]="_headerCellClass()"
12615
+ [class.rounded-tl-lg]="true"
12616
+ [class.rounded-bl-lg]="true"
12617
+ class="w-10 text-center">
12618
+ @if (!singleSelect()) {
12619
+ <clx-checkbox
12620
+ [color]="_color()"
12621
+ [ngModel]="_allSelected()"
12622
+ (ngModelChange)="_handleSelectAll($event)">
12623
+ </clx-checkbox>
12624
+ }
12625
+ </th>
12626
+ }
12627
+
12628
+ @for (col of columns(); track col.key; let first = $first; let last = $last) {
12629
+ <th
12630
+ [class]="_getHeaderCellClass(col)"
12631
+ [class.rounded-tl-lg]="first && !selectable()"
12632
+ [class.rounded-bl-lg]="first && !selectable()"
12633
+ [class.rounded-tr-lg]="last"
12634
+ [class.rounded-br-lg]="last"
12635
+ [style.width]="col.width"
12636
+ (click)="col.sortable && _handleSort(col.key)">
12637
+ <div class="flex items-center gap-1.5"
12638
+ [class.justify-end]="col.align === 'right'"
12639
+ [class.justify-center]="col.align === 'center'">
12640
+ @if (_getColumnDef(col.key)?.headerCell()?.templateRef; as tpl) {
12641
+ <ng-container [ngTemplateOutlet]="tpl"></ng-container>
12642
+ } @else {
12643
+ <span>{{ col.header || col.key }}</span>
12644
+ }
12645
+ @if (col.sortable) {
12646
+ <span class="opacity-50">
12647
+ @if (sortKey() === col.key && sortDir() === 'asc') {
12648
+ <span clx-icon name="arrow_upward" size="xs"></span>
12649
+ } @else if (sortKey() === col.key && sortDir() === 'desc') {
12650
+ <span clx-icon name="arrow_downward" size="xs"></span>
12651
+ } @else {
12652
+ <span clx-icon name="swap_vert" size="xs"></span>
12653
+ }
12654
+ </span>
12655
+ }
12656
+ </div>
12657
+ </th>
12658
+ }
12659
+ </tr>
12660
+ </thead>
12661
+
12662
+ <tbody>
12663
+ @for (item of _paginatedData(); track i; let i = $index) {
12664
+ <tr [class]="_rowClass()">
12665
+ @if (selectable()) {
12666
+ <td [class]="_cellClass()" class="text-center">
12667
+ <clx-checkbox
12668
+ [color]="_color()"
12669
+ [ngModel]="_isSelected(item)"
12670
+ (ngModelChange)="_handleSelectItem(item, $event)">
12671
+ </clx-checkbox>
12672
+ </td>
12673
+ }
12674
+
12675
+ @for (col of columns(); track col.key) {
12676
+ <td [class]="_getDataCellClass(col)">
12677
+ @if (_getColumnDef(col.key)?.cell()?.templateRef; as tpl) {
12678
+ <ng-container
12679
+ [ngTemplateOutlet]="tpl"
12680
+ [ngTemplateOutletContext]="{ $implicit: item, index: i }">
12681
+ </ng-container>
12682
+ } @else {
12683
+ {{ _getCellValue(item, col.key) }}
12684
+ }
12685
+ </td>
12686
+ }
12687
+ </tr>
12688
+ }
12689
+ </tbody>
12690
+ </table>
12691
+ </div>
12692
+
12693
+ <!-- ── Footer: clx-pagination ────────────────────────────────────────── -->
12694
+ @if (pagination()) {
12695
+ <div class="border-t border-clx-border-soft pt-3">
12696
+ <clx-pagination
12697
+ size="sm"
12698
+ [totalItems]="_totalItems()"
12699
+ [color]="_color()"
12700
+ [(currentPage)]="_currentPage"
12701
+ [(pageSize)]="pageSize"
12702
+ (pageChange)="_onPaginationPageChange($event.page)">
12703
+ </clx-pagination>
12704
+ </div>
12705
+ }
12706
+ }
13070
12707
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ClxCheckboxComponent, selector: "clx-checkbox", inputs: ["color", "variant", "size", "label", "value", "disabled"] }, { kind: "component", type: ClxInputComponent, selector: "clx-input", inputs: ["label", "placeholder", "type", "color", "hint", "prefixIcon", "suffixIcon", "prefixText", "suffixText", "status", "statusMessage", "size", "value", "disabled", "autocomplete"] }, { kind: "component", type: ClxSkeletonComponent, selector: "clx-skeleton", inputs: ["variant", "size", "width", "height"] }, { kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "component", type: ClxPaginationComponent, selector: "clx-pagination", inputs: ["totalItems", "color", "size", "showPageSize", "pageSizeOptions", "currentPage", "pageSize"], outputs: ["currentPageChange", "pageSizeChange", "pageChange", "sizeChange"] }, { kind: "component", type: ClxPageEmptyComponent, selector: "clx-page-empty", inputs: ["icon", "title", "description", "ctaLabel", "ctaIcon", "ctaColor", "size"], outputs: ["cta"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
13071
12708
  }
13072
12709
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxTableComponent, decorators: [{
@@ -13084,143 +12721,143 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
13084
12721
  ClxPaginationComponent,
13085
12722
  ClxPageEmptyComponent,
13086
12723
  ],
13087
- template: `
13088
- <!-- ── Toolbar: búsqueda ──────────────────────────────────────────────── -->
13089
- @if (searchable() && !loading() && _filteredData().length > 0) {
13090
- <div class="mb-3 max-w-80 min-w-40">
13091
- <clx-input
13092
- placeholder="Buscar..."
13093
- size="sm"
13094
- suffixIcon="search"
13095
- [color]="_color()"
13096
- [(ngModel)]="searchQuery">
13097
- </clx-input>
13098
- </div>
13099
- }
13100
-
13101
- @if (loading()) {
13102
- <!-- ── Loading State ───────────────────────────────────────────────── -->
13103
- <div class="space-y-3">
13104
- @for (row of [1, 2, 3, 4, 5]; track row) {
13105
- <div class="flex items-center gap-4">
13106
- @if (selectable()) {
13107
- <clx-skeleton variant="circular" size="xs"></clx-skeleton>
13108
- }
13109
- @for (col of columns(); track col.key) {
13110
- <clx-skeleton variant="text" size="md" [style.flex]="'1'"></clx-skeleton>
13111
- }
13112
- </div>
13113
- }
13114
- </div>
13115
- } @else if (_filteredData().length === 0) {
13116
- <!-- ── Empty State ─────────────────────────────────────────────────── -->
13117
- <div class="py-10">
13118
- <clx-page-empty
13119
- size="sm"
13120
- [icon]="emptyIcon()"
13121
- [title]="_emptyTitle()"
13122
- [description]="_emptyDescription()" />
13123
- </div>
13124
- } @else {
13125
- <!-- ── Tabla ───────────────────────────────────────────────────────── -->
13126
- <div class="overflow-x-auto">
13127
- <table [class]="_tableClass()">
13128
- <thead>
13129
- <tr [class]="_headerClass()">
13130
- @if (selectable()) {
13131
- <th [class]="_headerCellClass()"
13132
- [class.rounded-tl-lg]="true"
13133
- [class.rounded-bl-lg]="true"
13134
- class="w-10 text-center">
13135
- @if (!singleSelect()) {
13136
- <clx-checkbox
13137
- [color]="_color()"
13138
- [ngModel]="_allSelected()"
13139
- (ngModelChange)="_handleSelectAll($event)">
13140
- </clx-checkbox>
13141
- }
13142
- </th>
13143
- }
13144
-
13145
- @for (col of columns(); track col.key; let first = $first; let last = $last) {
13146
- <th
13147
- [class]="_headerCellClassMap().get(col.key)"
13148
- [class.rounded-tl-lg]="first && !selectable()"
13149
- [class.rounded-bl-lg]="first && !selectable()"
13150
- [class.rounded-tr-lg]="last"
13151
- [class.rounded-br-lg]="last"
13152
- [style.width]="col.width"
13153
- (click)="col.sortable && _handleSort(col.key)">
13154
- <div class="flex items-center gap-1.5"
13155
- [class.justify-end]="col.align === 'right'"
13156
- [class.justify-center]="col.align === 'center'">
13157
- @if (_getColumnDef(col.key)?.headerCell()?.templateRef; as tpl) {
13158
- <ng-container [ngTemplateOutlet]="tpl"></ng-container>
13159
- } @else {
13160
- <span>{{ col.header || col.key }}</span>
13161
- }
13162
- @if (col.sortable) {
13163
- <span class="opacity-50">
13164
- @if (sortKey() === col.key && sortDir() === 'asc') {
13165
- <span clx-icon name="arrow_upward" size="xs"></span>
13166
- } @else if (sortKey() === col.key && sortDir() === 'desc') {
13167
- <span clx-icon name="arrow_downward" size="xs"></span>
13168
- } @else {
13169
- <span clx-icon name="swap_vert" size="xs"></span>
13170
- }
13171
- </span>
13172
- }
13173
- </div>
13174
- </th>
13175
- }
13176
- </tr>
13177
- </thead>
13178
-
13179
- <tbody>
13180
- @for (item of _paginatedData(); track i; let i = $index) {
13181
- <tr [class]="_rowClass()">
13182
- @if (selectable()) {
13183
- <td [class]="_cellClass()" class="text-center">
13184
- <clx-checkbox
13185
- [color]="_color()"
13186
- [ngModel]="_isSelected(item)"
13187
- (ngModelChange)="_handleSelectItem(item, $event)">
13188
- </clx-checkbox>
13189
- </td>
13190
- }
13191
-
13192
- @for (col of columns(); track col.key) {
13193
- <td [class]="_dataCellClassMap().get(col.key)">
13194
- @if (_getColumnDef(col.key)?.cell()?.templateRef; as tpl) {
13195
- <ng-container
13196
- [ngTemplateOutlet]="tpl"
13197
- [ngTemplateOutletContext]="{ $implicit: item, index: i }">
13198
- </ng-container>
13199
- } @else {
13200
- {{ _getCellValue(item, col.key) }}
13201
- }
13202
- </td>
13203
- }
13204
- </tr>
13205
- }
13206
- </tbody>
13207
- </table>
13208
- </div>
13209
-
13210
- <!-- ── Footer: clx-pagination ────────────────────────────────────────── -->
13211
- @if (pagination()) {
13212
- <div class="border-t border-clx-border-soft pt-3">
13213
- <clx-pagination
13214
- size="sm"
13215
- [totalItems]="_totalItems()"
13216
- [color]="_color()"
13217
- [(currentPage)]="_currentPage"
13218
- [(pageSize)]="pageSize"
13219
- (pageChange)="_onPaginationPageChange($event.page)">
13220
- </clx-pagination>
13221
- </div>
13222
- }
13223
- }
12724
+ template: `
12725
+ <!-- ── Toolbar: búsqueda ──────────────────────────────────────────────── -->
12726
+ @if (searchable() && !loading() && _filteredData().length > 0) {
12727
+ <div class="mb-3 max-w-80 min-w-40">
12728
+ <clx-input
12729
+ placeholder="Buscar..."
12730
+ size="sm"
12731
+ suffixIcon="search"
12732
+ [color]="_color()"
12733
+ [(ngModel)]="searchQuery">
12734
+ </clx-input>
12735
+ </div>
12736
+ }
12737
+
12738
+ @if (loading()) {
12739
+ <!-- ── Loading State ───────────────────────────────────────────────── -->
12740
+ <div class="space-y-3">
12741
+ @for (row of [1, 2, 3, 4, 5]; track row) {
12742
+ <div class="flex items-center gap-4">
12743
+ @if (selectable()) {
12744
+ <clx-skeleton variant="circular" size="xs"></clx-skeleton>
12745
+ }
12746
+ @for (col of columns(); track col.key) {
12747
+ <clx-skeleton variant="text" size="md" [style.flex]="'1'"></clx-skeleton>
12748
+ }
12749
+ </div>
12750
+ }
12751
+ </div>
12752
+ } @else if (_filteredData().length === 0) {
12753
+ <!-- ── Empty State ─────────────────────────────────────────────────── -->
12754
+ <div class="py-10">
12755
+ <clx-page-empty
12756
+ size="sm"
12757
+ [icon]="emptyIcon()"
12758
+ [title]="_emptyTitle()"
12759
+ [description]="_emptyDescription()" />
12760
+ </div>
12761
+ } @else {
12762
+ <!-- ── Tabla ───────────────────────────────────────────────────────── -->
12763
+ <div class="overflow-x-auto">
12764
+ <table [class]="_tableClass()">
12765
+ <thead>
12766
+ <tr [class]="_headerClass()">
12767
+ @if (selectable()) {
12768
+ <th [class]="_headerCellClass()"
12769
+ [class.rounded-tl-lg]="true"
12770
+ [class.rounded-bl-lg]="true"
12771
+ class="w-10 text-center">
12772
+ @if (!singleSelect()) {
12773
+ <clx-checkbox
12774
+ [color]="_color()"
12775
+ [ngModel]="_allSelected()"
12776
+ (ngModelChange)="_handleSelectAll($event)">
12777
+ </clx-checkbox>
12778
+ }
12779
+ </th>
12780
+ }
12781
+
12782
+ @for (col of columns(); track col.key; let first = $first; let last = $last) {
12783
+ <th
12784
+ [class]="_getHeaderCellClass(col)"
12785
+ [class.rounded-tl-lg]="first && !selectable()"
12786
+ [class.rounded-bl-lg]="first && !selectable()"
12787
+ [class.rounded-tr-lg]="last"
12788
+ [class.rounded-br-lg]="last"
12789
+ [style.width]="col.width"
12790
+ (click)="col.sortable && _handleSort(col.key)">
12791
+ <div class="flex items-center gap-1.5"
12792
+ [class.justify-end]="col.align === 'right'"
12793
+ [class.justify-center]="col.align === 'center'">
12794
+ @if (_getColumnDef(col.key)?.headerCell()?.templateRef; as tpl) {
12795
+ <ng-container [ngTemplateOutlet]="tpl"></ng-container>
12796
+ } @else {
12797
+ <span>{{ col.header || col.key }}</span>
12798
+ }
12799
+ @if (col.sortable) {
12800
+ <span class="opacity-50">
12801
+ @if (sortKey() === col.key && sortDir() === 'asc') {
12802
+ <span clx-icon name="arrow_upward" size="xs"></span>
12803
+ } @else if (sortKey() === col.key && sortDir() === 'desc') {
12804
+ <span clx-icon name="arrow_downward" size="xs"></span>
12805
+ } @else {
12806
+ <span clx-icon name="swap_vert" size="xs"></span>
12807
+ }
12808
+ </span>
12809
+ }
12810
+ </div>
12811
+ </th>
12812
+ }
12813
+ </tr>
12814
+ </thead>
12815
+
12816
+ <tbody>
12817
+ @for (item of _paginatedData(); track i; let i = $index) {
12818
+ <tr [class]="_rowClass()">
12819
+ @if (selectable()) {
12820
+ <td [class]="_cellClass()" class="text-center">
12821
+ <clx-checkbox
12822
+ [color]="_color()"
12823
+ [ngModel]="_isSelected(item)"
12824
+ (ngModelChange)="_handleSelectItem(item, $event)">
12825
+ </clx-checkbox>
12826
+ </td>
12827
+ }
12828
+
12829
+ @for (col of columns(); track col.key) {
12830
+ <td [class]="_getDataCellClass(col)">
12831
+ @if (_getColumnDef(col.key)?.cell()?.templateRef; as tpl) {
12832
+ <ng-container
12833
+ [ngTemplateOutlet]="tpl"
12834
+ [ngTemplateOutletContext]="{ $implicit: item, index: i }">
12835
+ </ng-container>
12836
+ } @else {
12837
+ {{ _getCellValue(item, col.key) }}
12838
+ }
12839
+ </td>
12840
+ }
12841
+ </tr>
12842
+ }
12843
+ </tbody>
12844
+ </table>
12845
+ </div>
12846
+
12847
+ <!-- ── Footer: clx-pagination ────────────────────────────────────────── -->
12848
+ @if (pagination()) {
12849
+ <div class="border-t border-clx-border-soft pt-3">
12850
+ <clx-pagination
12851
+ size="sm"
12852
+ [totalItems]="_totalItems()"
12853
+ [color]="_color()"
12854
+ [(currentPage)]="_currentPage"
12855
+ [(pageSize)]="pageSize"
12856
+ (pageChange)="_onPaginationPageChange($event.page)">
12857
+ </clx-pagination>
12858
+ </div>
12859
+ }
12860
+ }
13224
12861
  `,
13225
12862
  encapsulation: ViewEncapsulation.None,
13226
12863
  changeDetection: ChangeDetectionStrategy.OnPush,
@@ -15236,5 +14873,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
15236
14873
  * Generated bundle index. Do not edit.
15237
14874
  */
15238
14875
 
15239
- export { CLX_ADDON_BORDER, CLX_ADDON_TEXT, CLX_ALERT_OPTIONS, CLX_ALERT_RESOLVE, CLX_BG_ADDON, CLX_BG_DISABLED, CLX_BG_ICON_WRAP, CLX_BG_SECTION, CLX_BG_SURFACE, CLX_BORDER_DEFAULT, CLX_BORDER_DISABLED, CLX_BORDER_MEDIUM, CLX_COLOR_HEX, CLX_COLOR_HEX_100, CLX_COLOR_MAP, CLX_FONT_CATALOG, CLX_MODAL_ANIM_CONFIG, CLX_MODAL_DATA, CLX_MODAL_REF, CLX_OPTION_DISABLED, CLX_PLACEHOLDER, CLX_RADIO_GROUP, CLX_RADIUS_MAP, CLX_TEXT_BODY, CLX_TEXT_DISABLED, CLX_TEXT_HEADING, CLX_TEXT_HINT, CLX_TEXT_IDLE, CLX_TEXT_INPUT, CLX_TEXT_LABEL, CLX_TEXT_OPTION, CLX_TEXT_SUBTITLE, CLX_TEXT_TITLE, CLX_THEME_CONFIG, CLX_THEME_DEFAULTS, CLX_TOAST_DEFAULTS, ClxAlertComponent, ClxAlertService, ClxAnimateDirective, ClxAnimateGroupDirective, ClxAnimateService, ClxAppLayoutComponent, ClxAvatarComponent, ClxBadgeComponent, ClxBrandComponent, ClxButtonComponent, ClxButtonGroupComponent, ClxCardBodyDirective, ClxCardComponent, ClxCardFooterDirective, ClxCardHeaderDirective, ClxCarouselComponent, ClxCarouselDirective, ClxCartComponent, ClxCartSummaryDrawer, ClxCellDirective, ClxChartComponent, ClxCheckboxComponent, ClxColorPickerComponent, ClxColumnDefDirective, ClxDateRangePickerComponent, ClxDatepickerComponent, ClxDrawerComponent, ClxDrawerService, ClxEditorComponent, ClxEditorLinkModalComponent, ClxFilterPanelComponent, ClxHeaderCellDirective, ClxIconComponent, ClxInputComponent, ClxListComponent, ClxListItemComponent, ClxMenuComponent, ClxMenuItemComponent, ClxModalComponent, ClxModalService, ClxNavGroupComponent, ClxNumberComponent, ClxPageEmptyComponent, ClxPageNotFoundComponent, ClxPageServerErrorComponent, ClxPageUnauthorizedComponent, ClxPaginationComponent, ClxProductComponent, ClxProductDetailComponent, ClxProfileComponent, ClxProgressBarComponent, ClxRadioComponent, ClxRadioGroupComponent, ClxRatingComponent, ClxSelectComponent, ClxSkeletonComponent, ClxSliderComponent, ClxSpinnerComponent, ClxStatCardComponent, ClxStepComponent, ClxStepperComponent, ClxSwitchComponent, ClxTabDirective, ClxTableComponent, ClxTabsComponent, ClxTagComponent, ClxTextareaComponent, ClxThemeService, ClxTimelineComponent, ClxTimelineItemComponent, ClxTimepickerComponent, ClxToastComponent, ClxToastContainerComponent, ClxToastService, ClxTooltipComponent, ClxTooltipDirective, ClxTreeComponent, ClxUploadComponent, ClxWishlistComponent, ClxWizardComponent, TIMEPICKER_SIZE_MAP, parseColorInput, provideCodexlyTheme, resolveColor, resolveContainerRadius, resolveRadius };
14876
+ export { CLX_ADDON_BORDER, CLX_ADDON_TEXT, CLX_ALERT_OPTIONS, CLX_ALERT_RESOLVE, CLX_BG_ADDON, CLX_BG_DISABLED, CLX_BG_ICON_WRAP, CLX_BG_SECTION, CLX_BG_SURFACE, CLX_BORDER_DEFAULT, CLX_BORDER_DISABLED, CLX_BORDER_MEDIUM, CLX_COLOR_HEX, CLX_COLOR_HEX_100, CLX_COLOR_MAP, CLX_MODAL_ANIM_CONFIG, CLX_MODAL_DATA, CLX_MODAL_REF, CLX_OPTION_DISABLED, CLX_PLACEHOLDER, CLX_RADIO_GROUP, CLX_RADIUS_MAP, CLX_TEXT_BODY, CLX_TEXT_DISABLED, CLX_TEXT_HEADING, CLX_TEXT_HINT, CLX_TEXT_IDLE, CLX_TEXT_INPUT, CLX_TEXT_LABEL, CLX_TEXT_OPTION, CLX_TEXT_SUBTITLE, CLX_TEXT_TITLE, CLX_THEME_CONFIG, CLX_THEME_DEFAULTS, CLX_TOAST_DEFAULTS, ClxAlertComponent, ClxAlertService, ClxAnimateDirective, ClxAnimateGroupDirective, ClxAnimateService, ClxAppLayoutComponent, ClxAvatarComponent, ClxBadgeComponent, ClxBrandComponent, ClxButtonComponent, ClxButtonGroupComponent, ClxCardBodyDirective, ClxCardComponent, ClxCardFooterDirective, ClxCardHeaderDirective, ClxCarouselComponent, ClxCarouselDirective, ClxCartComponent, ClxCartSummaryDrawer, ClxCellDirective, ClxChartComponent, ClxCheckboxComponent, ClxColorPickerComponent, ClxColumnDefDirective, ClxDateRangePickerComponent, ClxDatepickerComponent, ClxDrawerComponent, ClxDrawerService, ClxEditorComponent, ClxEditorLinkModalComponent, ClxFilterPanelComponent, ClxHeaderCellDirective, ClxIconComponent, ClxInputComponent, ClxListComponent, ClxListItemComponent, ClxMenuComponent, ClxMenuItemComponent, ClxModalComponent, ClxModalService, ClxNavGroupComponent, ClxNumberComponent, ClxPageEmptyComponent, ClxPageNotFoundComponent, ClxPageServerErrorComponent, ClxPageUnauthorizedComponent, ClxPaginationComponent, ClxProductComponent, ClxProductDetailComponent, ClxProfileComponent, ClxProgressBarComponent, ClxRadioComponent, ClxRadioGroupComponent, ClxRatingComponent, ClxSelectComponent, ClxSkeletonComponent, ClxSliderComponent, ClxSpinnerComponent, ClxStatCardComponent, ClxStepComponent, ClxStepperComponent, ClxSwitchComponent, ClxTabDirective, ClxTableComponent, ClxTabsComponent, ClxTagComponent, ClxTextareaComponent, ClxThemeService, ClxTimelineComponent, ClxTimelineItemComponent, ClxTimepickerComponent, ClxToastComponent, ClxToastContainerComponent, ClxToastService, ClxTooltipComponent, ClxTooltipDirective, ClxTreeComponent, ClxUploadComponent, ClxWishlistComponent, ClxWizardComponent, TIMEPICKER_SIZE_MAP, parseColorInput, provideCodexlyTheme, resolveColor, resolveContainerRadius, resolveRadius };
15240
14877
  //# sourceMappingURL=codexly-ui.mjs.map