cerxos-ui 0.0.4 → 0.0.6

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,7 +1,8 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, EventEmitter, Output, Input, ChangeDetectionStrategy, Attribute, forwardRef, ViewChild, HostListener, ElementRef, ViewChildren, Directive } from '@angular/core';
2
+ import { Component, EventEmitter, Output, Input, ChangeDetectionStrategy, Attribute, forwardRef, Directive, ContentChildren, ViewChild, HostListener, ElementRef, ViewChildren, ContentChild } from '@angular/core';
3
3
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
4
- import { NgIf } from '@angular/common';
4
+ import * as i1 from '@angular/common';
5
+ import { NgTemplateOutlet, CommonModule, NgIf } from '@angular/common';
5
6
 
6
7
  class CerxosUi {
7
8
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CerxosUi, deps: [], target: i0.ɵɵFactoryTarget.Component });
@@ -22,7 +23,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
22
23
 
23
24
  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 ' +
24
25
  'text-[var(--cxs-color-on-surface)]';
25
- const VARIANT_CLASSES$7 = {
26
+ const VARIANT_CLASSES$8 = {
26
27
  info: 'border-[var(--cxs-color-primary)] border-l-[var(--cxs-color-primary)] ' +
27
28
  'bg-[var(--cxs-color-primary-ghost)]',
28
29
  neutral: 'border-[var(--cxs-color-border)] border-l-[var(--cxs-color-border)] ' +
@@ -47,7 +48,7 @@ class CxsAlertComponent {
47
48
  closed = new EventEmitter();
48
49
  isVisible = true;
49
50
  get alertClass() {
50
- return [BASE_CLASSES$a, VARIANT_CLASSES$7[this.variant]].join(' ');
51
+ return [BASE_CLASSES$a, VARIANT_CLASSES$8[this.variant]].join(' ');
51
52
  }
52
53
  get titleClass() {
53
54
  return [TITLE_BASE, TITLE_VARIANT[this.variant]].join(' ');
@@ -174,7 +175,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
174
175
 
175
176
  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 ' +
176
177
  'leading-none';
177
- const VARIANT_CLASSES$6 = {
178
+ const VARIANT_CLASSES$7 = {
178
179
  primary: 'border-[var(--cxs-color-primary)] bg-[var(--cxs-color-primary-ghost)] ' +
179
180
  'text-[var(--cxs-color-primary)]',
180
181
  neutral: 'border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] ' +
@@ -190,7 +191,7 @@ class CxsBadgeComponent {
190
191
  variant = 'primary';
191
192
  size = 'md';
192
193
  get badgeClass() {
193
- return [BASE_CLASSES$8, VARIANT_CLASSES$6[this.variant], SIZE_CLASSES$7[this.size]].join(' ');
194
+ return [BASE_CLASSES$8, VARIANT_CLASSES$7[this.variant], SIZE_CLASSES$7[this.size]].join(' ');
194
195
  }
195
196
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
196
197
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CxsBadgeComponent, isStandalone: true, selector: "cxs-badge", inputs: { variant: "variant", size: "size" }, ngImport: i0, template: "<span [class]=\"badgeClass\">\r\n <ng-content></ng-content>\r\n</span>\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
@@ -399,7 +400,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
399
400
  const BASE_CLASSES$5 = 'relative inline-flex items-center justify-center gap-2 whitespace-nowrap font-medium transition-colors ' +
400
401
  'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
401
402
  'focus-visible:outline-[var(--cxs-color-focus)] disabled:pointer-events-none disabled:opacity-50';
402
- const VARIANT_CLASSES$5 = {
403
+ const VARIANT_CLASSES$6 = {
403
404
  primary: 'bg-[var(--cxs-color-primary)] text-[var(--cxs-color-on-primary)] ' +
404
405
  'hover:bg-[var(--cxs-color-primary-hover)] shadow-[var(--cxs-shadow-sm)]',
405
406
  secondary: 'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)] ' +
@@ -425,7 +426,7 @@ class CxsButtonComponent {
425
426
  return this.disabled || this.loading;
426
427
  }
427
428
  get buttonClass() {
428
- return [BASE_CLASSES$5, SIZE_CLASSES$4[this.size], VARIANT_CLASSES$5[this.variant], this.hostClass]
429
+ return [BASE_CLASSES$5, SIZE_CLASSES$4[this.size], VARIANT_CLASSES$6[this.variant], this.hostClass]
429
430
  .filter(Boolean)
430
431
  .join(' ');
431
432
  }
@@ -452,7 +453,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
452
453
 
453
454
  const BASE_CLASSES$4 = 'rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
454
455
  'bg-[var(--cxs-color-surface)] text-[var(--cxs-color-on-surface)]';
455
- const VARIANT_CLASSES$4 = {
456
+ const VARIANT_CLASSES$5 = {
456
457
  surface: 'bg-[var(--cxs-color-surface)]',
457
458
  muted: 'bg-[var(--cxs-color-surface-hover)]',
458
459
  outline: 'bg-transparent'
@@ -471,7 +472,7 @@ class CxsCardComponent {
471
472
  get cardClass() {
472
473
  return [
473
474
  BASE_CLASSES$4,
474
- VARIANT_CLASSES$4[this.variant],
475
+ VARIANT_CLASSES$5[this.variant],
475
476
  SIZE_CLASSES$3[this.size],
476
477
  this.elevated ? 'shadow-[var(--cxs-shadow-sm)]' : ''
477
478
  ]
@@ -501,7 +502,7 @@ const WRAPPER_ENABLED$1 = 'cursor-pointer';
501
502
  const WRAPPER_DISABLED$1 = 'cursor-not-allowed opacity-60';
502
503
  const LABEL_BASE$1 = 'text-[var(--cxs-color-on-surface)]';
503
504
  const LABEL_DISABLED$1 = 'text-[var(--cxs-color-on-surface-muted)]';
504
- const LABEL_SIZE_CLASSES$1 = {
505
+ const LABEL_SIZE_CLASSES$5 = {
505
506
  sm: 'text-sm',
506
507
  md: 'text-sm',
507
508
  lg: 'text-base'
@@ -517,7 +518,7 @@ const CONTROL_BASE$1 = "relative flex shrink-0 items-center justify-center round
517
518
  'peer-indeterminate:before:opacity-100 peer-indeterminate:after:opacity-0 ' +
518
519
  'peer-focus-visible:outline peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2 ' +
519
520
  'peer-focus-visible:outline-[var(--cxs-color-focus)]';
520
- const CONTROL_SIZE_CLASSES$1 = {
521
+ const CONTROL_SIZE_CLASSES$2 = {
521
522
  sm: 'h-4 w-4',
522
523
  md: 'h-5 w-5',
523
524
  lg: 'h-6 w-6'
@@ -555,7 +556,7 @@ class CxsCheckboxComponent {
555
556
  get labelClass() {
556
557
  return [
557
558
  LABEL_BASE$1,
558
- LABEL_SIZE_CLASSES$1[this.size],
559
+ LABEL_SIZE_CLASSES$5[this.size],
559
560
  this.isDisabled ? LABEL_DISABLED$1 : ''
560
561
  ]
561
562
  .filter(Boolean)
@@ -564,7 +565,7 @@ class CxsCheckboxComponent {
564
565
  get controlClass() {
565
566
  return [
566
567
  CONTROL_BASE$1,
567
- CONTROL_SIZE_CLASSES$1[this.size],
568
+ CONTROL_SIZE_CLASSES$2[this.size],
568
569
  MARK_SIZE_CLASSES[this.size]
569
570
  ].join(' ');
570
571
  }
@@ -780,6 +781,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
780
781
  type: Output
781
782
  }] } });
782
783
 
784
+ class CxsDataTableCellDirective {
785
+ template;
786
+ columnKey = '';
787
+ constructor(template) {
788
+ this.template = template;
789
+ }
790
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDataTableCellDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
791
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: CxsDataTableCellDirective, isStandalone: true, selector: "[cxsDataTableCell]", inputs: { columnKey: ["cxsDataTableCell", "columnKey"] }, ngImport: i0 });
792
+ }
793
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDataTableCellDirective, decorators: [{
794
+ type: Directive,
795
+ args: [{
796
+ selector: '[cxsDataTableCell]',
797
+ standalone: true
798
+ }]
799
+ }], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { columnKey: [{
800
+ type: Input,
801
+ args: ['cxsDataTableCell']
802
+ }] } });
803
+
783
804
  const WRAPPER_BASE_CLASSES$1 = 'w-full overflow-hidden';
784
805
  const WRAPPER_BORDERED_CLASSES$1 = 'rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)]';
785
806
  const TABLE_BASE_CLASSES$1 = 'w-full border-collapse text-sm text-[var(--cxs-color-on-surface)]';
@@ -817,8 +838,15 @@ const TOOLBAR_INPUT_CLASSES = 'w-full rounded-[var(--cxs-radius-md)] border bord
817
838
  'bg-[var(--cxs-color-surface)] px-3 py-2 text-sm text-[var(--cxs-color-on-surface)] ' +
818
839
  'placeholder:text-[var(--cxs-color-on-surface-muted)] focus-visible:outline focus-visible:outline-2 ' +
819
840
  'focus-visible:outline-offset-2 focus-visible:outline-[var(--cxs-color-focus)]';
841
+ const TOOLBAR_INPUT_INLINE_CLASSES = 'w-full sm:w-64 rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
842
+ 'bg-[var(--cxs-color-surface)] px-3 py-2 text-sm text-[var(--cxs-color-on-surface)] ' +
843
+ 'placeholder:text-[var(--cxs-color-on-surface-muted)] focus-visible:outline focus-visible:outline-2 ' +
844
+ 'focus-visible:outline-offset-2 focus-visible:outline-[var(--cxs-color-focus)]';
820
845
  const TOOLBAR_BUTTON_CLASSES = 'inline-flex items-center justify-center rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
821
846
  'px-3 py-2 text-sm transition-colors hover:bg-[var(--cxs-color-surface-hover)]';
847
+ const TITLE_BAR_CLASSES = 'mb-3 flex flex-wrap items-start justify-between gap-3';
848
+ const TITLE_TEXT_CLASSES = 'text-base font-semibold text-(--cxs-color-on-surface)';
849
+ const SUBTITLE_TEXT_CLASSES = 'text-sm text-(--cxs-color-on-surface-muted)';
822
850
  const BULK_BAR_CLASSES = 'mb-3 flex flex-wrap items-center justify-between gap-3 rounded-[var(--cxs-radius-md)] ' +
823
851
  'border border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] px-3 py-2 text-sm';
824
852
  const RESIZE_HANDLE_CLASSES = 'absolute right-0 top-0 h-full w-2 cursor-col-resize touch-none';
@@ -827,6 +855,8 @@ class CxsDataTableComponent {
827
855
  columns = [];
828
856
  data = [];
829
857
  caption;
858
+ title;
859
+ subtitle;
830
860
  ariaLabel = 'Data table';
831
861
  striped = false;
832
862
  bordered = false;
@@ -859,6 +889,7 @@ class CxsDataTableComponent {
859
889
  filterChange = new EventEmitter();
860
890
  selectionChange = new EventEmitter();
861
891
  bulkAction = new EventEmitter();
892
+ cellTemplates;
862
893
  currentPage = 1;
863
894
  currentPageSize = 10;
864
895
  globalFilter = '';
@@ -940,9 +971,21 @@ class CxsDataTableComponent {
940
971
  get toolbarInputClass() {
941
972
  return TOOLBAR_INPUT_CLASSES;
942
973
  }
974
+ get toolbarInputInlineClass() {
975
+ return TOOLBAR_INPUT_INLINE_CLASSES;
976
+ }
943
977
  get toolbarButtonClass() {
944
978
  return TOOLBAR_BUTTON_CLASSES;
945
979
  }
980
+ get titleBarClass() {
981
+ return TITLE_BAR_CLASSES;
982
+ }
983
+ get titleTextClass() {
984
+ return TITLE_TEXT_CLASSES;
985
+ }
986
+ get subtitleTextClass() {
987
+ return SUBTITLE_TEXT_CLASSES;
988
+ }
946
989
  get bulkBarClass() {
947
990
  return BULK_BAR_CLASSES;
948
991
  }
@@ -979,6 +1022,9 @@ class CxsDataTableComponent {
979
1022
  get selectedCount() {
980
1023
  return this.selectedKeys.length;
981
1024
  }
1025
+ get hasTitleBlock() {
1026
+ return Boolean(this.title || this.subtitle);
1027
+ }
982
1028
  get allVisibleSelected() {
983
1029
  if (!this.displayRows.length) {
984
1030
  return false;
@@ -1013,6 +1059,12 @@ class CxsDataTableComponent {
1013
1059
  .filter(Boolean)
1014
1060
  .join(' ');
1015
1061
  }
1062
+ cellTemplate(columnKey) {
1063
+ if (!this.cellTemplates) {
1064
+ return null;
1065
+ }
1066
+ return this.cellTemplates.find((template) => template.columnKey === columnKey)?.template ?? null;
1067
+ }
1016
1068
  cellValue(row, column) {
1017
1069
  const value = row[column.key];
1018
1070
  if (column.formatter) {
@@ -1283,11 +1335,11 @@ class CxsDataTableComponent {
1283
1335
  return value;
1284
1336
  }
1285
1337
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDataTableComponent, deps: [{ token: 'class', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
1286
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsDataTableComponent, isStandalone: true, selector: "cxs-data-table", inputs: { columns: "columns", data: "data", caption: "caption", ariaLabel: "ariaLabel", striped: "striped", bordered: "bordered", compact: "compact", loading: "loading", emptyMessage: "emptyMessage", emptyCell: "emptyCell", pageSize: "pageSize", pageIndex: "pageIndex", pageSizeOptions: "pageSizeOptions", showPagination: "showPagination", showPageSize: "showPageSize", manualPagination: "manualPagination", total: "total", sortKey: "sortKey", sortDirection: "sortDirection", manualSort: "manualSort", showToolbar: "showToolbar", showFilters: "showFilters", showColumnVisibility: "showColumnVisibility", showGlobalSearch: "showGlobalSearch", manualFilter: "manualFilter", selectable: "selectable", rowKey: "rowKey", selectedKeys: "selectedKeys", bulkActions: "bulkActions" }, outputs: { pageChange: "pageChange", pageSizeChange: "pageSizeChange", sortChange: "sortChange", filterChange: "filterChange", selectionChange: "selectionChange", bulkAction: "bulkAction" }, usesOnChanges: true, ngImport: i0, template: "@if (showToolbar) {\n <div [class]=\"toolbarClass\">\n <div [class]=\"toolbarGroupClass\">\n @if (showGlobalSearch) {\n <input\n type=\"search\"\n [class]=\"toolbarInputClass\"\n placeholder=\"Search\"\n [value]=\"globalFilter\"\n (input)=\"onGlobalFilterChange($any($event.target).value)\"\n />\n }\n </div>\n <div [class]=\"toolbarGroupClass\">\n @if (showFilters) {\n <button type=\"button\" [class]=\"toolbarButtonClass\" (click)=\"filtersOpen = !filtersOpen\">\n Filters\n </button>\n }\n @if (showColumnVisibility) {\n <details class=\"relative\">\n <summary [class]=\"toolbarButtonClass\">Columns</summary>\n <div\n class=\"absolute right-0 mt-2 w-48 rounded-(--cxs-radius-md) border border-(--cxs-color-border) bg-(--cxs-color-surface) p-2 shadow-(--cxs-shadow-sm)\"\n >\n @for (column of columns; track column) {\n <label class=\"flex items-center gap-2 px-2 py-1 text-sm\">\n <input\n type=\"checkbox\"\n [checked]=\"columnVisibility[column.key]\"\n (change)=\"toggleColumnVisibility(column.key)\"\n />\n <span>{{ column.label }}</span>\n </label>\n }\n </div>\n </details>\n }\n </div>\n </div>\n}\n\n@if (selectable && selectedCount > 0 && bulkActions.length > 0) {\n <div [class]=\"bulkBarClass\">\n <span>{{ selectedCount }} selected</span>\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (action of bulkActions; track action) {\n <button type=\"button\" [class]=\"toolbarButtonClass\" (click)=\"runBulkAction(action.id)\">\n {{ action.label }}\n </button>\n }\n </div>\n </div>\n}\n\n<div [class]=\"wrapperClass\">\n <table [class]=\"tableClass\" [attr.aria-label]=\"ariaLabel\">\n @if (caption) {\n <caption class=\"sr-only\">{{ caption }}</caption>\n }\n <thead>\n <tr [class]=\"headerRowClass\">\n @if (selectable) {\n <th class=\"px-3 py-2\">\n <input\n type=\"checkbox\"\n [checked]=\"allVisibleSelected\"\n [indeterminate]=\"someVisibleSelected\"\n (change)=\"toggleSelectAll()\"\n aria-label=\"Select all rows\"\n />\n </th>\n }\n @for (column of visibleColumns; track column) {\n <th\n class=\"relative\"\n [class]=\"headerCellClass(column) + ' ' + pinnedClass(column)\"\n [style.width]=\"columnWidth(column)\"\n [style.minWidth]=\"columnMinWidth(column)\"\n [style.left]=\"pinnedLeft(column)\"\n [style.right]=\"pinnedRight(column)\"\n scope=\"col\"\n [attr.aria-sort]=\"ariaSort(column)\"\n >\n @if (column.sortable) {\n <button\n type=\"button\"\n [class]=\"headerButtonClass()\"\n (click)=\"onSort(column)\"\n >\n <span>{{ column.label }}</span>\n @if (sortKey === column.key) {\n @if (sortDirection === 'asc') {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"h-4 w-4 text-(--cxs-color-on-surface-muted)\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M4.5 10.5 12 3m0 0 7.5 7.5M12 3v18\"\n />\n </svg>\n } @else {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"h-4 w-4 text-(--cxs-color-on-surface-muted)\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M19.5 13.5 12 21m0 0-7.5-7.5M12 21V3\"\n />\n </svg>\n }\n }\n </button>\n } @else {\n {{ column.label }}\n }\n @if (column.resizable !== false) {\n <span\n [class]=\"resizeHandleClass\"\n (mousedown)=\"onResizeStart($event, column)\"\n ></span>\n }\n </th>\n }\n </tr>\n @if (showFilters && filtersOpen) {\n <tr [class]=\"headerRowClass\">\n @if (selectable) {\n <th class=\"px-3 py-2\"></th>\n }\n @for (column of visibleColumns; track column) {\n <th\n [class]=\"headerCellClass(column) + ' ' + pinnedClass(column)\"\n [style.left]=\"pinnedLeft(column)\"\n [style.right]=\"pinnedRight(column)\"\n >\n @if (column.filterable) {\n @if (column.filterType === 'select') {\n <select\n [class]=\"headerFilterInputClass()\"\n [value]=\"columnFilterValue(column.key)\"\n (change)=\"onColumnFilterChange(column.key, $any($event.target).value)\"\n >\n <option value=\"\">All</option>\n @for (option of column.filterOptions ?? []; track option) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n } @else {\n <input\n [class]=\"headerFilterInputClass()\"\n [attr.type]=\"column.filterType === 'number' ? 'number' : 'text'\"\n placeholder=\"Filter\"\n [value]=\"columnFilterValue(column.key)\"\n (input)=\"onColumnFilterChange(column.key, $any($event.target).value)\"\n />\n }\n }\n </th>\n }\n </tr>\n }\n </thead>\n <tbody>\n @if (loading) {\n <tr [class]=\"bodyRowClass\">\n <td [class]=\"bodyCellClass({ key: '', label: '' })\" [attr.colspan]=\"colSpan\">\n <span [class]=\"emptyRowClass\">Loading...</span>\n </td>\n </tr>\n } @else if (displayRows.length === 0) {\n <tr [class]=\"bodyRowClass\">\n <td [class]=\"bodyCellClass({ key: '', label: '' })\" [attr.colspan]=\"colSpan\">\n <span [class]=\"emptyRowClass\">{{ emptyMessage }}</span>\n </td>\n </tr>\n } @else {\n @for (row of displayRows; track row) {\n <tr [class]=\"bodyRowClass\">\n @if (selectable) {\n <td class=\"px-3 py-2\">\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(row)\"\n (change)=\"toggleRowSelection(row)\"\n aria-label=\"Select row\"\n />\n </td>\n }\n @for (column of visibleColumns; track column) {\n <td\n [class]=\"bodyCellClass(column) + ' ' + pinnedClass(column)\"\n [style.left]=\"pinnedLeft(column)\"\n [style.right]=\"pinnedRight(column)\"\n >\n {{ cellValue(row, column) }}\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n@if (showPagination) {\n <div [class]=\"paginationClass\">\n <div class=\"flex items-center gap-2\">\n <button\n type=\"button\"\n [class]=\"pageButtonClass\"\n [disabled]=\"currentPage <= 1\"\n (click)=\"previousPage()\"\n >\n Previous\n </button>\n <button\n type=\"button\"\n [class]=\"pageButtonClass\"\n [disabled]=\"currentPage >= totalPages\"\n (click)=\"nextPage()\"\n >\n Next\n </button>\n <span class=\"text-(--cxs-color-on-surface-muted)\">{{ pageLabel }}</span>\n </div>\n @if (showPageSize) {\n <label class=\"flex items-center gap-2 text-(--cxs-color-on-surface-muted)\">\n <span>Rows</span>\n <select\n #pageSizeSelect\n [class]=\"pageSelectClass\"\n [value]=\"currentPageSize\"\n (change)=\"onPageSizeChange(pageSizeSelect.value)\"\n >\n @for (size of pageSizeOptions; track size) {\n <option [value]=\"size\">{{ size }}</option>\n }\n </select>\n </label>\n }\n </div>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
1338
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsDataTableComponent, isStandalone: true, selector: "cxs-data-table", inputs: { columns: "columns", data: "data", caption: "caption", title: "title", subtitle: "subtitle", ariaLabel: "ariaLabel", striped: "striped", bordered: "bordered", compact: "compact", loading: "loading", emptyMessage: "emptyMessage", emptyCell: "emptyCell", pageSize: "pageSize", pageIndex: "pageIndex", pageSizeOptions: "pageSizeOptions", showPagination: "showPagination", showPageSize: "showPageSize", manualPagination: "manualPagination", total: "total", sortKey: "sortKey", sortDirection: "sortDirection", manualSort: "manualSort", showToolbar: "showToolbar", showFilters: "showFilters", showColumnVisibility: "showColumnVisibility", showGlobalSearch: "showGlobalSearch", manualFilter: "manualFilter", selectable: "selectable", rowKey: "rowKey", selectedKeys: "selectedKeys", bulkActions: "bulkActions" }, outputs: { pageChange: "pageChange", pageSizeChange: "pageSizeChange", sortChange: "sortChange", filterChange: "filterChange", selectionChange: "selectionChange", bulkAction: "bulkAction" }, queries: [{ propertyName: "cellTemplates", predicate: CxsDataTableCellDirective }], usesOnChanges: true, ngImport: i0, template: "@if (hasTitleBlock) {\n <div [class]=\"titleBarClass\">\n <div class=\"min-w-0\">\n @if (title) {\n <div [class]=\"titleTextClass\">{{ title }}</div>\n }\n @if (subtitle) {\n <div [class]=\"subtitleTextClass\">{{ subtitle }}</div>\n }\n </div>\n @if (showToolbar) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @if (showGlobalSearch) {\n <input\n type=\"search\"\n [class]=\"toolbarInputInlineClass\"\n placeholder=\"Search\"\n [value]=\"globalFilter\"\n (input)=\"onGlobalFilterChange($any($event.target).value)\"\n />\n }\n @if (showFilters) {\n <button type=\"button\" [class]=\"toolbarButtonClass\" (click)=\"filtersOpen = !filtersOpen\">\n Filters\n </button>\n }\n @if (showColumnVisibility) {\n <details class=\"relative\">\n <summary [class]=\"toolbarButtonClass\">Columns</summary>\n <div\n class=\"absolute right-0 mt-2 w-48 rounded-(--cxs-radius-md) border border-(--cxs-color-border) bg-(--cxs-color-surface) p-2 shadow-(--cxs-shadow-sm)\"\n >\n @for (column of columns; track column) {\n <label class=\"flex items-center gap-2 px-2 py-1 text-sm\">\n <input\n type=\"checkbox\"\n [checked]=\"columnVisibility[column.key]\"\n (change)=\"toggleColumnVisibility(column.key)\"\n />\n <span>{{ column.label }}</span>\n </label>\n }\n </div>\n </details>\n }\n </div>\n }\n </div>\n} @else if (showToolbar) {\n <div [class]=\"toolbarClass\">\n <div [class]=\"toolbarGroupClass\">\n @if (showGlobalSearch) {\n <input\n type=\"search\"\n [class]=\"toolbarInputClass\"\n placeholder=\"Search\"\n [value]=\"globalFilter\"\n (input)=\"onGlobalFilterChange($any($event.target).value)\"\n />\n }\n </div>\n <div [class]=\"toolbarGroupClass\">\n @if (showFilters) {\n <button type=\"button\" [class]=\"toolbarButtonClass\" (click)=\"filtersOpen = !filtersOpen\">\n Filters\n </button>\n }\n @if (showColumnVisibility) {\n <details class=\"relative\">\n <summary [class]=\"toolbarButtonClass\">Columns</summary>\n <div\n class=\"absolute right-0 mt-2 w-48 rounded-(--cxs-radius-md) border border-(--cxs-color-border) bg-(--cxs-color-surface) p-2 shadow-(--cxs-shadow-sm)\"\n >\n @for (column of columns; track column) {\n <label class=\"flex items-center gap-2 px-2 py-1 text-sm\">\n <input\n type=\"checkbox\"\n [checked]=\"columnVisibility[column.key]\"\n (change)=\"toggleColumnVisibility(column.key)\"\n />\n <span>{{ column.label }}</span>\n </label>\n }\n </div>\n </details>\n }\n </div>\n </div>\n}\n\n@if (selectable && selectedCount > 0 && bulkActions.length > 0) {\n <div [class]=\"bulkBarClass\">\n <span>{{ selectedCount }} selected</span>\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (action of bulkActions; track action) {\n <button type=\"button\" [class]=\"toolbarButtonClass\" (click)=\"runBulkAction(action.id)\">\n {{ action.label }}\n </button>\n }\n </div>\n </div>\n}\n\n<div [class]=\"wrapperClass\">\n <table [class]=\"tableClass\" [attr.aria-label]=\"ariaLabel\">\n @if (caption) {\n <caption class=\"sr-only\">{{ caption }}</caption>\n }\n <thead>\n <tr [class]=\"headerRowClass\">\n @if (selectable) {\n <th class=\"px-3 py-2 text-left\">\n <input\n type=\"checkbox\"\n [checked]=\"allVisibleSelected\"\n [indeterminate]=\"someVisibleSelected\"\n (change)=\"toggleSelectAll()\"\n aria-label=\"Select all rows\"\n />\n </th>\n }\n @for (column of visibleColumns; track column) {\n <th\n class=\"relative\"\n [class]=\"headerCellClass(column) + ' ' + pinnedClass(column)\"\n [style.width]=\"columnWidth(column)\"\n [style.minWidth]=\"columnMinWidth(column)\"\n [style.left]=\"pinnedLeft(column)\"\n [style.right]=\"pinnedRight(column)\"\n scope=\"col\"\n [attr.aria-sort]=\"ariaSort(column)\"\n >\n @if (column.sortable) {\n <button\n type=\"button\"\n [class]=\"headerButtonClass()\"\n (click)=\"onSort(column)\"\n >\n <span>{{ column.label }}</span>\n @if (sortKey === column.key) {\n @if (sortDirection === 'asc') {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"h-4 w-4 text-(--cxs-color-on-surface-muted)\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M4.5 10.5 12 3m0 0 7.5 7.5M12 3v18\"\n />\n </svg>\n } @else {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"h-4 w-4 text-(--cxs-color-on-surface-muted)\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M19.5 13.5 12 21m0 0-7.5-7.5M12 21V3\"\n />\n </svg>\n }\n }\n </button>\n } @else {\n {{ column.label }}\n }\n @if (column.resizable !== false) {\n <span\n [class]=\"resizeHandleClass\"\n (mousedown)=\"onResizeStart($event, column)\"\n ></span>\n }\n </th>\n }\n </tr>\n @if (showFilters && filtersOpen) {\n <tr [class]=\"headerRowClass\">\n @if (selectable) {\n <th class=\"px-3 py-2 text-left\"></th>\n }\n @for (column of visibleColumns; track column) {\n <th\n [class]=\"headerCellClass(column) + ' ' + pinnedClass(column)\"\n [style.left]=\"pinnedLeft(column)\"\n [style.right]=\"pinnedRight(column)\"\n >\n @if (column.filterable) {\n @if (column.filterType === 'select') {\n <select\n [class]=\"headerFilterInputClass()\"\n [value]=\"columnFilterValue(column.key)\"\n (change)=\"onColumnFilterChange(column.key, $any($event.target).value)\"\n >\n <option value=\"\">All</option>\n @for (option of column.filterOptions ?? []; track option) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n } @else {\n <input\n [class]=\"headerFilterInputClass()\"\n [attr.type]=\"column.filterType === 'number' ? 'number' : 'text'\"\n [value]=\"columnFilterValue(column.key)\"\n (input)=\"onColumnFilterChange(column.key, $any($event.target).value)\"\n />\n }\n }\n </th>\n }\n </tr>\n }\n </thead>\n <tbody>\n @if (loading) {\n <tr [class]=\"bodyRowClass\">\n <td [class]=\"bodyCellClass({ key: '', label: '' })\" [attr.colspan]=\"colSpan\">\n <span [class]=\"emptyRowClass\">Loading...</span>\n </td>\n </tr>\n } @else if (displayRows.length === 0) {\n <tr [class]=\"bodyRowClass\">\n <td [class]=\"bodyCellClass({ key: '', label: '' })\" [attr.colspan]=\"colSpan\">\n <span [class]=\"emptyRowClass\">{{ emptyMessage }}</span>\n </td>\n </tr>\n } @else {\n @for (row of displayRows; track row) {\n <tr [class]=\"bodyRowClass\">\n @if (selectable) {\n <td class=\"px-3 py-2\">\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(row)\"\n (change)=\"toggleRowSelection(row)\"\n aria-label=\"Select row\"\n />\n </td>\n }\n @for (column of visibleColumns; track column) {\n <td\n [class]=\"bodyCellClass(column) + ' ' + pinnedClass(column)\"\n [style.left]=\"pinnedLeft(column)\"\n [style.right]=\"pinnedRight(column)\"\n >\n @if (cellTemplate(column.key); as template) {\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{ $implicit: row, value: row[column.key], column }\"\n ></ng-container>\n } @else {\n {{ cellValue(row, column) }}\n }\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n@if (showPagination) {\n <div [class]=\"paginationClass\">\n <div class=\"flex items-center gap-2\">\n <button\n type=\"button\"\n [class]=\"pageButtonClass\"\n [disabled]=\"currentPage <= 1\"\n (click)=\"previousPage()\"\n >\n Previous\n </button>\n <button\n type=\"button\"\n [class]=\"pageButtonClass\"\n [disabled]=\"currentPage >= totalPages\"\n (click)=\"nextPage()\"\n >\n Next\n </button>\n <span class=\"text-(--cxs-color-on-surface-muted)\">{{ pageLabel }}</span>\n </div>\n @if (showPageSize) {\n <label class=\"flex items-center gap-2 text-(--cxs-color-on-surface-muted)\">\n <span>Rows</span>\n <select\n #pageSizeSelect\n [class]=\"pageSelectClass\"\n [value]=\"currentPageSize\"\n (change)=\"onPageSizeChange(pageSizeSelect.value)\"\n >\n @for (size of pageSizeOptions; track size) {\n <option [value]=\"size\">{{ size }}</option>\n }\n </select>\n </label>\n }\n </div>\n}\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1287
1339
  }
1288
1340
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDataTableComponent, decorators: [{
1289
1341
  type: Component,
1290
- args: [{ selector: 'cxs-data-table', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (showToolbar) {\n <div [class]=\"toolbarClass\">\n <div [class]=\"toolbarGroupClass\">\n @if (showGlobalSearch) {\n <input\n type=\"search\"\n [class]=\"toolbarInputClass\"\n placeholder=\"Search\"\n [value]=\"globalFilter\"\n (input)=\"onGlobalFilterChange($any($event.target).value)\"\n />\n }\n </div>\n <div [class]=\"toolbarGroupClass\">\n @if (showFilters) {\n <button type=\"button\" [class]=\"toolbarButtonClass\" (click)=\"filtersOpen = !filtersOpen\">\n Filters\n </button>\n }\n @if (showColumnVisibility) {\n <details class=\"relative\">\n <summary [class]=\"toolbarButtonClass\">Columns</summary>\n <div\n class=\"absolute right-0 mt-2 w-48 rounded-(--cxs-radius-md) border border-(--cxs-color-border) bg-(--cxs-color-surface) p-2 shadow-(--cxs-shadow-sm)\"\n >\n @for (column of columns; track column) {\n <label class=\"flex items-center gap-2 px-2 py-1 text-sm\">\n <input\n type=\"checkbox\"\n [checked]=\"columnVisibility[column.key]\"\n (change)=\"toggleColumnVisibility(column.key)\"\n />\n <span>{{ column.label }}</span>\n </label>\n }\n </div>\n </details>\n }\n </div>\n </div>\n}\n\n@if (selectable && selectedCount > 0 && bulkActions.length > 0) {\n <div [class]=\"bulkBarClass\">\n <span>{{ selectedCount }} selected</span>\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (action of bulkActions; track action) {\n <button type=\"button\" [class]=\"toolbarButtonClass\" (click)=\"runBulkAction(action.id)\">\n {{ action.label }}\n </button>\n }\n </div>\n </div>\n}\n\n<div [class]=\"wrapperClass\">\n <table [class]=\"tableClass\" [attr.aria-label]=\"ariaLabel\">\n @if (caption) {\n <caption class=\"sr-only\">{{ caption }}</caption>\n }\n <thead>\n <tr [class]=\"headerRowClass\">\n @if (selectable) {\n <th class=\"px-3 py-2\">\n <input\n type=\"checkbox\"\n [checked]=\"allVisibleSelected\"\n [indeterminate]=\"someVisibleSelected\"\n (change)=\"toggleSelectAll()\"\n aria-label=\"Select all rows\"\n />\n </th>\n }\n @for (column of visibleColumns; track column) {\n <th\n class=\"relative\"\n [class]=\"headerCellClass(column) + ' ' + pinnedClass(column)\"\n [style.width]=\"columnWidth(column)\"\n [style.minWidth]=\"columnMinWidth(column)\"\n [style.left]=\"pinnedLeft(column)\"\n [style.right]=\"pinnedRight(column)\"\n scope=\"col\"\n [attr.aria-sort]=\"ariaSort(column)\"\n >\n @if (column.sortable) {\n <button\n type=\"button\"\n [class]=\"headerButtonClass()\"\n (click)=\"onSort(column)\"\n >\n <span>{{ column.label }}</span>\n @if (sortKey === column.key) {\n @if (sortDirection === 'asc') {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"h-4 w-4 text-(--cxs-color-on-surface-muted)\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M4.5 10.5 12 3m0 0 7.5 7.5M12 3v18\"\n />\n </svg>\n } @else {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"h-4 w-4 text-(--cxs-color-on-surface-muted)\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M19.5 13.5 12 21m0 0-7.5-7.5M12 21V3\"\n />\n </svg>\n }\n }\n </button>\n } @else {\n {{ column.label }}\n }\n @if (column.resizable !== false) {\n <span\n [class]=\"resizeHandleClass\"\n (mousedown)=\"onResizeStart($event, column)\"\n ></span>\n }\n </th>\n }\n </tr>\n @if (showFilters && filtersOpen) {\n <tr [class]=\"headerRowClass\">\n @if (selectable) {\n <th class=\"px-3 py-2\"></th>\n }\n @for (column of visibleColumns; track column) {\n <th\n [class]=\"headerCellClass(column) + ' ' + pinnedClass(column)\"\n [style.left]=\"pinnedLeft(column)\"\n [style.right]=\"pinnedRight(column)\"\n >\n @if (column.filterable) {\n @if (column.filterType === 'select') {\n <select\n [class]=\"headerFilterInputClass()\"\n [value]=\"columnFilterValue(column.key)\"\n (change)=\"onColumnFilterChange(column.key, $any($event.target).value)\"\n >\n <option value=\"\">All</option>\n @for (option of column.filterOptions ?? []; track option) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n } @else {\n <input\n [class]=\"headerFilterInputClass()\"\n [attr.type]=\"column.filterType === 'number' ? 'number' : 'text'\"\n placeholder=\"Filter\"\n [value]=\"columnFilterValue(column.key)\"\n (input)=\"onColumnFilterChange(column.key, $any($event.target).value)\"\n />\n }\n }\n </th>\n }\n </tr>\n }\n </thead>\n <tbody>\n @if (loading) {\n <tr [class]=\"bodyRowClass\">\n <td [class]=\"bodyCellClass({ key: '', label: '' })\" [attr.colspan]=\"colSpan\">\n <span [class]=\"emptyRowClass\">Loading...</span>\n </td>\n </tr>\n } @else if (displayRows.length === 0) {\n <tr [class]=\"bodyRowClass\">\n <td [class]=\"bodyCellClass({ key: '', label: '' })\" [attr.colspan]=\"colSpan\">\n <span [class]=\"emptyRowClass\">{{ emptyMessage }}</span>\n </td>\n </tr>\n } @else {\n @for (row of displayRows; track row) {\n <tr [class]=\"bodyRowClass\">\n @if (selectable) {\n <td class=\"px-3 py-2\">\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(row)\"\n (change)=\"toggleRowSelection(row)\"\n aria-label=\"Select row\"\n />\n </td>\n }\n @for (column of visibleColumns; track column) {\n <td\n [class]=\"bodyCellClass(column) + ' ' + pinnedClass(column)\"\n [style.left]=\"pinnedLeft(column)\"\n [style.right]=\"pinnedRight(column)\"\n >\n {{ cellValue(row, column) }}\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n@if (showPagination) {\n <div [class]=\"paginationClass\">\n <div class=\"flex items-center gap-2\">\n <button\n type=\"button\"\n [class]=\"pageButtonClass\"\n [disabled]=\"currentPage <= 1\"\n (click)=\"previousPage()\"\n >\n Previous\n </button>\n <button\n type=\"button\"\n [class]=\"pageButtonClass\"\n [disabled]=\"currentPage >= totalPages\"\n (click)=\"nextPage()\"\n >\n Next\n </button>\n <span class=\"text-(--cxs-color-on-surface-muted)\">{{ pageLabel }}</span>\n </div>\n @if (showPageSize) {\n <label class=\"flex items-center gap-2 text-(--cxs-color-on-surface-muted)\">\n <span>Rows</span>\n <select\n #pageSizeSelect\n [class]=\"pageSelectClass\"\n [value]=\"currentPageSize\"\n (change)=\"onPageSizeChange(pageSizeSelect.value)\"\n >\n @for (size of pageSizeOptions; track size) {\n <option [value]=\"size\">{{ size }}</option>\n }\n </select>\n </label>\n }\n </div>\n}\n" }]
1342
+ args: [{ selector: 'cxs-data-table', standalone: true, imports: [NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (hasTitleBlock) {\n <div [class]=\"titleBarClass\">\n <div class=\"min-w-0\">\n @if (title) {\n <div [class]=\"titleTextClass\">{{ title }}</div>\n }\n @if (subtitle) {\n <div [class]=\"subtitleTextClass\">{{ subtitle }}</div>\n }\n </div>\n @if (showToolbar) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @if (showGlobalSearch) {\n <input\n type=\"search\"\n [class]=\"toolbarInputInlineClass\"\n placeholder=\"Search\"\n [value]=\"globalFilter\"\n (input)=\"onGlobalFilterChange($any($event.target).value)\"\n />\n }\n @if (showFilters) {\n <button type=\"button\" [class]=\"toolbarButtonClass\" (click)=\"filtersOpen = !filtersOpen\">\n Filters\n </button>\n }\n @if (showColumnVisibility) {\n <details class=\"relative\">\n <summary [class]=\"toolbarButtonClass\">Columns</summary>\n <div\n class=\"absolute right-0 mt-2 w-48 rounded-(--cxs-radius-md) border border-(--cxs-color-border) bg-(--cxs-color-surface) p-2 shadow-(--cxs-shadow-sm)\"\n >\n @for (column of columns; track column) {\n <label class=\"flex items-center gap-2 px-2 py-1 text-sm\">\n <input\n type=\"checkbox\"\n [checked]=\"columnVisibility[column.key]\"\n (change)=\"toggleColumnVisibility(column.key)\"\n />\n <span>{{ column.label }}</span>\n </label>\n }\n </div>\n </details>\n }\n </div>\n }\n </div>\n} @else if (showToolbar) {\n <div [class]=\"toolbarClass\">\n <div [class]=\"toolbarGroupClass\">\n @if (showGlobalSearch) {\n <input\n type=\"search\"\n [class]=\"toolbarInputClass\"\n placeholder=\"Search\"\n [value]=\"globalFilter\"\n (input)=\"onGlobalFilterChange($any($event.target).value)\"\n />\n }\n </div>\n <div [class]=\"toolbarGroupClass\">\n @if (showFilters) {\n <button type=\"button\" [class]=\"toolbarButtonClass\" (click)=\"filtersOpen = !filtersOpen\">\n Filters\n </button>\n }\n @if (showColumnVisibility) {\n <details class=\"relative\">\n <summary [class]=\"toolbarButtonClass\">Columns</summary>\n <div\n class=\"absolute right-0 mt-2 w-48 rounded-(--cxs-radius-md) border border-(--cxs-color-border) bg-(--cxs-color-surface) p-2 shadow-(--cxs-shadow-sm)\"\n >\n @for (column of columns; track column) {\n <label class=\"flex items-center gap-2 px-2 py-1 text-sm\">\n <input\n type=\"checkbox\"\n [checked]=\"columnVisibility[column.key]\"\n (change)=\"toggleColumnVisibility(column.key)\"\n />\n <span>{{ column.label }}</span>\n </label>\n }\n </div>\n </details>\n }\n </div>\n </div>\n}\n\n@if (selectable && selectedCount > 0 && bulkActions.length > 0) {\n <div [class]=\"bulkBarClass\">\n <span>{{ selectedCount }} selected</span>\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (action of bulkActions; track action) {\n <button type=\"button\" [class]=\"toolbarButtonClass\" (click)=\"runBulkAction(action.id)\">\n {{ action.label }}\n </button>\n }\n </div>\n </div>\n}\n\n<div [class]=\"wrapperClass\">\n <table [class]=\"tableClass\" [attr.aria-label]=\"ariaLabel\">\n @if (caption) {\n <caption class=\"sr-only\">{{ caption }}</caption>\n }\n <thead>\n <tr [class]=\"headerRowClass\">\n @if (selectable) {\n <th class=\"px-3 py-2 text-left\">\n <input\n type=\"checkbox\"\n [checked]=\"allVisibleSelected\"\n [indeterminate]=\"someVisibleSelected\"\n (change)=\"toggleSelectAll()\"\n aria-label=\"Select all rows\"\n />\n </th>\n }\n @for (column of visibleColumns; track column) {\n <th\n class=\"relative\"\n [class]=\"headerCellClass(column) + ' ' + pinnedClass(column)\"\n [style.width]=\"columnWidth(column)\"\n [style.minWidth]=\"columnMinWidth(column)\"\n [style.left]=\"pinnedLeft(column)\"\n [style.right]=\"pinnedRight(column)\"\n scope=\"col\"\n [attr.aria-sort]=\"ariaSort(column)\"\n >\n @if (column.sortable) {\n <button\n type=\"button\"\n [class]=\"headerButtonClass()\"\n (click)=\"onSort(column)\"\n >\n <span>{{ column.label }}</span>\n @if (sortKey === column.key) {\n @if (sortDirection === 'asc') {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"h-4 w-4 text-(--cxs-color-on-surface-muted)\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M4.5 10.5 12 3m0 0 7.5 7.5M12 3v18\"\n />\n </svg>\n } @else {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke-width=\"1.5\"\n stroke=\"currentColor\"\n class=\"h-4 w-4 text-(--cxs-color-on-surface-muted)\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M19.5 13.5 12 21m0 0-7.5-7.5M12 21V3\"\n />\n </svg>\n }\n }\n </button>\n } @else {\n {{ column.label }}\n }\n @if (column.resizable !== false) {\n <span\n [class]=\"resizeHandleClass\"\n (mousedown)=\"onResizeStart($event, column)\"\n ></span>\n }\n </th>\n }\n </tr>\n @if (showFilters && filtersOpen) {\n <tr [class]=\"headerRowClass\">\n @if (selectable) {\n <th class=\"px-3 py-2 text-left\"></th>\n }\n @for (column of visibleColumns; track column) {\n <th\n [class]=\"headerCellClass(column) + ' ' + pinnedClass(column)\"\n [style.left]=\"pinnedLeft(column)\"\n [style.right]=\"pinnedRight(column)\"\n >\n @if (column.filterable) {\n @if (column.filterType === 'select') {\n <select\n [class]=\"headerFilterInputClass()\"\n [value]=\"columnFilterValue(column.key)\"\n (change)=\"onColumnFilterChange(column.key, $any($event.target).value)\"\n >\n <option value=\"\">All</option>\n @for (option of column.filterOptions ?? []; track option) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n } @else {\n <input\n [class]=\"headerFilterInputClass()\"\n [attr.type]=\"column.filterType === 'number' ? 'number' : 'text'\"\n [value]=\"columnFilterValue(column.key)\"\n (input)=\"onColumnFilterChange(column.key, $any($event.target).value)\"\n />\n }\n }\n </th>\n }\n </tr>\n }\n </thead>\n <tbody>\n @if (loading) {\n <tr [class]=\"bodyRowClass\">\n <td [class]=\"bodyCellClass({ key: '', label: '' })\" [attr.colspan]=\"colSpan\">\n <span [class]=\"emptyRowClass\">Loading...</span>\n </td>\n </tr>\n } @else if (displayRows.length === 0) {\n <tr [class]=\"bodyRowClass\">\n <td [class]=\"bodyCellClass({ key: '', label: '' })\" [attr.colspan]=\"colSpan\">\n <span [class]=\"emptyRowClass\">{{ emptyMessage }}</span>\n </td>\n </tr>\n } @else {\n @for (row of displayRows; track row) {\n <tr [class]=\"bodyRowClass\">\n @if (selectable) {\n <td class=\"px-3 py-2\">\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(row)\"\n (change)=\"toggleRowSelection(row)\"\n aria-label=\"Select row\"\n />\n </td>\n }\n @for (column of visibleColumns; track column) {\n <td\n [class]=\"bodyCellClass(column) + ' ' + pinnedClass(column)\"\n [style.left]=\"pinnedLeft(column)\"\n [style.right]=\"pinnedRight(column)\"\n >\n @if (cellTemplate(column.key); as template) {\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{ $implicit: row, value: row[column.key], column }\"\n ></ng-container>\n } @else {\n {{ cellValue(row, column) }}\n }\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n@if (showPagination) {\n <div [class]=\"paginationClass\">\n <div class=\"flex items-center gap-2\">\n <button\n type=\"button\"\n [class]=\"pageButtonClass\"\n [disabled]=\"currentPage <= 1\"\n (click)=\"previousPage()\"\n >\n Previous\n </button>\n <button\n type=\"button\"\n [class]=\"pageButtonClass\"\n [disabled]=\"currentPage >= totalPages\"\n (click)=\"nextPage()\"\n >\n Next\n </button>\n <span class=\"text-(--cxs-color-on-surface-muted)\">{{ pageLabel }}</span>\n </div>\n @if (showPageSize) {\n <label class=\"flex items-center gap-2 text-(--cxs-color-on-surface-muted)\">\n <span>Rows</span>\n <select\n #pageSizeSelect\n [class]=\"pageSelectClass\"\n [value]=\"currentPageSize\"\n (change)=\"onPageSizeChange(pageSizeSelect.value)\"\n >\n @for (size of pageSizeOptions; track size) {\n <option [value]=\"size\">{{ size }}</option>\n }\n </select>\n </label>\n }\n </div>\n}\n" }]
1291
1343
  }], ctorParameters: () => [{ type: undefined, decorators: [{
1292
1344
  type: Attribute,
1293
1345
  args: ['class']
@@ -1297,6 +1349,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
1297
1349
  type: Input
1298
1350
  }], caption: [{
1299
1351
  type: Input
1352
+ }], title: [{
1353
+ type: Input
1354
+ }], subtitle: [{
1355
+ type: Input
1300
1356
  }], ariaLabel: [{
1301
1357
  type: Input
1302
1358
  }], striped: [{
@@ -1361,6 +1417,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
1361
1417
  type: Output
1362
1418
  }], bulkAction: [{
1363
1419
  type: Output
1420
+ }], cellTemplates: [{
1421
+ type: ContentChildren,
1422
+ args: [CxsDataTableCellDirective]
1364
1423
  }] } });
1365
1424
 
1366
1425
  const OVERLAY_CLASSES = 'fixed inset-0 z-50 flex items-center justify-center bg-[rgba(15,23,42,0.45)] p-4';
@@ -1466,11 +1525,11 @@ class CxsDialogComponent {
1466
1525
  });
1467
1526
  }
1468
1527
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDialogComponent, deps: [{ token: 'class', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
1469
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsDialogComponent, isStandalone: true, selector: "cxs-dialog", inputs: { open: "open", title: "title", description: "description", ariaLabel: "ariaLabel", size: "size", dismissible: "dismissible", closeOnBackdrop: "closeOnBackdrop", closeOnEscape: "closeOnEscape" }, outputs: { openChange: "openChange", closed: "closed" }, viewQueries: [{ propertyName: "dialogPanel", first: true, predicate: ["dialogPanel"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (open) {\n <div [class]=\"overlayClass\" (click)=\"onBackdropClick($event)\">\n <div\n #dialogPanel\n [class]=\"panelClass\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-labelledby]=\"title ? titleId : null\"\n [attr.aria-describedby]=\"description ? descriptionId : null\"\n [attr.aria-label]=\"ariaLabelValue\"\n tabindex=\"-1\"\n (keydown)=\"onKeydown($event)\"\n >\n <div class=\"flex items-start gap-3\">\n <div class=\"flex-1\">\n @if (title) {\n <h2 [id]=\"titleId\" [class]=\"titleClass\">{{ title }}</h2>\n }\n @if (description) {\n <p [id]=\"descriptionId\" [class]=\"descriptionClass\">{{ description }}</p>\n }\n </div>\n @if (dismissible) {\n <button\n type=\"button\"\n [class]=\"closeButtonClass\"\n aria-label=\"Close dialog\"\n (click)=\"requestClose('dismiss')\"\n >\n X\n </button>\n }\n </div>\n\n <div [class]=\"bodyClass\">\n <ng-content></ng-content>\n </div>\n\n <div [class]=\"actionsClass\">\n <ng-content select=\"[cxsDialogActions]\"></ng-content>\n </div>\n </div>\n </div>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
1528
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsDialogComponent, isStandalone: true, selector: "cxs-dialog", inputs: { open: "open", title: "title", description: "description", ariaLabel: "ariaLabel", size: "size", dismissible: "dismissible", closeOnBackdrop: "closeOnBackdrop", closeOnEscape: "closeOnEscape" }, outputs: { openChange: "openChange", closed: "closed" }, viewQueries: [{ propertyName: "dialogPanel", first: true, predicate: ["dialogPanel"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (open) {\n <div [class]=\"overlayClass\" (click)=\"onBackdropClick($event)\">\n <div\n #dialogPanel\n [class]=\"panelClass\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-labelledby]=\"title ? titleId : null\"\n [attr.aria-describedby]=\"description ? descriptionId : null\"\n [attr.aria-label]=\"ariaLabelValue\"\n tabindex=\"-1\"\n (keydown)=\"onKeydown($event)\"\n >\n <div class=\"flex items-start gap-3\">\n <div class=\"flex-1\">\n @if (title) {\n <h2 [id]=\"titleId\" [class]=\"titleClass\">{{ title }}</h2>\n }\n @if (description) {\n <p [id]=\"descriptionId\" [class]=\"descriptionClass\">{{ description }}</p>\n }\n </div>\n @if (dismissible) {\n <button\n type=\"button\"\n [class]=\"closeButtonClass\"\n aria-label=\"Close dialog\"\n (click)=\"requestClose('dismiss')\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-6\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18 18 6M6 6l12 12\" />\n </svg>\n </button>\n }\n </div>\n\n <div [class]=\"bodyClass\">\n <ng-content></ng-content>\n </div>\n\n <div [class]=\"actionsClass\">\n <ng-content select=\"[cxsDialogActions]\"></ng-content>\n </div>\n </div>\n </div>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
1470
1529
  }
1471
1530
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDialogComponent, decorators: [{
1472
1531
  type: Component,
1473
- args: [{ selector: 'cxs-dialog', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (open) {\n <div [class]=\"overlayClass\" (click)=\"onBackdropClick($event)\">\n <div\n #dialogPanel\n [class]=\"panelClass\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-labelledby]=\"title ? titleId : null\"\n [attr.aria-describedby]=\"description ? descriptionId : null\"\n [attr.aria-label]=\"ariaLabelValue\"\n tabindex=\"-1\"\n (keydown)=\"onKeydown($event)\"\n >\n <div class=\"flex items-start gap-3\">\n <div class=\"flex-1\">\n @if (title) {\n <h2 [id]=\"titleId\" [class]=\"titleClass\">{{ title }}</h2>\n }\n @if (description) {\n <p [id]=\"descriptionId\" [class]=\"descriptionClass\">{{ description }}</p>\n }\n </div>\n @if (dismissible) {\n <button\n type=\"button\"\n [class]=\"closeButtonClass\"\n aria-label=\"Close dialog\"\n (click)=\"requestClose('dismiss')\"\n >\n X\n </button>\n }\n </div>\n\n <div [class]=\"bodyClass\">\n <ng-content></ng-content>\n </div>\n\n <div [class]=\"actionsClass\">\n <ng-content select=\"[cxsDialogActions]\"></ng-content>\n </div>\n </div>\n </div>\n}\n" }]
1532
+ args: [{ selector: 'cxs-dialog', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (open) {\n <div [class]=\"overlayClass\" (click)=\"onBackdropClick($event)\">\n <div\n #dialogPanel\n [class]=\"panelClass\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-labelledby]=\"title ? titleId : null\"\n [attr.aria-describedby]=\"description ? descriptionId : null\"\n [attr.aria-label]=\"ariaLabelValue\"\n tabindex=\"-1\"\n (keydown)=\"onKeydown($event)\"\n >\n <div class=\"flex items-start gap-3\">\n <div class=\"flex-1\">\n @if (title) {\n <h2 [id]=\"titleId\" [class]=\"titleClass\">{{ title }}</h2>\n }\n @if (description) {\n <p [id]=\"descriptionId\" [class]=\"descriptionClass\">{{ description }}</p>\n }\n </div>\n @if (dismissible) {\n <button\n type=\"button\"\n [class]=\"closeButtonClass\"\n aria-label=\"Close dialog\"\n (click)=\"requestClose('dismiss')\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-6\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18 18 6M6 6l12 12\" />\n </svg>\n </button>\n }\n </div>\n\n <div [class]=\"bodyClass\">\n <ng-content></ng-content>\n </div>\n\n <div [class]=\"actionsClass\">\n <ng-content select=\"[cxsDialogActions]\"></ng-content>\n </div>\n </div>\n </div>\n}\n" }]
1474
1533
  }], ctorParameters: () => [{ type: undefined, decorators: [{
1475
1534
  type: Attribute,
1476
1535
  args: ['class']
@@ -1505,7 +1564,10 @@ const BASE_CLASSES$3 = 'w-full rounded-[var(--cxs-radius-md)] border border-[var
1505
1564
  'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
1506
1565
  'focus-visible:outline-[var(--cxs-color-focus)] focus-visible:border-[var(--cxs-color-focus)] ' +
1507
1566
  'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-60';
1508
- const VARIANT_CLASSES$3 = {
1567
+ const WRAPPER_CLASSES$6 = 'flex w-full flex-col gap-1';
1568
+ const LABEL_BASE_CLASSES$4 = 'font-medium text-(--cxs-color-on-surface)';
1569
+ const LABEL_DISABLED_CLASSES$4 = 'text-[var(--cxs-color-on-surface-muted)]';
1570
+ const VARIANT_CLASSES$4 = {
1509
1571
  outline: 'bg-[var(--cxs-color-surface)]',
1510
1572
  filled: 'bg-[var(--cxs-color-surface-hover)]'
1511
1573
  };
@@ -1514,7 +1576,12 @@ const SIZE_CLASSES$2 = {
1514
1576
  md: 'h-10 px-3 text-sm',
1515
1577
  lg: 'h-12 px-4 text-base'
1516
1578
  };
1517
- const INVALID_CLASSES$3 = 'border-[var(--cxs-color-danger)] focus-visible:border-[var(--cxs-color-danger)] ' +
1579
+ const LABEL_SIZE_CLASSES$4 = {
1580
+ sm: 'text-sm',
1581
+ md: 'text-sm',
1582
+ lg: 'text-base'
1583
+ };
1584
+ const INVALID_CLASSES$4 = 'border-[var(--cxs-color-danger)] focus-visible:border-[var(--cxs-color-danger)] ' +
1518
1585
  'focus-visible:outline-[var(--cxs-color-danger)]';
1519
1586
  const POPOVER_CLASSES = 'absolute left-0 top-full z-10 mt-2 w-full rounded-[var(--cxs-radius-md)] border ' +
1520
1587
  'border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] p-3 shadow-[var(--cxs-shadow-sm)]';
@@ -1534,6 +1601,7 @@ const DAY_TODAY = 'border border-[var(--cxs-color-primary)]';
1534
1601
  const DAY_SELECTED = 'bg-[var(--cxs-color-primary)] text-[var(--cxs-color-on-primary)]';
1535
1602
  const DAY_HOVER = 'hover:bg-[var(--cxs-color-surface-hover)]';
1536
1603
  class CxsDatepickerComponent {
1604
+ static nextId = 0;
1537
1605
  value = '';
1538
1606
  variant = 'outline';
1539
1607
  size = 'md';
@@ -1543,6 +1611,7 @@ class CxsDatepickerComponent {
1543
1611
  required = false;
1544
1612
  invalid = false;
1545
1613
  autofocus = false;
1614
+ label;
1546
1615
  id;
1547
1616
  name;
1548
1617
  min;
@@ -1551,8 +1620,7 @@ class CxsDatepickerComponent {
1551
1620
  ariaLabel;
1552
1621
  ariaDescribedby;
1553
1622
  valueChange = new EventEmitter();
1554
- static nextId = 0;
1555
- fallbackId = `cxs-datepicker-panel-${CxsDatepickerComponent.nextId++}`;
1623
+ instanceId = `cxs-datepicker-${CxsDatepickerComponent.nextId++}`;
1556
1624
  disabledFromControl = false;
1557
1625
  onChange = () => { };
1558
1626
  onTouched = () => { };
@@ -1568,18 +1636,48 @@ class CxsDatepickerComponent {
1568
1636
  return this.disabled || this.disabledFromControl;
1569
1637
  }
1570
1638
  get panelId() {
1571
- return this.id ? `${this.id}-panel` : this.fallbackId;
1639
+ return `${this.inputId ?? this.instanceId}-panel`;
1572
1640
  }
1573
1641
  get inputClass() {
1574
1642
  return [
1575
1643
  BASE_CLASSES$3,
1576
1644
  SIZE_CLASSES$2[this.size],
1577
- VARIANT_CLASSES$3[this.variant],
1578
- this.invalid ? INVALID_CLASSES$3 : ''
1645
+ VARIANT_CLASSES$4[this.variant],
1646
+ this.invalid ? INVALID_CLASSES$4 : ''
1579
1647
  ]
1580
1648
  .filter(Boolean)
1581
1649
  .join(' ');
1582
1650
  }
1651
+ get wrapperClass() {
1652
+ return WRAPPER_CLASSES$6;
1653
+ }
1654
+ get labelClass() {
1655
+ return [
1656
+ LABEL_BASE_CLASSES$4,
1657
+ LABEL_SIZE_CLASSES$4[this.size],
1658
+ this.isDisabled ? LABEL_DISABLED_CLASSES$4 : ''
1659
+ ]
1660
+ .filter(Boolean)
1661
+ .join(' ');
1662
+ }
1663
+ get inputId() {
1664
+ if (this.id) {
1665
+ return this.id;
1666
+ }
1667
+ return this.label ? this.instanceId : null;
1668
+ }
1669
+ get labelId() {
1670
+ if (!this.label) {
1671
+ return null;
1672
+ }
1673
+ return `${this.inputId}-label`;
1674
+ }
1675
+ get ariaLabelValue() {
1676
+ if (this.label) {
1677
+ return null;
1678
+ }
1679
+ return this.ariaLabel ?? null;
1680
+ }
1583
1681
  get popoverClass() {
1584
1682
  return POPOVER_CLASSES;
1585
1683
  }
@@ -1755,13 +1853,13 @@ class CxsDatepickerComponent {
1755
1853
  return new Date(date.getFullYear(), date.getMonth(), date.getDate());
1756
1854
  }
1757
1855
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDatepickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1758
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsDatepickerComponent, isStandalone: true, selector: "cxs-datepicker", inputs: { value: "value", variant: "variant", size: "size", useNative: "useNative", disabled: "disabled", readonly: "readonly", required: "required", invalid: "invalid", autofocus: "autofocus", id: "id", name: "name", min: "min", max: "max", placeholder: "placeholder", ariaLabel: "ariaLabel", ariaDescribedby: "ariaDescribedby" }, outputs: { valueChange: "valueChange" }, host: { listeners: { "document:click": "onDocumentClick($event)", "document:keydown.escape": "onEscape()" } }, providers: [
1856
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsDatepickerComponent, isStandalone: true, selector: "cxs-datepicker", inputs: { value: "value", variant: "variant", size: "size", useNative: "useNative", disabled: "disabled", readonly: "readonly", required: "required", invalid: "invalid", autofocus: "autofocus", label: "label", id: "id", name: "name", min: "min", max: "max", placeholder: "placeholder", ariaLabel: "ariaLabel", ariaDescribedby: "ariaDescribedby" }, outputs: { valueChange: "valueChange" }, host: { listeners: { "document:click": "onDocumentClick($event)", "document:keydown.escape": "onEscape()" } }, providers: [
1759
1857
  {
1760
1858
  provide: NG_VALUE_ACCESSOR,
1761
1859
  useExisting: forwardRef(() => CxsDatepickerComponent),
1762
1860
  multi: true
1763
1861
  }
1764
- ], ngImport: i0, template: "@if (useNative) {\r\n <input\r\n type=\"date\"\r\n [class]=\"inputClass\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.min]=\"min\"\r\n [attr.max]=\"max\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.autofocus]=\"autofocus ? true : null\"\r\n [value]=\"value\"\r\n [disabled]=\"isDisabled\"\r\n [readonly]=\"readonly\"\r\n [required]=\"required\"\r\n (input)=\"onInput($event)\"\r\n (blur)=\"onBlur()\"\r\n />\r\n} @else {\r\n <div class=\"relative w-full\">\r\n <input\r\n type=\"text\"\r\n [class]=\"inputClass\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.aria-expanded]=\"isOpen ? 'true' : 'false'\"\r\n [attr.aria-controls]=\"panelId\"\r\n [attr.autofocus]=\"autofocus ? true : null\"\r\n [attr.data-cxs-datepicker]=\"panelId\"\r\n [value]=\"value\"\r\n [disabled]=\"isDisabled\"\r\n [readonly]=\"true\"\r\n [required]=\"required\"\r\n (click)=\"open()\"\r\n (focus)=\"open()\"\r\n (blur)=\"onBlur()\"\r\n />\r\n @if (isOpen) {\r\n <div [class]=\"popoverClass\" [attr.id]=\"panelId\" role=\"dialog\" aria-label=\"Choose date\">\r\n <div class=\"flex items-center justify-between\">\r\n <button type=\"button\" [class]=\"navButtonClass\" aria-label=\"Previous month\" (click)=\"prevMonth()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15.75 19.5 8.25 12l7.5-7.5\" />\r\n </svg>\r\n </button>\r\n <div class=\"flex items-center gap-2\">\r\n <select\r\n [class]=\"selectClass\"\r\n [disabled]=\"isDisabled\"\r\n [value]=\"displayMonth.getMonth()\"\r\n aria-label=\"Month\"\r\n (change)=\"onMonthChange($event)\"\r\n >\r\n @for (month of monthOptions; track month.value) {\r\n <option [value]=\"month.value\">{{ month.label }}</option>\r\n }\r\n </select>\r\n <select\r\n [class]=\"selectClass\"\r\n [disabled]=\"isDisabled\"\r\n [value]=\"displayMonth.getFullYear()\"\r\n aria-label=\"Year\"\r\n (change)=\"onYearChange($event)\"\r\n >\r\n @for (year of yearOptions; track year) {\r\n <option [value]=\"year\">{{ year }}</option>\r\n }\r\n </select>\r\n </div>\r\n <button type=\"button\" [class]=\"navButtonClass\" aria-label=\"Next month\" (click)=\"nextMonth()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m8.25 4.5 7.5 7.5-7.5 7.5\" />\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"mt-3 grid grid-cols-7 gap-1 text-center text-xs text-(--cxs-color-on-surface-muted)\">\r\n @for (label of weekDayLabels; track label) {\r\n <div>{{ label }}</div>\r\n }\r\n </div>\r\n\r\n <div class=\"mt-2 grid grid-cols-7 gap-1\" role=\"grid\">\r\n @for (day of calendarDays; track day.key) {\r\n <button\r\n type=\"button\"\r\n [class]=\"dayButtonClass(day)\"\r\n [disabled]=\"day.disabled\"\r\n [attr.data-date]=\"day.key\"\r\n [attr.aria-selected]=\"day.key === value ? 'true' : 'false'\"\r\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\r\n (click)=\"onDateSelect(day)\"\r\n >\r\n {{ day.label }}\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
1862
+ ], ngImport: i0, template: "<div [class]=\"wrapperClass\">\n @if (label) {\n <label [class]=\"labelClass\" [attr.id]=\"labelId\" [attr.for]=\"inputId\">\n {{ label }}\n </label>\n }\n @if (useNative) {\n <input\n type=\"date\"\n [class]=\"inputClass\"\n [attr.id]=\"inputId\"\n [attr.name]=\"name\"\n [attr.min]=\"min\"\n [attr.max]=\"max\"\n [attr.placeholder]=\"placeholder\"\n [attr.aria-label]=\"ariaLabelValue\"\n [attr.aria-labelledby]=\"labelId\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [value]=\"value\"\n [disabled]=\"isDisabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n />\n } @else {\n <div class=\"relative w-full\">\n <input\n type=\"text\"\n [class]=\"inputClass\"\n [attr.id]=\"inputId\"\n [attr.name]=\"name\"\n [attr.placeholder]=\"placeholder\"\n [attr.aria-label]=\"ariaLabelValue\"\n [attr.aria-labelledby]=\"labelId\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-expanded]=\"isOpen ? 'true' : 'false'\"\n [attr.aria-controls]=\"panelId\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [attr.data-cxs-datepicker]=\"panelId\"\n [value]=\"value\"\n [disabled]=\"isDisabled\"\n [readonly]=\"true\"\n [required]=\"required\"\n (click)=\"open()\"\n (focus)=\"open()\"\n (blur)=\"onBlur()\"\n />\n @if (isOpen) {\n <div [class]=\"popoverClass\" [attr.id]=\"panelId\" role=\"dialog\" aria-label=\"Choose date\">\n <div class=\"flex items-center justify-between\">\n <button type=\"button\" [class]=\"navButtonClass\" aria-label=\"Previous month\" (click)=\"prevMonth()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15.75 19.5 8.25 12l7.5-7.5\" />\n </svg>\n </button>\n <div class=\"flex items-center gap-2\">\n <select\n [class]=\"selectClass\"\n [disabled]=\"isDisabled\"\n [value]=\"displayMonth.getMonth()\"\n aria-label=\"Month\"\n (change)=\"onMonthChange($event)\"\n >\n @for (month of monthOptions; track month.value) {\n <option [value]=\"month.value\">{{ month.label }}</option>\n }\n </select>\n <select\n [class]=\"selectClass\"\n [disabled]=\"isDisabled\"\n [value]=\"displayMonth.getFullYear()\"\n aria-label=\"Year\"\n (change)=\"onYearChange($event)\"\n >\n @for (year of yearOptions; track year) {\n <option [value]=\"year\">{{ year }}</option>\n }\n </select>\n </div>\n <button type=\"button\" [class]=\"navButtonClass\" aria-label=\"Next month\" (click)=\"nextMonth()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m8.25 4.5 7.5 7.5-7.5 7.5\" />\n </svg>\n </button>\n </div>\n\n <div class=\"mt-3 grid grid-cols-7 gap-1 text-center text-xs text-(--cxs-color-on-surface-muted)\">\n @for (label of weekDayLabels; track label) {\n <div>{{ label }}</div>\n }\n </div>\n\n <div class=\"mt-2 grid grid-cols-7 gap-1\" role=\"grid\">\n @for (day of calendarDays; track day.key) {\n <button\n type=\"button\"\n [class]=\"dayButtonClass(day)\"\n [disabled]=\"day.disabled\"\n [attr.data-date]=\"day.key\"\n [attr.aria-selected]=\"day.key === value ? 'true' : 'false'\"\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\n (click)=\"onDateSelect(day)\"\n >\n {{ day.label }}\n </button>\n }\n </div>\n </div>\n }\n </div>\n }\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
1765
1863
  }
1766
1864
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDatepickerComponent, decorators: [{
1767
1865
  type: Component,
@@ -1771,7 +1869,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
1771
1869
  useExisting: forwardRef(() => CxsDatepickerComponent),
1772
1870
  multi: true
1773
1871
  }
1774
- ], template: "@if (useNative) {\r\n <input\r\n type=\"date\"\r\n [class]=\"inputClass\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.min]=\"min\"\r\n [attr.max]=\"max\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.autofocus]=\"autofocus ? true : null\"\r\n [value]=\"value\"\r\n [disabled]=\"isDisabled\"\r\n [readonly]=\"readonly\"\r\n [required]=\"required\"\r\n (input)=\"onInput($event)\"\r\n (blur)=\"onBlur()\"\r\n />\r\n} @else {\r\n <div class=\"relative w-full\">\r\n <input\r\n type=\"text\"\r\n [class]=\"inputClass\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.aria-expanded]=\"isOpen ? 'true' : 'false'\"\r\n [attr.aria-controls]=\"panelId\"\r\n [attr.autofocus]=\"autofocus ? true : null\"\r\n [attr.data-cxs-datepicker]=\"panelId\"\r\n [value]=\"value\"\r\n [disabled]=\"isDisabled\"\r\n [readonly]=\"true\"\r\n [required]=\"required\"\r\n (click)=\"open()\"\r\n (focus)=\"open()\"\r\n (blur)=\"onBlur()\"\r\n />\r\n @if (isOpen) {\r\n <div [class]=\"popoverClass\" [attr.id]=\"panelId\" role=\"dialog\" aria-label=\"Choose date\">\r\n <div class=\"flex items-center justify-between\">\r\n <button type=\"button\" [class]=\"navButtonClass\" aria-label=\"Previous month\" (click)=\"prevMonth()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15.75 19.5 8.25 12l7.5-7.5\" />\r\n </svg>\r\n </button>\r\n <div class=\"flex items-center gap-2\">\r\n <select\r\n [class]=\"selectClass\"\r\n [disabled]=\"isDisabled\"\r\n [value]=\"displayMonth.getMonth()\"\r\n aria-label=\"Month\"\r\n (change)=\"onMonthChange($event)\"\r\n >\r\n @for (month of monthOptions; track month.value) {\r\n <option [value]=\"month.value\">{{ month.label }}</option>\r\n }\r\n </select>\r\n <select\r\n [class]=\"selectClass\"\r\n [disabled]=\"isDisabled\"\r\n [value]=\"displayMonth.getFullYear()\"\r\n aria-label=\"Year\"\r\n (change)=\"onYearChange($event)\"\r\n >\r\n @for (year of yearOptions; track year) {\r\n <option [value]=\"year\">{{ year }}</option>\r\n }\r\n </select>\r\n </div>\r\n <button type=\"button\" [class]=\"navButtonClass\" aria-label=\"Next month\" (click)=\"nextMonth()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\r\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m8.25 4.5 7.5 7.5-7.5 7.5\" />\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"mt-3 grid grid-cols-7 gap-1 text-center text-xs text-(--cxs-color-on-surface-muted)\">\r\n @for (label of weekDayLabels; track label) {\r\n <div>{{ label }}</div>\r\n }\r\n </div>\r\n\r\n <div class=\"mt-2 grid grid-cols-7 gap-1\" role=\"grid\">\r\n @for (day of calendarDays; track day.key) {\r\n <button\r\n type=\"button\"\r\n [class]=\"dayButtonClass(day)\"\r\n [disabled]=\"day.disabled\"\r\n [attr.data-date]=\"day.key\"\r\n [attr.aria-selected]=\"day.key === value ? 'true' : 'false'\"\r\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\r\n (click)=\"onDateSelect(day)\"\r\n >\r\n {{ day.label }}\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n}\r\n" }]
1872
+ ], template: "<div [class]=\"wrapperClass\">\n @if (label) {\n <label [class]=\"labelClass\" [attr.id]=\"labelId\" [attr.for]=\"inputId\">\n {{ label }}\n </label>\n }\n @if (useNative) {\n <input\n type=\"date\"\n [class]=\"inputClass\"\n [attr.id]=\"inputId\"\n [attr.name]=\"name\"\n [attr.min]=\"min\"\n [attr.max]=\"max\"\n [attr.placeholder]=\"placeholder\"\n [attr.aria-label]=\"ariaLabelValue\"\n [attr.aria-labelledby]=\"labelId\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [value]=\"value\"\n [disabled]=\"isDisabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n />\n } @else {\n <div class=\"relative w-full\">\n <input\n type=\"text\"\n [class]=\"inputClass\"\n [attr.id]=\"inputId\"\n [attr.name]=\"name\"\n [attr.placeholder]=\"placeholder\"\n [attr.aria-label]=\"ariaLabelValue\"\n [attr.aria-labelledby]=\"labelId\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-expanded]=\"isOpen ? 'true' : 'false'\"\n [attr.aria-controls]=\"panelId\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [attr.data-cxs-datepicker]=\"panelId\"\n [value]=\"value\"\n [disabled]=\"isDisabled\"\n [readonly]=\"true\"\n [required]=\"required\"\n (click)=\"open()\"\n (focus)=\"open()\"\n (blur)=\"onBlur()\"\n />\n @if (isOpen) {\n <div [class]=\"popoverClass\" [attr.id]=\"panelId\" role=\"dialog\" aria-label=\"Choose date\">\n <div class=\"flex items-center justify-between\">\n <button type=\"button\" [class]=\"navButtonClass\" aria-label=\"Previous month\" (click)=\"prevMonth()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15.75 19.5 8.25 12l7.5-7.5\" />\n </svg>\n </button>\n <div class=\"flex items-center gap-2\">\n <select\n [class]=\"selectClass\"\n [disabled]=\"isDisabled\"\n [value]=\"displayMonth.getMonth()\"\n aria-label=\"Month\"\n (change)=\"onMonthChange($event)\"\n >\n @for (month of monthOptions; track month.value) {\n <option [value]=\"month.value\">{{ month.label }}</option>\n }\n </select>\n <select\n [class]=\"selectClass\"\n [disabled]=\"isDisabled\"\n [value]=\"displayMonth.getFullYear()\"\n aria-label=\"Year\"\n (change)=\"onYearChange($event)\"\n >\n @for (year of yearOptions; track year) {\n <option [value]=\"year\">{{ year }}</option>\n }\n </select>\n </div>\n <button type=\"button\" [class]=\"navButtonClass\" aria-label=\"Next month\" (click)=\"nextMonth()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-3\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"m8.25 4.5 7.5 7.5-7.5 7.5\" />\n </svg>\n </button>\n </div>\n\n <div class=\"mt-3 grid grid-cols-7 gap-1 text-center text-xs text-(--cxs-color-on-surface-muted)\">\n @for (label of weekDayLabels; track label) {\n <div>{{ label }}</div>\n }\n </div>\n\n <div class=\"mt-2 grid grid-cols-7 gap-1\" role=\"grid\">\n @for (day of calendarDays; track day.key) {\n <button\n type=\"button\"\n [class]=\"dayButtonClass(day)\"\n [disabled]=\"day.disabled\"\n [attr.data-date]=\"day.key\"\n [attr.aria-selected]=\"day.key === value ? 'true' : 'false'\"\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\n (click)=\"onDateSelect(day)\"\n >\n {{ day.label }}\n </button>\n }\n </div>\n </div>\n }\n </div>\n }\n</div>\n" }]
1775
1873
  }], propDecorators: { value: [{
1776
1874
  type: Input
1777
1875
  }], variant: [{
@@ -1790,6 +1888,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
1790
1888
  type: Input
1791
1889
  }], autofocus: [{
1792
1890
  type: Input
1891
+ }], label: [{
1892
+ type: Input
1793
1893
  }], id: [{
1794
1894
  type: Input
1795
1895
  }], name: [{
@@ -1820,7 +1920,11 @@ const BASE_CLASSES$2 = 'w-full rounded-[var(--cxs-radius-md)] border border-[var
1820
1920
  'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
1821
1921
  'focus-visible:outline-[var(--cxs-color-focus)] focus-visible:border-[var(--cxs-color-focus)] ' +
1822
1922
  'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-60';
1823
- const VARIANT_CLASSES$2 = {
1923
+ const WRAPPER_CLASSES$5 = 'flex w-full flex-col gap-1';
1924
+ const LABEL_BASE_CLASSES$3 = 'font-medium text-(--cxs-color-on-surface)';
1925
+ const LABEL_DISABLED_CLASSES$3 = 'text-[var(--cxs-color-on-surface-muted)]';
1926
+ const ERROR_BASE_CLASSES = 'text-[var(--cxs-color-danger)]';
1927
+ const VARIANT_CLASSES$3 = {
1824
1928
  outline: 'bg-[var(--cxs-color-surface)]',
1825
1929
  filled: 'bg-[var(--cxs-color-surface-hover)]'
1826
1930
  };
@@ -1829,9 +1933,20 @@ const SIZE_CLASSES$1 = {
1829
1933
  md: 'h-10 px-3 text-sm',
1830
1934
  lg: 'h-12 px-4 text-base'
1831
1935
  };
1832
- const INVALID_CLASSES$2 = 'border-[var(--cxs-color-danger)] focus-visible:border-[var(--cxs-color-danger)] ' +
1936
+ const LABEL_SIZE_CLASSES$3 = {
1937
+ sm: 'text-sm',
1938
+ md: 'text-sm',
1939
+ lg: 'text-base'
1940
+ };
1941
+ const ERROR_SIZE_CLASSES = {
1942
+ sm: 'text-xs',
1943
+ md: 'text-xs',
1944
+ lg: 'text-sm'
1945
+ };
1946
+ const INVALID_CLASSES$3 = 'border-[var(--cxs-color-danger)] focus-visible:border-[var(--cxs-color-danger)] ' +
1833
1947
  'focus-visible:outline-[var(--cxs-color-danger)]';
1834
1948
  class CxsInputComponent {
1949
+ static nextId = 0;
1835
1950
  value = '';
1836
1951
  type = 'text';
1837
1952
  variant = 'outline';
@@ -1841,6 +1956,7 @@ class CxsInputComponent {
1841
1956
  required = false;
1842
1957
  invalid = false;
1843
1958
  autofocus = false;
1959
+ label;
1844
1960
  id;
1845
1961
  name;
1846
1962
  placeholder;
@@ -1850,6 +1966,7 @@ class CxsInputComponent {
1850
1966
  ariaLabel;
1851
1967
  ariaDescribedby;
1852
1968
  valueChange = new EventEmitter();
1969
+ instanceId = `cxs-input-${CxsInputComponent.nextId++}`;
1853
1970
  disabledFromControl = false;
1854
1971
  onChange = () => { };
1855
1972
  onTouched = () => { };
@@ -1860,12 +1977,55 @@ class CxsInputComponent {
1860
1977
  return [
1861
1978
  BASE_CLASSES$2,
1862
1979
  SIZE_CLASSES$1[this.size],
1863
- VARIANT_CLASSES$2[this.variant],
1864
- this.invalid ? INVALID_CLASSES$2 : ''
1980
+ VARIANT_CLASSES$3[this.variant],
1981
+ this.invalid ? INVALID_CLASSES$3 : ''
1865
1982
  ]
1866
1983
  .filter(Boolean)
1867
1984
  .join(' ');
1868
1985
  }
1986
+ get wrapperClass() {
1987
+ return WRAPPER_CLASSES$5;
1988
+ }
1989
+ get labelClass() {
1990
+ return [
1991
+ LABEL_BASE_CLASSES$3,
1992
+ LABEL_SIZE_CLASSES$3[this.size],
1993
+ this.isDisabled ? LABEL_DISABLED_CLASSES$3 : ''
1994
+ ]
1995
+ .filter(Boolean)
1996
+ .join(' ');
1997
+ }
1998
+ get inputId() {
1999
+ if (this.id) {
2000
+ return this.id;
2001
+ }
2002
+ return this.label ? this.instanceId : null;
2003
+ }
2004
+ get labelId() {
2005
+ if (!this.label) {
2006
+ return null;
2007
+ }
2008
+ return `${this.inputId}-label`;
2009
+ }
2010
+ get errorId() {
2011
+ return `${this.instanceId}-error`;
2012
+ }
2013
+ get ariaLabelValue() {
2014
+ if (this.label) {
2015
+ return null;
2016
+ }
2017
+ return this.ariaLabel ?? null;
2018
+ }
2019
+ get ariaDescribedbyValue() {
2020
+ const tokens = [this.ariaDescribedby].filter(Boolean);
2021
+ if (this.invalid) {
2022
+ tokens.push(this.errorId);
2023
+ }
2024
+ return tokens.length > 0 ? tokens.join(' ') : null;
2025
+ }
2026
+ get errorClass() {
2027
+ return [ERROR_BASE_CLASSES, ERROR_SIZE_CLASSES[this.size]].join(' ');
2028
+ }
1869
2029
  writeValue(value) {
1870
2030
  this.value = value ?? '';
1871
2031
  }
@@ -1889,23 +2049,23 @@ class CxsInputComponent {
1889
2049
  this.onTouched();
1890
2050
  }
1891
2051
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1892
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CxsInputComponent, isStandalone: true, selector: "cxs-input", inputs: { value: "value", type: "type", variant: "variant", size: "size", disabled: "disabled", readonly: "readonly", required: "required", invalid: "invalid", autofocus: "autofocus", id: "id", name: "name", placeholder: "placeholder", autocomplete: "autocomplete", inputmode: "inputmode", spellcheck: "spellcheck", ariaLabel: "ariaLabel", ariaDescribedby: "ariaDescribedby" }, outputs: { valueChange: "valueChange" }, providers: [
2052
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsInputComponent, isStandalone: true, selector: "cxs-input", inputs: { value: "value", type: "type", variant: "variant", size: "size", disabled: "disabled", readonly: "readonly", required: "required", invalid: "invalid", autofocus: "autofocus", label: "label", id: "id", name: "name", placeholder: "placeholder", autocomplete: "autocomplete", inputmode: "inputmode", spellcheck: "spellcheck", ariaLabel: "ariaLabel", ariaDescribedby: "ariaDescribedby" }, outputs: { valueChange: "valueChange" }, providers: [
1893
2053
  {
1894
2054
  provide: NG_VALUE_ACCESSOR,
1895
2055
  useExisting: forwardRef(() => CxsInputComponent),
1896
2056
  multi: true
1897
2057
  }
1898
- ], ngImport: i0, template: "<input\r\n [class]=\"inputClass\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.type]=\"type\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.autocomplete]=\"autocomplete\"\r\n [attr.inputmode]=\"inputmode\"\r\n [attr.spellcheck]=\"spellcheck === null ? null : spellcheck\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\r\n [attr.autofocus]=\"autofocus ? true : null\"\r\n [disabled]=\"isDisabled\"\r\n [readonly]=\"readonly\"\r\n [required]=\"required\"\r\n [value]=\"value\"\r\n (input)=\"onInput($event)\"\r\n (blur)=\"onBlur()\"\r\n/>\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
2058
+ ], ngImport: i0, template: "<div [class]=\"wrapperClass\">\n @if (label) {\n <label [class]=\"labelClass\" [attr.id]=\"labelId\" [attr.for]=\"inputId\">\n {{ label }}\n </label>\n }\n <input\n [class]=\"inputClass\"\n [attr.id]=\"inputId\"\n [attr.name]=\"name\"\n [attr.type]=\"type\"\n [attr.placeholder]=\"placeholder\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.inputmode]=\"inputmode\"\n [attr.spellcheck]=\"spellcheck === null ? null : spellcheck\"\n [attr.aria-label]=\"ariaLabelValue\"\n [attr.aria-labelledby]=\"labelId\"\n [attr.aria-describedby]=\"ariaDescribedbyValue\"\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [disabled]=\"isDisabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n [value]=\"value\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n />\n @if (invalid) {\n <div [class]=\"errorClass\" [attr.id]=\"errorId\" aria-live=\"polite\">\n <ng-content select=\"[cxsInputError]\"></ng-content>\n </div>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1899
2059
  }
1900
2060
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsInputComponent, decorators: [{
1901
2061
  type: Component,
1902
- args: [{ selector: 'cxs-input', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
2062
+ args: [{ selector: 'cxs-input', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
1903
2063
  {
1904
2064
  provide: NG_VALUE_ACCESSOR,
1905
2065
  useExisting: forwardRef(() => CxsInputComponent),
1906
2066
  multi: true
1907
2067
  }
1908
- ], template: "<input\r\n [class]=\"inputClass\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.type]=\"type\"\r\n [attr.placeholder]=\"placeholder\"\r\n [attr.autocomplete]=\"autocomplete\"\r\n [attr.inputmode]=\"inputmode\"\r\n [attr.spellcheck]=\"spellcheck === null ? null : spellcheck\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\r\n [attr.autofocus]=\"autofocus ? true : null\"\r\n [disabled]=\"isDisabled\"\r\n [readonly]=\"readonly\"\r\n [required]=\"required\"\r\n [value]=\"value\"\r\n (input)=\"onInput($event)\"\r\n (blur)=\"onBlur()\"\r\n/>\r\n" }]
2068
+ ], template: "<div [class]=\"wrapperClass\">\n @if (label) {\n <label [class]=\"labelClass\" [attr.id]=\"labelId\" [attr.for]=\"inputId\">\n {{ label }}\n </label>\n }\n <input\n [class]=\"inputClass\"\n [attr.id]=\"inputId\"\n [attr.name]=\"name\"\n [attr.type]=\"type\"\n [attr.placeholder]=\"placeholder\"\n [attr.autocomplete]=\"autocomplete\"\n [attr.inputmode]=\"inputmode\"\n [attr.spellcheck]=\"spellcheck === null ? null : spellcheck\"\n [attr.aria-label]=\"ariaLabelValue\"\n [attr.aria-labelledby]=\"labelId\"\n [attr.aria-describedby]=\"ariaDescribedbyValue\"\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\n [attr.autofocus]=\"autofocus ? true : null\"\n [disabled]=\"isDisabled\"\n [readonly]=\"readonly\"\n [required]=\"required\"\n [value]=\"value\"\n (input)=\"onInput($event)\"\n (blur)=\"onBlur()\"\n />\n @if (invalid) {\n <div [class]=\"errorClass\" [attr.id]=\"errorId\" aria-live=\"polite\">\n <ng-content select=\"[cxsInputError]\"></ng-content>\n </div>\n }\n</div>\n" }]
1909
2069
  }], propDecorators: { value: [{
1910
2070
  type: Input
1911
2071
  }], type: [{
@@ -1924,6 +2084,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
1924
2084
  type: Input
1925
2085
  }], autofocus: [{
1926
2086
  type: Input
2087
+ }], label: [{
2088
+ type: Input
1927
2089
  }], id: [{
1928
2090
  type: Input
1929
2091
  }], name: [{
@@ -2085,12 +2247,467 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2085
2247
  args: ['menuItem', { read: ElementRef }]
2086
2248
  }] } });
2087
2249
 
2250
+ const WRAPPER_CLASSES$4 = 'flex w-full flex-col gap-1';
2251
+ const LABEL_BASE_CLASSES$2 = 'font-medium text-(--cxs-color-on-surface)';
2252
+ const LABEL_DISABLED_CLASSES$2 = 'text-[var(--cxs-color-on-surface-muted)]';
2253
+ const CONTROL_BASE_CLASSES = 'flex w-full flex-wrap items-center gap-2 rounded-[var(--cxs-radius-md)] border ' +
2254
+ 'border-[var(--cxs-color-border)] transition-colors ' +
2255
+ 'focus-within:outline focus-within:outline-2 focus-within:outline-offset-2 ' +
2256
+ 'focus-within:outline-[var(--cxs-color-focus)] focus-within:border-[var(--cxs-color-focus)]';
2257
+ const CONTROL_DISABLED_CLASSES = 'pointer-events-none cursor-not-allowed opacity-60';
2258
+ const VARIANT_CLASSES$2 = {
2259
+ outline: 'bg-[var(--cxs-color-surface)]',
2260
+ filled: 'bg-[var(--cxs-color-surface-hover)]'
2261
+ };
2262
+ const CONTROL_SIZE_CLASSES$1 = {
2263
+ sm: 'min-h-8 px-2 py-1 text-sm',
2264
+ md: 'min-h-10 px-3 py-1.5 text-sm',
2265
+ lg: 'min-h-12 px-4 py-2 text-base'
2266
+ };
2267
+ const LABEL_SIZE_CLASSES$2 = {
2268
+ sm: 'text-sm',
2269
+ md: 'text-sm',
2270
+ lg: 'text-base'
2271
+ };
2272
+ const INPUT_CLASSES = 'flex-1 min-w-[6rem] bg-transparent outline-none placeholder:text-[var(--cxs-color-on-surface-muted)]';
2273
+ const CHIP_BASE_CLASSES = 'inline-flex items-center gap-1 rounded-[var(--cxs-radius-sm)] ' +
2274
+ 'bg-[var(--cxs-color-surface-hover)] text-[var(--cxs-color-on-surface)]';
2275
+ const CHIP_SIZE_CLASSES = {
2276
+ sm: 'px-2 py-0.5 text-xs',
2277
+ md: 'px-2 py-0.5 text-xs',
2278
+ lg: 'px-2.5 py-1 text-sm'
2279
+ };
2280
+ const CHIP_REMOVE_CLASSES = 'inline-flex h-4 w-4 items-center justify-center rounded-full ' +
2281
+ 'text-[var(--cxs-color-on-surface-muted)] hover:text-[var(--cxs-color-on-surface)]';
2282
+ const PANEL_CLASSES$1 = 'absolute left-0 top-full z-10 mt-2 w-full rounded-[var(--cxs-radius-md)] border ' +
2283
+ 'border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] p-1 shadow-[var(--cxs-shadow-sm)]';
2284
+ const OPTION_BASE_CLASSES = 'flex w-full items-center justify-between rounded-[var(--cxs-radius-sm)] px-3 py-2 text-left ' +
2285
+ 'text-sm text-[var(--cxs-color-on-surface)] transition-colors hover:bg-[var(--cxs-color-surface-hover)]';
2286
+ const OPTION_DISABLED_CLASSES = 'cursor-not-allowed opacity-50 hover:bg-transparent';
2287
+ const EMPTY_STATE_CLASSES = 'px-3 py-2 text-sm text-[var(--cxs-color-on-surface-muted)]';
2288
+ const INVALID_CLASSES$2 = 'border-[var(--cxs-color-danger)] focus-within:border-[var(--cxs-color-danger)] ' +
2289
+ 'focus-within:outline-[var(--cxs-color-danger)]';
2290
+ class CxsMultiSelectComponent {
2291
+ elementRef;
2292
+ static nextId = 0;
2293
+ options = [];
2294
+ value = [];
2295
+ variant = 'outline';
2296
+ size = 'md';
2297
+ disabled = false;
2298
+ readonly = false;
2299
+ invalid = false;
2300
+ placeholder;
2301
+ label;
2302
+ maxSelections;
2303
+ id;
2304
+ name;
2305
+ ariaLabel;
2306
+ ariaDescribedby;
2307
+ valueChange = new EventEmitter();
2308
+ inputEl;
2309
+ instanceId = `cxs-multi-select-${CxsMultiSelectComponent.nextId++}`;
2310
+ listId = `${this.instanceId}-list`;
2311
+ query = '';
2312
+ isOpen = false;
2313
+ disabledFromControl = false;
2314
+ onChange = () => { };
2315
+ onTouched = () => { };
2316
+ constructor(elementRef) {
2317
+ this.elementRef = elementRef;
2318
+ }
2319
+ get isDisabled() {
2320
+ return this.disabled || this.disabledFromControl;
2321
+ }
2322
+ get isAtMax() {
2323
+ return this.maxSelections !== undefined &&
2324
+ this.maxSelections !== null &&
2325
+ this.value.length >= this.maxSelections;
2326
+ }
2327
+ get wrapperClass() {
2328
+ return WRAPPER_CLASSES$4;
2329
+ }
2330
+ get labelClass() {
2331
+ return [
2332
+ LABEL_BASE_CLASSES$2,
2333
+ LABEL_SIZE_CLASSES$2[this.size],
2334
+ this.isDisabled ? LABEL_DISABLED_CLASSES$2 : ''
2335
+ ]
2336
+ .filter(Boolean)
2337
+ .join(' ');
2338
+ }
2339
+ get controlClass() {
2340
+ return [
2341
+ CONTROL_BASE_CLASSES,
2342
+ CONTROL_SIZE_CLASSES$1[this.size],
2343
+ VARIANT_CLASSES$2[this.variant],
2344
+ this.invalid ? INVALID_CLASSES$2 : '',
2345
+ this.isDisabled ? CONTROL_DISABLED_CLASSES : ''
2346
+ ]
2347
+ .filter(Boolean)
2348
+ .join(' ');
2349
+ }
2350
+ get inputClass() {
2351
+ return INPUT_CLASSES;
2352
+ }
2353
+ get chipClass() {
2354
+ return [CHIP_BASE_CLASSES, CHIP_SIZE_CLASSES[this.size]].join(' ');
2355
+ }
2356
+ get chipRemoveClass() {
2357
+ return CHIP_REMOVE_CLASSES;
2358
+ }
2359
+ get panelClass() {
2360
+ return PANEL_CLASSES$1;
2361
+ }
2362
+ get optionClass() {
2363
+ return OPTION_BASE_CLASSES;
2364
+ }
2365
+ get optionDisabledClass() {
2366
+ return OPTION_DISABLED_CLASSES;
2367
+ }
2368
+ get emptyStateClass() {
2369
+ return EMPTY_STATE_CLASSES;
2370
+ }
2371
+ get inputId() {
2372
+ if (this.id) {
2373
+ return this.id;
2374
+ }
2375
+ return this.label ? this.instanceId : null;
2376
+ }
2377
+ get labelId() {
2378
+ if (!this.label) {
2379
+ return null;
2380
+ }
2381
+ return `${this.inputId}-label`;
2382
+ }
2383
+ get ariaLabelValue() {
2384
+ if (this.label) {
2385
+ return null;
2386
+ }
2387
+ return this.ariaLabel ?? null;
2388
+ }
2389
+ get selectedOptions() {
2390
+ const optionsByValue = new Map(this.options.map((option) => [option.value, option]));
2391
+ return this.value.map((val) => optionsByValue.get(val) ?? { label: val, value: val });
2392
+ }
2393
+ get filteredOptions() {
2394
+ const selected = new Set(this.value);
2395
+ const query = this.query.trim().toLowerCase();
2396
+ return this.options.filter((option) => {
2397
+ if (selected.has(option.value)) {
2398
+ return false;
2399
+ }
2400
+ if (!query) {
2401
+ return true;
2402
+ }
2403
+ return option.label.toLowerCase().includes(query) || option.value.toLowerCase().includes(query);
2404
+ });
2405
+ }
2406
+ writeValue(value) {
2407
+ this.value = value ? [...value] : [];
2408
+ }
2409
+ registerOnChange(fn) {
2410
+ this.onChange = fn;
2411
+ }
2412
+ registerOnTouched(fn) {
2413
+ this.onTouched = fn;
2414
+ }
2415
+ setDisabledState(isDisabled) {
2416
+ this.disabledFromControl = isDisabled;
2417
+ }
2418
+ focusInput() {
2419
+ if (this.isDisabled || this.readonly) {
2420
+ return;
2421
+ }
2422
+ this.inputEl?.nativeElement.focus();
2423
+ }
2424
+ open() {
2425
+ if (this.isDisabled || this.readonly) {
2426
+ return;
2427
+ }
2428
+ this.isOpen = true;
2429
+ }
2430
+ close() {
2431
+ this.isOpen = false;
2432
+ }
2433
+ onQueryInput(event) {
2434
+ const target = event.target;
2435
+ this.query = target.value;
2436
+ this.open();
2437
+ }
2438
+ onKeydown(event) {
2439
+ if (event.key === 'Backspace' && !this.query && this.value.length > 0) {
2440
+ this.removeValue(this.value[this.value.length - 1]);
2441
+ }
2442
+ }
2443
+ selectOption(option) {
2444
+ if (this.isDisabled || this.readonly || this.isAtMax) {
2445
+ return;
2446
+ }
2447
+ if (this.value.includes(option.value)) {
2448
+ return;
2449
+ }
2450
+ const nextValue = [...this.value, option.value];
2451
+ this.updateValue(nextValue);
2452
+ this.query = '';
2453
+ this.open();
2454
+ this.focusInput();
2455
+ }
2456
+ removeValue(value) {
2457
+ if (this.isDisabled || this.readonly) {
2458
+ return;
2459
+ }
2460
+ const nextValue = this.value.filter((item) => item !== value);
2461
+ this.updateValue(nextValue);
2462
+ }
2463
+ onOptionMouseDown(event) {
2464
+ event.preventDefault();
2465
+ }
2466
+ onChipMouseDown(event) {
2467
+ event.preventDefault();
2468
+ }
2469
+ onBlur() {
2470
+ this.onTouched();
2471
+ }
2472
+ updateValue(nextValue) {
2473
+ this.value = [...nextValue];
2474
+ this.onChange(this.value);
2475
+ this.valueChange.emit(this.value);
2476
+ }
2477
+ onDocumentClick(event) {
2478
+ if (!this.isOpen) {
2479
+ return;
2480
+ }
2481
+ const target = event.target;
2482
+ if (target && !this.elementRef.nativeElement.contains(target)) {
2483
+ this.close();
2484
+ }
2485
+ }
2486
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsMultiSelectComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
2487
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsMultiSelectComponent, isStandalone: true, selector: "cxs-multi-select", inputs: { options: "options", value: "value", variant: "variant", size: "size", disabled: "disabled", readonly: "readonly", invalid: "invalid", placeholder: "placeholder", label: "label", maxSelections: "maxSelections", id: "id", name: "name", ariaLabel: "ariaLabel", ariaDescribedby: "ariaDescribedby" }, outputs: { valueChange: "valueChange" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, providers: [
2488
+ {
2489
+ provide: NG_VALUE_ACCESSOR,
2490
+ useExisting: forwardRef(() => CxsMultiSelectComponent),
2491
+ multi: true
2492
+ }
2493
+ ], viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["inputEl"], descendants: true }], ngImport: i0, template: "<div [class]=\"wrapperClass\">\n @if (label) {\n <label [class]=\"labelClass\" [attr.id]=\"labelId\" [attr.for]=\"inputId\">\n {{ label }}\n </label>\n }\n <div class=\"relative\">\n <div [class]=\"controlClass\" (click)=\"focusInput()\">\n @for (chip of selectedOptions; track chip.value) {\n <span [class]=\"chipClass\">\n <span>{{ chip.label }}</span>\n <button\n type=\"button\"\n [class]=\"chipRemoveClass\"\n [attr.aria-label]=\"'Remove ' + chip.label\"\n (mousedown)=\"onChipMouseDown($event)\"\n (click)=\"removeValue(chip.value)\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\n stroke=\"currentColor\" class=\"size-3\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18 18 6M6 6l12 12\"/>\n</svg>\n </button>\n </span>\n }\n <input\n #inputEl\n type=\"text\"\n [class]=\"inputClass\"\n [attr.id]=\"inputId\"\n [attr.name]=\"name\"\n [attr.placeholder]=\"placeholder\"\n [attr.aria-label]=\"ariaLabelValue\"\n [attr.aria-labelledby]=\"labelId\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-expanded]=\"isOpen ? 'true' : 'false'\"\n [attr.aria-controls]=\"listId\"\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\n [disabled]=\"isDisabled\"\n [readonly]=\"readonly || isAtMax\"\n [value]=\"query\"\n (input)=\"onQueryInput($event)\"\n (focus)=\"open()\"\n (blur)=\"onBlur()\"\n (keydown)=\"onKeydown($event)\"\n />\n </div>\n @if (isOpen) {\n <div [class]=\"panelClass\" [attr.id]=\"listId\" role=\"listbox\">\n @if (filteredOptions.length === 0) {\n <div [class]=\"emptyStateClass\">\n No matches\n </div>\n } @else {\n @for (option of filteredOptions; track option.value) {\n <button\n type=\"button\"\n [class]=\"optionClass + (isAtMax || readonly ? ' ' + optionDisabledClass : '')\"\n [disabled]=\"isAtMax || readonly\"\n role=\"option\"\n (mousedown)=\"onOptionMouseDown($event)\"\n (click)=\"selectOption(option)\"\n >\n <span>{{ option.label }}</span>\n </button>\n }\n }\n </div>\n }\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2494
+ }
2495
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsMultiSelectComponent, decorators: [{
2496
+ type: Component,
2497
+ args: [{ selector: 'cxs-multi-select', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
2498
+ {
2499
+ provide: NG_VALUE_ACCESSOR,
2500
+ useExisting: forwardRef(() => CxsMultiSelectComponent),
2501
+ multi: true
2502
+ }
2503
+ ], template: "<div [class]=\"wrapperClass\">\n @if (label) {\n <label [class]=\"labelClass\" [attr.id]=\"labelId\" [attr.for]=\"inputId\">\n {{ label }}\n </label>\n }\n <div class=\"relative\">\n <div [class]=\"controlClass\" (click)=\"focusInput()\">\n @for (chip of selectedOptions; track chip.value) {\n <span [class]=\"chipClass\">\n <span>{{ chip.label }}</span>\n <button\n type=\"button\"\n [class]=\"chipRemoveClass\"\n [attr.aria-label]=\"'Remove ' + chip.label\"\n (mousedown)=\"onChipMouseDown($event)\"\n (click)=\"removeValue(chip.value)\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\"\n stroke=\"currentColor\" class=\"size-3\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18 18 6M6 6l12 12\"/>\n</svg>\n </button>\n </span>\n }\n <input\n #inputEl\n type=\"text\"\n [class]=\"inputClass\"\n [attr.id]=\"inputId\"\n [attr.name]=\"name\"\n [attr.placeholder]=\"placeholder\"\n [attr.aria-label]=\"ariaLabelValue\"\n [attr.aria-labelledby]=\"labelId\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-expanded]=\"isOpen ? 'true' : 'false'\"\n [attr.aria-controls]=\"listId\"\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\n [disabled]=\"isDisabled\"\n [readonly]=\"readonly || isAtMax\"\n [value]=\"query\"\n (input)=\"onQueryInput($event)\"\n (focus)=\"open()\"\n (blur)=\"onBlur()\"\n (keydown)=\"onKeydown($event)\"\n />\n </div>\n @if (isOpen) {\n <div [class]=\"panelClass\" [attr.id]=\"listId\" role=\"listbox\">\n @if (filteredOptions.length === 0) {\n <div [class]=\"emptyStateClass\">\n No matches\n </div>\n } @else {\n @for (option of filteredOptions; track option.value) {\n <button\n type=\"button\"\n [class]=\"optionClass + (isAtMax || readonly ? ' ' + optionDisabledClass : '')\"\n [disabled]=\"isAtMax || readonly\"\n role=\"option\"\n (mousedown)=\"onOptionMouseDown($event)\"\n (click)=\"selectOption(option)\"\n >\n <span>{{ option.label }}</span>\n </button>\n }\n }\n </div>\n }\n </div>\n</div>\n" }]
2504
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { options: [{
2505
+ type: Input
2506
+ }], value: [{
2507
+ type: Input
2508
+ }], variant: [{
2509
+ type: Input
2510
+ }], size: [{
2511
+ type: Input
2512
+ }], disabled: [{
2513
+ type: Input
2514
+ }], readonly: [{
2515
+ type: Input
2516
+ }], invalid: [{
2517
+ type: Input
2518
+ }], placeholder: [{
2519
+ type: Input
2520
+ }], label: [{
2521
+ type: Input
2522
+ }], maxSelections: [{
2523
+ type: Input
2524
+ }], id: [{
2525
+ type: Input
2526
+ }], name: [{
2527
+ type: Input
2528
+ }], ariaLabel: [{
2529
+ type: Input
2530
+ }], ariaDescribedby: [{
2531
+ type: Input
2532
+ }], valueChange: [{
2533
+ type: Output
2534
+ }], inputEl: [{
2535
+ type: ViewChild,
2536
+ args: ['inputEl']
2537
+ }], onDocumentClick: [{
2538
+ type: HostListener,
2539
+ args: ['document:click', ['$event']]
2540
+ }] } });
2541
+
2542
+ class CxsTabLabelDirective {
2543
+ templateRef;
2544
+ constructor(templateRef) {
2545
+ this.templateRef = templateRef;
2546
+ }
2547
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsTabLabelDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
2548
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: CxsTabLabelDirective, isStandalone: true, selector: "[cxsTabLabel]", ngImport: i0 });
2549
+ }
2550
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsTabLabelDirective, decorators: [{
2551
+ type: Directive,
2552
+ args: [{
2553
+ selector: '[cxsTabLabel]',
2554
+ standalone: true
2555
+ }]
2556
+ }], ctorParameters: () => [{ type: i0.TemplateRef }] });
2557
+
2558
+ class CxsTabPanelComponent {
2559
+ static nextId = 0;
2560
+ id;
2561
+ label;
2562
+ disabled = false;
2563
+ labelTemplate;
2564
+ templateRef;
2565
+ instanceId = `cxs-tab-${CxsTabPanelComponent.nextId++}`;
2566
+ get resolvedId() {
2567
+ return this.id ?? this.instanceId;
2568
+ }
2569
+ get tabId() {
2570
+ return `${this.resolvedId}-tab`;
2571
+ }
2572
+ get panelId() {
2573
+ return `${this.resolvedId}-panel`;
2574
+ }
2575
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsTabPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2576
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CxsTabPanelComponent, isStandalone: true, selector: "cxs-tab-panel", inputs: { id: "id", label: "label", disabled: "disabled" }, queries: [{ propertyName: "labelTemplate", first: true, predicate: CxsTabLabelDirective, descendants: true }], viewQueries: [{ propertyName: "templateRef", first: true, predicate: ["content"], descendants: true, static: true }], ngImport: i0, template: "<ng-template #content>\n <ng-content></ng-content>\n</ng-template>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
2577
+ }
2578
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsTabPanelComponent, decorators: [{
2579
+ type: Component,
2580
+ args: [{ selector: 'cxs-tab-panel', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-template #content>\n <ng-content></ng-content>\n</ng-template>\n" }]
2581
+ }], propDecorators: { id: [{
2582
+ type: Input
2583
+ }], label: [{
2584
+ type: Input
2585
+ }], disabled: [{
2586
+ type: Input
2587
+ }], labelTemplate: [{
2588
+ type: ContentChild,
2589
+ args: [CxsTabLabelDirective]
2590
+ }], templateRef: [{
2591
+ type: ViewChild,
2592
+ args: ['content', { static: true }]
2593
+ }] } });
2594
+
2595
+ const WRAPPER_CLASSES$3 = 'w-full';
2596
+ const TAB_LIST_CLASSES = 'flex flex-wrap items-center gap-6 border-b border-[var(--cxs-color-border)]';
2597
+ const TAB_BUTTON_BASE_CLASSES = 'inline-flex items-center gap-2 border-b-2 pb-3 text-sm font-medium transition-colors';
2598
+ const TAB_BUTTON_INACTIVE_CLASSES = 'border-transparent text-[var(--cxs-color-on-surface-muted)] hover:text-[var(--cxs-color-on-surface)]';
2599
+ const TAB_BUTTON_ACTIVE_CLASSES = 'border-[var(--cxs-color-primary)] text-[var(--cxs-color-primary)]';
2600
+ const TAB_BUTTON_DISABLED_CLASSES = 'cursor-not-allowed opacity-50';
2601
+ const PANEL_WRAPPER_CLASSES = 'pt-4';
2602
+ const PANEL_CLASSES = 'rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
2603
+ 'bg-[var(--cxs-color-surface)] p-4 text-sm text-[var(--cxs-color-on-surface)]';
2604
+ class CxsTabsComponent {
2605
+ ariaLabel = 'Tabs';
2606
+ activeId;
2607
+ activeIdChange = new EventEmitter();
2608
+ panels;
2609
+ get wrapperClass() {
2610
+ return WRAPPER_CLASSES$3;
2611
+ }
2612
+ get tabListClass() {
2613
+ return TAB_LIST_CLASSES;
2614
+ }
2615
+ get tabButtonBaseClass() {
2616
+ return TAB_BUTTON_BASE_CLASSES;
2617
+ }
2618
+ get tabButtonInactiveClass() {
2619
+ return TAB_BUTTON_INACTIVE_CLASSES;
2620
+ }
2621
+ get tabButtonActiveClass() {
2622
+ return TAB_BUTTON_ACTIVE_CLASSES;
2623
+ }
2624
+ get tabButtonDisabledClass() {
2625
+ return TAB_BUTTON_DISABLED_CLASSES;
2626
+ }
2627
+ get panelWrapperClass() {
2628
+ return PANEL_WRAPPER_CLASSES;
2629
+ }
2630
+ get panelClass() {
2631
+ return PANEL_CLASSES;
2632
+ }
2633
+ get panelList() {
2634
+ return this.panels?.toArray() ?? [];
2635
+ }
2636
+ get activePanel() {
2637
+ return this.resolveActivePanel();
2638
+ }
2639
+ ngAfterContentInit() {
2640
+ this.ensureActiveTab();
2641
+ this.panels?.changes.subscribe(() => this.ensureActiveTab());
2642
+ }
2643
+ isActive(panel) {
2644
+ return this.activeId === panel.resolvedId;
2645
+ }
2646
+ tabButtonClass(panel) {
2647
+ return [
2648
+ TAB_BUTTON_BASE_CLASSES,
2649
+ this.isActive(panel) ? TAB_BUTTON_ACTIVE_CLASSES : TAB_BUTTON_INACTIVE_CLASSES,
2650
+ panel.disabled ? TAB_BUTTON_DISABLED_CLASSES : ''
2651
+ ]
2652
+ .filter(Boolean)
2653
+ .join(' ');
2654
+ }
2655
+ selectTab(panel) {
2656
+ if (panel.disabled) {
2657
+ return;
2658
+ }
2659
+ this.activeId = panel.resolvedId;
2660
+ this.activeIdChange.emit(panel.resolvedId);
2661
+ }
2662
+ panelLabel(panel) {
2663
+ return panel.label ?? panel.resolvedId;
2664
+ }
2665
+ ensureActiveTab() {
2666
+ const nextActive = this.resolveActivePanel();
2667
+ if (!nextActive) {
2668
+ return;
2669
+ }
2670
+ if (this.activeId !== nextActive.resolvedId) {
2671
+ this.activeId = nextActive.resolvedId;
2672
+ this.activeIdChange.emit(nextActive.resolvedId);
2673
+ }
2674
+ }
2675
+ resolveActivePanel() {
2676
+ const panels = this.panelList;
2677
+ if (!panels.length) {
2678
+ return null;
2679
+ }
2680
+ if (this.activeId) {
2681
+ const active = panels.find((panel) => panel.resolvedId === this.activeId);
2682
+ if (active && !active.disabled) {
2683
+ return active;
2684
+ }
2685
+ }
2686
+ return panels.find((panel) => !panel.disabled) ?? panels[0];
2687
+ }
2688
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsTabsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2689
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsTabsComponent, isStandalone: true, selector: "cxs-tabs", inputs: { ariaLabel: "ariaLabel", activeId: "activeId" }, outputs: { activeIdChange: "activeIdChange" }, queries: [{ propertyName: "panels", predicate: CxsTabPanelComponent }], ngImport: i0, template: "<div [class]=\"wrapperClass\">\n <div [class]=\"tabListClass\" role=\"tablist\" [attr.aria-label]=\"ariaLabel\">\n @for (panel of panelList; track panel.resolvedId) {\n <button\n type=\"button\"\n [class]=\"tabButtonClass(panel)\"\n role=\"tab\"\n [attr.id]=\"panel.tabId\"\n [attr.aria-controls]=\"panel.panelId\"\n [attr.aria-selected]=\"isActive(panel) ? 'true' : 'false'\"\n [disabled]=\"panel.disabled\"\n (click)=\"selectTab(panel)\"\n >\n @if (panel.labelTemplate) {\n <ng-container [ngTemplateOutlet]=\"panel.labelTemplate.templateRef\"></ng-container>\n } @else {\n <span>{{ panelLabel(panel) }}</span>\n }\n </button>\n }\n </div>\n\n @if (activePanel) {\n <div [class]=\"panelWrapperClass\">\n <div\n [class]=\"panelClass\"\n role=\"tabpanel\"\n [attr.id]=\"activePanel.panelId\"\n [attr.aria-labelledby]=\"activePanel.tabId\"\n >\n <ng-container [ngTemplateOutlet]=\"activePanel.templateRef\"></ng-container>\n </div>\n </div>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2690
+ }
2691
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsTabsComponent, decorators: [{
2692
+ type: Component,
2693
+ args: [{ selector: 'cxs-tabs', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"wrapperClass\">\n <div [class]=\"tabListClass\" role=\"tablist\" [attr.aria-label]=\"ariaLabel\">\n @for (panel of panelList; track panel.resolvedId) {\n <button\n type=\"button\"\n [class]=\"tabButtonClass(panel)\"\n role=\"tab\"\n [attr.id]=\"panel.tabId\"\n [attr.aria-controls]=\"panel.panelId\"\n [attr.aria-selected]=\"isActive(panel) ? 'true' : 'false'\"\n [disabled]=\"panel.disabled\"\n (click)=\"selectTab(panel)\"\n >\n @if (panel.labelTemplate) {\n <ng-container [ngTemplateOutlet]=\"panel.labelTemplate.templateRef\"></ng-container>\n } @else {\n <span>{{ panelLabel(panel) }}</span>\n }\n </button>\n }\n </div>\n\n @if (activePanel) {\n <div [class]=\"panelWrapperClass\">\n <div\n [class]=\"panelClass\"\n role=\"tabpanel\"\n [attr.id]=\"activePanel.panelId\"\n [attr.aria-labelledby]=\"activePanel.tabId\"\n >\n <ng-container [ngTemplateOutlet]=\"activePanel.templateRef\"></ng-container>\n </div>\n </div>\n }\n</div>\n" }]
2694
+ }], propDecorators: { ariaLabel: [{
2695
+ type: Input
2696
+ }], activeId: [{
2697
+ type: Input
2698
+ }], activeIdChange: [{
2699
+ type: Output
2700
+ }], panels: [{
2701
+ type: ContentChildren,
2702
+ args: [CxsTabPanelComponent]
2703
+ }] } });
2704
+
2088
2705
  const WRAPPER_BASE = 'inline-flex items-center gap-2 select-none';
2089
2706
  const WRAPPER_ENABLED = 'cursor-pointer';
2090
2707
  const WRAPPER_DISABLED = 'cursor-not-allowed opacity-60';
2091
2708
  const LABEL_BASE = 'text-[var(--cxs-color-on-surface)]';
2092
2709
  const LABEL_DISABLED = 'text-[var(--cxs-color-on-surface-muted)]';
2093
- const LABEL_SIZE_CLASSES = {
2710
+ const LABEL_SIZE_CLASSES$1 = {
2094
2711
  sm: 'text-sm',
2095
2712
  md: 'text-sm',
2096
2713
  lg: 'text-base'
@@ -2149,7 +2766,7 @@ class CxsRadioComponent {
2149
2766
  get labelClass() {
2150
2767
  return [
2151
2768
  LABEL_BASE,
2152
- LABEL_SIZE_CLASSES[this.size],
2769
+ LABEL_SIZE_CLASSES$1[this.size],
2153
2770
  this.isDisabled ? LABEL_DISABLED : ''
2154
2771
  ]
2155
2772
  .filter(Boolean)
@@ -2240,6 +2857,9 @@ const BASE_CLASSES$1 = 'w-full appearance-none rounded-[var(--cxs-radius-md)] bo
2240
2857
  'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
2241
2858
  'focus-visible:outline-[var(--cxs-color-focus)] focus-visible:border-[var(--cxs-color-focus)] ' +
2242
2859
  'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-60';
2860
+ const WRAPPER_CLASSES$2 = 'flex w-full flex-col gap-1';
2861
+ const LABEL_BASE_CLASSES$1 = 'font-medium text-(--cxs-color-on-surface)';
2862
+ const LABEL_DISABLED_CLASSES$1 = 'text-[var(--cxs-color-on-surface-muted)]';
2243
2863
  const VARIANT_CLASSES$1 = {
2244
2864
  outline: 'bg-[var(--cxs-color-surface)]',
2245
2865
  filled: 'bg-[var(--cxs-color-surface-hover)]'
@@ -2249,15 +2869,22 @@ const SIZE_CLASSES = {
2249
2869
  md: 'h-10 pl-3 pr-9 text-sm',
2250
2870
  lg: 'h-12 pl-4 pr-10 text-base'
2251
2871
  };
2872
+ const LABEL_SIZE_CLASSES = {
2873
+ sm: 'text-sm',
2874
+ md: 'text-sm',
2875
+ lg: 'text-base'
2876
+ };
2252
2877
  const INVALID_CLASSES = 'border-[var(--cxs-color-danger)] focus-visible:border-[var(--cxs-color-danger)] ' +
2253
2878
  'focus-visible:outline-[var(--cxs-color-danger)]';
2254
2879
  class CxsSelectComponent {
2880
+ static nextId = 0;
2255
2881
  value = '';
2256
2882
  variant = 'outline';
2257
2883
  size = 'md';
2258
2884
  disabled = false;
2259
2885
  required = false;
2260
2886
  invalid = false;
2887
+ label;
2261
2888
  placeholder;
2262
2889
  placeholderValue = '';
2263
2890
  id;
@@ -2265,6 +2892,7 @@ class CxsSelectComponent {
2265
2892
  ariaLabel;
2266
2893
  ariaDescribedby;
2267
2894
  valueChange = new EventEmitter();
2895
+ instanceId = `cxs-select-${CxsSelectComponent.nextId++}`;
2268
2896
  disabledFromControl = false;
2269
2897
  onChange = () => { };
2270
2898
  onTouched = () => { };
@@ -2281,6 +2909,36 @@ class CxsSelectComponent {
2281
2909
  .filter(Boolean)
2282
2910
  .join(' ');
2283
2911
  }
2912
+ get wrapperClass() {
2913
+ return WRAPPER_CLASSES$2;
2914
+ }
2915
+ get labelClass() {
2916
+ return [
2917
+ LABEL_BASE_CLASSES$1,
2918
+ LABEL_SIZE_CLASSES[this.size],
2919
+ this.isDisabled ? LABEL_DISABLED_CLASSES$1 : ''
2920
+ ]
2921
+ .filter(Boolean)
2922
+ .join(' ');
2923
+ }
2924
+ get selectId() {
2925
+ if (this.id) {
2926
+ return this.id;
2927
+ }
2928
+ return this.label ? this.instanceId : null;
2929
+ }
2930
+ get labelId() {
2931
+ if (!this.label) {
2932
+ return null;
2933
+ }
2934
+ return `${this.selectId}-label`;
2935
+ }
2936
+ get ariaLabelValue() {
2937
+ if (this.label) {
2938
+ return null;
2939
+ }
2940
+ return this.ariaLabel ?? null;
2941
+ }
2284
2942
  get selectValue() {
2285
2943
  if (this.placeholder && this.value === '') {
2286
2944
  return this.placeholderValue;
@@ -2310,13 +2968,13 @@ class CxsSelectComponent {
2310
2968
  this.onTouched();
2311
2969
  }
2312
2970
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2313
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CxsSelectComponent, isStandalone: true, selector: "cxs-select", inputs: { value: "value", variant: "variant", size: "size", disabled: "disabled", required: "required", invalid: "invalid", placeholder: "placeholder", placeholderValue: "placeholderValue", id: "id", name: "name", ariaLabel: "ariaLabel", ariaDescribedby: "ariaDescribedby" }, outputs: { valueChange: "valueChange" }, providers: [
2971
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: CxsSelectComponent, isStandalone: true, selector: "cxs-select", inputs: { value: "value", variant: "variant", size: "size", disabled: "disabled", required: "required", invalid: "invalid", label: "label", placeholder: "placeholder", placeholderValue: "placeholderValue", id: "id", name: "name", ariaLabel: "ariaLabel", ariaDescribedby: "ariaDescribedby" }, outputs: { valueChange: "valueChange" }, providers: [
2314
2972
  {
2315
2973
  provide: NG_VALUE_ACCESSOR,
2316
2974
  useExisting: forwardRef(() => CxsSelectComponent),
2317
2975
  multi: true
2318
2976
  }
2319
- ], ngImport: i0, template: "<div class=\"relative\">\r\n <select\r\n [class]=\"selectClass\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\r\n [disabled]=\"isDisabled\"\r\n [required]=\"required\"\r\n [value]=\"selectValue\"\r\n (change)=\"onSelectChange($event)\"\r\n (blur)=\"onBlur()\"\r\n >\r\n <option *ngIf=\"placeholder\" [value]=\"placeholderValue\" disabled>\r\n {{ placeholder }}\r\n </option>\r\n <ng-content></ng-content>\r\n </select>\r\n <span\r\n class=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-[var(--cxs-color-on-surface-muted)]\"\r\n aria-hidden=\"true\"\r\n >\r\n <svg viewBox=\"0 0 20 20\" fill=\"currentColor\" class=\"h-4 w-4\">\r\n <path\r\n fill-rule=\"evenodd\"\r\n d=\"M5.23 7.21a.75.75 0 0 1 1.06.02L10 10.94l3.71-3.71a.75.75 0 1 1 1.06 1.06l-4.24 4.25a.75.75 0 0 1-1.06 0L5.21 8.29a.75.75 0 0 1 .02-1.08Z\"\r\n clip-rule=\"evenodd\"\r\n />\r\n </svg>\r\n </span>\r\n</div>\r\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2977
+ ], ngImport: i0, template: "<div [class]=\"wrapperClass\">\n <label *ngIf=\"label\" [class]=\"labelClass\" [attr.id]=\"labelId\" [attr.for]=\"selectId\">\n {{ label }}\n </label>\n <div class=\"relative\">\n <select\n [class]=\"selectClass\"\n [attr.id]=\"selectId\"\n [attr.name]=\"name\"\n [attr.aria-label]=\"ariaLabelValue\"\n [attr.aria-labelledby]=\"labelId\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\n [disabled]=\"isDisabled\"\n [required]=\"required\"\n [value]=\"selectValue\"\n (change)=\"onSelectChange($event)\"\n (blur)=\"onBlur()\"\n >\n <option *ngIf=\"placeholder\" [value]=\"placeholderValue\" disabled>\n {{ placeholder }}\n </option>\n <ng-content></ng-content>\n </select>\n <span\n class=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-[var(--cxs-color-on-surface-muted)]\"\n aria-hidden=\"true\"\n >\n <svg viewBox=\"0 0 20 20\" fill=\"currentColor\" class=\"h-4 w-4\">\n <path\n fill-rule=\"evenodd\"\n d=\"M5.23 7.21a.75.75 0 0 1 1.06.02L10 10.94l3.71-3.71a.75.75 0 1 1 1.06 1.06l-4.24 4.25a.75.75 0 0 1-1.06 0L5.21 8.29a.75.75 0 0 1 .02-1.08Z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </span>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2320
2978
  }
2321
2979
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsSelectComponent, decorators: [{
2322
2980
  type: Component,
@@ -2326,7 +2984,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2326
2984
  useExisting: forwardRef(() => CxsSelectComponent),
2327
2985
  multi: true
2328
2986
  }
2329
- ], template: "<div class=\"relative\">\r\n <select\r\n [class]=\"selectClass\"\r\n [attr.id]=\"id\"\r\n [attr.name]=\"name\"\r\n [attr.aria-label]=\"ariaLabel\"\r\n [attr.aria-describedby]=\"ariaDescribedby\"\r\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\r\n [disabled]=\"isDisabled\"\r\n [required]=\"required\"\r\n [value]=\"selectValue\"\r\n (change)=\"onSelectChange($event)\"\r\n (blur)=\"onBlur()\"\r\n >\r\n <option *ngIf=\"placeholder\" [value]=\"placeholderValue\" disabled>\r\n {{ placeholder }}\r\n </option>\r\n <ng-content></ng-content>\r\n </select>\r\n <span\r\n class=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-[var(--cxs-color-on-surface-muted)]\"\r\n aria-hidden=\"true\"\r\n >\r\n <svg viewBox=\"0 0 20 20\" fill=\"currentColor\" class=\"h-4 w-4\">\r\n <path\r\n fill-rule=\"evenodd\"\r\n d=\"M5.23 7.21a.75.75 0 0 1 1.06.02L10 10.94l3.71-3.71a.75.75 0 1 1 1.06 1.06l-4.24 4.25a.75.75 0 0 1-1.06 0L5.21 8.29a.75.75 0 0 1 .02-1.08Z\"\r\n clip-rule=\"evenodd\"\r\n />\r\n </svg>\r\n </span>\r\n</div>\r\n" }]
2987
+ ], template: "<div [class]=\"wrapperClass\">\n <label *ngIf=\"label\" [class]=\"labelClass\" [attr.id]=\"labelId\" [attr.for]=\"selectId\">\n {{ label }}\n </label>\n <div class=\"relative\">\n <select\n [class]=\"selectClass\"\n [attr.id]=\"selectId\"\n [attr.name]=\"name\"\n [attr.aria-label]=\"ariaLabelValue\"\n [attr.aria-labelledby]=\"labelId\"\n [attr.aria-describedby]=\"ariaDescribedby\"\n [attr.aria-invalid]=\"invalid ? 'true' : null\"\n [disabled]=\"isDisabled\"\n [required]=\"required\"\n [value]=\"selectValue\"\n (change)=\"onSelectChange($event)\"\n (blur)=\"onBlur()\"\n >\n <option *ngIf=\"placeholder\" [value]=\"placeholderValue\" disabled>\n {{ placeholder }}\n </option>\n <ng-content></ng-content>\n </select>\n <span\n class=\"pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-[var(--cxs-color-on-surface-muted)]\"\n aria-hidden=\"true\"\n >\n <svg viewBox=\"0 0 20 20\" fill=\"currentColor\" class=\"h-4 w-4\">\n <path\n fill-rule=\"evenodd\"\n d=\"M5.23 7.21a.75.75 0 0 1 1.06.02L10 10.94l3.71-3.71a.75.75 0 1 1 1.06 1.06l-4.24 4.25a.75.75 0 0 1-1.06 0L5.21 8.29a.75.75 0 0 1 .02-1.08Z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </span>\n </div>\n</div>\n" }]
2330
2988
  }], propDecorators: { value: [{
2331
2989
  type: Input
2332
2990
  }], variant: [{
@@ -2339,6 +2997,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2339
2997
  type: Input
2340
2998
  }], invalid: [{
2341
2999
  type: Input
3000
+ }], label: [{
3001
+ type: Input
2342
3002
  }], placeholder: [{
2343
3003
  type: Input
2344
3004
  }], placeholderValue: [{
@@ -2479,25 +3139,25 @@ const TRACK_BASE_CLASSES = 'relative inline-flex items-center rounded-full borde
2479
3139
  'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
2480
3140
  'focus-visible:outline-[var(--cxs-color-focus)] disabled:pointer-events-none disabled:opacity-60';
2481
3141
  const TRACK_SIZE_CLASSES = {
2482
- sm: 'h-5 w-9 p-0.5',
3142
+ sm: 'h-6 w-11 p-0.5',
2483
3143
  md: 'h-6 w-11 p-0.5',
2484
- lg: 'h-8 w-14 p-0.5'
3144
+ lg: 'h-6 w-11 p-0.5'
2485
3145
  };
2486
3146
  const TRACK_STATE_CLASSES = {
2487
3147
  on: 'bg-[var(--cxs-color-primary)] border-[var(--cxs-color-primary)]',
2488
- off: 'bg-[var(--cxs-color-surface)] border-[var(--cxs-color-border)]'
3148
+ off: 'bg-[var(--cxs-color-surface-hover)] border-[var(--cxs-color-border)]'
2489
3149
  };
2490
- const THUMB_BASE_CLASSES = 'absolute left-0.5 top-0.5 rounded-full transition-transform duration-200 ease-out';
3150
+ const THUMB_BASE_CLASSES = 'absolute left-0.5 top-1/2 -translate-y-1/2 rounded-full transition-transform duration-200 ease-out';
2491
3151
  const THUMB_SIZE_CLASSES = {
2492
- sm: 'h-4 w-4',
3152
+ sm: 'h-5 w-5',
2493
3153
  md: 'h-5 w-5',
2494
- lg: 'h-7 w-7'
3154
+ lg: 'h-5 w-5'
2495
3155
  };
2496
3156
  const THUMB_STATE_CLASSES = {
2497
3157
  on: {
2498
- sm: 'translate-x-[18px] bg-[var(--cxs-color-on-primary)]',
2499
- md: 'translate-x-[22px] bg-[var(--cxs-color-on-primary)]',
2500
- lg: 'translate-x-[26px] bg-[var(--cxs-color-on-primary)]'
3158
+ sm: 'translate-x-[20px] bg-[var(--cxs-color-on-primary)]',
3159
+ md: 'translate-x-[20px] bg-[var(--cxs-color-on-primary)]',
3160
+ lg: 'translate-x-[20px] bg-[var(--cxs-color-on-primary)]'
2501
3161
  },
2502
3162
  off: 'translate-x-0 bg-[var(--cxs-color-surface)]'
2503
3163
  };
@@ -2680,11 +3340,11 @@ class CxsToastComponent {
2680
3340
  }
2681
3341
  }
2682
3342
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsToastComponent, deps: [{ token: 'class', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
2683
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsToastComponent, isStandalone: true, selector: "cxs-toast", inputs: { open: "open", title: "title", message: "message", ariaLabel: "ariaLabel", variant: "variant", dismissible: "dismissible", duration: "duration", position: "position", maxWidth: "maxWidth" }, outputs: { openChange: "openChange", dismissed: "dismissed" }, usesOnChanges: true, ngImport: i0, template: "@if (open) {\n <div [class]=\"hostClassName\">\n <div\n [class]=\"toastClass\"\n [attr.role]=\"role\"\n [attr.aria-live]=\"ariaLive\"\n [attr.aria-label]=\"ariaLabelValue\"\n >\n <div class=\"flex-1\">\n @if (title) {\n <p [class]=\"titleClass\">{{ title }}</p>\n }\n @if (message) {\n <p [class]=\"messageClass\">{{ message }}</p>\n }\n <ng-content></ng-content>\n <div [class]=\"actionsClass\">\n <ng-content select=\"[cxsToastAction]\"></ng-content>\n </div>\n </div>\n @if (dismissible) {\n <button\n type=\"button\"\n [class]=\"closeButtonClass\"\n aria-label=\"Dismiss notification\"\n (click)=\"requestClose('dismiss')\"\n >\n X\n </button>\n }\n </div>\n </div>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
3343
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CxsToastComponent, isStandalone: true, selector: "cxs-toast", inputs: { open: "open", title: "title", message: "message", ariaLabel: "ariaLabel", variant: "variant", dismissible: "dismissible", duration: "duration", position: "position", maxWidth: "maxWidth" }, outputs: { openChange: "openChange", dismissed: "dismissed" }, usesOnChanges: true, ngImport: i0, template: "@if (open) {\n <div [class]=\"hostClassName\">\n <div\n [class]=\"toastClass\"\n [attr.role]=\"role\"\n [attr.aria-live]=\"ariaLive\"\n [attr.aria-label]=\"ariaLabelValue\"\n >\n <div class=\"flex-1\">\n @if (title) {\n <p [class]=\"titleClass\">{{ title }}</p>\n }\n @if (message) {\n <p [class]=\"messageClass\">{{ message }}</p>\n }\n <ng-content></ng-content>\n <div [class]=\"actionsClass\">\n <ng-content select=\"[cxsToastAction]\"></ng-content>\n </div>\n </div>\n @if (dismissible) {\n <button\n type=\"button\"\n [class]=\"closeButtonClass\"\n aria-label=\"Dismiss notification\"\n (click)=\"requestClose('dismiss')\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-6\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18 18 6M6 6l12 12\" />\n </svg>\n\n </button>\n }\n </div>\n </div>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
2684
3344
  }
2685
3345
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsToastComponent, decorators: [{
2686
3346
  type: Component,
2687
- args: [{ selector: 'cxs-toast', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (open) {\n <div [class]=\"hostClassName\">\n <div\n [class]=\"toastClass\"\n [attr.role]=\"role\"\n [attr.aria-live]=\"ariaLive\"\n [attr.aria-label]=\"ariaLabelValue\"\n >\n <div class=\"flex-1\">\n @if (title) {\n <p [class]=\"titleClass\">{{ title }}</p>\n }\n @if (message) {\n <p [class]=\"messageClass\">{{ message }}</p>\n }\n <ng-content></ng-content>\n <div [class]=\"actionsClass\">\n <ng-content select=\"[cxsToastAction]\"></ng-content>\n </div>\n </div>\n @if (dismissible) {\n <button\n type=\"button\"\n [class]=\"closeButtonClass\"\n aria-label=\"Dismiss notification\"\n (click)=\"requestClose('dismiss')\"\n >\n X\n </button>\n }\n </div>\n </div>\n}\n" }]
3347
+ args: [{ selector: 'cxs-toast', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (open) {\n <div [class]=\"hostClassName\">\n <div\n [class]=\"toastClass\"\n [attr.role]=\"role\"\n [attr.aria-live]=\"ariaLive\"\n [attr.aria-label]=\"ariaLabelValue\"\n >\n <div class=\"flex-1\">\n @if (title) {\n <p [class]=\"titleClass\">{{ title }}</p>\n }\n @if (message) {\n <p [class]=\"messageClass\">{{ message }}</p>\n }\n <ng-content></ng-content>\n <div [class]=\"actionsClass\">\n <ng-content select=\"[cxsToastAction]\"></ng-content>\n </div>\n </div>\n @if (dismissible) {\n <button\n type=\"button\"\n [class]=\"closeButtonClass\"\n aria-label=\"Dismiss notification\"\n (click)=\"requestClose('dismiss')\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"size-6\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18 18 6M6 6l12 12\" />\n </svg>\n\n </button>\n }\n </div>\n </div>\n}\n" }]
2688
3348
  }], ctorParameters: () => [{ type: undefined, decorators: [{
2689
3349
  type: Attribute,
2690
3350
  args: ['class']
@@ -2902,5 +3562,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2902
3562
  * Generated bundle index. Do not edit.
2903
3563
  */
2904
3564
 
2905
- export { CerxosUi, CxsAccordionComponent, CxsAccordionItemComponent, CxsAlertComponent, CxsAvatarComponent, CxsBadgeComponent, CxsBreadcrumbComponent, CxsButtonComponent, CxsCardComponent, CxsCarouselComponent, CxsCheckboxComponent, CxsDataTableComponent, CxsDatepickerComponent, CxsDialogComponent, CxsInputComponent, CxsMenubarComponent, CxsRadioComponent, CxsSelectComponent, CxsTableComponent, CxsThemeDirective, CxsToastComponent, CxsToggleComponent, CxsTooltipComponent };
3565
+ export { CerxosUi, CxsAccordionComponent, CxsAccordionItemComponent, 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 };
2906
3566
  //# sourceMappingURL=cerxos-ui.mjs.map