cerxos-ui 0.0.5 → 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, Directive, ContentChildren, ViewChild, HostListener, ElementRef, ViewChildren } 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 { NgTemplateOutlet, 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
  }
@@ -837,8 +838,15 @@ const TOOLBAR_INPUT_CLASSES = 'w-full rounded-[var(--cxs-radius-md)] border bord
837
838
  'bg-[var(--cxs-color-surface)] px-3 py-2 text-sm text-[var(--cxs-color-on-surface)] ' +
838
839
  'placeholder:text-[var(--cxs-color-on-surface-muted)] focus-visible:outline focus-visible:outline-2 ' +
839
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)]';
840
845
  const TOOLBAR_BUTTON_CLASSES = 'inline-flex items-center justify-center rounded-[var(--cxs-radius-md)] border border-[var(--cxs-color-border)] ' +
841
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)';
842
850
  const BULK_BAR_CLASSES = 'mb-3 flex flex-wrap items-center justify-between gap-3 rounded-[var(--cxs-radius-md)] ' +
843
851
  'border border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] px-3 py-2 text-sm';
844
852
  const RESIZE_HANDLE_CLASSES = 'absolute right-0 top-0 h-full w-2 cursor-col-resize touch-none';
@@ -847,6 +855,8 @@ class CxsDataTableComponent {
847
855
  columns = [];
848
856
  data = [];
849
857
  caption;
858
+ title;
859
+ subtitle;
850
860
  ariaLabel = 'Data table';
851
861
  striped = false;
852
862
  bordered = false;
@@ -961,9 +971,21 @@ class CxsDataTableComponent {
961
971
  get toolbarInputClass() {
962
972
  return TOOLBAR_INPUT_CLASSES;
963
973
  }
974
+ get toolbarInputInlineClass() {
975
+ return TOOLBAR_INPUT_INLINE_CLASSES;
976
+ }
964
977
  get toolbarButtonClass() {
965
978
  return TOOLBAR_BUTTON_CLASSES;
966
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
+ }
967
989
  get bulkBarClass() {
968
990
  return BULK_BAR_CLASSES;
969
991
  }
@@ -1000,6 +1022,9 @@ class CxsDataTableComponent {
1000
1022
  get selectedCount() {
1001
1023
  return this.selectedKeys.length;
1002
1024
  }
1025
+ get hasTitleBlock() {
1026
+ return Boolean(this.title || this.subtitle);
1027
+ }
1003
1028
  get allVisibleSelected() {
1004
1029
  if (!this.displayRows.length) {
1005
1030
  return false;
@@ -1310,11 +1335,11 @@ class CxsDataTableComponent {
1310
1335
  return value;
1311
1336
  }
1312
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 });
1313
- 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" }, queries: [{ propertyName: "cellTemplates", predicate: CxsDataTableCellDirective }], 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 @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 });
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 });
1314
1339
  }
1315
1340
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDataTableComponent, decorators: [{
1316
1341
  type: Component,
1317
- args: [{ selector: 'cxs-data-table', standalone: true, imports: [NgTemplateOutlet], 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 @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" }]
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" }]
1318
1343
  }], ctorParameters: () => [{ type: undefined, decorators: [{
1319
1344
  type: Attribute,
1320
1345
  args: ['class']
@@ -1324,6 +1349,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
1324
1349
  type: Input
1325
1350
  }], caption: [{
1326
1351
  type: Input
1352
+ }], title: [{
1353
+ type: Input
1354
+ }], subtitle: [{
1355
+ type: Input
1327
1356
  }], ariaLabel: [{
1328
1357
  type: Input
1329
1358
  }], striped: [{
@@ -1496,11 +1525,11 @@ class CxsDialogComponent {
1496
1525
  });
1497
1526
  }
1498
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 });
1499
- 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 });
1500
1529
  }
