cerxos-ui 0.0.14 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, EventEmitter, ElementRef, HostListener, ViewChildren, ViewChild, Output, Input, ChangeDetectionStrategy, Attribute, forwardRef, Directive, ContentChildren, ContentChild, HostBinding } from '@angular/core';
2
+ import { Component, EventEmitter, ElementRef, HostListener, ViewChildren, ViewChild, Output, Input, ChangeDetectionStrategy, Attribute, forwardRef, Directive, ContentChildren, ContentChild, HostBinding, signal, Injectable, inject, Pipe } from '@angular/core';
3
3
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
4
4
  import * as i1 from '@angular/common';
5
5
  import { NgTemplateOutlet, CommonModule } from '@angular/common';
@@ -272,9 +272,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
272
272
  args: ['window:resize']
273
273
  }] } });
274
274
 
275
- const BASE_CLASSES$a = 'relative flex w-full gap-3 rounded-[var(--cxs-radius-md)] border border-l-4 px-4 py-3 text-sm ' +
275
+ const BASE_CLASSES$c = 'relative flex w-full gap-3 rounded-[var(--cxs-radius-md)] border border-l-4 px-4 py-3 text-sm ' +
276
276
  'text-[var(--cxs-color-on-surface)]';
277
- const VARIANT_CLASSES$8 = {
277
+ const VARIANT_CLASSES$9 = {
278
278
  info: 'border-[var(--cxs-color-primary)] border-l-[var(--cxs-color-primary)] ' +
279
279
  'bg-[var(--cxs-color-primary-ghost)]',
280
280
  neutral: 'border-[var(--cxs-color-border)] border-l-[var(--cxs-color-border)] ' +
@@ -299,7 +299,7 @@ class CxsAlertComponent {
299
299
  closed = new EventEmitter();
300
300
  isVisible = true;
301
301
  get alertClass() {
302
- return [BASE_CLASSES$a, VARIANT_CLASSES$8[this.variant]].join(' ');
302
+ return [BASE_CLASSES$c, VARIANT_CLASSES$9[this.variant]].join(' ');
303
303
  }
304
304
  get titleClass() {
305
305
  return [TITLE_BASE, TITLE_VARIANT[this.variant]].join(' ');
@@ -327,7 +327,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
327
327
  type: Output
328
328
  }] } });
329
329
 
330
- const BASE_CLASSES$9 = 'grid';
330
+ const BASE_CLASSES$b = 'grid';
331
331
  const SPACING_CLASSES = {
332
332
  sm: 'gap-2',
333
333
  md: 'gap-3',
@@ -336,7 +336,7 @@ const SPACING_CLASSES = {
336
336
  class CxsAccordionComponent {
337
337
  spacing = 'md';
338
338
  get accordionClass() {
339
- return [BASE_CLASSES$9, SPACING_CLASSES[this.spacing]].join(' ');
339
+ return [BASE_CLASSES$b, SPACING_CLASSES[this.spacing]].join(' ');
340
340
  }
341
341
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsAccordionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
342
342
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.10", type: CxsAccordionComponent, isStandalone: true, selector: "cxs-accordion", inputs: { spacing: "spacing" }, ngImport: i0, template: "<div [class]=\"accordionClass\">\n <ng-content></ng-content>\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
@@ -424,9 +424,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
424
424
  type: Output
425
425
  }] } });
426
426
 
427
- const BASE_CLASSES$8 = 'inline-flex items-center gap-1 rounded-[var(--cxs-radius-md)] border px-2.5 py-0.5 text-xs font-medium ' +
427
+ const BASE_CLASSES$a = 'inline-flex items-center gap-1 rounded-[var(--cxs-radius-md)] border px-2.5 py-0.5 text-xs font-medium ' +
428
428
  'leading-none';
429
- const VARIANT_CLASSES$7 = {
429
+ const VARIANT_CLASSES$8 = {
430
430
  primary: 'border-[var(--cxs-color-primary)] bg-[var(--cxs-color-primary-ghost)] ' +
431
431
  'text-[var(--cxs-color-primary)]',
432
432
  neutral: 'border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] ' +
@@ -434,7 +434,7 @@ const VARIANT_CLASSES$7 = {
434
434
  danger: 'border-[var(--cxs-color-danger)] bg-[var(--cxs-color-surface)] ' +
435
435
  'text-[var(--cxs-color-danger)]'
436
436
  };
437
- const SIZE_CLASSES$7 = {
437
+ const SIZE_CLASSES$8 = {
438
438
  sm: 'text-[11px]',
439
439
  md: 'text-xs'
440
440
  };
@@ -442,7 +442,7 @@ class CxsBadgeComponent {
442
442
  variant = 'primary';
443
443
  size = 'md';
444
444
  get badgeClass() {
445
- return [BASE_CLASSES$8, VARIANT_CLASSES$7[this.variant], SIZE_CLASSES$7[this.size]].join(' ');
445
+ return [BASE_CLASSES$a, VARIANT_CLASSES$8[this.variant], SIZE_CLASSES$8[this.size]].join(' ');
446
446
  }
447
447
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
448
448
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.10", type: CxsBadgeComponent, isStandalone: true, selector: "cxs-badge", inputs: { variant: "variant", size: "size" }, ngImport: i0, template: "<span [class]=\"badgeClass\">\n <ng-content></ng-content>\n</span>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
@@ -456,10 +456,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
456
456
  type: Input
457
457
  }] } });
458
458
 
459
- const BASE_CLASSES$7 = 'inline-flex items-center justify-center overflow-hidden border border-[var(--cxs-color-border)] ' +
459
+ const BASE_CLASSES$9 = 'inline-flex items-center justify-center overflow-hidden border border-[var(--cxs-color-border)] ' +
460
460
  'bg-[var(--cxs-color-primary-ghost)] text-[var(--cxs-color-primary)] font-semibold uppercase ' +
461
461
  'select-none';
462
- const SIZE_CLASSES$6 = {
462
+ const SIZE_CLASSES$7 = {
463
463
  sm: 'h-8 w-8 text-[11px]',
464
464
  md: 'h-10 w-10 text-xs',
465
465
  lg: 'h-14 w-14 text-sm'
@@ -490,7 +490,7 @@ class CxsAvatarComponent {
490
490
  this.hostClass = hostClass;
491
491
  }
492
492
  get avatarClass() {
493
- return [BASE_CLASSES$7, SIZE_CLASSES$6[this.size], SHAPE_CLASSES[this.shape], this.hostClass]
493
+ return [BASE_CLASSES$9, SIZE_CLASSES$7[this.size], SHAPE_CLASSES[this.shape], this.hostClass]
494
494
  .filter(Boolean)
495
495
  .join(' ');
496
496
  }
@@ -559,14 +559,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
559
559
  type: Input
560
560
  }] } });
561
561
 
562
- const BASE_CLASSES$6 = 'flex flex-wrap items-center gap-x-1 gap-y-1';
562
+ const BASE_CLASSES$8 = 'flex flex-wrap items-center gap-x-1 gap-y-1';
563
563
  const ITEM_CLASSES = 'flex items-center gap-1';
564
564
  const LINK_BASE_CLASSES = 'rounded-[var(--cxs-radius-md)] transition-colors focus-visible:outline focus-visible:outline-2 ' +
565
565
  'focus-visible:outline-offset-2 focus-visible:outline-[var(--cxs-color-focus)]';
566
566
  const NON_LINK_CLASSES = 'text-[var(--cxs-color-on-surface-muted)]';
567
567
  const SEPARATOR_CLASSES = 'text-[var(--cxs-color-on-surface-muted)] select-none';
568
568
  const DISABLED_CLASSES = 'text-[var(--cxs-color-on-surface-muted)] opacity-60';
569
- const SIZE_CLASSES$5 = {
569
+ const SIZE_CLASSES$6 = {
570
570
  sm: 'text-xs',
571
571
  md: 'text-sm',
572
572
  lg: 'text-base'
@@ -587,7 +587,7 @@ class CxsBreadcrumbComponent {
587
587
  variant = 'default';
588
588
  disabled = false;
589
589
  get listClass() {
590
- return [BASE_CLASSES$6, SIZE_CLASSES$5[this.size], this.disabled ? 'opacity-60' : '']
590
+ return [BASE_CLASSES$8, SIZE_CLASSES$6[this.size], this.disabled ? 'opacity-60' : '']
591
591
  .filter(Boolean)
592
592
  .join(' ');
593
593
  }
@@ -648,14 +648,111 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
648
648
  type: Input
649
649
  }] } });
650
650
 
