cerxos-ui 0.0.23 → 0.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/cerxos-ui.mjs +108 -15
- package/fesm2022/cerxos-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/cerxos-ui.d.ts +28 -5
package/fesm2022/cerxos-ui.mjs
CHANGED
|
@@ -1250,6 +1250,39 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
1250
1250
|
args: ['cxsDataTableCell']
|
|
1251
1251
|
}] } });
|
|
1252
1252
|
|
|
1253
|
+
/** Prefix of the browser storage entry that holds a table's rows-per-page choice. */
|
|
1254
|
+
const CXS_DATA_TABLE_PAGE_SIZE_STORAGE_PREFIX = 'cxs-data-table:page-size:';
|
|
1255
|
+
/**
|
|
1256
|
+
* Reads the rows-per-page choice saved under `key`.
|
|
1257
|
+
* Returns `fallback` when nothing is saved, the saved value is not one of `options`,
|
|
1258
|
+
* or browser storage is unavailable.
|
|
1259
|
+
*/
|
|
1260
|
+
function readCxsDataTablePageSize(key, options, fallback) {
|
|
1261
|
+
try {
|
|
1262
|
+
const raw = getLocalStorage()?.getItem(CXS_DATA_TABLE_PAGE_SIZE_STORAGE_PREFIX + key);
|
|
1263
|
+
if (raw === null || raw === undefined) {
|
|
1264
|
+
return fallback;
|
|
1265
|
+
}
|
|
1266
|
+
const parsed = raw === 'all' ? 'all' : Number(raw);
|
|
1267
|
+
return options.includes(parsed) ? parsed : fallback;
|
|
1268
|
+
}
|
|
1269
|
+
catch {
|
|
1270
|
+
return fallback;
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
/** Saves the rows-per-page choice under `key`. Storage failures are ignored. */
|
|
1274
|
+
function writeCxsDataTablePageSize(key, size) {
|
|
1275
|
+
try {
|
|
1276
|
+
getLocalStorage()?.setItem(CXS_DATA_TABLE_PAGE_SIZE_STORAGE_PREFIX + key, String(size));
|
|
1277
|
+
}
|
|
1278
|
+
catch {
|
|
1279
|
+
// Storage can be blocked or full; the table still works without remembering.
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
function getLocalStorage() {
|
|
1283
|
+
return typeof localStorage === 'undefined' ? null : localStorage;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1253
1286
|
const WRAPPER_BASE_CLASSES$1 = 'w-full overflow-x-auto';
|
|
1254
1287
|
const WRAPPER_OVERFLOW_HIDDEN_CLASSES = 'overflow-y-hidden';
|
|
1255
1288
|
const WRAPPER_OVERFLOW_VISIBLE_CLASSES = 'overflow-y-visible';
|
|
@@ -1270,7 +1303,7 @@ const HEADER_FILTER_INPUT_CLASSES = 'w-full rounded-[var(--cxs-radius-md)] borde
|
|
|
1270
1303
|
'focus-visible:outline-offset-2 focus-visible:outline-[var(--cxs-color-focus)]';
|
|
1271
1304
|
const BODY_ROW_BASE_CLASSES$1 = 'border-b border-[var(--cxs-color-border)] last:border-b-0';
|
|
1272
1305
|
const BODY_ROW_STRIPED_CLASSES$1 = 'odd:bg-[var(--cxs-color-surface)] even:bg-[var(--cxs-color-surface-hover)]';
|
|
1273
|
-
const BODY_CELL_BASE_CLASSES$1 = 'px-3 py-2 align-
|
|
1306
|
+
const BODY_CELL_BASE_CLASSES$1 = 'px-3 py-2 align-middle';
|
|
1274
1307
|
const BODY_CELL_COMPACT_CLASSES$1 = 'px-2 py-1.5';
|
|
1275
1308
|
const ALIGN_CLASSES$2 = {
|
|
1276
1309
|
left: 'text-left',
|
|
@@ -1323,6 +1356,7 @@ class CxsDataTableComponent {
|
|
|
1323
1356
|
pageSize = 10;
|
|
1324
1357
|
pageIndex = 1;
|
|
1325
1358
|
pageSizeOptions = [10, 20, 50];
|
|
1359
|
+
pageSizeStorageKey;
|
|
1326
1360
|
showPagination = true;
|
|
1327
1361
|
showPageSize = true;
|
|
1328
1362
|
manualPagination = false;
|
|
@@ -1346,8 +1380,10 @@ class CxsDataTableComponent {
|
|
|
1346
1380
|
selectionChange = new EventEmitter();
|
|
1347
1381
|
bulkAction = new EventEmitter();
|
|
1348
1382
|
cellTemplates;
|
|
1383
|
+
columnsPanel;
|
|
1384
|
+
columnsPanelSummary;
|
|
1349
1385
|
currentPage = 1;
|
|
1350
|
-
|
|
1386
|
+
selectedPageSize = 10;
|
|
1351
1387
|
globalFilter = '';
|
|
1352
1388
|
columnFilters = {};
|
|
1353
1389
|
columnVisibility = {};
|
|
@@ -1357,6 +1393,7 @@ class CxsDataTableComponent {
|
|
|
1357
1393
|
pinnedOffsetsLeft = {};
|
|
1358
1394
|
pinnedOffsetsRight = {};
|
|
1359
1395
|
filtersOpen = true;
|
|
1396
|
+
columnsPanelOpen = false;
|
|
1360
1397
|
resizeStartX = 0;
|
|
1361
1398
|
resizeStartWidth = 0;
|
|
1362
1399
|
constructor(hostClass) {
|
|
@@ -1367,7 +1404,10 @@ class CxsDataTableComponent {
|
|
|
1367
1404
|
this.currentPage = Math.max(1, this.pageIndex);
|
|
1368
1405
|
}
|
|
1369
1406
|
if (changes['pageSize']) {
|
|
1370
|
-
this.
|
|
1407
|
+
this.selectedPageSize = this.pageSize === 0 ? 'all' : Math.max(1, this.pageSize);
|
|
1408
|
+
}
|
|
1409
|
+
if ((changes['pageSizeStorageKey'] || changes['pageSizeOptions']) && this.pageSizeStorageKey) {
|
|
1410
|
+
this.selectedPageSize = readCxsDataTablePageSize(this.pageSizeStorageKey, this.pageSizeOptions, this.selectedPageSize);
|
|
1371
1411
|
}
|
|
1372
1412
|
if (changes['columns']) {
|
|
1373
1413
|
this.initializeVisibility();
|
|
@@ -1465,7 +1505,13 @@ class CxsDataTableComponent {
|
|
|
1465
1505
|
return this.data.length;
|
|
1466
1506
|
}
|
|
1467
1507
|
get totalPages() {
|
|
1468
|
-
|
|
1508
|
+
if (this.selectedPageSize === 'all') {
|
|
1509
|
+
return 1;
|
|
1510
|
+
}
|
|
1511
|
+
return Math.max(1, Math.ceil(this.totalItems / this.selectedPageSize));
|
|
1512
|
+
}
|
|
1513
|
+
get pageSizeValue() {
|
|
1514
|
+
return String(this.selectedPageSize);
|
|
1469
1515
|
}
|
|
1470
1516
|
get pageLabel() {
|
|
1471
1517
|
return `Page ${this.currentPage} of ${this.totalPages}`;
|
|
@@ -1473,11 +1519,11 @@ class CxsDataTableComponent {
|
|
|
1473
1519
|
get displayRows() {
|
|
1474
1520
|
const filtered = this.manualFilter ? this.data : this.getFilteredData(this.data);
|
|
1475
1521
|
const sorted = this.manualSort ? filtered : this.getSortedData(filtered);
|
|
1476
|
-
if (this.manualPagination) {
|
|
1522
|
+
if (this.manualPagination || this.selectedPageSize === 'all') {
|
|
1477
1523
|
return sorted;
|
|
1478
1524
|
}
|
|
1479
|
-
const start = (this.currentPage - 1) * this.
|
|
1480
|
-
return sorted.slice(start, start + this.
|
|
1525
|
+
const start = (this.currentPage - 1) * this.selectedPageSize;
|
|
1526
|
+
return sorted.slice(start, start + this.selectedPageSize);
|
|
1481
1527
|
}
|
|
1482
1528
|
get visibleColumns() {
|
|
1483
1529
|
return this.columns.filter((column) => this.columnVisibility[column.key] !== false);
|
|
@@ -1608,13 +1654,28 @@ class CxsDataTableComponent {
|
|
|
1608
1654
|
previousPage() {
|
|
1609
1655
|
this.goToPage(this.currentPage - 1);
|
|
1610
1656
|
}
|
|
1657
|
+
pageSizeLabel(size) {
|
|
1658
|
+
return size === 'all' ? 'All' : String(size);
|
|
1659
|
+
}
|
|
1660
|
+
isPageSizeSelected(size) {
|
|
1661
|
+
return size === this.selectedPageSize;
|
|
1662
|
+
}
|
|
1611
1663
|
onPageSizeChange(value) {
|
|
1612
|
-
|
|
1613
|
-
if (
|
|
1614
|
-
|
|
1664
|
+
let nextSize;
|
|
1665
|
+
if (value === 'all') {
|
|
1666
|
+
nextSize = 'all';
|
|
1615
1667
|
}
|
|
1616
|
-
|
|
1617
|
-
|
|
1668
|
+
else {
|
|
1669
|
+
nextSize = Number(value);
|
|
1670
|
+
if (!Number.isFinite(nextSize) || nextSize <= 0) {
|
|
1671
|
+
return;
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
this.selectedPageSize = nextSize;
|
|
1675
|
+
if (this.pageSizeStorageKey) {
|
|
1676
|
+
writeCxsDataTablePageSize(this.pageSizeStorageKey, nextSize);
|
|
1677
|
+
}
|
|
1678
|
+
this.pageSizeChange.emit(nextSize === 'all' ? 0 : nextSize);
|
|
1618
1679
|
this.goToPage(1);
|
|
1619
1680
|
}
|
|
1620
1681
|
onGlobalFilterChange(value) {
|
|
@@ -1630,6 +1691,27 @@ class CxsDataTableComponent {
|
|
|
1630
1691
|
columnFilterValue(columnKey) {
|
|
1631
1692
|
return this.columnFilters[columnKey] || '';
|
|
1632
1693
|
}
|
|
1694
|
+
onColumnsPanelToggle(event) {
|
|
1695
|
+
this.columnsPanelOpen = event.target.open;
|
|
1696
|
+
}
|
|
1697
|
+
closeColumnsPanel(restoreFocus) {
|
|
1698
|
+
if (!this.columnsPanelOpen) {
|
|
1699
|
+
return;
|
|
1700
|
+
}
|
|
1701
|
+
this.columnsPanelOpen = false;
|
|
1702
|
+
if (restoreFocus) {
|
|
1703
|
+
this.columnsPanelSummary?.nativeElement.focus();
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
onDocumentClick(event) {
|
|
1707
|
+
if (!this.columnsPanelOpen) {
|
|
1708
|
+
return;
|
|
1709
|
+
}
|
|
1710
|
+
const target = event.target;
|
|
1711
|
+
if (target && !this.columnsPanel?.nativeElement.contains(target)) {
|
|
1712
|
+
this.closeColumnsPanel(false);
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1633
1715
|
toggleColumnVisibility(columnKey) {
|
|
1634
1716
|
this.columnVisibility[columnKey] = !this.columnVisibility[columnKey];
|
|
1635
1717
|
this.updatePinnedOffsets();
|
|
@@ -1800,11 +1882,11 @@ class CxsDataTableComponent {
|
|
|
1800
1882
|
return value;
|
|
1801
1883
|
}
|
|
1802
1884
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsDataTableComponent, deps: [{ token: 'class', attribute: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
1803
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", 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", allowOverflow: "allowOverflow", columnBorders: "columnBorders", 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 <div [class]=\"toolbarInputWrapperClass\">\n <svg\n [class]=\"toolbarInputIconClass\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"m21 21-4.35-4.35m1.85-5.65a7.5 7.5 0 1 1-15 0 7.5 7.5 0 0 1 15 0Z\"\n />\n </svg>\n <input\n type=\"search\"\n [class]=\"toolbarInputInlineClass\"\n placeholder=\"Search...\"\n [value]=\"globalFilter\"\n (input)=\"onGlobalFilterChange($any($event.target).value)\"\n />\n </div>\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 <div [class]=\"toolbarInputWrapperClass\">\n <svg\n [class]=\"toolbarInputIconClass\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"m21 21-4.35-4.35m1.85-5.65a7.5 7.5 0 1 1-15 0 7.5 7.5 0 0 1 15 0Z\"\n />\n </svg>\n <input\n type=\"search\"\n [class]=\"toolbarInputClass\"\n placeholder=\"Search...\"\n [value]=\"globalFilter\"\n (input)=\"onGlobalFilterChange($any($event.target).value)\"\n />\n </div>\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 });
|
|
1885
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", 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", allowOverflow: "allowOverflow", columnBorders: "columnBorders", pageSize: "pageSize", pageIndex: "pageIndex", pageSizeOptions: "pageSizeOptions", pageSizeStorageKey: "pageSizeStorageKey", 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" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, queries: [{ propertyName: "cellTemplates", predicate: CxsDataTableCellDirective }], viewQueries: [{ propertyName: "columnsPanel", first: true, predicate: ["columnsPanel"], descendants: true, read: ElementRef }, { propertyName: "columnsPanelSummary", first: true, predicate: ["columnsPanelSummary"], descendants: true, read: ElementRef }], usesOnChanges: true, ngImport: i0, template: "<ng-template #columnsPanelTemplate>\n <details\n #columnsPanel\n class=\"relative\"\n [open]=\"columnsPanelOpen\"\n (toggle)=\"onColumnsPanelToggle($event)\"\n (keydown.escape)=\"closeColumnsPanel(true)\"\n >\n <summary #columnsPanelSummary [class]=\"toolbarButtonClass\">Columns</summary>\n <div\n class=\"absolute right-0 z-40 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</ng-template>\n\n@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 <div [class]=\"toolbarInputWrapperClass\">\n <svg\n [class]=\"toolbarInputIconClass\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"m21 21-4.35-4.35m1.85-5.65a7.5 7.5 0 1 1-15 0 7.5 7.5 0 0 1 15 0Z\"\n />\n </svg>\n <input\n type=\"search\"\n [class]=\"toolbarInputInlineClass\"\n placeholder=\"Search...\"\n [value]=\"globalFilter\"\n (input)=\"onGlobalFilterChange($any($event.target).value)\"\n />\n </div>\n }\n @if (showFilters) {\n <button type=\"button\" [class]=\"toolbarButtonClass\" (click)=\"filtersOpen = !filtersOpen\">\n Filters\n </button>\n }\n @if (showColumnVisibility) {\n <ng-container [ngTemplateOutlet]=\"columnsPanelTemplate\"></ng-container>\n }\n </div>\n }\n </div>\n} @else if (showToolbar) {\n <div [class]=\"toolbarClass\">\n <div [class]=\"toolbarGroupClass\">\n @if (showGlobalSearch) {\n <div [class]=\"toolbarInputWrapperClass\">\n <svg\n [class]=\"toolbarInputIconClass\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"m21 21-4.35-4.35m1.85-5.65a7.5 7.5 0 1 1-15 0 7.5 7.5 0 0 1 15 0Z\"\n />\n </svg>\n <input\n type=\"search\"\n [class]=\"toolbarInputClass\"\n placeholder=\"Search...\"\n [value]=\"globalFilter\"\n (input)=\"onGlobalFilterChange($any($event.target).value)\"\n />\n </div>\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 <ng-container [ngTemplateOutlet]=\"columnsPanelTemplate\"></ng-container>\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]=\"pageSizeValue\"\n (change)=\"onPageSizeChange(pageSizeSelect.value)\"\n >\n @for (size of pageSizeOptions; track size) {\n <option [value]=\"size\" [selected]=\"isPageSizeSelected(size)\">{{ pageSizeLabel(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 });
|
|
1804
1886
|
}
|
|
1805
1887
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: CxsDataTableComponent, decorators: [{
|
|
1806
1888
|
type: Component,
|
|
1807
|
-
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 <div [class]=\"toolbarInputWrapperClass\">\n <svg\n [class]=\"toolbarInputIconClass\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"m21 21-4.35-4.35m1.85-5.65a7.5 7.5 0 1 1-15 0 7.5 7.5 0 0 1 15 0Z\"\n />\n </svg>\n <input\n type=\"search\"\n [class]=\"toolbarInputInlineClass\"\n placeholder=\"Search...\"\n [value]=\"globalFilter\"\n (input)=\"onGlobalFilterChange($any($event.target).value)\"\n />\n </div>\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 <div [class]=\"toolbarInputWrapperClass\">\n <svg\n [class]=\"toolbarInputIconClass\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"m21 21-4.35-4.35m1.85-5.65a7.5 7.5 0 1 1-15 0 7.5 7.5 0 0 1 15 0Z\"\n />\n </svg>\n <input\n type=\"search\"\n [class]=\"toolbarInputClass\"\n placeholder=\"Search...\"\n [value]=\"globalFilter\"\n (input)=\"onGlobalFilterChange($any($event.target).value)\"\n />\n </div>\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" }]
|
|
1889
|
+
args: [{ selector: 'cxs-data-table', standalone: true, imports: [NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-template #columnsPanelTemplate>\n <details\n #columnsPanel\n class=\"relative\"\n [open]=\"columnsPanelOpen\"\n (toggle)=\"onColumnsPanelToggle($event)\"\n (keydown.escape)=\"closeColumnsPanel(true)\"\n >\n <summary #columnsPanelSummary [class]=\"toolbarButtonClass\">Columns</summary>\n <div\n class=\"absolute right-0 z-40 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</ng-template>\n\n@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 <div [class]=\"toolbarInputWrapperClass\">\n <svg\n [class]=\"toolbarInputIconClass\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"m21 21-4.35-4.35m1.85-5.65a7.5 7.5 0 1 1-15 0 7.5 7.5 0 0 1 15 0Z\"\n />\n </svg>\n <input\n type=\"search\"\n [class]=\"toolbarInputInlineClass\"\n placeholder=\"Search...\"\n [value]=\"globalFilter\"\n (input)=\"onGlobalFilterChange($any($event.target).value)\"\n />\n </div>\n }\n @if (showFilters) {\n <button type=\"button\" [class]=\"toolbarButtonClass\" (click)=\"filtersOpen = !filtersOpen\">\n Filters\n </button>\n }\n @if (showColumnVisibility) {\n <ng-container [ngTemplateOutlet]=\"columnsPanelTemplate\"></ng-container>\n }\n </div>\n }\n </div>\n} @else if (showToolbar) {\n <div [class]=\"toolbarClass\">\n <div [class]=\"toolbarGroupClass\">\n @if (showGlobalSearch) {\n <div [class]=\"toolbarInputWrapperClass\">\n <svg\n [class]=\"toolbarInputIconClass\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n aria-hidden=\"true\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"m21 21-4.35-4.35m1.85-5.65a7.5 7.5 0 1 1-15 0 7.5 7.5 0 0 1 15 0Z\"\n />\n </svg>\n <input\n type=\"search\"\n [class]=\"toolbarInputClass\"\n placeholder=\"Search...\"\n [value]=\"globalFilter\"\n (input)=\"onGlobalFilterChange($any($event.target).value)\"\n />\n </div>\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 <ng-container [ngTemplateOutlet]=\"columnsPanelTemplate\"></ng-container>\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]=\"pageSizeValue\"\n (change)=\"onPageSizeChange(pageSizeSelect.value)\"\n >\n @for (size of pageSizeOptions; track size) {\n <option [value]=\"size\" [selected]=\"isPageSizeSelected(size)\">{{ pageSizeLabel(size) }}</option>\n }\n </select>\n </label>\n }\n </div>\n}\n" }]
|
|
1808
1890
|
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
1809
1891
|
type: Attribute,
|
|
1810
1892
|
args: ['class']
|
|
@@ -1842,6 +1924,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
1842
1924
|
type: Input
|
|
1843
1925
|
}], pageSizeOptions: [{
|
|
1844
1926
|
type: Input
|
|
1927
|
+
}], pageSizeStorageKey: [{
|
|
1928
|
+
type: Input
|
|
1845
1929
|
}], showPagination: [{
|
|
1846
1930
|
type: Input
|
|
1847
1931
|
}], showPageSize: [{
|
|
@@ -1889,6 +1973,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
1889
1973
|
}], cellTemplates: [{
|
|
1890
1974
|
type: ContentChildren,
|
|
1891
1975
|
args: [CxsDataTableCellDirective]
|
|
1976
|
+
}], columnsPanel: [{
|
|
1977
|
+
type: ViewChild,
|
|
1978
|
+
args: ['columnsPanel', { read: ElementRef }]
|
|
1979
|
+
}], columnsPanelSummary: [{
|
|
1980
|
+
type: ViewChild,
|
|
1981
|
+
args: ['columnsPanelSummary', { read: ElementRef }]
|
|
1982
|
+
}], onDocumentClick: [{
|
|
1983
|
+
type: HostListener,
|
|
1984
|
+
args: ['document:click', ['$event']]
|
|
1892
1985
|
}] } });
|
|
1893
1986
|
|
|
1894
1987
|
const OVERLAY_CLASSES = 'cxs-dialog-overlay fixed inset-0 z-50 flex items-center justify-center bg-[rgba(15,23,42,0.45)] p-4';
|
|
@@ -5200,5 +5293,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImpo
|
|
|
5200
5293
|
* Generated bundle index. Do not edit.
|
|
5201
5294
|
*/
|
|
5202
5295
|
|
|
5203
|
-
export { CXS_USER_PREFERENCE_CHANGED_EVENT, CXS_USER_SESSION_STORAGE_KEY, CerxosUi, CxsAccordionComponent, CxsAccordionItemComponent, CxsActionMenuComponent, CxsAlertComponent, CxsAvatarComponent, CxsBadgeComponent, CxsBreadcrumbComponent, CxsButtonComponent, CxsCardComponent, CxsCarouselComponent, CxsCheckboxComponent, CxsCurrencyPipe, CxsDataTableCellDirective, CxsDataTableComponent, CxsDatePipe, CxsDatepickerComponent, CxsDialogComponent, CxsHabitGridComponent, CxsHoverCardComponent, CxsHoverCardContentDirective, CxsHoverCardTriggerDirective, CxsIconComponent, CxsInputComponent, CxsMenubarComponent, CxsMultiSelectComponent, CxsPreferenceFormattingService, CxsProgressBarComponent, CxsRadioChipGroupComponent, CxsRadioComponent, CxsSelectComponent, CxsSkeletonComponent, CxsSliderComponent, CxsTabLabelDirective, CxsTabPanelComponent, CxsTableComponent, CxsTabsComponent, CxsThemeDirective, CxsToastComponent, CxsToggleComponent, CxsTooltipComponent };
|
|
5296
|
+
export { CXS_DATA_TABLE_PAGE_SIZE_STORAGE_PREFIX, CXS_USER_PREFERENCE_CHANGED_EVENT, CXS_USER_SESSION_STORAGE_KEY, CerxosUi, CxsAccordionComponent, CxsAccordionItemComponent, CxsActionMenuComponent, CxsAlertComponent, CxsAvatarComponent, CxsBadgeComponent, CxsBreadcrumbComponent, CxsButtonComponent, CxsCardComponent, CxsCarouselComponent, CxsCheckboxComponent, CxsCurrencyPipe, CxsDataTableCellDirective, CxsDataTableComponent, CxsDatePipe, CxsDatepickerComponent, CxsDialogComponent, CxsHabitGridComponent, CxsHoverCardComponent, CxsHoverCardContentDirective, CxsHoverCardTriggerDirective, CxsIconComponent, CxsInputComponent, CxsMenubarComponent, CxsMultiSelectComponent, CxsPreferenceFormattingService, CxsProgressBarComponent, CxsRadioChipGroupComponent, CxsRadioComponent, CxsSelectComponent, CxsSkeletonComponent, CxsSliderComponent, CxsTabLabelDirective, CxsTabPanelComponent, CxsTableComponent, CxsTabsComponent, CxsThemeDirective, CxsToastComponent, CxsToggleComponent, CxsTooltipComponent, readCxsDataTablePageSize, writeCxsDataTablePageSize };
|
|
5204
5297
|
//# sourceMappingURL=cerxos-ui.mjs.map
|