1501
1530
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDialogComponent, decorators: [{
1502
1531
  type: Component,
1503
- 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" }]
1504
1533
  }], ctorParameters: () => [{ type: undefined, decorators: [{
1505
1534
  type: Attribute,
1506
1535
  args: ['class']
@@ -1535,7 +1564,10 @@ const BASE_CLASSES$3 = 'w-full rounded-[var(--cxs-radius-md)] border border-[var
1535
1564
  'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
1536
1565
  'focus-visible:outline-[var(--cxs-color-focus)] focus-visible:border-[var(--cxs-color-focus)] ' +
1537
1566
  'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-60';
1538
- 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 = {
1539
1571
  outline: 'bg-[var(--cxs-color-surface)]',
1540
1572
  filled: 'bg-[var(--cxs-color-surface-hover)]'
1541
1573
  };
@@ -1544,7 +1576,12 @@ const SIZE_CLASSES$2 = {
1544
1576
  md: 'h-10 px-3 text-sm',
1545
1577
  lg: 'h-12 px-4 text-base'
1546
1578
  };
1547
- 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)] ' +
1548
1585
  'focus-visible:outline-[var(--cxs-color-danger)]';
1549
1586
  const POPOVER_CLASSES = 'absolute left-0 top-full z-10 mt-2 w-full rounded-[var(--cxs-radius-md)] border ' +
1550
1587
  'border-[var(--cxs-color-border)] bg-[var(--cxs-color-surface)] p-3 shadow-[var(--cxs-shadow-sm)]';
@@ -1564,6 +1601,7 @@ const DAY_TODAY = 'border border-[var(--cxs-color-primary)]';
1564
1601
  const DAY_SELECTED = 'bg-[var(--cxs-color-primary)] text-[var(--cxs-color-on-primary)]';
1565
1602
  const DAY_HOVER = 'hover:bg-[var(--cxs-color-surface-hover)]';
1566
1603
  class CxsDatepickerComponent {
1604
+ static nextId = 0;
1567
1605
  value = '';
1568
1606
  variant = 'outline';
1569
1607
  size = 'md';
@@ -1573,6 +1611,7 @@ class CxsDatepickerComponent {
1573
1611
  required = false;
1574
1612
  invalid = false;
1575
1613
  autofocus = false;
1614
+ label;
1576
1615
  id;
1577
1616
  name;
1578
1617
  min;
@@ -1581,8 +1620,7 @@ class CxsDatepickerComponent {
1581
1620
  ariaLabel;
1582
1621
  ariaDescribedby;
1583
1622
  valueChange = new EventEmitter();
1584
- static nextId = 0;
1585
- fallbackId = `cxs-datepicker-panel-${CxsDatepickerComponent.nextId++}`;
1623
+ instanceId = `cxs-datepicker-${CxsDatepickerComponent.nextId++}`;
1586
1624
  disabledFromControl = false;
1587
1625
  onChange = () => { };
1588
1626
  onTouched = () => { };
@@ -1598,18 +1636,48 @@ class CxsDatepickerComponent {
1598
1636
  return this.disabled || this.disabledFromControl;
1599
1637
  }
1600
1638
  get panelId() {
1601
- return this.id ? `${this.id}-panel` : this.fallbackId;
1639
+ return `${this.inputId ?? this.instanceId}-panel`;
1602
1640
  }
1603
1641
  get inputClass() {
1604
1642
  return [
1605
1643
  BASE_CLASSES$3,
1606
1644
  SIZE_CLASSES$2[this.size],
1607
- VARIANT_CLASSES$3[this.variant],
1608
- this.invalid ? INVALID_CLASSES$3 : ''
1645
+ VARIANT_CLASSES$4[this.variant],
1646
+ this.invalid ? INVALID_CLASSES$4 : ''
1609
1647
  ]
1610
1648
  .filter(Boolean)
1611
1649
  .join(' ');
1612
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
+ }
1613
1681
  get popoverClass() {
1614
1682
  return POPOVER_CLASSES;
1615
1683
  }
@@ -1785,13 +1853,13 @@ class CxsDatepickerComponent {
1785
1853
  return new Date(date.getFullYear(), date.getMonth(), date.getDate());
1786
1854
  }
1787
1855
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDatepickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1788
- 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: [
1789
1857
  {
1790
1858
  provide: NG_VALUE_ACCESSOR,
1791
1859
  useExisting: forwardRef(() => CxsDatepickerComponent),
1792
1860
  multi: true
1793
1861
  }
1794
- ], 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 });
1795
1863
  }
1796
1864
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsDatepickerComponent, decorators: [{
1797
1865
  type: Component,
@@ -1801,7 +1869,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
1801
1869
  useExisting: forwardRef(() => CxsDatepickerComponent),
1802
1870
  multi: true
1803
1871
  }
1804
- ], 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" }]
1805
1873
  }], propDecorators: { value: [{
1806
1874
  type: Input
1807
1875
  }], variant: [{
@@ -1820,6 +1888,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
1820
1888
  type: Input
1821
1889
  }], autofocus: [{
1822
1890
  type: Input
1891
+ }], label: [{
1892
+ type: Input
1823
1893
  }], id: [{
1824
1894
  type: Input
1825
1895
  }], name: [{
@@ -1850,7 +1920,11 @@ const BASE_CLASSES$2 = 'w-full rounded-[var(--cxs-radius-md)] border border-[var
1850
1920
  'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
1851
1921
  'focus-visible:outline-[var(--cxs-color-focus)] focus-visible:border-[var(--cxs-color-focus)] ' +
1852
1922
  'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-60';
1853
- 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 = {
1854
1928
  outline: 'bg-[var(--cxs-color-surface)]',
1855
1929
  filled: 'bg-[var(--cxs-color-surface-hover)]'
1856
1930
  };
@@ -1859,9 +1933,20 @@ const SIZE_CLASSES$1 = {
1859
1933
  md: 'h-10 px-3 text-sm',
1860
1934
  lg: 'h-12 px-4 text-base'
1861
1935
  };
1862
- 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)] ' +
1863
1947
  'focus-visible:outline-[var(--cxs-color-danger)]';
1864
1948
  class CxsInputComponent {
1949
+ static nextId = 0;
1865
1950
  value = '';
1866
1951
  type = 'text';
1867
1952
  variant = 'outline';
@@ -1871,6 +1956,7 @@ class CxsInputComponent {
1871
1956
  required = false;
1872
1957
  invalid = false;
1873
1958
  autofocus = false;
1959
+ label;
1874
1960
  id;
1875
1961
  name;
1876
1962
  placeholder;
@@ -1880,6 +1966,7 @@ class CxsInputComponent {
1880
1966
  ariaLabel;
1881
1967
  ariaDescribedby;
1882
1968
  valueChange = new EventEmitter();
1969
+ instanceId = `cxs-input-${CxsInputComponent.nextId++}`;
1883
1970
  disabledFromControl = false;
1884
1971
  onChange = () => { };
1885
1972
  onTouched = () => { };
@@ -1890,12 +1977,55 @@ class CxsInputComponent {
1890
1977
  return [
1891
1978
  BASE_CLASSES$2,
1892
1979
  SIZE_CLASSES$1[this.size],
1893
- VARIANT_CLASSES$2[this.variant],
1894
- this.invalid ? INVALID_CLASSES$2 : ''
1980
+ VARIANT_CLASSES$3[this.variant],
1981
+ this.invalid ? INVALID_CLASSES$3 : ''
1895
1982
  ]
1896
1983
  .filter(Boolean)
1897
1984
  .join(' ');
1898
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
+ }
1899
2029
  writeValue(value) {
1900
2030
  this.value = value ?? '';
1901
2031
  }
@@ -1919,23 +2049,23 @@ class CxsInputComponent {
1919
2049
  this.onTouched();
1920
2050
  }
1921
2051
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1922
- 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: [
1923
2053
  {
1924
2054
  provide: NG_VALUE_ACCESSOR,
1925
2055
  useExisting: forwardRef(() => CxsInputComponent),
1926
2056
  multi: true
1927
2057
  }
1928
- ], 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 });
1929
2059
  }
1930
2060
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsInputComponent, decorators: [{
1931
2061
  type: Component,
1932
- args: [{ selector: 'cxs-input', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
2062
+ args: [{ selector: 'cxs-input', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
1933
2063
  {
1934
2064
  provide: NG_VALUE_ACCESSOR,
1935
2065
  useExisting: forwardRef(() => CxsInputComponent),
1936
2066
  multi: true
1937
2067
  }
1938
- ], 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" }]
1939
2069
  }], propDecorators: { value: [{
1940
2070
  type: Input
1941
2071
  }], type: [{
@@ -1954,6 +2084,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
1954
2084
  type: Input
1955
2085
  }], autofocus: [{
1956
2086
  type: Input
2087
+ }], label: [{
2088
+ type: Input
1957
2089
  }], id: [{
1958
2090
  type: Input
1959
2091
  }], name: [{
@@ -2115,12 +2247,467 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2115
2247
  args: ['menuItem', { read: ElementRef }]
2116
2248
  }] } });
2117
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
+
2118
2705
  const WRAPPER_BASE = 'inline-flex items-center gap-2 select-none';
2119
2706
  const WRAPPER_ENABLED = 'cursor-pointer';
2120
2707
  const WRAPPER_DISABLED = 'cursor-not-allowed opacity-60';
2121
2708
  const LABEL_BASE = 'text-[var(--cxs-color-on-surface)]';
2122
2709
  const LABEL_DISABLED = 'text-[var(--cxs-color-on-surface-muted)]';
2123
- const LABEL_SIZE_CLASSES = {
2710
+ const LABEL_SIZE_CLASSES$1 = {
2124
2711
  sm: 'text-sm',
2125
2712
  md: 'text-sm',
2126
2713
  lg: 'text-base'
@@ -2179,7 +2766,7 @@ class CxsRadioComponent {
2179
2766
  get labelClass() {
2180
2767
  return [
2181
2768
  LABEL_BASE,
2182
- LABEL_SIZE_CLASSES[this.size],
2769
+ LABEL_SIZE_CLASSES$1[this.size],
2183
2770
  this.isDisabled ? LABEL_DISABLED : ''
2184
2771
  ]
2185
2772
  .filter(Boolean)
@@ -2270,6 +2857,9 @@ const BASE_CLASSES$1 = 'w-full appearance-none rounded-[var(--cxs-radius-md)] bo
2270
2857
  'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
2271
2858
  'focus-visible:outline-[var(--cxs-color-focus)] focus-visible:border-[var(--cxs-color-focus)] ' +
2272
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)]';
2273
2863
  const VARIANT_CLASSES$1 = {
2274
2864
  outline: 'bg-[var(--cxs-color-surface)]',
2275
2865
  filled: 'bg-[var(--cxs-color-surface-hover)]'
@@ -2279,15 +2869,22 @@ const SIZE_CLASSES = {
2279
2869
  md: 'h-10 pl-3 pr-9 text-sm',
2280
2870
  lg: 'h-12 pl-4 pr-10 text-base'
2281
2871
  };
2872
+ const LABEL_SIZE_CLASSES = {
2873
+ sm: 'text-sm',
2874
+ md: 'text-sm',
2875
+ lg: 'text-base'
2876
+ };
2282
2877
  const INVALID_CLASSES = 'border-[var(--cxs-color-danger)] focus-visible:border-[var(--cxs-color-danger)] ' +
2283
2878
  'focus-visible:outline-[var(--cxs-color-danger)]';
2284
2879
  class CxsSelectComponent {
2880
+ static nextId = 0;
2285
2881
  value = '';
2286
2882
  variant = 'outline';
2287
2883
  size = 'md';
2288
2884
  disabled = false;
2289
2885
  required = false;
2290
2886
  invalid = false;
2887
+ label;
2291
2888
  placeholder;
2292
2889
  placeholderValue = '';
2293
2890
  id;
@@ -2295,6 +2892,7 @@ class CxsSelectComponent {
2295
2892
  ariaLabel;
2296
2893
  ariaDescribedby;
2297
2894
  valueChange = new EventEmitter();
2895
+ instanceId = `cxs-select-${CxsSelectComponent.nextId++}`;
2298
2896
  disabledFromControl = false;
2299
2897
  onChange = () => { };
2300
2898
  onTouched = () => { };
@@ -2311,6 +2909,36 @@ class CxsSelectComponent {
2311
2909
  .filter(Boolean)
2312
2910
  .join(' ');
2313
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
+ }
2314
2942
  get selectValue() {
2315
2943
  if (this.placeholder && this.value === '') {
2316
2944
  return this.placeholderValue;
@@ -2340,13 +2968,13 @@ class CxsSelectComponent {
2340
2968
  this.onTouched();
2341
2969
  }
2342
2970
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2343
- 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: [
2344
2972
  {
2345
2973
  provide: NG_VALUE_ACCESSOR,
2346
2974
  useExisting: forwardRef(() => CxsSelectComponent),
2347
2975
  multi: true
2348
2976
  }
2349
- ], 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 });
2350
2978
  }
2351
2979
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsSelectComponent, decorators: [{
2352
2980
  type: Component,
@@ -2356,7 +2984,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2356
2984
  useExisting: forwardRef(() => CxsSelectComponent),
2357
2985
  multi: true
2358
2986
  }
2359
- ], 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" }]
2360
2988
  }], propDecorators: { value: [{
2361
2989
  type: Input
2362
2990
  }], variant: [{
@@ -2369,6 +2997,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2369
2997
  type: Input
2370
2998
  }], invalid: [{
2371
2999
  type: Input
3000
+ }], label: [{
3001
+ type: Input
2372
3002
  }], placeholder: [{
2373
3003
  type: Input
2374
3004
  }], placeholderValue: [{
@@ -2509,25 +3139,25 @@ const TRACK_BASE_CLASSES = 'relative inline-flex items-center rounded-full borde
2509
3139
  'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 ' +
2510
3140
  'focus-visible:outline-[var(--cxs-color-focus)] disabled:pointer-events-none disabled:opacity-60';
2511
3141
  const TRACK_SIZE_CLASSES = {
2512
- sm: 'h-5 w-9 p-0.5',
3142
+ sm: 'h-6 w-11 p-0.5',
2513
3143
  md: 'h-6 w-11 p-0.5',
2514
- lg: 'h-8 w-14 p-0.5'
3144
+ lg: 'h-6 w-11 p-0.5'
2515
3145
  };
2516
3146
  const TRACK_STATE_CLASSES = {
2517
3147
  on: 'bg-[var(--cxs-color-primary)] border-[var(--cxs-color-primary)]',
2518
- off: 'bg-[var(--cxs-color-surface)] border-[var(--cxs-color-border)]'
3148
+ off: 'bg-[var(--cxs-color-surface-hover)] border-[var(--cxs-color-border)]'
2519
3149
  };
2520
- 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';
2521
3151
  const THUMB_SIZE_CLASSES = {
2522
- sm: 'h-4 w-4',
3152
+ sm: 'h-5 w-5',
2523
3153
  md: 'h-5 w-5',
2524
- lg: 'h-7 w-7'
3154
+ lg: 'h-5 w-5'
2525
3155
  };
2526
3156
  const THUMB_STATE_CLASSES = {
2527
3157
  on: {
2528
- sm: 'translate-x-[18px] bg-[var(--cxs-color-on-primary)]',
2529
- md: 'translate-x-[22px] bg-[var(--cxs-color-on-primary)]',
2530
- 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)]'
2531
3161
  },
2532
3162
  off: 'translate-x-0 bg-[var(--cxs-color-surface)]'
2533
3163
  };
@@ -2710,11 +3340,11 @@ class CxsToastComponent {
2710
3340
  }
2711
3341
  }
2712
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 });
2713
- 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 });
2714
3344
  }
2715
3345
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CxsToastComponent, decorators: [{
2716
3346
  type: Component,
2717
- 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" }]
2718
3348
  }], ctorParameters: () => [{ type: undefined, decorators: [{
2719
3349
  type: Attribute,
2720
3350
  args: ['class']
@@ -2932,5 +3562,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2932
3562
  * Generated bundle index. Do not edit.
2933
3563
  */
2934
3564
 
2935
- export { CerxosUi, CxsAccordionComponent, CxsAccordionItemComponent, CxsAlertComponent, CxsAvatarComponent, CxsBadgeComponent, CxsBreadcrumbComponent, CxsButtonComponent, CxsCardComponent, CxsCarouselComponent, CxsCheckboxComponent, CxsDataTableCellDirective, 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 };
2936
3566
  //# sourceMappingURL=cerxos-ui.mjs.map