651
- const BASE_CLASSES$5 = 'relative inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium transition-colors ' +
651
+ const BASE_CLASSES$7 = 'inline-block shrink-0';
652
+ const SIZE_CLASSES$5 = {
653
+ sm: 'h-4 w-4',
654
+ md: 'h-5 w-5',
655
+ lg: 'h-6 w-6'
656
+ };
657
+ const ICONS = {
658
+ bell: {
659
+ viewBox: '0 0 24 24',
660
+ paths: [
661
+ 'M15 17h5l-1.4-1.4A2 2 0 0 1 18 14.2V11a6 6 0 1 0-12 0v3.2a2 2 0 0 1-.6 1.4L4 17h5',
662
+ 'M10.3 20a2 2 0 0 0 3.4 0'
663
+ ]
664
+ },
665
+ 'chevron-down': {
666
+ viewBox: '0 0 24 24',
667
+ paths: ['m6 9 6 6 6-6']
668
+ },
669
+ 'chevron-left': {
670
+ viewBox: '0 0 24 24',
671
+ paths: ['m15 18-6-6 6-6']
672
+ },
673
+ 'chevron-right': {
674
+ viewBox: '0 0 24 24',
675
+ paths: ['m9 18 6-6-6-6']
676
+ },
677
+ 'chevron-up': {
678
+ viewBox: '0 0 24 24',
679
+ paths: ['m18 15-6-6-6 6']
680
+ },
681
+ plus: {
682
+ viewBox: '0 0 24 24',
683
+ paths: ['M12 5v14', 'M5 12h14']
684
+ },
685
+ search: {
686
+ viewBox: '0 0 24 24',
687
+ paths: ['m21 21-4.34-4.34', 'M11 19a8 8 0 1 1 0-16 8 8 0 0 1 0 16Z']
688
+ },
689
+ user: {
690
+ viewBox: '0 0 24 24',
691
+ paths: [
692
+ 'M16 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2',
693
+ 'M10 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8'
694
+ ]
695
+ },
696
+ x: {
697
+ viewBox: '0 0 24 24',
698
+ paths: ['M18 6 6 18', 'M6 6l12 12']
699
+ }
700
+ };
701
+ class CxsIconComponent {
702
+ hostClass;
703
+ static nextId = 0;
704
+ name;
705
+ size = 'md';
706
+ label;
707
+ instanceId = ++CxsIconComponent.nextId;
708
+ constructor(hostClass) {
709
+ this.hostClass = hostClass;
710
+ }
711
+ get icon() {
712
+ const icon = ICONS[this.name];
713
+ if (!icon) {
714
+ throw new Error(`Unsupported cxs icon: ${this.name}`);
715
+ }
716
+ return icon;
717
+ }
718
+ get iconClass() {
719
+ return [BASE_CLASSES$7, SIZE_CLASSES$5[this.size], this.hostClass].filter(Boolean).join(' ');
720
+ }
721
+ get titleId() {
722
+ return this.label ? `cxs-icon-title-${this.instanceId}` : null;
723
+ }
724
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsIconComponent, deps: [{ token: 'class', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
725
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: CxsIconComponent, isStandalone: true, selector: "cxs-icon", inputs: { name: "name", size: "size", label: "label" }, host: { classAttribute: "inline-flex shrink-0" }, ngImport: i0, template: "<svg\n [attr.viewBox]=\"icon.viewBox\"\n [class]=\"iconClass\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n [attr.role]=\"label ? 'img' : null\"\n [attr.aria-hidden]=\"label ? null : 'true'\"\n [attr.aria-labelledby]=\"titleId\"\n>\n @if (titleId) {\n <title [id]=\"titleId\">{{ label }}</title>\n }\n\n @for (path of icon.paths; track path) {\n <path [attr.d]=\"path\" stroke-width=\"1.75\"></path>\n }\n</svg>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
726
+ }
727
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsIconComponent, decorators: [{
728
+ type: Component,
729
+ args: [{ selector: 'cxs-icon', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, host: {
730
+ class: 'inline-flex shrink-0'
731
+ }, template: "<svg\n [attr.viewBox]=\"icon.viewBox\"\n [class]=\"iconClass\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n [attr.role]=\"label ? 'img' : null\"\n [attr.aria-hidden]=\"label ? null : 'true'\"\n [attr.aria-labelledby]=\"titleId\"\n>\n @if (titleId) {\n <title [id]=\"titleId\">{{ label }}</title>\n }\n\n @for (path of icon.paths; track path) {\n <path [attr.d]=\"path\" stroke-width=\"1.75\"></path>\n }\n</svg>\n" }]
732
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
733
+ type: Attribute,
734
+ args: ['class']
735
+ }] }], propDecorators: { name: [{
736
+ type: Input,
737
+ args: [{ required: true }]
738
+ }], size: [{
739
+ type: Input
740
+ }], label: [{
741
+ type: Input
742
+ }] } });
743
+
744
+ const BASE_CLASSES$6 = 'relative inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium transition-colors ' +
652
745
  'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
653
746
  'focus-visible:outline-[var(--cxs-color-focus)] disabled:pointer-events-none disabled:opacity-50';
654
- const VARIANT_CLASSES$6 = {
747
+ const VARIANT_CLASSES$7 = {
655
748
  primary: 'bg-[var(--cxs-color-primary)] text-[var(--cxs-color-on-primary)] ' +
656
749
  'hover:bg-[var(--cxs-color-primary-hover)] shadow-[var(--cxs-shadow-sm)]',
750
+ danger: 'bg-[var(--cxs-color-danger-surface)] text-[var(--cxs-color-danger)] ' +
751
+ 'hover:bg-[var(--cxs-color-danger-surface-hover)] shadow-[var(--cxs-shadow-sm)]',
657
752
  secondary: 'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] ' +
658
753
  'border border-[var(--cxs-color-border)] hover:bg-[var(--cxs-color-surface-hover)]',
754
+ outline: 'border border-[var(--cxs-color-border)] bg-transparent text-[var(--cxs-color-primary)] ' +
755
+ 'hover:bg-[var(--cxs-color-primary-ghost)]',
659
756
  ghost: 'bg-transparent text-[var(--cxs-color-primary)] hover:bg-[var(--cxs-color-primary-ghost)]'
660
757
  };
661
758
  const SIZE_CLASSES$4 = {
@@ -663,6 +760,11 @@ const SIZE_CLASSES$4 = {
663
760
  md: 'h-10 px-4 text-sm rounded-[var(--cxs-radius-md)]',
664
761
  lg: 'h-12 px-5 text-base rounded-[var(--cxs-radius-md)]'
665
762
  };
763
+ const ICON_ONLY_SIZE_CLASSES = {
764
+ sm: 'h-8 w-8 rounded-full p-0',
765
+ md: 'h-10 w-10 rounded-full p-0',
766
+ lg: 'h-12 w-12 rounded-full p-0'
767
+ };
666
768
  class CxsButtonComponent {
667
769
  hostClass;
668
770
  variant = 'primary';
@@ -670,23 +772,54 @@ class CxsButtonComponent {
670
772
  disabled = false;
671
773
  loading = false;
672
774
  type = 'button';
775
+ icon;
776
+ iconPosition = 'start';
777
+ iconOnly = false;
778
+ ariaLabel;
673
779
  constructor(hostClass) {
674
780
  this.hostClass = hostClass;
675
781
  }
676
782
  get isDisabled() {
677
783
  return this.disabled || this.loading;
678
784
  }
785
+ get leadingIconName() {
786
+ if (this.loading || !this.icon || this.iconPosition !== 'start') {
787
+ return null;
788
+ }
789
+ return this.icon;
790
+ }
791
+ get trailingIconName() {
792
+ if (this.loading || !this.icon || this.iconPosition !== 'end') {
793
+ return null;
794
+ }
795
+ return this.icon;
796
+ }
797
+ get ariaLabelValue() {
798
+ if (!this.iconOnly) {
799
+ return this.ariaLabel?.trim() || null;
800
+ }
801
+ if (!this.ariaLabel?.trim()) {
802
+ throw new Error('cxs-button with iconOnly=true requires ariaLabel.');
803
+ }
804
+ return this.ariaLabel.trim();
805
+ }
679
806
  get buttonClass() {
680
- return [BASE_CLASSES$5, SIZE_CLASSES$4[this.size], VARIANT_CLASSES$6[this.variant], this.hostClass]
807
+ return [
808
+ BASE_CLASSES$6,
809
+ this.iconOnly ? ICON_ONLY_SIZE_CLASSES[this.size] : SIZE_CLASSES$4[this.size],
810
+ VARIANT_CLASSES$7[this.variant],
811
+ this.iconOnly ? 'gap-0' : '',
812
+ this.hostClass
813
+ ]
681
814
  .filter(Boolean)
682
815
  .join(' ');
683
816
  }
684
817
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsButtonComponent, deps: [{ token: 'class', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
685
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: CxsButtonComponent, isStandalone: true, selector: "cxs-button", inputs: { variant: "variant", size: "size", disabled: "disabled", loading: "loading", type: "type" }, ngImport: i0, template: "<button\n [class]=\"buttonClass\"\n [attr.type]=\"type\"\n [disabled]=\"isDisabled\"\n [attr.aria-busy]=\"loading ? 'true' : null\"\n>\n @if (loading) {\n <span\n class=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"\n aria-hidden=\"true\"\n ></span>\n }\n <ng-content select=\"[cxsButtonIcon]\"></ng-content>\n <span class=\"truncate\">\n <ng-content></ng-content>\n </span>\n</button>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
818
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: CxsButtonComponent, isStandalone: true, selector: "cxs-button", inputs: { variant: "variant", size: "size", disabled: "disabled", loading: "loading", type: "type", icon: "icon", iconPosition: "iconPosition", iconOnly: "iconOnly", ariaLabel: "ariaLabel" }, ngImport: i0, template: "<button\n [class]=\"buttonClass\"\n [attr.type]=\"type\"\n [disabled]=\"isDisabled\"\n [attr.aria-busy]=\"loading ? 'true' : null\"\n [attr.aria-label]=\"ariaLabelValue\"\n>\n @if (loading) {\n <span\n class=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"\n aria-hidden=\"true\"\n ></span>\n }\n\n @if (leadingIconName; as iconName) {\n <cxs-icon [name]=\"iconName\" [size]=\"size\"></cxs-icon>\n }\n\n <ng-content select=\"[cxsButtonIcon]\"></ng-content>\n\n @if (!iconOnly) {\n <span class=\"truncate\">\n <ng-content></ng-content>\n </span>\n }\n\n @if (trailingIconName; as iconName) {\n <cxs-icon [name]=\"iconName\" [size]=\"size\"></cxs-icon>\n }\n</button>\n", dependencies: [{ kind: "component", type: CxsIconComponent, selector: "cxs-icon", inputs: ["name", "size", "label"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
686
819
  }
687
820
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsButtonComponent, decorators: [{
688
821
  type: Component,
689
- args: [{ selector: 'cxs-button', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\n [class]=\"buttonClass\"\n [attr.type]=\"type\"\n [disabled]=\"isDisabled\"\n [attr.aria-busy]=\"loading ? 'true' : null\"\n>\n @if (loading) {\n <span\n class=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"\n aria-hidden=\"true\"\n ></span>\n }\n <ng-content select=\"[cxsButtonIcon]\"></ng-content>\n <span class=\"truncate\">\n <ng-content></ng-content>\n </span>\n</button>\n" }]
822
+ args: [{ selector: 'cxs-button', standalone: true, imports: [CxsIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\n [class]=\"buttonClass\"\n [attr.type]=\"type\"\n [disabled]=\"isDisabled\"\n [attr.aria-busy]=\"loading ? 'true' : null\"\n [attr.aria-label]=\"ariaLabelValue\"\n>\n @if (loading) {\n <span\n class=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"\n aria-hidden=\"true\"\n ></span>\n }\n\n @if (leadingIconName; as iconName) {\n <cxs-icon [name]=\"iconName\" [size]=\"size\"></cxs-icon>\n }\n\n <ng-content select=\"[cxsButtonIcon]\"></ng-content>\n\n @if (!iconOnly) {\n <span class=\"truncate\">\n <ng-content></ng-content>\n </span>\n }\n\n @if (trailingIconName; as iconName) {\n <cxs-icon [name]=\"iconName\" [size]=\"size\"></cxs-icon>\n }\n</button>\n" }]
690
823
  }], ctorParameters: () => [{ type: undefined, decorators: [{
691
824
  type: Attribute,
692
825
  args: ['class']
@@ -700,11 +833,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
700
833
  type: Input
701
834
  }], type: [{
702
835
  type: Input
836
+ }], icon: [{
837
+ type: Input
838
+ }], iconPosition: [{
839
+ type: Input
840
+ }], iconOnly: [{
841
+ type: Input
842
+ }], ariaLabel: [{
843
+ type: Input
703
844
  }] } });
704
845
 
705
- const BASE_CLASSES$4 = 'rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
846
+ const BASE_CLASSES$5 = 'rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
706
847
  'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)]';
707
- const VARIANT_CLASSES$5 = {
848
+ const VARIANT_CLASSES$6 = {
708
849
  surface: 'bg-[var(--cxs-color-surface)]',
709
850
  muted: 'bg-[var(--cxs-color-surface-hover)]',
710
851
  outline: 'bg-transparent'
@@ -722,8 +863,8 @@ class CxsCardComponent {
722
863
  ariaLabelledby;
723
864
  get cardClass() {
724
865
  return [
725
- BASE_CLASSES$4,
726
- VARIANT_CLASSES$5[this.variant],
866
+ BASE_CLASSES$5,
867
+ VARIANT_CLASSES$6[this.variant],
727
868
  SIZE_CLASSES$3[this.size],
728
869
  this.elevated ? 'shadow-[var(--cxs-shadow-sm)]' : ''
729
870
  ]
@@ -753,7 +894,7 @@ const WRAPPER_ENABLED$1 = 'cursor-pointer';
753
894
  const WRAPPER_DISABLED$1 = 'cursor-not-allowed opacity-60';
754
895
  const LABEL_BASE$1 = 'text-[var(--cxs-color-on-surface)]';
755
896
  const LABEL_DISABLED$1 = 'text-[var(--cxs-color-on-surface-muted)]';
756
- const LABEL_SIZE_CLASSES$5 = {
897
+ const LABEL_SIZE_CLASSES$6 = {
757
898
  sm: 'text-sm',
758
899
  md: 'text-sm',
759
900
  lg: 'text-base'
@@ -807,7 +948,7 @@ class CxsCheckboxComponent {
807
948
  get labelClass() {
808
949
  return [
809
950
  LABEL_BASE$1,
810
- LABEL_SIZE_CLASSES$5[this.size],
951
+ LABEL_SIZE_CLASSES$6[this.size],
811
952
  this.isDisabled ? LABEL_DISABLED$1 : ''
812
953
  ]
813
954
  .filter(Boolean)
@@ -1829,16 +1970,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
1829
1970
  args: ['dialogPanel']
1830
1971
  }] } });
1831
1972
 
1832
- const BASE_CLASSES$3 = 'w-full rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
1973
+ const BASE_CLASSES$4 = 'w-full rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
1833
1974
  'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] ' +
1834
1975
  'placeholder:text-[var(--cxs-color-on-surface-muted)] transition-colors ' +
1835
1976
  'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
1836
1977
  'focus-visible:outline-[var(--cxs-color-focus)] focus-visible:border-[var(--cxs-color-focus)] ' +
1837
1978
  'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-60';
1838
- const WRAPPER_CLASSES$6 = 'flex w-full flex-col gap-1';
1839
- const LABEL_BASE_CLASSES$4 = 'font-medium text-(--cxs-color-on-surface)';
1840
- const LABEL_DISABLED_CLASSES$4 = 'text-[var(--cxs-color-on-surface-muted)]';
1841
- const VARIANT_CLASSES$4 = {
1979
+ const WRAPPER_CLASSES$8 = 'flex w-full flex-col gap-1';
1980
+ const LABEL_BASE_CLASSES$5 = 'font-medium text-(--cxs-color-on-surface)';
1981
+ const LABEL_DISABLED_CLASSES$5 = 'text-[var(--cxs-color-on-surface-muted)]';
1982
+ const VARIANT_CLASSES$5 = {
1842
1983
  outline: 'bg-[var(--cxs-color-surface)]',
1843
1984
  filled: 'bg-[var(--cxs-color-surface-hover)]'
1844
1985
  };
@@ -1847,7 +1988,7 @@ const SIZE_CLASSES$2 = {
1847
1988
  md: 'h-10 px-3 text-sm',
1848
1989
  lg: 'h-12 px-4 text-base'
1849
1990
  };
1850
- const LABEL_SIZE_CLASSES$4 = {
1991
+ const LABEL_SIZE_CLASSES$5 = {
1851
1992
  sm: 'text-sm',
1852
1993
  md: 'text-sm',
1853
1994
  lg: 'text-base'
@@ -1911,22 +2052,22 @@ class CxsDatepickerComponent {
1911
2052
  }
1912
2053
  get inputClass() {
1913
2054
  return [
1914
- BASE_CLASSES$3,
2055
+ BASE_CLASSES$4,
1915
2056
  SIZE_CLASSES$2[this.size],
1916
- VARIANT_CLASSES$4[this.variant],
2057
+ VARIANT_CLASSES$5[this.variant],
1917
2058
  this.invalid ? INVALID_CLASSES$4 : ''
1918
2059
  ]
1919
2060
  .filter(Boolean)
1920
2061
  .join(' ');
1921
2062
  }
1922
2063
  get wrapperClass() {
1923
- return WRAPPER_CLASSES$6;
2064
+ return WRAPPER_CLASSES$8;
1924
2065
  }
1925
2066
  get labelClass() {
1926
2067
  return [
1927
- LABEL_BASE_CLASSES$4,
1928
- LABEL_SIZE_CLASSES$4[this.size],
1929
- this.isDisabled ? LABEL_DISABLED_CLASSES$4 : ''
2068
+ LABEL_BASE_CLASSES$5,
2069
+ LABEL_SIZE_CLASSES$5[this.size],
2070
+ this.isDisabled ? LABEL_DISABLED_CLASSES$5 : ''
1930
2071
  ]
1931
2072
  .filter(Boolean)
1932
2073
  .join(' ');
@@ -2185,17 +2326,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
2185
2326
  args: ['document:keydown.escape']
2186
2327
  }] } });
2187
2328
 
2188
- const BASE_CLASSES$2 = 'w-full rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
2329
+ const BASE_CLASSES$3 = 'w-full rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
2189
2330
  'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] ' +
2190
2331
  'placeholder:text-[var(--cxs-color-on-surface-muted)] transition-colors ' +
2191
2332
  'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
2192
2333
  'focus-visible:outline-[var(--cxs-color-focus)] focus-visible:border-[var(--cxs-color-focus)] ' +
2193
2334
  'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-60';
2194
- const WRAPPER_CLASSES$5 = 'flex w-full flex-col gap-1';
2195
- const LABEL_BASE_CLASSES$3 = 'font-medium text-(--cxs-color-on-surface)';
2196
- const LABEL_DISABLED_CLASSES$3 = 'text-[var(--cxs-color-on-surface-muted)]';
2335
+ const WRAPPER_CLASSES$7 = 'flex w-full flex-col gap-1';
2336
+ const LABEL_BASE_CLASSES$4 = 'font-medium text-(--cxs-color-on-surface)';
2337
+ const LABEL_DISABLED_CLASSES$4 = 'text-[var(--cxs-color-on-surface-muted)]';
2197
2338
  const ERROR_BASE_CLASSES = 'text-[var(--cxs-color-danger)]';
2198
- const VARIANT_CLASSES$3 = {
2339
+ const VARIANT_CLASSES$4 = {
2199
2340
  outline: 'bg-[var(--cxs-color-surface)]',
2200
2341
  filled: 'bg-[var(--cxs-color-surface-hover)]'
2201
2342
  };
@@ -2204,7 +2345,7 @@ const SIZE_CLASSES$1 = {
2204
2345
  md: 'h-10 px-3 text-sm',
2205
2346
  lg: 'h-12 px-4 text-base'
2206
2347
  };
2207
- const LABEL_SIZE_CLASSES$3 = {
2348
+ const LABEL_SIZE_CLASSES$4 = {
2208
2349
  sm: 'text-sm',
2209
2350
  md: 'text-sm',
2210
2351
  lg: 'text-base'
@@ -2246,22 +2387,22 @@ class CxsInputComponent {
2246
2387
  }
2247
2388
  get inputClass() {
2248
2389
  return [
2249
- BASE_CLASSES$2,
2390
+ BASE_CLASSES$3,
2250
2391
  SIZE_CLASSES$1[this.size],
2251
- VARIANT_CLASSES$3[this.variant],
2392
+ VARIANT_CLASSES$4[this.variant],
2252
2393
  this.invalid ? INVALID_CLASSES$3 : ''
2253
2394
  ]
2254
2395
  .filter(Boolean)
2255
2396
  .join(' ');
2256
2397
  }
2257
2398
  get wrapperClass() {
2258
- return WRAPPER_CLASSES$5;
2399
+ return WRAPPER_CLASSES$7;
2259
2400
  }
2260
2401
  get labelClass() {
2261
2402
  return [
2262
- LABEL_BASE_CLASSES$3,
2263
- LABEL_SIZE_CLASSES$3[this.size],
2264
- this.isDisabled ? LABEL_DISABLED_CLASSES$3 : ''
2403
+ LABEL_BASE_CLASSES$4,
2404
+ LABEL_SIZE_CLASSES$4[this.size],
2405
+ this.isDisabled ? LABEL_DISABLED_CLASSES$4 : ''
2265
2406
  ]
2266
2407
  .filter(Boolean)
2267
2408
  .join(' ');
@@ -2518,15 +2659,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
2518
2659
  args: ['menuItem', { read: ElementRef }]
2519
2660
  }] } });
2520
2661
 
2521
- const WRAPPER_CLASSES$4 = 'flex w-full flex-col gap-1';
2522
- const LABEL_BASE_CLASSES$2 = 'font-medium text-(--cxs-color-on-surface)';
2523
- const LABEL_DISABLED_CLASSES$2 = 'text-[var(--cxs-color-on-surface-muted)]';
2662
+ const WRAPPER_CLASSES$6 = 'flex w-full flex-col gap-1';
2663
+ const LABEL_BASE_CLASSES$3 = 'font-medium text-(--cxs-color-on-surface)';
2664
+ const LABEL_DISABLED_CLASSES$3 = 'text-[var(--cxs-color-on-surface-muted)]';
2524
2665
  const CONTROL_BASE_CLASSES = 'flex w-full flex-wrap items-center gap-2 rounded-[var(--cxs-radius-md)] border ' +
2525
2666
  'border-[var(--cxs-color-border)] transition-colors ' +
2526
2667
  'focus-within:outline focus-within:outline-2 focus-within:outline-offset-2 ' +
2527
2668
  'focus-within:outline-[var(--cxs-color-focus)] focus-within:border-[var(--cxs-color-focus)]';
2528
2669
  const CONTROL_DISABLED_CLASSES = 'pointer-events-none cursor-not-allowed opacity-60';
2529
- const VARIANT_CLASSES$2 = {
2670
+ const VARIANT_CLASSES$3 = {
2530
2671
  outline: 'bg-[var(--cxs-color-surface)]',
2531
2672
  filled: 'bg-[var(--cxs-color-surface-hover)]'
2532
2673
  };
@@ -2535,7 +2676,7 @@ const CONTROL_SIZE_CLASSES$1 = {
2535
2676
  md: 'min-h-10 px-3 py-1.5 text-sm',
2536
2677
  lg: 'min-h-12 px-4 py-2 text-base'
2537
2678
  };
2538
- const LABEL_SIZE_CLASSES$2 = {
2679
+ const LABEL_SIZE_CLASSES$3 = {
2539
2680
  sm: 'text-sm',
2540
2681
  md: 'text-sm',
2541
2682
  lg: 'text-base'
@@ -2596,13 +2737,13 @@ class CxsMultiSelectComponent {
2596
2737
  this.value.length >= this.maxSelections;
2597
2738
  }
2598
2739
  get wrapperClass() {
2599
- return WRAPPER_CLASSES$4;
2740
+ return WRAPPER_CLASSES$6;
2600
2741
  }
2601
2742
  get labelClass() {
2602
2743
  return [
2603
- LABEL_BASE_CLASSES$2,
2604
- LABEL_SIZE_CLASSES$2[this.size],
2605
- this.isDisabled ? LABEL_DISABLED_CLASSES$2 : ''
2744
+ LABEL_BASE_CLASSES$3,
2745
+ LABEL_SIZE_CLASSES$3[this.size],
2746
+ this.isDisabled ? LABEL_DISABLED_CLASSES$3 : ''
2606
2747
  ]
2607
2748
  .filter(Boolean)
2608
2749
  .join(' ');
@@ -2611,7 +2752,7 @@ class CxsMultiSelectComponent {
2611
2752
  return [
2612
2753
  CONTROL_BASE_CLASSES,
2613
2754
  CONTROL_SIZE_CLASSES$1[this.size],
2614
- VARIANT_CLASSES$2[this.variant],
2755
+ VARIANT_CLASSES$3[this.variant],
2615
2756
  this.invalid ? INVALID_CLASSES$2 : '',
2616
2757
  this.isDisabled ? CONTROL_DISABLED_CLASSES : ''
2617
2758
  ]
@@ -2810,6 +2951,106 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
2810
2951
  args: ['document:click', ['$event']]
2811
2952
  }] } });
2812
2953
 
2954
+ const WRAPPER_CLASSES$5 = 'flex w-full flex-col gap-1.5';
2955
+ const HEADER_CLASSES$1 = 'flex items-center justify-between gap-3';
2956
+ const LABEL_CLASSES = 'text-sm font-medium text-[var(--cxs-color-on-surface)]';
2957
+ const VALUE_CLASSES$1 = 'text-sm text-[var(--cxs-color-on-surface-muted)]';
2958
+ const TRACK_BASE_CLASSES$1 = 'relative w-full overflow-hidden rounded-full bg-[var(--cxs-color-surface-hover)]';
2959
+ const TRACK_SIZE_CLASSES$1 = {
2960
+ sm: 'h-2',
2961
+ md: 'h-3',
2962
+ lg: 'h-4'
2963
+ };
2964
+ const FILL_BASE_CLASSES = 'h-full rounded-full transition-[width] duration-300 ease-out';
2965
+ const INDETERMINATE_FILL_CLASSES = 'absolute inset-y-0 left-0 w-2/5 rounded-full animate-[cxs-progress-indeterminate_1.4s_ease-in-out_infinite]';
2966
+ const FILL_VARIANT_CLASSES = {
2967
+ primary: 'bg-[var(--cxs-color-primary)]',
2968
+ neutral: 'bg-[var(--cxs-color-on-surface-muted)]',
2969
+ danger: 'bg-[var(--cxs-color-danger)]'
2970
+ };
2971
+ class CxsProgressBarComponent {
2972
+ static nextId = 0;
2973
+ value = 0;
2974
+ max = 100;
2975
+ variant = 'primary';
2976
+ size = 'md';
2977
+ label;
2978
+ showValue = false;
2979
+ indeterminate = false;
2980
+ ariaLabel = 'Progress';
2981
+ labelId = `cxs-progress-bar-label-${++CxsProgressBarComponent.nextId}`;
2982
+ get wrapperClass() {
2983
+ return WRAPPER_CLASSES$5;
2984
+ }
2985
+ get headerClass() {
2986
+ return HEADER_CLASSES$1;
2987
+ }
2988
+ get labelClass() {
2989
+ return LABEL_CLASSES;
2990
+ }
2991
+ get valueClass() {
2992
+ return VALUE_CLASSES$1;
2993
+ }
2994
+ get trackClass() {
2995
+ return [TRACK_BASE_CLASSES$1, TRACK_SIZE_CLASSES$1[this.size]].join(' ');
2996
+ }
2997
+ get fillClass() {
2998
+ return [FILL_BASE_CLASSES, FILL_VARIANT_CLASSES[this.variant]].join(' ');
2999
+ }
3000
+ get indeterminateFillClass() {
3001
+ return [INDETERMINATE_FILL_CLASSES, FILL_VARIANT_CLASSES[this.variant]].join(' ');
3002
+ }
3003
+ get normalizedMax() {
3004
+ return Number.isFinite(this.max) && this.max > 0 ? this.max : 100;
3005
+ }
3006
+ get clampedValue() {
3007
+ if (!Number.isFinite(this.value)) {
3008
+ return 0;
3009
+ }
3010
+ return Math.min(Math.max(this.value, 0), this.normalizedMax);
3011
+ }
3012
+ get progressPercent() {
3013
+ return (this.clampedValue / this.normalizedMax) * 100;
3014
+ }
3015
+ get progressText() {
3016
+ return `${Math.round(this.progressPercent)}%`;
3017
+ }
3018
+ get statusText() {
3019
+ return this.indeterminate ? 'Loading' : this.progressText;
3020
+ }
3021
+ get ariaLabelValue() {
3022
+ return this.label ? null : this.ariaLabel;
3023
+ }
3024
+ get ariaValueNow() {
3025
+ return this.indeterminate ? null : this.clampedValue;
3026
+ }
3027
+ get ariaValueText() {
3028
+ return this.indeterminate ? 'Loading' : this.showValue ? this.progressText : null;
3029
+ }
3030
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsProgressBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3031
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: CxsProgressBarComponent, isStandalone: true, selector: "cxs-progress-bar", inputs: { value: "value", max: "max", variant: "variant", size: "size", label: "label", showValue: "showValue", indeterminate: "indeterminate", ariaLabel: "ariaLabel" }, ngImport: i0, template: "<div [class]=\"wrapperClass\">\n @if (label || showValue) {\n <div [class]=\"headerClass\">\n @if (label) {\n <span [id]=\"labelId\" [class]=\"labelClass\">{{ label }}</span>\n }\n\n @if (showValue) {\n <span [class]=\"valueClass\">{{ statusText }}</span>\n }\n </div>\n }\n\n <div\n [class]=\"trackClass\"\n role=\"progressbar\"\n [attr.aria-label]=\"ariaLabelValue\"\n [attr.aria-labelledby]=\"label ? labelId : null\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"normalizedMax\"\n [attr.aria-valuenow]=\"ariaValueNow\"\n [attr.aria-valuetext]=\"ariaValueText\"\n >\n @if (indeterminate) {\n <div [class]=\"indeterminateFillClass\" aria-hidden=\"true\"></div>\n } @else {\n <div [class]=\"fillClass\" [style.width.%]=\"progressPercent\"></div>\n }\n </div>\n</div>\n", styles: ["@keyframes cxs-progress-indeterminate{0%{transform:translate(-100%)}50%{transform:translate(60%)}to{transform:translate(250%)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3032
+ }
3033
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsProgressBarComponent, decorators: [{
3034
+ type: Component,
3035
+ args: [{ selector: 'cxs-progress-bar', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"wrapperClass\">\n @if (label || showValue) {\n <div [class]=\"headerClass\">\n @if (label) {\n <span [id]=\"labelId\" [class]=\"labelClass\">{{ label }}</span>\n }\n\n @if (showValue) {\n <span [class]=\"valueClass\">{{ statusText }}</span>\n }\n </div>\n }\n\n <div\n [class]=\"trackClass\"\n role=\"progressbar\"\n [attr.aria-label]=\"ariaLabelValue\"\n [attr.aria-labelledby]=\"label ? labelId : null\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"normalizedMax\"\n [attr.aria-valuenow]=\"ariaValueNow\"\n [attr.aria-valuetext]=\"ariaValueText\"\n >\n @if (indeterminate) {\n <div [class]=\"indeterminateFillClass\" aria-hidden=\"true\"></div>\n } @else {\n <div [class]=\"fillClass\" [style.width.%]=\"progressPercent\"></div>\n }\n </div>\n</div>\n", styles: ["@keyframes cxs-progress-indeterminate{0%{transform:translate(-100%)}50%{transform:translate(60%)}to{transform:translate(250%)}}\n"] }]
3036
+ }], propDecorators: { value: [{
3037
+ type: Input
3038
+ }], max: [{
3039
+ type: Input
3040
+ }], variant: [{
3041
+ type: Input
3042
+ }], size: [{
3043
+ type: Input
3044
+ }], label: [{
3045
+ type: Input
3046
+ }], showValue: [{
3047
+ type: Input
3048
+ }], indeterminate: [{
3049
+ type: Input
3050
+ }], ariaLabel: [{
3051
+ type: Input
3052
+ }] } });
3053
+
2813
3054
  class CxsTabLabelDirective {
2814
3055
  templateRef;
2815
3056
  constructor(templateRef) {
@@ -2863,7 +3104,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
2863
3104
  args: ['content', { static: true }]
2864
3105
  }] } });
2865
3106
 
2866
- const WRAPPER_CLASSES$3 = 'w-full';
3107
+ const WRAPPER_CLASSES$4 = 'w-full';
2867
3108
  const TAB_LIST_CLASSES = 'flex flex-wrap items-center gap-6 border-b border-[var(--cxs-color-border)]';
2868
3109
  const TAB_BUTTON_BASE_CLASSES = 'inline-flex items-center gap-2 border-b-2 pb-3 text-sm font-medium transition-colors';
2869
3110
  const TAB_BUTTON_INACTIVE_CLASSES = 'border-transparent text-[var(--cxs-color-on-surface-muted)] hover:text-[var(--cxs-color-on-surface)]';
@@ -2878,7 +3119,7 @@ class CxsTabsComponent {
2878
3119
  activeIdChange = new EventEmitter();
2879
3120
  panels;
2880
3121
  get wrapperClass() {
2881
- return WRAPPER_CLASSES$3;
3122
+ return WRAPPER_CLASSES$4;
2882
3123
  }
2883
3124
  get tabListClass() {
2884
3125
  return TAB_LIST_CLASSES;
@@ -2978,7 +3219,7 @@ const WRAPPER_ENABLED = 'cursor-pointer';
2978
3219
  const WRAPPER_DISABLED = 'cursor-not-allowed opacity-60';
2979
3220
  const LABEL_BASE = 'text-[var(--cxs-color-on-surface)]';
2980
3221
  const LABEL_DISABLED = 'text-[var(--cxs-color-on-surface-muted)]';
2981
- const LABEL_SIZE_CLASSES$1 = {
3222
+ const LABEL_SIZE_CLASSES$2 = {
2982
3223
  sm: 'text-sm',
2983
3224
  md: 'text-sm',
2984
3225
  lg: 'text-base'
@@ -3037,7 +3278,7 @@ class CxsRadioComponent {
3037
3278
  get labelClass() {
3038
3279
  return [
3039
3280
  LABEL_BASE,
3040
- LABEL_SIZE_CLASSES$1[this.size],
3281
+ LABEL_SIZE_CLASSES$2[this.size],
3041
3282
  this.isDisabled ? LABEL_DISABLED : ''
3042
3283
  ]
3043
3284
  .filter(Boolean)
@@ -3122,16 +3363,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
3122
3363
  type: Output
3123
3364
  }] } });
3124
3365
 
3125
- const BASE_CLASSES$1 = 'w-full appearance-none rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
3366
+ const BASE_CLASSES$2 = 'w-full appearance-none rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
3126
3367
  'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] ' +
3127
3368
  'placeholder:text-[var(--cxs-color-on-surface-muted)] transition-colors ' +
3128
3369
  'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
3129
3370
  'focus-visible:outline-[var(--cxs-color-focus)] focus-visible:border-[var(--cxs-color-focus)] ' +
3130
3371
  'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-60';
3131
- const WRAPPER_CLASSES$2 = 'flex w-full flex-col gap-1';
3132
- const LABEL_BASE_CLASSES$1 = 'font-medium text-(--cxs-color-on-surface)';
3133
- const LABEL_DISABLED_CLASSES$1 = 'text-[var(--cxs-color-on-surface-muted)]';
3134
- const VARIANT_CLASSES$1 = {
3372
+ const WRAPPER_CLASSES$3 = 'flex w-full flex-col gap-1';
3373
+ const LABEL_BASE_CLASSES$2 = 'font-medium text-(--cxs-color-on-surface)';
3374
+ const LABEL_DISABLED_CLASSES$2 = 'text-[var(--cxs-color-on-surface-muted)]';
3375
+ const VARIANT_CLASSES$2 = {
3135
3376
  outline: 'bg-[var(--cxs-color-surface)]',
3136
3377
  filled: 'bg-[var(--cxs-color-surface-hover)]'
3137
3378
  };
@@ -3140,7 +3381,7 @@ const SIZE_CLASSES = {
3140
3381
  md: 'h-10 pl-3 pr-9 text-sm',
3141
3382
  lg: 'h-12 pl-4 pr-10 text-base'
3142
3383
  };
3143
- const LABEL_SIZE_CLASSES = {
3384
+ const LABEL_SIZE_CLASSES$1 = {
3144
3385
  sm: 'text-sm',
3145
3386
  md: 'text-sm',
3146
3387
  lg: 'text-base'
@@ -3172,22 +3413,22 @@ class CxsSelectComponent {
3172
3413
  }
3173
3414
  get selectClass() {
3174
3415
  return [
3175
- BASE_CLASSES$1,
3416
+ BASE_CLASSES$2,
3176
3417
  SIZE_CLASSES[this.size],
3177
- VARIANT_CLASSES$1[this.variant],
3418
+ VARIANT_CLASSES$2[this.variant],
3178
3419
  this.invalid ? INVALID_CLASSES : ''
3179
3420
  ]
3180
3421
  .filter(Boolean)
3181
3422
  .join(' ');
3182
3423
  }
3183
3424
  get wrapperClass() {
3184
- return WRAPPER_CLASSES$2;
3425
+ return WRAPPER_CLASSES$3;
3185
3426
  }
3186
3427
  get labelClass() {
3187
3428
  return [
3188
- LABEL_BASE_CLASSES$1,
3189
- LABEL_SIZE_CLASSES[this.size],
3190
- this.isDisabled ? LABEL_DISABLED_CLASSES$1 : ''
3429
+ LABEL_BASE_CLASSES$2,
3430
+ LABEL_SIZE_CLASSES$1[this.size],
3431
+ this.isDisabled ? LABEL_DISABLED_CLASSES$2 : ''
3191
3432
  ]
3192
3433
  .filter(Boolean)
3193
3434
  .join(' ');
@@ -3286,6 +3527,274 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
3286
3527
  type: Output
3287
3528
  }] } });
3288
3529
 
3530
+ const BASE_CLASSES$1 = 'cxs-skeleton block overflow-hidden bg-[var(--cxs-color-skeleton-base)]';
3531
+ const VARIANT_CLASSES$1 = {
3532
+ line: 'rounded-[var(--cxs-radius-md)]',
3533
+ block: 'rounded-[var(--cxs-radius-md)]',
3534
+ circle: 'rounded-full'
3535
+ };
3536
+ const SIZE_DIMENSIONS = {
3537
+ line: {
3538
+ sm: { width: '100%', height: '0.75rem' },
3539
+ md: { width: '100%', height: '1rem' },
3540
+ lg: { width: '100%', height: '1.25rem' }
3541
+ },
3542
+ block: {
3543
+ sm: { width: '100%', height: '3rem' },
3544
+ md: { width: '100%', height: '4rem' },
3545
+ lg: { width: '100%', height: '5rem' }
3546
+ },
3547
+ circle: {
3548
+ sm: { width: '2rem', height: '2rem' },
3549
+ md: { width: '3rem', height: '3rem' },
3550
+ lg: { width: '4rem', height: '4rem' }
3551
+ }
3552
+ };
3553
+ class CxsSkeletonComponent {
3554
+ hostClass;
3555
+ variant = 'line';
3556
+ size = 'md';
3557
+ animated = true;
3558
+ width;
3559
+ height;
3560
+ ariaLabel;
3561
+ constructor(hostClass) {
3562
+ this.hostClass = hostClass;
3563
+ }
3564
+ get skeletonClass() {
3565
+ return [
3566
+ BASE_CLASSES$1,
3567
+ VARIANT_CLASSES$1[this.variant],
3568
+ this.animated ? 'cxs-skeleton--animated' : '',
3569
+ this.hostClass
3570
+ ]
3571
+ .filter(Boolean)
3572
+ .join(' ');
3573
+ }
3574
+ get resolvedWidth() {
3575
+ return this.width ?? SIZE_DIMENSIONS[this.variant][this.size].width;
3576
+ }
3577
+ get resolvedHeight() {
3578
+ return this.height ?? SIZE_DIMENSIONS[this.variant][this.size].height;
3579
+ }
3580
+ get role() {
3581
+ return this.ariaLabel ? 'status' : null;
3582
+ }
3583
+ get ariaLabelValue() {
3584
+ return this.ariaLabel ?? null;
3585
+ }
3586
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsSkeletonComponent, deps: [{ token: 'class', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
3587
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.10", type: CxsSkeletonComponent, isStandalone: true, selector: "cxs-skeleton", inputs: { variant: "variant", size: "size", animated: "animated", width: "width", height: "height", ariaLabel: "ariaLabel" }, ngImport: i0, template: "<div\n [class]=\"skeletonClass\"\n [attr.role]=\"role\"\n [attr.aria-label]=\"ariaLabelValue\"\n [attr.aria-live]=\"role ? 'polite' : null\"\n [attr.aria-hidden]=\"role ? null : 'true'\"\n [style.width]=\"resolvedWidth\"\n [style.height]=\"resolvedHeight\"\n></div>\n", styles: [":host{display:block}.cxs-skeleton{position:relative}.cxs-skeleton--animated:after{content:\"\";position:absolute;inset:0;transform:translate(-100%);background:linear-gradient(90deg,transparent,var(--cxs-color-skeleton-highlight),transparent);animation:cxs-skeleton-shimmer 1.5s ease-in-out infinite}@keyframes cxs-skeleton-shimmer{to{transform:translate(100%)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3588
+ }
3589
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsSkeletonComponent, decorators: [{
3590
+ type: Component,
3591
+ args: [{ selector: 'cxs-skeleton', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n [class]=\"skeletonClass\"\n [attr.role]=\"role\"\n [attr.aria-label]=\"ariaLabelValue\"\n [attr.aria-live]=\"role ? 'polite' : null\"\n [attr.aria-hidden]=\"role ? null : 'true'\"\n [style.width]=\"resolvedWidth\"\n [style.height]=\"resolvedHeight\"\n></div>\n", styles: [":host{display:block}.cxs-skeleton{position:relative}.cxs-skeleton--animated:after{content:\"\";position:absolute;inset:0;transform:translate(-100%);background:linear-gradient(90deg,transparent,var(--cxs-color-skeleton-highlight),transparent);animation:cxs-skeleton-shimmer 1.5s ease-in-out infinite}@keyframes cxs-skeleton-shimmer{to{transform:translate(100%)}}\n"] }]
3592
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
3593
+ type: Attribute,
3594
+ args: ['class']
3595
+ }] }], propDecorators: { variant: [{
3596
+ type: Input
3597
+ }], size: [{
3598
+ type: Input
3599
+ }], animated: [{
3600
+ type: Input
3601
+ }], width: [{
3602
+ type: Input
3603
+ }], height: [{
3604
+ type: Input
3605
+ }], ariaLabel: [{
3606
+ type: Input
3607
+ }] } });
3608
+
3609
+ const WRAPPER_CLASSES$2 = 'flex w-full flex-col gap-1.5';
3610
+ const HEADER_CLASSES = 'flex items-center justify-between gap-3';
3611
+ const LABEL_BASE_CLASSES$1 = 'font-medium text-[var(--cxs-color-on-surface)]';
3612
+ const LABEL_DISABLED_CLASSES$1 = 'text-[var(--cxs-color-on-surface-muted)]';
3613
+ const VALUE_CLASSES = 'text-sm text-[var(--cxs-color-on-surface-muted)]';
3614
+ const LABEL_SIZE_CLASSES = {
3615
+ sm: 'text-sm',
3616
+ md: 'text-sm',
3617
+ lg: 'text-base'
3618
+ };
3619
+ const INPUT_BASE_CLASSES = 'cxs-slider block w-full appearance-none bg-transparent focus:outline-none ' +
3620
+ 'disabled:cursor-not-allowed disabled:opacity-60';
3621
+ const INPUT_SIZE_CLASSES = {
3622
+ sm: 'cxs-slider--sm',
3623
+ md: 'cxs-slider--md',
3624
+ lg: 'cxs-slider--lg'
3625
+ };
3626
+ const INPUT_VARIANT_CLASSES = {
3627
+ primary: 'cxs-slider--primary',
3628
+ danger: 'cxs-slider--danger'
3629
+ };
3630
+ class CxsSliderComponent {
3631
+ static nextId = 0;
3632
+ value = 0;
3633
+ min = 0;
3634
+ max = 100;
3635
+ step = 1;
3636
+ variant = 'primary';
3637
+ size = 'md';
3638
+ disabled = false;
3639
+ required = false;
3640
+ showValue = false;
3641
+ label;
3642
+ id;
3643
+ name;
3644
+ ariaLabel = 'Slider';
3645
+ ariaDescribedby;
3646
+ valueChange = new EventEmitter();
3647
+ instanceId = `cxs-slider-${CxsSliderComponent.nextId++}`;
3648
+ disabledFromControl = false;
3649
+ onChange = () => { };
3650
+ onTouched = () => { };
3651
+ get isDisabled() {
3652
+ return this.disabled || this.disabledFromControl;
3653
+ }
3654
+ get normalizedMin() {
3655
+ return Number.isFinite(this.min) ? this.min : 0;
3656
+ }
3657
+ get normalizedMax() {
3658
+ if (!Number.isFinite(this.max) || this.max <= this.normalizedMin) {
3659
+ return this.normalizedMin + 100;
3660
+ }
3661
+ return this.max;
3662
+ }
3663
+ get normalizedStep() {
3664
+ return Number.isFinite(this.step) && this.step > 0 ? this.step : 1;
3665
+ }
3666
+ get clampedValue() {
3667
+ if (!Number.isFinite(this.value)) {
3668
+ return this.normalizedMin;
3669
+ }
3670
+ return Math.min(Math.max(this.value, this.normalizedMin), this.normalizedMax);
3671
+ }
3672
+ get progressPercent() {
3673
+ return (((this.clampedValue - this.normalizedMin) / (this.normalizedMax - this.normalizedMin)) *
3674
+ 100);
3675
+ }
3676
+ get sliderClass() {
3677
+ return [
3678
+ INPUT_BASE_CLASSES,
3679
+ INPUT_SIZE_CLASSES[this.size],
3680
+ INPUT_VARIANT_CLASSES[this.variant]
3681
+ ].join(' ');
3682
+ }
3683
+ get wrapperClass() {
3684
+ return WRAPPER_CLASSES$2;
3685
+ }
3686
+ get headerClass() {
3687
+ return HEADER_CLASSES;
3688
+ }
3689
+ get labelClass() {
3690
+ return [
3691
+ LABEL_BASE_CLASSES$1,
3692
+ LABEL_SIZE_CLASSES[this.size],
3693
+ this.isDisabled ? LABEL_DISABLED_CLASSES$1 : ''
3694
+ ]
3695
+ .filter(Boolean)
3696
+ .join(' ');
3697
+ }
3698
+ get valueClass() {
3699
+ return VALUE_CLASSES;
3700
+ }
3701
+ get inputId() {
3702
+ return this.id ?? this.instanceId;
3703
+ }
3704
+ get labelId() {
3705
+ return this.label ? `${this.inputId}-label` : null;
3706
+ }
3707
+ get ariaLabelValue() {
3708
+ return this.label ? null : this.ariaLabel;
3709
+ }
3710
+ get ariaDescribedbyValue() {
3711
+ const tokens = [this.ariaDescribedby].filter(Boolean);
3712
+ return tokens.length > 0 ? tokens.join(' ') : null;
3713
+ }
3714
+ get valueText() {
3715
+ const displayValue = Number.isInteger(this.clampedValue)
3716
+ ? `${this.clampedValue}`
3717
+ : `${this.clampedValue}`;
3718
+ return displayValue;
3719
+ }
3720
+ get fillColor() {
3721
+ return this.variant === 'danger'
3722
+ ? 'var(--cxs-color-danger)'
3723
+ : 'var(--cxs-color-primary)';
3724
+ }
3725
+ writeValue(value) {
3726
+ this.value = value ?? this.normalizedMin;
3727
+ }
3728
+ registerOnChange(fn) {
3729
+ this.onChange = fn;
3730
+ }
3731
+ registerOnTouched(fn) {
3732
+ this.onTouched = fn;
3733
+ }
3734
+ setDisabledState(isDisabled) {
3735
+ this.disabledFromControl = isDisabled;
3736
+ }
3737
+ onInput(event) {
3738
+ const target = event.target;
3739
+ const nextValue = Number.parseFloat(target.value);
3740
+ const value = Number.isFinite(nextValue) ? nextValue : this.normalizedMin;
3741
+ this.value = value;
3742
+ this.onChange(value);
3743
+ this.valueChange.emit(value);
3744
+ }
3745
+ onBlur() {
3746
+ this.onTouched();
3747
+ }
3748
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsSliderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3749
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: CxsSliderComponent, isStandalone: true, selector: "cxs-slider", inputs: { value: "value", min: "min", max: "max", step: "step", variant: "variant", size: "size", disabled: "disabled", required: "required", showValue: "showValue", label: "label", id: "id", name: "name", ariaLabel: "ariaLabel", ariaDescribedby: "ariaDescribedby" }, outputs: { valueChange: "valueChange" }, providers: [
3750
+ {
3751
+ provide: NG_VALUE_ACCESSOR,
3752
+ useExisting: forwardRef(() => CxsSliderComponent),
3753
+ multi: true
3754
+ }
3755
+ ], ngImport: i0, template: "<div [class]=\"wrapperClass\">\n @if (label || showValue) {\n <div [class]=\"headerClass\">\n @if (label) {\n <label [for]=\"inputId\" [id]=\"labelId\" [class]=\"labelClass\">{{ label }}</label>\n }\n\n @if (showValue) {\n <span [class]=\"valueClass\">{{ valueText }}</span>\n }\n </div>\n }\n\n <input\n type=\"range\"\n [class]=\"sliderClass\"\n [id]=\"inputId\"\n [name]=\"name || null\"\n [disabled]=\"isDisabled\"\n [required]=\"required\"\n [value]=\"clampedValue\"\n [attr.min]=\"normalizedMin\"\n [attr.max]=\"normalizedMax\"\n [attr.step]=\"normalizedStep\"\n [attr.aria-label]=\"ariaLabelValue\"\n [attr.aria-labelledby]=\"labelId\"\n [attr.aria-describedby]=\"ariaDescribedbyValue\"\n [attr.aria-valuetext]=\"valueText\"\n [style.--cxs-slider-percent]=\"progressPercent + '%'\"\n [style.--cxs-slider-fill]=\"fillColor\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n />\n</div>\n", styles: [".cxs-slider{--cxs-slider-track-color: var(--cxs-color-surface-hover);--cxs-slider-thumb-color: var(--cxs-color-surface);cursor:pointer}.cxs-slider--sm{--cxs-slider-track-height: .375rem;--cxs-slider-thumb-size: 1rem}.cxs-slider--md{--cxs-slider-track-height: .5rem;--cxs-slider-thumb-size: 1.125rem}.cxs-slider--lg{--cxs-slider-track-height: .625rem;--cxs-slider-thumb-size: 1.25rem}.cxs-slider::-webkit-slider-runnable-track{height:var(--cxs-slider-track-height);border-radius:9999px;background:linear-gradient(to right,var(--cxs-slider-fill) 0%,var(--cxs-slider-fill) var(--cxs-slider-percent),var(--cxs-slider-track-color) var(--cxs-slider-percent),var(--cxs-slider-track-color) 100%)}.cxs-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:var(--cxs-slider-thumb-size);height:var(--cxs-slider-thumb-size);margin-top:calc((var(--cxs-slider-track-height) - var(--cxs-slider-thumb-size)) / 2);border:2px solid var(--cxs-slider-fill);border-radius:9999px;background:var(--cxs-slider-thumb-color);box-shadow:var(--cxs-shadow-sm)}.cxs-slider::-moz-range-track{height:var(--cxs-slider-track-height);border:0;border-radius:9999px;background:var(--cxs-slider-track-color)}.cxs-slider::-moz-range-progress{height:var(--cxs-slider-track-height);border-radius:9999px;background:var(--cxs-slider-fill)}.cxs-slider::-moz-range-thumb{width:var(--cxs-slider-thumb-size);height:var(--cxs-slider-thumb-size);border:2px solid var(--cxs-slider-fill);border-radius:9999px;background:var(--cxs-slider-thumb-color);box-shadow:var(--cxs-shadow-sm)}.cxs-slider:focus-visible::-webkit-slider-thumb{outline:2px solid var(--cxs-color-focus);outline-offset:2px}.cxs-slider:focus-visible::-moz-range-thumb{outline:2px solid var(--cxs-color-focus);outline-offset:2px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3756
+ }
3757
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsSliderComponent, decorators: [{
3758
+ type: Component,
3759
+ args: [{ selector: 'cxs-slider', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
3760
+ {
3761
+ provide: NG_VALUE_ACCESSOR,
3762
+ useExisting: forwardRef(() => CxsSliderComponent),
3763
+ multi: true
3764
+ }
3765
+ ], template: "<div [class]=\"wrapperClass\">\n @if (label || showValue) {\n <div [class]=\"headerClass\">\n @if (label) {\n <label [for]=\"inputId\" [id]=\"labelId\" [class]=\"labelClass\">{{ label }}</label>\n }\n\n @if (showValue) {\n <span [class]=\"valueClass\">{{ valueText }}</span>\n }\n </div>\n }\n\n <input\n type=\"range\"\n [class]=\"sliderClass\"\n [id]=\"inputId\"\n [name]=\"name || null\"\n [disabled]=\"isDisabled\"\n [required]=\"required\"\n [value]=\"clampedValue\"\n [attr.min]=\"normalizedMin\"\n [attr.max]=\"normalizedMax\"\n [attr.step]=\"normalizedStep\"\n [attr.aria-label]=\"ariaLabelValue\"\n [attr.aria-labelledby]=\"labelId\"\n [attr.aria-describedby]=\"ariaDescribedbyValue\"\n [attr.aria-valuetext]=\"valueText\"\n [style.--cxs-slider-percent]=\"progressPercent + '%'\"\n [style.--cxs-slider-fill]=\"fillColor\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n />\n</div>\n", styles: [".cxs-slider{--cxs-slider-track-color: var(--cxs-color-surface-hover);--cxs-slider-thumb-color: var(--cxs-color-surface);cursor:pointer}.cxs-slider--sm{--cxs-slider-track-height: .375rem;--cxs-slider-thumb-size: 1rem}.cxs-slider--md{--cxs-slider-track-height: .5rem;--cxs-slider-thumb-size: 1.125rem}.cxs-slider--lg{--cxs-slider-track-height: .625rem;--cxs-slider-thumb-size: 1.25rem}.cxs-slider::-webkit-slider-runnable-track{height:var(--cxs-slider-track-height);border-radius:9999px;background:linear-gradient(to right,var(--cxs-slider-fill) 0%,var(--cxs-slider-fill) var(--cxs-slider-percent),var(--cxs-slider-track-color) var(--cxs-slider-percent),var(--cxs-slider-track-color) 100%)}.cxs-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:var(--cxs-slider-thumb-size);height:var(--cxs-slider-thumb-size);margin-top:calc((var(--cxs-slider-track-height) - var(--cxs-slider-thumb-size)) / 2);border:2px solid var(--cxs-slider-fill);border-radius:9999px;background:var(--cxs-slider-thumb-color);box-shadow:var(--cxs-shadow-sm)}.cxs-slider::-moz-range-track{height:var(--cxs-slider-track-height);border:0;border-radius:9999px;background:var(--cxs-slider-track-color)}.cxs-slider::-moz-range-progress{height:var(--cxs-slider-track-height);border-radius:9999px;background:var(--cxs-slider-fill)}.cxs-slider::-moz-range-thumb{width:var(--cxs-slider-thumb-size);height:var(--cxs-slider-thumb-size);border:2px solid var(--cxs-slider-fill);border-radius:9999px;background:var(--cxs-slider-thumb-color);box-shadow:var(--cxs-shadow-sm)}.cxs-slider:focus-visible::-webkit-slider-thumb{outline:2px solid var(--cxs-color-focus);outline-offset:2px}.cxs-slider:focus-visible::-moz-range-thumb{outline:2px solid var(--cxs-color-focus);outline-offset:2px}\n"] }]
3766
+ }], propDecorators: { value: [{
3767
+ type: Input
3768
+ }], min: [{
3769
+ type: Input
3770
+ }], max: [{
3771
+ type: Input
3772
+ }], step: [{
3773
+ type: Input
3774
+ }], variant: [{
3775
+ type: Input
3776
+ }], size: [{
3777
+ type: Input
3778
+ }], disabled: [{
3779
+ type: Input
3780
+ }], required: [{
3781
+ type: Input
3782
+ }], showValue: [{
3783
+ type: Input
3784
+ }], label: [{
3785
+ type: Input
3786
+ }], id: [{
3787
+ type: Input
3788
+ }], name: [{
3789
+ type: Input
3790
+ }], ariaLabel: [{
3791
+ type: Input
3792
+ }], ariaDescribedby: [{
3793
+ type: Input
3794
+ }], valueChange: [{
3795
+ type: Output
3796
+ }] } });
3797
+
3289
3798
  const WRAPPER_BASE_CLASSES = 'w-full overflow-hidden';
3290
3799
  const WRAPPER_BORDERED_CLASSES = 'rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)]';
3291
3800
  const TABLE_BASE_CLASSES = 'w-full border-collapse text-sm text-[var(--cxs-color-on-surface)]';
@@ -3875,6 +4384,180 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
3875
4384
  type: Input
3876
4385
  }] } });
3877
4386
 
4387
+ const CXS_USER_SESSION_STORAGE_KEY = 'user_session';
4388
+ const CXS_USER_PREFERENCE_CHANGED_EVENT = 'cxs:user-preference-changed';
4389
+ const DATE_FORMAT_PREFERENCE_KEY = 'ui.dateFormat';
4390
+ const CURRENCY_FORMAT_PREFERENCE_KEY = 'ui.currencyFormat';
4391
+ const DATE_FORMAT_ALIASES = ['dateFormat', 'date_format'];
4392
+ const CURRENCY_FORMAT_ALIASES = ['currencyFormat', 'currency_format', 'currency'];
4393
+ const DEFAULT_DATE_FORMAT = 'mdy';
4394
+ const DEFAULT_CURRENCY_FORMAT = 'usd';
4395
+ const CURRENCY_FORMATS = {
4396
+ usd: { currency: 'USD', locale: 'en-US' },
4397
+ myr: { currency: 'MYR', locale: 'en-MY' },
4398
+ eur: { currency: 'EUR', locale: 'en-IE' },
4399
+ gbp: { currency: 'GBP', locale: 'en-GB' },
4400
+ jpy: { currency: 'JPY', locale: 'ja-JP' }
4401
+ };
4402
+ class CxsPreferenceFormattingService {
4403
+ preferenceVersionSignal = signal(0, ...(ngDevMode ? [{ debugName: "preferenceVersionSignal" }] : /* istanbul ignore next */ []));
4404
+ preferenceVersion = this.preferenceVersionSignal.asReadonly();
4405
+ constructor() {
4406
+ this.addPreferenceListeners();
4407
+ }
4408
+ formatDate(value) {
4409
+ if (value === null || value === undefined || value === '') {
4410
+ return '';
4411
+ }
4412
+ const date = value instanceof Date ? value : this.parseDateString(value);
4413
+ if (!date) {
4414
+ return String(value);
4415
+ }
4416
+ const format = this.dateFormatPreference();
4417
+ const year = date.getFullYear();
4418
+ const month = this.padDatePart(date.getMonth() + 1);
4419
+ const day = this.padDatePart(date.getDate());
4420
+ if (format === 'dmy') {
4421
+ return `${day}/${month}/${year}`;
4422
+ }
4423
+ if (format === 'ymd') {
4424
+ return `${year}-${month}-${day}`;
4425
+ }
4426
+ return `${month}/${day}/${year}`;
4427
+ }
4428
+ formatCurrency(value) {
4429
+ if (value === null || value === undefined || value === '') {
4430
+ return '';
4431
+ }
4432
+ const amount = typeof value === 'number' ? value : Number(value);
4433
+ if (!Number.isFinite(amount)) {
4434
+ return String(value);
4435
+ }
4436
+ const config = CURRENCY_FORMATS[this.currencyFormatPreference()];
4437
+ return new Intl.NumberFormat(config.locale, {
4438
+ currency: config.currency,
4439
+ style: 'currency'
4440
+ }).format(amount);
4441
+ }
4442
+ dateFormatPreference() {
4443
+ const value = this.getPreference(DATE_FORMAT_PREFERENCE_KEY, DATE_FORMAT_ALIASES);
4444
+ return this.isDateFormatPreference(value) ? value : DEFAULT_DATE_FORMAT;
4445
+ }
4446
+ currencyFormatPreference() {
4447
+ const value = this.getPreference(CURRENCY_FORMAT_PREFERENCE_KEY, CURRENCY_FORMAT_ALIASES);
4448
+ return this.isCurrencyFormatPreference(value) ? value : DEFAULT_CURRENCY_FORMAT;
4449
+ }
4450
+ getPreference(key, aliases) {
4451
+ const preferences = this.readSession()?.preferences ?? [];
4452
+ const keys = [key, ...aliases];
4453
+ const preference = keys
4454
+ .map((preferenceKey) => preferences.find((item) => item.key === preferenceKey))
4455
+ .find(Boolean);
4456
+ return preference?.value?.trim().toLowerCase();
4457
+ }
4458
+ readSession() {
4459
+ const storage = this.getLocalStorage();
4460
+ if (!storage) {
4461
+ return null;
4462
+ }
4463
+ const raw = storage.getItem(CXS_USER_SESSION_STORAGE_KEY);
4464
+ if (!raw) {
4465
+ return null;
4466
+ }
4467
+ try {
4468
+ return JSON.parse(raw);
4469
+ }
4470
+ catch {
4471
+ return null;
4472
+ }
4473
+ }
4474
+ parseDateString(value) {
4475
+ const apiDateMatch = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
4476
+ if (apiDateMatch) {
4477
+ const [, year, month, day] = apiDateMatch;
4478
+ return new Date(Number(year), Number(month) - 1, Number(day));
4479
+ }
4480
+ const parsed = new Date(value);
4481
+ return Number.isNaN(parsed.getTime()) ? null : parsed;
4482
+ }
4483
+ padDatePart(value) {
4484
+ return String(value).padStart(2, '0');
4485
+ }
4486
+ isDateFormatPreference(value) {
4487
+ return value === 'mdy' || value === 'dmy' || value === 'ymd';
4488
+ }
4489
+ isCurrencyFormatPreference(value) {
4490
+ return (value === 'usd' ||
4491
+ value === 'myr' ||
4492
+ value === 'eur' ||
4493
+ value === 'gbp' ||
4494
+ value === 'jpy');
4495
+ }
4496
+ addPreferenceListeners() {
4497
+ if (typeof window === 'undefined') {
4498
+ return;
4499
+ }
4500
+ window.addEventListener('storage', (event) => {
4501
+ if (event.key === CXS_USER_SESSION_STORAGE_KEY) {
4502
+ this.bumpPreferenceVersion();
4503
+ }
4504
+ });
4505
+ window.addEventListener(CXS_USER_PREFERENCE_CHANGED_EVENT, () => {
4506
+ this.bumpPreferenceVersion();
4507
+ });
4508
+ }
4509
+ bumpPreferenceVersion() {
4510
+ this.preferenceVersionSignal.update((version) => version + 1);
4511
+ }
4512
+ getLocalStorage() {
4513
+ return typeof localStorage === 'undefined' ? null : localStorage;
4514
+ }
4515
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsPreferenceFormattingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4516
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsPreferenceFormattingService, providedIn: 'root' });
4517
+ }
4518
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsPreferenceFormattingService, decorators: [{
4519
+ type: Injectable,
4520
+ args: [{
4521
+ providedIn: 'root'
4522
+ }]
4523
+ }], ctorParameters: () => [] });
4524
+
4525
+ class CxsCurrencyPipe {
4526
+ formatter = inject(CxsPreferenceFormattingService);
4527
+ transform(value) {
4528
+ this.formatter.preferenceVersion();
4529
+ return this.formatter.formatCurrency(value);
4530
+ }
4531
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsCurrencyPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
4532
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.10", ngImport: i0, type: CxsCurrencyPipe, isStandalone: true, name: "cxsCurrency", pure: false });
4533
+ }
4534
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsCurrencyPipe, decorators: [{
4535
+ type: Pipe,
4536
+ args: [{
4537
+ name: 'cxsCurrency',
4538
+ standalone: true,
4539
+ pure: false
4540
+ }]
4541
+ }] });
4542
+
4543
+ class CxsDatePipe {
4544
+ formatter = inject(CxsPreferenceFormattingService);
4545
+ transform(value) {
4546
+ this.formatter.preferenceVersion();
4547
+ return this.formatter.formatDate(value);
4548
+ }
4549
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsDatePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
4550
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.10", ngImport: i0, type: CxsDatePipe, isStandalone: true, name: "cxsDate", pure: false });
4551
+ }
4552
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsDatePipe, decorators: [{
4553
+ type: Pipe,
4554
+ args: [{
4555
+ name: 'cxsDate',
4556
+ standalone: true,
4557
+ pure: false
4558
+ }]
4559
+ }] });
4560
+
3878
4561
  /*
3879
4562
  * Public API Surface of cerxos-ui
3880
4563
  */
@@ -3883,5 +4566,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
3883
4566
  * Generated bundle index. Do not edit.
3884
4567
  */
3885
4568
 
3886
- export { CerxosUi, CxsAccordionComponent, CxsAccordionItemComponent, CxsActionMenuComponent, CxsAlertComponent, CxsAvatarComponent, CxsBadgeComponent, CxsBreadcrumbComponent, CxsButtonComponent, CxsCardComponent, CxsCarouselComponent, CxsCheckboxComponent, CxsDataTableCellDirective, CxsDataTableComponent, CxsDatepickerComponent, CxsDialogComponent, CxsInputComponent, CxsMenubarComponent, CxsMultiSelectComponent, CxsRadioComponent, CxsSelectComponent, CxsTabLabelDirective, CxsTabPanelComponent, CxsTableComponent, CxsTabsComponent, CxsThemeDirective, CxsToastComponent, CxsToggleComponent, CxsTooltipComponent };
4569
+ export { CXS_USER_PREFERENCE_CHANGED_EVENT, CXS_USER_SESSION_STORAGE_KEY, CerxosUi, CxsAccordionComponent, CxsAccordionItemComponent, CxsActionMenuComponent, CxsAlertComponent, CxsAvatarComponent, CxsBadgeComponent, CxsBreadcrumbComponent, CxsButtonComponent, CxsCardComponent, CxsCarouselComponent, CxsCheckboxComponent, CxsCurrencyPipe, CxsDataTableCellDirective, CxsDataTableComponent, CxsDatePipe, CxsDatepickerComponent, CxsDialogComponent, CxsIconComponent, CxsInputComponent, CxsMenubarComponent, CxsMultiSelectComponent, CxsPreferenceFormattingService, CxsProgressBarComponent, CxsRadioComponent, CxsSelectComponent, CxsSkeletonComponent, CxsSliderComponent, CxsTabLabelDirective, CxsTabPanelComponent, CxsTableComponent, CxsTabsComponent, CxsThemeDirective, CxsToastComponent, CxsToggleComponent, CxsTooltipComponent };
3887
4570
  //# sourceMappingURL=cerxos-ui.mjs.map