@frame-kit/ui-ng 0.2.21 → 0.2.23
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/frame-kit-ui-ng-ui-data-table.mjs +17 -3
- package/fesm2022/frame-kit-ui-ng-ui-data-table.mjs.map +1 -1
- package/fesm2022/frame-kit-ui-ng-ui-list-editor.mjs +2 -5
- package/fesm2022/frame-kit-ui-ng-ui-list-editor.mjs.map +1 -1
- package/package.json +2 -2
- package/types/frame-kit-ui-ng-ui-data-table.d.ts +12 -1
- package/ui/data-table/README.md +12 -3
|
@@ -440,6 +440,11 @@ class TableEngineService {
|
|
|
440
440
|
controlledSortState = signal(undefined, ...(ngDevMode ? [{ debugName: "controlledSortState" }] : /* istanbul ignore next */ []));
|
|
441
441
|
controlledFilterState = signal(undefined, ...(ngDevMode ? [{ debugName: "controlledFilterState" }] : /* istanbul ignore next */ []));
|
|
442
442
|
controlledPageState = signal(undefined, ...(ngDevMode ? [{ debugName: "controlledPageState" }] : /* istanbul ignore next */ []));
|
|
443
|
+
/**
|
|
444
|
+
* When true the rows arrive already sorted (by a server, for the current
|
|
445
|
+
* sort state) and are kept in the order given.
|
|
446
|
+
*/
|
|
447
|
+
manualSorting = signal(false, ...(ngDevMode ? [{ debugName: "manualSorting" }] : /* istanbul ignore next */ []));
|
|
443
448
|
// ===== EFFECTIVE STATE =====
|
|
444
449
|
sortState = computed(() => {
|
|
445
450
|
const controlled = this.controlledSortState();
|
|
@@ -478,7 +483,7 @@ class TableEngineService {
|
|
|
478
483
|
sortedRows = computed(() => {
|
|
479
484
|
const rows = this.rows();
|
|
480
485
|
const sort = this.sortState();
|
|
481
|
-
if (!sort || !sort.direction) {
|
|
486
|
+
if (this.manualSorting() || !sort || !sort.direction) {
|
|
482
487
|
return rows;
|
|
483
488
|
}
|
|
484
489
|
const column = this.columns().find((c) => c.id === sort.columnId);
|
|
@@ -741,6 +746,12 @@ class DataTableComponent {
|
|
|
741
746
|
// ===== CONTROLLED STATE =====
|
|
742
747
|
/** Controlled sort state; pass null to let the table manage sorting internally. */
|
|
743
748
|
sortState = input(null, ...(ngDevMode ? [{ debugName: "sortState" }] : /* istanbul ignore next */ []));
|
|
749
|
+
/**
|
|
750
|
+
* When true the table never reorders `rows`: they arrive sorted by the
|
|
751
|
+
* consumer (a server-paged list sorted by the server) and render as given.
|
|
752
|
+
* Headers still show `sortState` and emit `sortChange`.
|
|
753
|
+
*/
|
|
754
|
+
manualSorting = input(false, ...(ngDevMode ? [{ debugName: "manualSorting" }] : /* istanbul ignore next */ []));
|
|
744
755
|
/** Controlled filter state; pass null to let the table manage filtering internally. */
|
|
745
756
|
filterState = input(null, ...(ngDevMode ? [{ debugName: "filterState" }] : /* istanbul ignore next */ []));
|
|
746
757
|
/** Controlled page state; pass null to let the table manage pagination internally. */
|
|
@@ -916,6 +927,9 @@ class DataTableComponent {
|
|
|
916
927
|
const sort = this.sortState();
|
|
917
928
|
this.engine.controlledSortState.set(sort === null ? undefined : sort);
|
|
918
929
|
});
|
|
930
|
+
effect(() => {
|
|
931
|
+
this.engine.manualSorting.set(this.manualSorting());
|
|
932
|
+
});
|
|
919
933
|
effect(() => {
|
|
920
934
|
const filter = this.filterState();
|
|
921
935
|
this.engine.controlledFilterState.set(filter === null ? undefined : filter);
|
|
@@ -1282,7 +1296,7 @@ class DataTableComponent {
|
|
|
1282
1296
|
return sort.direction;
|
|
1283
1297
|
}
|
|
1284
1298
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DataTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1285
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: DataTableComponent, isStandalone: true, selector: "fk-data-table", inputs: { className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, sortState: { classPropertyName: "sortState", publicName: "sortState", isSignal: true, isRequired: false, transformFunction: null }, filterState: { classPropertyName: "filterState", publicName: "filterState", isSignal: true, isRequired: false, transformFunction: null }, pageState: { classPropertyName: "pageState", publicName: "pageState", isSignal: true, isRequired: false, transformFunction: null }, rowSelection: { classPropertyName: "rowSelection", publicName: "rowSelection", isSignal: true, isRequired: false, transformFunction: null }, selectedKeys: { classPropertyName: "selectedKeys", publicName: "selectedKeys", isSignal: true, isRequired: false, transformFunction: null }, getRowId: { classPropertyName: "getRowId", publicName: "getRowId", isSignal: true, isRequired: false, transformFunction: null }, selectionDisabled: { classPropertyName: "selectionDisabled", publicName: "selectionDisabled", isSignal: true, isRequired: false, transformFunction: null }, selectionColumnPosition: { classPropertyName: "selectionColumnPosition", publicName: "selectionColumnPosition", isSignal: true, isRequired: false, transformFunction: null }, selectionLabel: { classPropertyName: "selectionLabel", publicName: "selectionLabel", isSignal: true, isRequired: false, transformFunction: null }, rowDetailTemplate: { classPropertyName: "rowDetailTemplate", publicName: "rowDetailTemplate", isSignal: true, isRequired: false, transformFunction: null }, expansionColumnPosition: { classPropertyName: "expansionColumnPosition", publicName: "expansionColumnPosition", isSignal: true, isRequired: false, transformFunction: null }, expandedKeys: { classPropertyName: "expandedKeys", publicName: "expandedKeys", isSignal: true, isRequired: false, transformFunction: null }, expandableRow: { classPropertyName: "expandableRow", publicName: "expandableRow", isSignal: true, isRequired: false, transformFunction: null }, expansionLabel: { classPropertyName: "expansionLabel", publicName: "expansionLabel", isSignal: true, isRequired: false, transformFunction: null }, groupHeadingRenderer: { classPropertyName: "groupHeadingRenderer", publicName: "groupHeadingRenderer", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortChange: "sortChange", filterChange: "filterChange", pageChange: "pageChange", rowClick: "rowClick", selectionChange: "selectionChange", expansionChange: "expansionChange", columnResize: "columnResize" }, host: { properties: { "class": "this.hostClass", "attr.id": "this.hostId" } }, providers: [
|
|
1299
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: DataTableComponent, isStandalone: true, selector: "fk-data-table", inputs: { className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, sortState: { classPropertyName: "sortState", publicName: "sortState", isSignal: true, isRequired: false, transformFunction: null }, manualSorting: { classPropertyName: "manualSorting", publicName: "manualSorting", isSignal: true, isRequired: false, transformFunction: null }, filterState: { classPropertyName: "filterState", publicName: "filterState", isSignal: true, isRequired: false, transformFunction: null }, pageState: { classPropertyName: "pageState", publicName: "pageState", isSignal: true, isRequired: false, transformFunction: null }, rowSelection: { classPropertyName: "rowSelection", publicName: "rowSelection", isSignal: true, isRequired: false, transformFunction: null }, selectedKeys: { classPropertyName: "selectedKeys", publicName: "selectedKeys", isSignal: true, isRequired: false, transformFunction: null }, getRowId: { classPropertyName: "getRowId", publicName: "getRowId", isSignal: true, isRequired: false, transformFunction: null }, selectionDisabled: { classPropertyName: "selectionDisabled", publicName: "selectionDisabled", isSignal: true, isRequired: false, transformFunction: null }, selectionColumnPosition: { classPropertyName: "selectionColumnPosition", publicName: "selectionColumnPosition", isSignal: true, isRequired: false, transformFunction: null }, selectionLabel: { classPropertyName: "selectionLabel", publicName: "selectionLabel", isSignal: true, isRequired: false, transformFunction: null }, rowDetailTemplate: { classPropertyName: "rowDetailTemplate", publicName: "rowDetailTemplate", isSignal: true, isRequired: false, transformFunction: null }, expansionColumnPosition: { classPropertyName: "expansionColumnPosition", publicName: "expansionColumnPosition", isSignal: true, isRequired: false, transformFunction: null }, expandedKeys: { classPropertyName: "expandedKeys", publicName: "expandedKeys", isSignal: true, isRequired: false, transformFunction: null }, expandableRow: { classPropertyName: "expandableRow", publicName: "expandableRow", isSignal: true, isRequired: false, transformFunction: null }, expansionLabel: { classPropertyName: "expansionLabel", publicName: "expansionLabel", isSignal: true, isRequired: false, transformFunction: null }, groupHeadingRenderer: { classPropertyName: "groupHeadingRenderer", publicName: "groupHeadingRenderer", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortChange: "sortChange", filterChange: "filterChange", pageChange: "pageChange", rowClick: "rowClick", selectionChange: "selectionChange", expansionChange: "expansionChange", columnResize: "columnResize" }, host: { properties: { "class": "this.hostClass", "attr.id": "this.hostId" } }, providers: [
|
|
1286
1300
|
TableEngineService,
|
|
1287
1301
|
VirtualizationEngineService,
|
|
1288
1302
|
ResponsiveStrategyService,
|
|
@@ -1300,7 +1314,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
1300
1314
|
VirtualizationEngineService,
|
|
1301
1315
|
ResponsiveStrategyService,
|
|
1302
1316
|
], template: "@if (activeMode() === 'stack') {\n <!-- Stack path: mobile card view -->\n <fk-data-table-stack\n [rows]=\"engine.processedRows()\"\n [columns]=\"columns()\"\n [config]=\"mergedConfig()\"\n [trackByFn]=\"mergedConfig().trackBy\"\n [rowSelection]=\"rowSelection()\"\n [selectedKeys]=\"effectiveSelectedKeysForTemplate()\"\n [getRowId]=\"getRowId()\"\n [selectionDisabled]=\"selectionDisabled()\"\n [selectionLabel]=\"selectionLabel()\"\n [groupHeadingRenderer]=\"groupHeadingRenderer()\"\n (rowClick)=\"rowClick.emit($event)\"\n (toggleRow)=\"onToggleRow($event.row, $event.event)\"\n />\n} @else if (useVirtualization()) {\n <!-- Virtual path: div/grid-based with virtual scrolling -->\n <div role=\"table\" [attr.aria-label]=\"ariaLabel()\">\n @if (mergedConfig().showHeader) {\n <div class=\"fk-data-table__head\" role=\"rowgroup\">\n <div class=\"fk-data-table__head-row\" role=\"row\">\n @if (rowSelection() && selectionColumnPosition() === 'start') {\n <div\n class=\"fk-data-table__th fk-data-table__selection-cell\"\n role=\"columnheader\"\n >\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"\n headerSelectionState() === 'checked'\n ? 'Deselect all on page'\n : 'Select all on page'\n \"\n [checked]=\"headerSelectionState() === 'checked'\"\n [indeterminate]=\"headerSelectionState() === 'indeterminate'\"\n (click)=\"onToggleAllVisible($event)\"\n />\n </div>\n }\n @for (column of visibleColumns(); track column.id) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div\n class=\"fk-data-table__th\"\n role=\"columnheader\"\n [fkColumnResize]=\"column.id\"\n [enabled]=\"column.resizable === true\"\n (columnResize)=\"onColumnResize($event)\"\n [class.fk-data-table__th--sortable]=\"column.sortable\"\n [class.fk-data-table__th--align-center]=\"\n column.align === 'center'\n \"\n [class.fk-data-table__th--align-end]=\"column.align === 'end'\"\n [class.fk-data-table__th--pinned-start]=\"\n column.pinned === 'start'\n \"\n [class.fk-data-table__th--pinned-end]=\"column.pinned === 'end'\"\n [style.width]=\"column.width ?? null\"\n [style.min-width]=\"column.minWidth ?? null\"\n [style.max-width]=\"column.maxWidth ?? null\"\n [style.flex]=\"column.flex ?? null\"\n [style.--fk-data-table-pin-offset]=\"getPinOffset(column)\"\n [attr.aria-sort]=\"\n getSortDirection(column.id) === 'asc'\n ? 'ascending'\n : getSortDirection(column.id) === 'desc'\n ? 'descending'\n : null\n \"\n (click)=\"onHeaderClick(column)\"\n >\n @if (column.headerRenderer) {\n <ng-container\n [ngTemplateOutlet]=\"column.headerRenderer\"\n [ngTemplateOutletContext]=\"{ $implicit: column }\"\n />\n } @else {\n {{ column.header }}\n }\n\n @if (column.sortable) {\n <span\n class=\"fk-data-table__sort-indicator\"\n [class.fk-data-table__sort-indicator--asc]=\"\n getSortDirection(column.id) === 'asc'\n \"\n [class.fk-data-table__sort-indicator--desc]=\"\n getSortDirection(column.id) === 'desc'\n \"\n aria-hidden=\"true\"\n >\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M5 2L8 6H2L5 2Z\" fill=\"currentColor\" />\n </svg>\n </span>\n }\n </div>\n }\n @if (rowSelection() && selectionColumnPosition() === 'end') {\n <div\n class=\"fk-data-table__th fk-data-table__selection-cell\"\n role=\"columnheader\"\n >\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"\n headerSelectionState() === 'checked'\n ? 'Deselect all on page'\n : 'Select all on page'\n \"\n [checked]=\"headerSelectionState() === 'checked'\"\n [indeterminate]=\"headerSelectionState() === 'indeterminate'\"\n (click)=\"onToggleAllVisible($event)\"\n />\n </div>\n }\n </div>\n </div>\n }\n\n <div\n #virtualViewport\n class=\"fk-data-table__viewport\"\n role=\"rowgroup\"\n (scroll)=\"onVirtualScroll($event)\"\n >\n <div\n class=\"fk-data-table__sentinel\"\n [style.height.px]=\"virtEngine.totalHeight()\"\n ></div>\n\n <div\n class=\"fk-data-table__virtual-body\"\n [style.transform]=\"'translateY(' + virtEngine.offsetY() + 'px)'\"\n >\n @for (\n row of virtualRows();\n track mergedConfig().trackBy(virtualStartIndex() + $index, row);\n let i = $index\n ) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div\n class=\"fk-data-table__row\"\n role=\"row\"\n [class.fk-data-table__row--selected]=\"isRowSelected(row)\"\n [style.height.px]=\"mergedConfig().rowHeight\"\n [ngStyle]=\"getRowStyle(row, virtualStartIndex() + i)\"\n (click)=\"onRowClick(row, virtualStartIndex() + i)\"\n >\n @if (rowSelection() && selectionColumnPosition() === 'start') {\n <div\n class=\"fk-data-table__td fk-data-table__selection-cell\"\n role=\"cell\"\n >\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"selectionLabel()\"\n [checked]=\"isRowSelected(row)\"\n [disabled]=\"isRowSelectionDisabled(row)\"\n (click)=\"onToggleRow(row, $event)\"\n />\n </div>\n }\n @for (column of visibleColumns(); track column.id) {\n <div\n class=\"fk-data-table__td\"\n role=\"cell\"\n [class.fk-data-table__td--truncate]=\"column.truncate\"\n [class.fk-data-table__td--align-center]=\"\n column.align === 'center'\n \"\n [class.fk-data-table__td--align-end]=\"column.align === 'end'\"\n [class.fk-data-table__td--pinned-start]=\"\n column.pinned === 'start'\n \"\n [class.fk-data-table__td--pinned-end]=\"column.pinned === 'end'\"\n [style.width]=\"column.width ?? null\"\n [style.min-width]=\"column.minWidth ?? null\"\n [style.max-width]=\"column.maxWidth ?? null\"\n [style.flex]=\"column.flex ?? null\"\n [style.--fk-data-table-pin-offset]=\"getPinOffset(column)\"\n >\n @if (column.cellRenderer) {\n <ng-container\n [ngTemplateOutlet]=\"column.cellRenderer\"\n [ngTemplateOutletContext]=\"{\n $implicit: getCellValue(column, row),\n row: row,\n }\"\n />\n } @else {\n {{ getCellValue(column, row) }}\n }\n </div>\n }\n @if (rowSelection() && selectionColumnPosition() === 'end') {\n <div\n class=\"fk-data-table__td fk-data-table__selection-cell\"\n role=\"cell\"\n >\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"selectionLabel()\"\n [checked]=\"isRowSelected(row)\"\n [disabled]=\"isRowSelectionDisabled(row)\"\n (click)=\"onToggleRow(row, $event)\"\n />\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n @if (isEmpty()) {\n <div class=\"fk-data-table__empty\" role=\"row\">\n <div role=\"cell\">{{ mergedConfig().emptyMessage }}</div>\n </div>\n }\n </div>\n} @else {\n <!-- Standard path: semantic table -->\n <div class=\"fk-data-table__scroll\">\n <table class=\"fk-data-table__table\" [attr.aria-label]=\"ariaLabel()\">\n @if (mergedConfig().showHeader) {\n <thead class=\"fk-data-table__head\">\n <tr class=\"fk-data-table__head-row\">\n @if (rowSelection() && selectionColumnPosition() === 'start') {\n <th class=\"fk-data-table__th fk-data-table__selection-cell\">\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"\n headerSelectionState() === 'checked'\n ? 'Deselect all on page'\n : 'Select all on page'\n \"\n [checked]=\"headerSelectionState() === 'checked'\"\n [indeterminate]=\"headerSelectionState() === 'indeterminate'\"\n (click)=\"onToggleAllVisible($event)\"\n />\n </th>\n }\n @if (hasExpansionStart()) {\n <th\n class=\"fk-data-table__th fk-data-table__expand-cell\"\n aria-hidden=\"true\"\n ></th>\n }\n @for (column of visibleColumns(); track column.id) {\n <th\n class=\"fk-data-table__th\"\n [fkColumnResize]=\"column.id\"\n [enabled]=\"column.resizable === true\"\n (columnResize)=\"onColumnResize($event)\"\n [class.fk-data-table__th--sortable]=\"column.sortable\"\n [class.fk-data-table__th--align-center]=\"\n column.align === 'center'\n \"\n [class.fk-data-table__th--align-end]=\"column.align === 'end'\"\n [class.fk-data-table__th--pinned-start]=\"\n column.pinned === 'start'\n \"\n [class.fk-data-table__th--pinned-end]=\"column.pinned === 'end'\"\n [style.width]=\"column.width ?? null\"\n [style.min-width]=\"column.minWidth ?? null\"\n [style.max-width]=\"column.maxWidth ?? null\"\n [style.--fk-data-table-pin-offset]=\"getPinOffset(column)\"\n [attr.aria-sort]=\"\n getSortDirection(column.id) === 'asc'\n ? 'ascending'\n : getSortDirection(column.id) === 'desc'\n ? 'descending'\n : null\n \"\n (click)=\"onHeaderClick(column)\"\n >\n @if (column.headerRenderer) {\n <ng-container\n [ngTemplateOutlet]=\"column.headerRenderer\"\n [ngTemplateOutletContext]=\"{ $implicit: column }\"\n />\n } @else {\n {{ column.header }}\n }\n\n @if (column.sortable) {\n <span\n class=\"fk-data-table__sort-indicator\"\n [class.fk-data-table__sort-indicator--asc]=\"\n getSortDirection(column.id) === 'asc'\n \"\n [class.fk-data-table__sort-indicator--desc]=\"\n getSortDirection(column.id) === 'desc'\n \"\n aria-hidden=\"true\"\n >\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M5 2L8 6H2L5 2Z\" fill=\"currentColor\" />\n </svg>\n </span>\n }\n </th>\n }\n @if (rowSelection() && selectionColumnPosition() === 'end') {\n <th class=\"fk-data-table__th fk-data-table__selection-cell\">\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"\n headerSelectionState() === 'checked'\n ? 'Deselect all on page'\n : 'Select all on page'\n \"\n [checked]=\"headerSelectionState() === 'checked'\"\n [indeterminate]=\"headerSelectionState() === 'indeterminate'\"\n (click)=\"onToggleAllVisible($event)\"\n />\n </th>\n }\n @if (hasExpansionEnd()) {\n <th\n class=\"fk-data-table__th fk-data-table__expand-cell\"\n aria-hidden=\"true\"\n ></th>\n }\n </tr>\n </thead>\n }\n\n <tbody class=\"fk-data-table__body\">\n @for (\n row of engine.processedRows();\n track mergedConfig().trackBy($index, row);\n let i = $index\n ) {\n <!--\n A heading opens each run of rows sharing a group key. Emitted from\n inside the row loop rather than by pre-grouping the rows, so the\n table still renders exactly the rows it was given, in the order it\n was given them.\n -->\n @if (groupHeadingFor(row, i); as heading) {\n <tr class=\"fk-data-table__group-heading\">\n <th\n scope=\"colgroup\"\n class=\"fk-data-table__group-heading-cell\"\n [attr.colspan]=\"groupHeadingSpan()\"\n >\n @if (groupHeadingRenderer()) {\n <ng-container\n [ngTemplateOutlet]=\"groupHeadingRenderer()!\"\n [ngTemplateOutletContext]=\"{ $implicit: heading, row: row }\"\n />\n } @else {\n {{ heading }}\n }\n </th>\n </tr>\n }\n\n <tr\n class=\"fk-data-table__row\"\n [class.fk-data-table__row--selected]=\"isRowSelected(row)\"\n [class.fk-data-table__row--expanded]=\"\n hasExpansion() && isRowExpanded(row)\n \"\n [ngStyle]=\"getRowStyle(row, i)\"\n (click)=\"onRowClick(row, i)\"\n >\n @if (rowSelection() && selectionColumnPosition() === 'start') {\n <td class=\"fk-data-table__td fk-data-table__selection-cell\">\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"selectionLabel()\"\n [checked]=\"isRowSelected(row)\"\n [disabled]=\"isRowSelectionDisabled(row)\"\n (click)=\"onToggleRow(row, $event)\"\n />\n </td>\n }\n @if (hasExpansionStart()) {\n <td class=\"fk-data-table__td fk-data-table__expand-cell\">\n @if (isRowExpandable(row)) {\n <button\n type=\"button\"\n class=\"fk-data-table__expand-button\"\n [class.fk-data-table__expand-button--expanded]=\"\n isRowExpanded(row)\n \"\n [attr.aria-label]=\"expansionLabel()\"\n [attr.aria-expanded]=\"isRowExpanded(row)\"\n (click)=\"onToggleExpand(row, $event)\"\n >\n <svg\n class=\"fk-data-table__expand-chevron\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n aria-hidden=\"true\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M3 1.5L6.5 5L3 8.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n }\n </td>\n }\n @for (column of visibleColumns(); track column.id) {\n <td\n class=\"fk-data-table__td\"\n [class.fk-data-table__td--truncate]=\"column.truncate\"\n [class.fk-data-table__td--align-center]=\"\n column.align === 'center'\n \"\n [class.fk-data-table__td--align-end]=\"column.align === 'end'\"\n [class.fk-data-table__td--pinned-start]=\"\n column.pinned === 'start'\n \"\n [class.fk-data-table__td--pinned-end]=\"column.pinned === 'end'\"\n [style.--fk-data-table-pin-offset]=\"getPinOffset(column)\"\n >\n @if (column.cellRenderer) {\n <ng-container\n [ngTemplateOutlet]=\"column.cellRenderer\"\n [ngTemplateOutletContext]=\"{\n $implicit: getCellValue(column, row),\n row: row,\n }\"\n />\n } @else {\n {{ getCellValue(column, row) }}\n }\n </td>\n }\n @if (rowSelection() && selectionColumnPosition() === 'end') {\n <td class=\"fk-data-table__td fk-data-table__selection-cell\">\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"selectionLabel()\"\n [checked]=\"isRowSelected(row)\"\n [disabled]=\"isRowSelectionDisabled(row)\"\n (click)=\"onToggleRow(row, $event)\"\n />\n </td>\n }\n @if (hasExpansionEnd()) {\n <td class=\"fk-data-table__td fk-data-table__expand-cell\">\n @if (isRowExpandable(row)) {\n <button\n type=\"button\"\n class=\"fk-data-table__expand-button\"\n [class.fk-data-table__expand-button--expanded]=\"\n isRowExpanded(row)\n \"\n [attr.aria-label]=\"expansionLabel()\"\n [attr.aria-expanded]=\"isRowExpanded(row)\"\n (click)=\"onToggleExpand(row, $event)\"\n >\n <svg\n class=\"fk-data-table__expand-chevron\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n aria-hidden=\"true\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M3 1.5L6.5 5L3 8.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n }\n </td>\n }\n </tr>\n @if (hasExpansion() && isRowExpanded(row)) {\n <tr class=\"fk-data-table__detail-row\">\n <td\n class=\"fk-data-table__detail-cell\"\n [attr.colspan]=\"totalColumnCount()\"\n >\n <ng-container\n [ngTemplateOutlet]=\"rowDetailTemplate()!\"\n [ngTemplateOutletContext]=\"{\n $implicit: row,\n row: row,\n index: i,\n }\"\n />\n </td>\n </tr>\n }\n }\n </tbody>\n </table>\n\n @if (isEmpty()) {\n <div class=\"fk-data-table__empty\">\n {{ mergedConfig().emptyMessage }}\n </div>\n }\n </div>\n}\n\n@if (loading()) {\n <div class=\"fk-data-table__loading-overlay\" aria-live=\"polite\">\n <span class=\"fk-data-table__loading-text\">Loading\u2026</span>\n </div>\n}\n", styles: [":host{display:block;position:relative;border:var(--fk-data-table-border-width, 1px) solid var(--fk-data-table-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-data-table-border-radius, var(--fk-radius-md, .375rem));overflow:hidden}.fk-data-table__scroll{overflow-x:auto;width:100%;max-height:var(--fk-data-table-viewport-height)}.fk-data-table__table{width:100%;border-collapse:collapse;border-spacing:0}.fk-data-table__head{background:var(--fk-data-table-head-bg, var(--fk-color-surface-muted, #f7f9fb))}.fk-data-table__head-row{display:flex}.fk-data-table__table .fk-data-table__head-row{display:table-row}.fk-data-table__th{position:relative;padding:var(--fk-data-table-cell-padding, var(--fk-rhythm-3, .75rem));text-align:start;font-weight:var(--fk-data-table-head-font-weight, var(--fk-font-weight-semibold, 600));font-size:var(--fk-data-table-head-font-size, var(--fk-typography-small-font-size, .875rem));color:var(--fk-data-table-head-color, var(--fk-color-text-muted, #6b7a8d));border-bottom:1px solid var(--fk-data-table-border-color, var(--fk-color-border, #d9e2ee));white-space:nowrap;-webkit-user-select:none;user-select:none;flex:1}.fk-data-table__th--sortable{cursor:pointer}.fk-data-table__th--sortable:hover{color:var(--fk-data-table-head-hover-color, var(--fk-color-text, #1f2d3d))}.fk-data-table__th--align-center{text-align:center}.fk-data-table__th--align-end{text-align:end}.fk-data-table__table .fk-data-table__th{flex:none}.fk-data-table__sort-indicator{display:inline-flex;margin-inline-start:var(--fk-rhythm-1, .25rem);opacity:.3;transition:transform .15s ease,opacity .15s ease}.fk-data-table__sort-indicator--asc{opacity:1;transform:rotate(0)}.fk-data-table__sort-indicator--desc{opacity:1;transform:rotate(180deg)}.fk-data-table__viewport{overflow-y:auto;position:relative;max-height:var(--fk-data-table-viewport-height, 600px)}.fk-data-table__sentinel{position:absolute;top:0;left:0;width:1px;visibility:hidden}.fk-data-table__virtual-body{position:relative;will-change:transform}.fk-data-table__group-heading{background:var(--fk-data-table-group-heading-bg, var(--fk-color-surface-muted, #f7f9fb))}.fk-data-table__group-heading-cell{padding:var(--fk-data-table-group-heading-padding, var(--fk-rhythm-2, .5rem) var(--fk-data-table-cell-padding, var(--fk-rhythm-3, .75rem)));text-align:start;font-size:var(--fk-data-table-group-heading-font-size, var(--fk-typography-caption-font-size, .75rem));font-weight:var(--fk-data-table-group-heading-font-weight, var(--fk-font-weight-semibold, 600));letter-spacing:var(--fk-data-table-group-heading-letter-spacing, .04em);text-transform:var(--fk-data-table-group-heading-text-transform, uppercase);color:var(--fk-data-table-group-heading-color, var(--fk-color-text-muted, #6b7a8d));border-block:1px solid var(--fk-data-table-border-color, var(--fk-color-border, #d9e2ee))}.fk-data-table__body{background:var(--fk-data-table-body-bg, var(--fk-color-surface, #ffffff))}.fk-data-table__row{display:flex;border-bottom:1px solid var(--fk-data-table-border-color, var(--fk-color-border, #d9e2ee));cursor:pointer}.fk-data-table__row:hover{background:var(--fk-data-table-row-hover-bg, var(--fk-color-surface-muted, #f7f9fb))}.fk-data-table__row:last-child{border-bottom:none}.fk-data-table__table .fk-data-table__row{display:table-row}.fk-data-table__td{padding:var(--fk-data-table-cell-padding, var(--fk-rhythm-3, .75rem));font-size:var(--fk-data-table-body-font-size, var(--fk-typography-body-font-size, .875rem));color:var(--fk-data-table-body-color, var(--fk-color-text, #1f2d3d));vertical-align:middle;flex:1}.fk-data-table__td--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fk-data-table__td--align-center{text-align:center}.fk-data-table__td--align-end{text-align:end}.fk-data-table__table .fk-data-table__td{flex:none}.fk-data-table__empty{padding:var(--fk-data-table-empty-padding, var(--fk-rhythm-8, 2rem));text-align:center;color:var(--fk-data-table-empty-color, var(--fk-color-text-muted, #6b7a8d));font-size:var(--fk-data-table-body-font-size, var(--fk-typography-body-font-size, .875rem))}.fk-data-table__loading-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:var(--fk-data-table-loading-bg, var(--fk-color-surface-overlay, rgba(255, 255, 255, .7)));z-index:1}.fk-data-table__loading-text{font-size:var(--fk-data-table-body-font-size, var(--fk-typography-body-font-size, .875rem));color:var(--fk-data-table-loading-color, var(--fk-color-text-muted, #6b7a8d))}.fk-data-table__resize-handle{position:absolute;top:0;right:0;bottom:0;width:var(--fk-data-table-resize-handle-width, 4px);cursor:col-resize;background:transparent;z-index:1}.fk-data-table__resize-handle:hover,.fk-data-table__resize-handle:active{background:var(--fk-data-table-resize-handle-color, var(--fk-color-primary, #3b82f6))}.fk-data-table__th--pinned-start,.fk-data-table__td--pinned-start{position:sticky;left:var(--fk-data-table-pin-offset, 0);z-index:2;background:inherit}.fk-data-table__th--pinned-end,.fk-data-table__td--pinned-end{position:sticky;right:var(--fk-data-table-pin-offset, 0);z-index:2;background:inherit}.fk-data-table__selection-cell{flex:none;width:var(--fk-data-table-selection-cell-width, 2.75rem);min-width:var(--fk-data-table-selection-cell-width, 2.75rem);max-width:var(--fk-data-table-selection-cell-width, 2.75rem);text-align:center;cursor:default}.fk-data-table__selection-cell:hover{color:inherit}.fk-data-table__row--selected{background:var(--fk-data-table-row-selected-bg, var(--fk-color-primary-light, #eaf4ff))}.fk-data-table__row--selected:hover{background:var(--fk-data-table-row-selected-hover-bg, var(--fk-color-primary-light, #dbe9ff))}.fk-data-table__expand-cell{flex:none;width:var(--fk-data-table-expand-cell-width, 2.5rem);min-width:var(--fk-data-table-expand-cell-width, 2.5rem);max-width:var(--fk-data-table-expand-cell-width, 2.5rem);text-align:center;cursor:default;padding-inline:var(--fk-rhythm-1, .25rem)}.fk-data-table__expand-button{appearance:none;display:inline-flex;align-items:center;justify-content:center;width:var(--fk-data-table-expand-button-size, 1.5rem);height:var(--fk-data-table-expand-button-size, 1.5rem);padding:0;background:transparent;border:1px solid transparent;border-radius:var(--fk-data-table-expand-button-radius, .25rem);color:var(--fk-data-table-expand-color, var(--fk-color-text-muted, #5d6b80));cursor:pointer;transition:background-color .15s ease,color .15s ease,transform .15s ease}.fk-data-table__expand-button:hover{background:var(--fk-data-table-expand-button-hover-bg, var(--fk-color-surface-muted, #f1f4f8));color:var(--fk-data-table-expand-color-hover, var(--fk-color-text, #1c2433))}.fk-data-table__expand-button:focus-visible{outline:2px solid var(--fk-data-table-expand-focus-ring, var(--fk-color-primary, #0066cc));outline-offset:2px}.fk-data-table__expand-button--expanded{color:var(--fk-data-table-expand-color-active, var(--fk-color-primary, #0066cc))}.fk-data-table__expand-button--expanded .fk-data-table__expand-chevron{transform:rotate(90deg)}.fk-data-table__expand-chevron{transition:transform .15s ease}.fk-data-table__row--expanded{background:var(--fk-data-table-row-expanded-bg, var(--fk-color-surface-muted, #f7f9fb))}.fk-data-table__detail-row{background:var(--fk-data-table-detail-row-bg, var(--fk-color-surface, #ffffff))}.fk-data-table__detail-cell{padding:var(--fk-data-table-detail-cell-padding, var(--fk-rhythm-4, 1rem));border-top:1px solid var(--fk-data-table-detail-border-color, var(--fk-color-border, #d9e2ee));border-bottom:1px solid var(--fk-data-table-detail-border-color, var(--fk-color-border, #d9e2ee))}.fk-data-table__checkbox{appearance:none;width:var(--fk-data-table-checkbox-size, 1rem);height:var(--fk-data-table-checkbox-size, 1rem);margin:0;border:1px solid var(--fk-data-table-checkbox-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-data-table-checkbox-radius, .25rem);background:var(--fk-data-table-checkbox-bg, var(--fk-color-surface, #ffffff));cursor:pointer;transition:background-color .15s ease,border-color .15s ease,box-shadow .15s ease;position:relative;vertical-align:middle}.fk-data-table__checkbox:focus-visible{outline:none;box-shadow:var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18))}.fk-data-table__checkbox:hover:not(:disabled){border-color:var(--fk-data-table-checkbox-hover-border-color, var(--fk-color-primary, #0a84ff))}.fk-data-table__checkbox:checked,.fk-data-table__checkbox:indeterminate{background:var(--fk-data-table-checkbox-checked-bg, var(--fk-color-primary, #0a84ff));border-color:var(--fk-data-table-checkbox-checked-border-color, var(--fk-color-primary, #0a84ff))}.fk-data-table__checkbox:checked:after{content:\"\";position:absolute;inset:0;background:var(--fk-data-table-checkbox-icon-color, var(--fk-white, #ffffff));mask:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='currentColor' d='M6.5 11L3 7.5l1-1L6.5 9 12 3.5l1 1z'/></svg>\") center/75% 75% no-repeat;-webkit-mask:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='currentColor' d='M6.5 11L3 7.5l1-1L6.5 9 12 3.5l1 1z'/></svg>\") center/75% 75% no-repeat}.fk-data-table__checkbox:indeterminate:after{content:\"\";position:absolute;inset:0;background:var(--fk-data-table-checkbox-icon-color, var(--fk-white, #ffffff));mask:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><rect x='3' y='7' width='10' height='2' rx='1' fill='currentColor'/></svg>\") center/75% 75% no-repeat;-webkit-mask:url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><rect x='3' y='7' width='10' height='2' rx='1' fill='currentColor'/></svg>\") center/75% 75% no-repeat}.fk-data-table__checkbox:disabled{cursor:not-allowed;opacity:.5}.fk-data-table--resizing{cursor:col-resize;-webkit-user-select:none;user-select:none}.fk-data-table--sticky-header .fk-data-table__head{position:sticky;top:0;z-index:1}.fk-data-table--sticky-header .fk-data-table__table .fk-data-table__th{position:sticky;top:0;z-index:1;background:var(--fk-data-table-head-bg, var(--fk-color-surface-muted, #f7f9fb))}\n"] }]
|
|
1303
|
-
}], ctorParameters: () => [], propDecorators: { className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], sortState: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortState", required: false }] }], filterState: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterState", required: false }] }], pageState: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageState", required: false }] }], rowSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowSelection", required: false }] }], selectedKeys: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedKeys", required: false }] }], getRowId: [{ type: i0.Input, args: [{ isSignal: true, alias: "getRowId", required: false }] }], selectionDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionDisabled", required: false }] }], selectionColumnPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionColumnPosition", required: false }] }], selectionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionLabel", required: false }] }], rowDetailTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowDetailTemplate", required: false }] }], expansionColumnPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "expansionColumnPosition", required: false }] }], expandedKeys: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedKeys", required: false }] }], expandableRow: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandableRow", required: false }] }], expansionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "expansionLabel", required: false }] }], groupHeadingRenderer: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupHeadingRenderer", required: false }] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], expansionChange: [{ type: i0.Output, args: ["expansionChange"] }], columnResize: [{ type: i0.Output, args: ["columnResize"] }], virtualViewport: [{ type: i0.ViewChild, args: ['virtualViewport', { isSignal: true }] }], hostClass: [{
|
|
1317
|
+
}], ctorParameters: () => [], propDecorators: { className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], sortState: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortState", required: false }] }], manualSorting: [{ type: i0.Input, args: [{ isSignal: true, alias: "manualSorting", required: false }] }], filterState: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterState", required: false }] }], pageState: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageState", required: false }] }], rowSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowSelection", required: false }] }], selectedKeys: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedKeys", required: false }] }], getRowId: [{ type: i0.Input, args: [{ isSignal: true, alias: "getRowId", required: false }] }], selectionDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionDisabled", required: false }] }], selectionColumnPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionColumnPosition", required: false }] }], selectionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionLabel", required: false }] }], rowDetailTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowDetailTemplate", required: false }] }], expansionColumnPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "expansionColumnPosition", required: false }] }], expandedKeys: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedKeys", required: false }] }], expandableRow: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandableRow", required: false }] }], expansionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "expansionLabel", required: false }] }], groupHeadingRenderer: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupHeadingRenderer", required: false }] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], expansionChange: [{ type: i0.Output, args: ["expansionChange"] }], columnResize: [{ type: i0.Output, args: ["columnResize"] }], virtualViewport: [{ type: i0.ViewChild, args: ['virtualViewport', { isSignal: true }] }], hostClass: [{
|
|
1304
1318
|
type: HostBinding,
|
|
1305
1319
|
args: ['class']
|
|
1306
1320
|
}], hostId: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frame-kit-ui-ng-ui-data-table.mjs","sources":["../../../../packages/ui-ng/ui/data-table/column-resize.directive.ts","../../../../packages/ui-ng/ui/data-table/data-table.types.ts","../../../../packages/ui-ng/ui/data-table/data-table-group.service.ts","../../../../packages/ui-ng/ui/data-table/data-table-grouping.util.ts","../../../../packages/ui-ng/ui/data-table/data-table-stack.component.ts","../../../../packages/ui-ng/ui/data-table/data-table-stack.component.html","../../../../packages/ui-ng/ui/data-table/responsive-strategy.service.ts","../../../../packages/ui-ng/ui/data-table/table-engine.service.ts","../../../../packages/ui-ng/ui/data-table/virtualization-engine.service.ts","../../../../packages/ui-ng/ui/data-table/data-table.component.ts","../../../../packages/ui-ng/ui/data-table/data-table.component.html","../../../../packages/ui-ng/ui/data-table/data-table-group.component.ts","../../../../packages/ui-ng/ui/data-table/frame-kit-ui-ng-ui-data-table.ts"],"sourcesContent":["import {\n Directive,\n ElementRef,\n inject,\n input,\n NgZone,\n OnDestroy,\n OnInit,\n output,\n Renderer2,\n} from '@angular/core';\n\nimport type { ColumnResizeEvent } from './data-table.types';\n\n@Directive({\n selector: '[fkColumnResize]',\n standalone: true,\n})\nexport class ColumnResizeDirective implements OnInit, OnDestroy {\n readonly columnId = input.required<string>({ alias: 'fkColumnResize' });\n readonly enabled = input<boolean>(true);\n readonly minWidth = input<number>(50);\n readonly maxWidth = input<number | null>(null);\n\n readonly columnResize = output<ColumnResizeEvent>();\n\n private readonly el = inject(ElementRef<HTMLElement>);\n private readonly renderer = inject(Renderer2);\n private readonly ngZone = inject(NgZone);\n\n private handle: HTMLElement | null = null;\n private startX = 0;\n private startWidth = 0;\n private dragging = false;\n\n private moveListener: (() => void) | null = null;\n private upListener: (() => void) | null = null;\n\n ngOnInit(): void {\n if (!this.enabled()) {\n return;\n }\n\n this.handle = this.renderer.createElement('div');\n this.renderer.addClass(this.handle, 'fk-data-table__resize-handle');\n this.renderer.appendChild(this.el.nativeElement, this.handle);\n\n this.ngZone.runOutsideAngular(() => {\n this.handle?.addEventListener('mousedown', this.onMouseDown);\n this.handle?.addEventListener('touchstart', this.onTouchStart, {\n passive: false,\n });\n });\n }\n\n ngOnDestroy(): void {\n this.cleanupListeners();\n this.handle?.removeEventListener('mousedown', this.onMouseDown);\n this.handle?.removeEventListener('touchstart', this.onTouchStart);\n }\n\n private readonly onMouseDown = (event: MouseEvent): void => {\n event.preventDefault();\n\n this.startDrag(event.clientX);\n\n this.moveListener = this.renderer.listen(\n 'document',\n 'mousemove',\n (e: MouseEvent) => this.onDrag(e.clientX),\n );\n\n this.upListener = this.renderer.listen('document', 'mouseup', () =>\n this.endDrag(),\n );\n };\n\n private readonly onTouchStart = (event: TouchEvent): void => {\n event.preventDefault();\n\n const touch = event.touches[0];\n\n this.startDrag(touch.clientX);\n\n this.moveListener = this.renderer.listen(\n 'document',\n 'touchmove',\n (e: TouchEvent) => this.onDrag(e.touches[0].clientX),\n );\n\n this.upListener = this.renderer.listen('document', 'touchend', () =>\n this.endDrag(),\n );\n };\n\n private startDrag(clientX: number): void {\n this.dragging = true;\n this.startX = clientX;\n this.startWidth = this.el.nativeElement.offsetWidth;\n this.renderer.addClass(document.body, 'fk-data-table--resizing');\n }\n\n private onDrag(clientX: number): void {\n if (!this.dragging) {\n return;\n }\n\n const diff = clientX - this.startX;\n const min = this.minWidth();\n const max = this.maxWidth();\n\n let newWidth = this.startWidth + diff;\n\n if (newWidth < min) {\n newWidth = min;\n }\n\n if (max !== null && newWidth > max) {\n newWidth = max;\n }\n\n this.renderer.setStyle(this.el.nativeElement, 'width', `${newWidth}px`);\n }\n\n private endDrag(): void {\n if (!this.dragging) {\n return;\n }\n\n this.dragging = false;\n this.renderer.removeClass(document.body, 'fk-data-table--resizing');\n this.cleanupListeners();\n\n const finalWidth = this.el.nativeElement.offsetWidth;\n\n this.ngZone.run(() => {\n this.columnResize.emit({\n columnId: this.columnId(),\n width: finalWidth,\n });\n });\n }\n\n private cleanupListeners(): void {\n if (this.moveListener) {\n this.moveListener();\n this.moveListener = null;\n }\n\n if (this.upListener) {\n this.upListener();\n this.upListener = null;\n }\n }\n}\n","import type { TemplateRef } from '@angular/core';\n\n// ===== COLUMN DEFINITION =====\n\nexport interface ColumnDef<T = unknown> {\n id: string;\n header: string;\n accessor: keyof T | ((row: T) => unknown);\n sortAccessor?: (row: T) => unknown;\n width?: string;\n minWidth?: string;\n maxWidth?: string;\n flex?: number;\n sortable?: boolean;\n align?: 'start' | 'center' | 'end';\n truncate?: boolean;\n visible?: boolean;\n className?: string;\n headerClassName?: string;\n cellRenderer?: TemplateRef<{ $implicit: unknown; row: T }>;\n headerRenderer?: TemplateRef<{ $implicit: ColumnDef<T> }>;\n\n priority?: number;\n hideBelow?: 'sm' | 'md' | 'lg';\n mobileLabel?: string;\n\n resizable?: boolean;\n pinnable?: boolean;\n pinned?: 'start' | 'end' | null;\n}\n\n// ===== TABLE CONFIGURATION =====\n\nexport interface TableConfig<T = unknown> {\n responsiveMode: 'auto' | 'scroll' | 'stack' | 'priority';\n forceScroll: boolean;\n stickyHeader: boolean;\n showHeader: boolean;\n rowExpansion: boolean;\n emptyMessage: string;\n trackBy: (index: number, row: T) => unknown;\n rowStyleFn: ((row: T, index: number) => Record<string, string> | null) | null;\n /**\n * Groups consecutive rows under a heading. Returns the group key for a row,\n * or `null` to leave it ungrouped; a heading is emitted wherever the key\n * changes from the previous row.\n *\n * Grouping reads the rows in the order they are already sorted — it does not\n * reorder them. Sort by the same field you group on, or the same group will\n * open more than once.\n *\n * Mutually exclusive with virtualization, which assumes every row is\n * `rowHeight` tall; a heading is not. Setting this turns virtualization off.\n */\n groupBy: ((row: T) => string | null) | null;\n virtualization: boolean | 'auto';\n virtualizationThreshold: number;\n rowHeight: number;\n overscan: number;\n breakpoints: {\n sm: string;\n md: string;\n };\n}\n\nexport const DEFAULT_TABLE_CONFIG: TableConfig = {\n responsiveMode: 'auto',\n forceScroll: false,\n stickyHeader: true,\n showHeader: true,\n rowExpansion: false,\n emptyMessage: 'No data available',\n groupBy: null,\n trackBy: (index: number) => index,\n rowStyleFn: null,\n virtualization: 'auto',\n virtualizationThreshold: 200,\n rowHeight: 48,\n overscan: 10,\n breakpoints: {\n sm: '(max-width: 35.999em)',\n md: '(max-width: 47.999em)',\n },\n};\n\n// ===== ROW SELECTION =====\n\nexport type SelectionDisabled<T = unknown> = boolean | ((row: T) => boolean);\n\nexport type SelectionColumnPosition = 'start' | 'end';\n\nexport type HeaderSelectionState = 'checked' | 'unchecked' | 'indeterminate';\n\n// ===== ROW EXPANSION =====\n\nexport type ExpansionColumnPosition = 'start' | 'end';\n\n// ===== STATE =====\n\nexport type SortDirection = 'asc' | 'desc' | null;\n\nexport interface SortState {\n columnId: string;\n direction: SortDirection;\n}\n\nexport interface FilterState {\n query: string;\n columnFilters: Record<string, unknown>;\n}\n\nexport interface PageState {\n page: number;\n pageSize: number;\n totalRows: number;\n}\n\n// ===== COLUMN RESIZE =====\n\nexport interface ColumnResizeEvent {\n columnId: string;\n width: number;\n}\n\n// ===== ROW CONTEXT =====\n\nexport interface TableRowContext<T = unknown> {\n row: T;\n index: number;\n selected: boolean;\n expanded: boolean;\n}\n","import { Injectable } from '@angular/core';\n\nimport type { DataTableComponent } from './data-table.component';\n\n/**\n * Coordinator scoped to a single `<fk-data-table-group>`. Mirrors\n * `AccordionGroupCoordinator` — when a wrapped data-table expands a\n * row, the previously-active row is collapsed so only one detail\n * panel is open at a time.\n *\n * The wrapped data-table picks this up via `inject({ optional: true })`\n * and routes every expansion toggle through it. Absence of the\n * coordinator means multi-expand behavior — that's the default.\n */\n@Injectable()\nexport class DataTableGroupCoordinator {\n private activeTable: DataTableComponent<unknown> | null = null;\n private activeKey: unknown = null;\n\n /**\n * Resolve an expansion request. Caller passes the new expanded\n * state alongside the table + row key; coordinator returns the\n * Set the caller should commit. For multi-table groups this also\n * collapses any active row on a sibling table.\n */\n resolveToggle(\n table: DataTableComponent<unknown>,\n key: unknown,\n nextExpanded: boolean,\n currentKeysOnThisTable: ReadonlySet<unknown>,\n ): {\n keysForThisTable: Set<unknown>;\n /** Optional: a sibling table the host should clear by calling its `clearExpansion`. */\n siblingTableToClear: DataTableComponent<unknown> | null;\n } {\n if (!nextExpanded) {\n // Collapse: drop the key from this table's set. If it was the\n // active one, clear our pointer.\n const next = new Set(currentKeysOnThisTable);\n\n next.delete(key);\n\n if (this.activeTable === table && this.activeKey === key) {\n this.activeTable = null;\n this.activeKey = null;\n }\n\n return { keysForThisTable: next, siblingTableToClear: null };\n }\n\n // Expand: replace this table's set with just the new key, and\n // surface any sibling table that needs to drop its active row.\n const next = new Set<unknown>([key]);\n const sibling =\n this.activeTable && this.activeTable !== table ? this.activeTable : null;\n\n this.activeTable = table;\n this.activeKey = key;\n\n return { keysForThisTable: next, siblingTableToClear: sibling };\n }\n\n /**\n * Called when a data-table inside the group disconnects. Clears the\n * active pointer if it was tracking this table.\n */\n unregister(table: DataTableComponent<unknown>): void {\n if (this.activeTable === table) {\n this.activeTable = null;\n this.activeKey = null;\n }\n }\n}\n","import type { TableConfig } from './data-table.types';\n\n/**\n * The group heading to emit before a row, or null when the row continues the\n * group above it.\n *\n * Shared by the semantic-table and stack render paths so the two cannot answer\n * the question differently — a heading appearing on desktop and not on mobile\n * is the kind of drift that only shows up on someone's phone.\n *\n * Reads the rows in the order it is given rather than reordering, so a caller\n * sorting on one field while grouping by another sees the group open more than\n * once. That is deliberate: silently merging them would report a grouping the\n * data does not have.\n */\nexport function groupHeadingForRow<T>(\n rows: readonly T[],\n row: T,\n index: number,\n groupBy: TableConfig<T>['groupBy'],\n): string | null {\n if (!groupBy) {\n return null;\n }\n\n const key = groupBy(row);\n\n if (key === null) {\n return null;\n }\n\n if (index === 0) {\n return key;\n }\n\n const previous = rows[index - 1];\n\n return previous !== undefined && groupBy(previous) === key ? null : key;\n}\n","import { NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n output,\n signal,\n type TemplateRef,\n} from '@angular/core';\n\nimport { groupHeadingForRow } from './data-table-grouping.util';\nimport type {\n ColumnDef,\n SelectionDisabled,\n TableConfig,\n TableRowContext,\n} from './data-table.types';\n\nexport interface StackToggleRowEvent<T = unknown> {\n row: T;\n event: Event;\n}\n\n@Component({\n selector: 'fk-data-table-stack',\n standalone: true,\n imports: [NgTemplateOutlet],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './data-table-stack.component.html',\n styleUrl: './data-table-stack.component.scss',\n})\nexport class DataTableStackComponent<T = unknown> {\n /** Row data array rendered as stacked cards in mobile layout. */\n readonly rows = input<T[]>([]);\n /** Column definitions used to extract field labels and cell values. */\n readonly columns = input<ColumnDef<T>[]>([]);\n /** Merged table configuration passed down from the host data-table. */\n readonly config = input<TableConfig<T> | null>(null);\n /** TrackBy function used by the `@for` loop over rows. */\n readonly trackByFn = input<(index: number, row: T) => unknown>(\n (index: number) => index,\n );\n\n // ===== GROUPING =====\n /**\n * Template rendered inside a group heading. Mirrors the semantic-table path\n * so a grouped table looks grouped at every viewport.\n */\n readonly groupHeadingRenderer = input<TemplateRef<{\n $implicit: string;\n row: T;\n }> | null>(null);\n\n // ===== SELECTION =====\n // Mirrors the host data-table's selection inputs. The stack path renders a\n // checkbox at the top-left of each card when `rowSelection` is true and\n // bubbles toggle events up to the host so it can route them through the\n // shared engine.\n /** Mirrors the host table's `rowSelection` input to show checkboxes on each card. */\n readonly rowSelection = input<boolean>(false);\n /** Currently selected row keys forwarded from the host table engine. */\n readonly selectedKeys = input<Set<unknown>>(new Set());\n /** Row identity resolver forwarded from the host table. */\n readonly getRowId = input<((row: T) => unknown) | null>(null);\n /** Predicate (or static boolean) that disables selection for matching rows. */\n readonly selectionDisabled = input<SelectionDisabled<T>>(false);\n /** Accessible label for each card's selection checkbox. */\n readonly selectionLabel = input<string>('Select row');\n\n /** The group heading to open before this card, if it starts a new group. */\n groupHeadingFor(row: T, index: number): string | null {\n return groupHeadingForRow(\n this.rows(),\n row,\n index,\n this.config()?.groupBy ?? null,\n );\n }\n\n /** Fires when the user clicks a card row, emitting the row context. */\n readonly rowClick = output<TableRowContext<T>>();\n /** Fires when the user toggles a card's selection checkbox, bubbling up to the host. */\n readonly toggleRow = output<StackToggleRowEvent<T>>();\n\n readonly expandedRows = signal<Set<number>>(new Set());\n\n readonly visibleFieldCount = 3;\n\n readonly primaryColumns = computed(() => {\n return this.columns().slice(0, this.visibleFieldCount);\n });\n\n readonly secondaryColumns = computed(() => {\n return this.columns().slice(this.visibleFieldCount);\n });\n\n readonly hasSecondary = computed(() => {\n return this.secondaryColumns().length > 0;\n });\n\n getCellValue(column: ColumnDef<T>, row: T): unknown {\n if (typeof column.accessor === 'function') {\n return column.accessor(row);\n }\n\n return row[column.accessor as keyof T];\n }\n\n getLabel(column: ColumnDef<T>): string {\n return column.mobileLabel ?? column.header;\n }\n\n isExpanded(index: number): boolean {\n return this.expandedRows().has(index);\n }\n\n toggleExpand(index: number): void {\n const next = new Set(this.expandedRows());\n\n if (next.has(index)) {\n next.delete(index);\n } else {\n next.add(index);\n }\n\n this.expandedRows.set(next);\n }\n\n onRowClick(row: T, index: number): void {\n this.rowClick.emit({\n row,\n index,\n selected: this.isRowSelected(row),\n expanded: this.isExpanded(index),\n });\n }\n\n onToggleSelection(row: T, event: Event): void {\n event.stopPropagation();\n\n if (this.isRowSelectionDisabled(row)) {\n return;\n }\n\n this.toggleRow.emit({ row, event });\n }\n\n isRowSelected(row: T): boolean {\n if (!this.rowSelection()) {\n return false;\n }\n\n return this.selectedKeys().has(this.getSelectionKey(row));\n }\n\n isRowSelectionDisabled(row: T): boolean {\n const disabled = this.selectionDisabled();\n\n if (typeof disabled === 'function') {\n return disabled(row);\n }\n\n return disabled;\n }\n\n private getSelectionKey(row: T): unknown {\n const idFn = this.getRowId();\n\n if (idFn) {\n return idFn(row);\n }\n\n return row;\n }\n}\n","<div class=\"fk-data-table-stack\">\n @for (row of rows(); track trackByFn()($index, row); let i = $index) {\n @if (groupHeadingFor(row, i); as heading) {\n <div class=\"fk-data-table-stack__group-heading\">\n @if (groupHeadingRenderer()) {\n <ng-container\n [ngTemplateOutlet]=\"groupHeadingRenderer()!\"\n [ngTemplateOutletContext]=\"{ $implicit: heading, row: row }\"\n />\n } @else {\n {{ heading }}\n }\n </div>\n }\n\n <div\n class=\"fk-data-table-stack__card\"\n [class.fk-data-table-stack__card--selected]=\"isRowSelected(row)\"\n >\n @if (rowSelection()) {\n <div class=\"fk-data-table-stack__select\">\n <input\n type=\"checkbox\"\n class=\"fk-data-table-stack__checkbox\"\n [attr.aria-label]=\"selectionLabel()\"\n [checked]=\"isRowSelected(row)\"\n [disabled]=\"isRowSelectionDisabled(row)\"\n (click)=\"onToggleSelection(row, $event)\"\n />\n </div>\n }\n\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div class=\"fk-data-table-stack__primary\" (click)=\"onRowClick(row, i)\">\n @for (column of primaryColumns(); track column.id) {\n <div class=\"fk-data-table-stack__field\">\n <span class=\"fk-data-table-stack__label\">{{\n getLabel(column)\n }}</span>\n <span class=\"fk-data-table-stack__value\">\n @if (column.cellRenderer) {\n <ng-container\n [ngTemplateOutlet]=\"column.cellRenderer\"\n [ngTemplateOutletContext]=\"{\n $implicit: getCellValue(column, row),\n row: row,\n }\"\n />\n } @else {\n {{ getCellValue(column, row) }}\n }\n </span>\n </div>\n }\n </div>\n\n @if (hasSecondary()) {\n @if (isExpanded(i)) {\n <div class=\"fk-data-table-stack__secondary\">\n @for (column of secondaryColumns(); track column.id) {\n <div class=\"fk-data-table-stack__field\">\n <span class=\"fk-data-table-stack__label\">{{\n getLabel(column)\n }}</span>\n <span class=\"fk-data-table-stack__value\">\n @if (column.cellRenderer) {\n <ng-container\n [ngTemplateOutlet]=\"column.cellRenderer\"\n [ngTemplateOutletContext]=\"{\n $implicit: getCellValue(column, row),\n row: row,\n }\"\n />\n } @else {\n {{ getCellValue(column, row) }}\n }\n </span>\n </div>\n }\n </div>\n }\n\n <button\n class=\"fk-data-table-stack__toggle\"\n type=\"button\"\n [attr.aria-expanded]=\"isExpanded(i)\"\n (click)=\"toggleExpand(i)\"\n >\n {{ isExpanded(i) ? 'Show less' : 'Show more' }}\n </button>\n }\n </div>\n }\n\n @if (rows().length === 0) {\n <div class=\"fk-data-table-stack__empty\">\n {{ config()?.emptyMessage ?? 'No data available' }}\n </div>\n }\n</div>\n","import { BreakpointObserver } from '@angular/cdk/layout';\nimport {\n computed,\n DestroyRef,\n inject,\n Injectable,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport type { ColumnDef, TableConfig } from './data-table.types';\n\nexport type Breakpoint = 'sm' | 'md' | 'lg';\nexport type ActiveMode = 'table' | 'stack';\n\n@Injectable()\nexport class ResponsiveStrategyService<T = unknown> {\n // ===== INJECTIONS =====\n private readonly breakpointObserver = inject(BreakpointObserver);\n private readonly destroyRef = inject(DestroyRef);\n\n // ===== SOURCE DATA =====\n readonly columns = signal<ColumnDef<T>[]>([]);\n readonly config = signal<TableConfig<T> | null>(null);\n\n // ===== STATE =====\n readonly currentBreakpoint = signal<Breakpoint>('lg');\n\n // ===== COMPUTED =====\n readonly activeMode: ReturnType<typeof computed<ActiveMode>> = computed(\n () => {\n const cfg = this.config();\n\n if (!cfg) {\n return 'table';\n }\n\n if (cfg.forceScroll) {\n return 'table';\n }\n\n const mode = cfg.responsiveMode;\n const bp = this.currentBreakpoint();\n\n if (mode === 'scroll') {\n return 'table';\n }\n\n if (mode === 'stack') {\n return bp === 'sm' ? 'stack' : 'table';\n }\n\n if (mode === 'priority') {\n return 'table';\n }\n\n // mode === \"auto\"\n if (bp === 'sm') {\n return 'stack';\n }\n\n return 'table';\n },\n );\n\n readonly responsiveColumns = computed(() => {\n const cols = this.columns();\n const cfg = this.config();\n\n if (!cfg || cfg.forceScroll) {\n return cols;\n }\n\n const bp = this.currentBreakpoint();\n const mode = cfg.responsiveMode;\n\n if (bp === 'lg') {\n return cols;\n }\n\n if (mode === 'scroll') {\n return cols;\n }\n\n // For \"auto\", \"priority\", or \"stack\" at md breakpoint — apply priority hiding\n if (bp === 'md' && (mode === 'auto' || mode === 'priority')) {\n return cols.filter((col) => {\n if (col.hideBelow === 'md' || col.hideBelow === 'lg') {\n return false;\n }\n\n if (col.priority !== undefined && col.priority >= 2) {\n return false;\n }\n\n return true;\n });\n }\n\n return cols;\n });\n\n readonly hiddenColumns = computed(() => {\n const all = this.columns();\n const visible = this.responsiveColumns();\n const visibleIds = new Set(visible.map((c) => c.id));\n\n return all.filter((c) => !visibleIds.has(c.id));\n });\n\n // ===== INITIALIZATION =====\n private initialized = false;\n\n init(breakpoints: { sm: string; md: string }): void {\n if (this.initialized) {\n return;\n }\n\n this.initialized = true;\n\n this.breakpointObserver\n .observe([breakpoints.sm, breakpoints.md])\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((result) => {\n if (result.breakpoints[breakpoints.sm]) {\n this.currentBreakpoint.set('sm');\n } else if (result.breakpoints[breakpoints.md]) {\n this.currentBreakpoint.set('md');\n } else {\n this.currentBreakpoint.set('lg');\n }\n });\n }\n}\n","import { computed, Injectable, signal } from '@angular/core';\n\nimport type {\n ColumnDef,\n FilterState,\n PageState,\n SortDirection,\n SortState,\n} from './data-table.types';\n\n@Injectable()\nexport class TableEngineService<T = unknown> {\n // ===== SOURCE DATA =====\n readonly rows = signal<T[]>([]);\n readonly columns = signal<ColumnDef<T>[]>([]);\n\n // ===== INTERNAL STATE =====\n private readonly internalSortState = signal<SortState | null>(null);\n private readonly internalFilterState = signal<FilterState>({\n query: '',\n columnFilters: {},\n });\n private readonly internalPageState = signal<PageState | null>(null);\n\n // ===== CONTROLLED STATE =====\n readonly controlledSortState = signal<SortState | null | undefined>(\n undefined,\n );\n readonly controlledFilterState = signal<FilterState | null | undefined>(\n undefined,\n );\n readonly controlledPageState = signal<PageState | null | undefined>(\n undefined,\n );\n\n // ===== EFFECTIVE STATE =====\n readonly sortState = computed(() => {\n const controlled = this.controlledSortState();\n\n if (controlled !== undefined) {\n return controlled;\n }\n\n return this.internalSortState();\n });\n\n readonly filterState = computed(() => {\n const controlled = this.controlledFilterState();\n\n if (controlled !== undefined && controlled !== null) {\n return controlled;\n }\n\n return this.internalFilterState();\n });\n\n readonly pageState = computed(() => {\n const controlled = this.controlledPageState();\n\n if (controlled !== undefined) {\n return controlled;\n }\n\n return this.internalPageState();\n });\n\n // ===== SELECTION =====\n // Engine-owned (uncontrolled) selection state. The host data-table reads\n // from a controlled `selectedKeys` input when present and only writes\n // through `setSelectedKeys` here when running in uncontrolled mode.\n // Action methods stay pure — they compute the next Set from a current\n // Set and return it; they never mutate the input Set.\n readonly selectedKeys = signal<Set<unknown>>(new Set());\n\n // ===== EXPANSION =====\n // Mirror of selection: engine-owned Set of expanded row keys when the\n // host runs in uncontrolled mode. The host swaps to a controlled\n // `expandedKeys` input when supplied, the same way selection does.\n readonly expandedKeys = signal<Set<unknown>>(new Set());\n\n // ===== PROCESSED ROWS =====\n readonly sortedRows = computed(() => {\n const rows = this.rows();\n const sort = this.sortState();\n\n if (!sort || !sort.direction) {\n return rows;\n }\n\n const column = this.columns().find((c) => c.id === sort.columnId);\n\n if (!column) {\n return rows;\n }\n\n const direction = sort.direction;\n\n return [...rows].sort((a, b) => {\n const valA = column.sortAccessor\n ? column.sortAccessor(a)\n : this.resolveAccessor(column.accessor, a);\n const valB = column.sortAccessor\n ? column.sortAccessor(b)\n : this.resolveAccessor(column.accessor, b);\n\n return this.compare(valA, valB, direction);\n });\n });\n\n readonly filteredRows = computed(() => {\n const rows = this.sortedRows();\n const filter = this.filterState();\n\n if (!filter.query && Object.keys(filter.columnFilters).length === 0) {\n return rows;\n }\n\n const columns = this.columns();\n const query = filter.query.toLowerCase();\n\n return rows.filter((row) => {\n if (query) {\n const matches = columns.some((col) => {\n const val = this.resolveAccessor(col.accessor, row);\n\n return String(val ?? '')\n .toLowerCase()\n .includes(query);\n });\n\n if (!matches) {\n return false;\n }\n }\n\n return true;\n });\n });\n\n readonly processedRows = computed(() => {\n const rows = this.filteredRows();\n const page = this.pageState();\n\n if (!page) {\n return rows;\n }\n\n const start = page.page * page.pageSize;\n\n return rows.slice(start, start + page.pageSize);\n });\n\n readonly totalFilteredRows = computed(() => {\n return this.filteredRows().length;\n });\n\n // ===== ACTIONS =====\n toggleSort(columnId: string): SortState {\n const current = this.sortState();\n\n let direction: SortDirection;\n\n if (current?.columnId === columnId) {\n if (current.direction === 'asc') {\n direction = 'desc';\n } else if (current.direction === 'desc') {\n direction = null;\n } else {\n direction = 'asc';\n }\n } else {\n direction = 'asc';\n }\n\n const next: SortState = { columnId, direction };\n\n if (this.controlledSortState() === undefined) {\n this.internalSortState.set(next);\n }\n\n return next;\n }\n\n setFilter(query: string): FilterState {\n const next: FilterState = {\n ...this.filterState(),\n query,\n };\n\n if (this.controlledFilterState() === undefined) {\n this.internalFilterState.set(next);\n }\n\n return next;\n }\n\n setPage(page: number, pageSize?: number): PageState {\n const current = this.pageState();\n const next: PageState = {\n page,\n pageSize: pageSize ?? current?.pageSize ?? 10,\n totalRows: this.totalFilteredRows(),\n };\n\n if (this.controlledPageState() === undefined) {\n this.internalPageState.set(next);\n }\n\n return next;\n }\n\n /**\n * Replace the engine's internal selection state. Used by the host\n * data-table when running in uncontrolled mode (controlled mode goes\n * through the parent and never touches the engine here).\n */\n setSelectedKeys(next: Set<unknown>): void {\n this.selectedKeys.set(next);\n }\n\n /**\n * Replace the engine's internal expansion state. Used by the host\n * data-table when running in uncontrolled mode.\n */\n setExpandedKeys(next: Set<unknown>): void {\n this.expandedKeys.set(next);\n }\n\n /**\n * Toggle a single key in a Set. Derives from `current` and returns a\n * brand-new Set — never mutates the input.\n */\n toggleSelection(\n key: unknown,\n current: ReadonlySet<unknown> = this.selectedKeys(),\n ): Set<unknown> {\n const next = new Set(current);\n\n if (next.has(key)) {\n next.delete(key);\n } else {\n next.add(key);\n }\n\n return next;\n }\n\n /**\n * Page-local select-all. Toggles every key in `visibleKeys`:\n * - if all visible keys are already selected → deselect them\n * - otherwise → select them all (existing selections outside the visible\n * range stay intact)\n *\n * `disabledKeys` is excluded from both the toggle target and the\n * \"all-selected\" check, so a row marked `selectionDisabled` never\n * blocks the header checkbox from going fully checked.\n */\n toggleVisibleRows(\n visibleKeys: Iterable<unknown>,\n disabledKeys: ReadonlySet<unknown> = new Set(),\n current: ReadonlySet<unknown> = this.selectedKeys(),\n ): Set<unknown> {\n const eligible: unknown[] = [];\n\n for (const key of visibleKeys) {\n if (!disabledKeys.has(key)) {\n eligible.push(key);\n }\n }\n\n const allSelected =\n eligible.length > 0 && eligible.every((key) => current.has(key));\n\n const next = new Set(current);\n\n if (allSelected) {\n for (const key of eligible) {\n next.delete(key);\n }\n } else {\n for (const key of eligible) {\n next.add(key);\n }\n }\n\n return next;\n }\n\n clearSelection(): Set<unknown> {\n return new Set<unknown>();\n }\n\n isSelected(key: unknown): boolean {\n return this.selectedKeys().has(key);\n }\n\n // ===== HELPERS =====\n private resolveAccessor(\n accessor: keyof T | ((row: T) => unknown),\n row: T,\n ): unknown {\n if (typeof accessor === 'function') {\n return accessor(row);\n }\n\n return row[accessor];\n }\n\n private compare(a: unknown, b: unknown, direction: 'asc' | 'desc'): number {\n const multiplier = direction === 'asc' ? 1 : -1;\n\n if (a == null && b == null) {\n return 0;\n }\n\n if (a == null) {\n return 1 * multiplier;\n }\n\n if (b == null) {\n return -1 * multiplier;\n }\n\n if (typeof a === 'string' && typeof b === 'string') {\n return a.localeCompare(b) * multiplier;\n }\n\n if (typeof a === 'number' && typeof b === 'number') {\n return (a - b) * multiplier;\n }\n\n return String(a).localeCompare(String(b)) * multiplier;\n }\n}\n","import { computed, Injectable, type Signal, signal } from '@angular/core';\n\n@Injectable()\nexport class VirtualizationEngineService {\n // ===== CONFIGURATION =====\n readonly rowHeight = signal<number>(48);\n readonly overscan = signal<number>(10);\n readonly totalRows = signal<number>(0);\n\n // ===== VIEWPORT STATE =====\n readonly viewportHeight = signal<number>(0);\n readonly scrollTop = signal<number>(0);\n\n // ===== COMPUTED =====\n readonly visibleRange: Signal<{ start: number; end: number }> = computed(\n () => {\n const height = this.viewportHeight();\n const scroll = this.scrollTop();\n const rh = this.rowHeight();\n const os = this.overscan();\n const total = this.totalRows();\n\n if (rh <= 0 || total === 0) {\n return { start: 0, end: 0 };\n }\n\n const visibleCount = Math.ceil(height / rh);\n const firstVisible = Math.floor(scroll / rh);\n\n const start = Math.max(0, firstVisible - os);\n const end = Math.min(total, firstVisible + visibleCount + os);\n\n return { start, end };\n },\n );\n\n readonly totalHeight: Signal<number> = computed(() => {\n return this.totalRows() * this.rowHeight();\n });\n\n readonly offsetY: Signal<number> = computed(() => {\n return this.visibleRange().start * this.rowHeight();\n });\n\n readonly visibleCount: Signal<number> = computed(() => {\n const range = this.visibleRange();\n\n return range.end - range.start;\n });\n\n // ===== ACTIONS =====\n onScroll(scrollTop: number): void {\n this.scrollTop.set(scrollTop);\n }\n\n onViewportResize(height: number): void {\n this.viewportHeight.set(height);\n }\n}\n","import { NgStyle, NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n effect,\n ElementRef,\n HostBinding,\n inject,\n input,\n NgZone,\n output,\n type TemplateRef,\n viewChild,\n} from '@angular/core';\n\nimport { ColumnResizeDirective } from './column-resize.directive';\nimport {\n type ColumnDef,\n type ColumnResizeEvent,\n DEFAULT_TABLE_CONFIG,\n type ExpansionColumnPosition,\n type FilterState,\n type HeaderSelectionState,\n type PageState,\n type SelectionColumnPosition,\n type SelectionDisabled,\n type SortState,\n type TableConfig,\n type TableRowContext,\n} from './data-table.types';\nimport { DataTableGroupCoordinator } from './data-table-group.service';\nimport { DataTableStackComponent } from './data-table-stack.component';\nimport { ResponsiveStrategyService } from './responsive-strategy.service';\nimport { TableEngineService } from './table-engine.service';\nimport { groupHeadingForRow } from './data-table-grouping.util';\nimport { VirtualizationEngineService } from './virtualization-engine.service';\n\n@Component({\n selector: 'fk-data-table',\n standalone: true,\n imports: [\n NgStyle,\n NgTemplateOutlet,\n DataTableStackComponent,\n ColumnResizeDirective,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n TableEngineService,\n VirtualizationEngineService,\n ResponsiveStrategyService,\n ],\n templateUrl: './data-table.component.html',\n styleUrl: './data-table.component.scss',\n})\nexport class DataTableComponent<T = unknown> {\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== DATA =====\n /** Column definitions that describe the table schema, headers, and cell rendering. */\n readonly columns = input<ColumnDef<T>[]>([]);\n /** Array of row data objects rendered by the table. */\n readonly rows = input<T[]>([]);\n /** Partial table configuration merged with the defaults. */\n readonly config = input<Partial<TableConfig<T>>>({});\n /** When true, shows the loading overlay and suppresses the empty state. */\n readonly loading = input<boolean>(false);\n\n // ===== CONTROLLED STATE =====\n /** Controlled sort state; pass null to let the table manage sorting internally. */\n readonly sortState = input<SortState | null>(null);\n /** Controlled filter state; pass null to let the table manage filtering internally. */\n readonly filterState = input<FilterState | null>(null);\n /** Controlled page state; pass null to let the table manage pagination internally. */\n readonly pageState = input<PageState | null>(null);\n\n // ===== SELECTION =====\n // Opt-in via `rowSelection`. When the parent passes a `selectedKeys` Set the\n // table runs in controlled mode (parent owns state, table emits a new Set on\n // every change). When `selectedKeys` is null the table manages selection\n // internally — useful for Storybook and simple cases.\n //\n // `getRowId` is REQUIRED when `rowSelection` is true. Without a stable\n // row identity selection silently breaks across pagination. The constructor\n // logs a console error if it's missing in dev.\n /** Opt-in to row selection; requires `getRowId` for controlled mode across pagination. */\n readonly rowSelection = input<boolean>(false);\n /** Controlled set of selected row keys; null lets the table manage selection internally. */\n readonly selectedKeys = input<Set<unknown> | null>(null);\n /** Function that returns a stable unique key for each row, required when `rowSelection` is true. */\n readonly getRowId = input<((row: T) => unknown) | null>(null);\n /** Predicate (or static boolean) that disables selection for matching rows. */\n readonly selectionDisabled = input<SelectionDisabled<T>>(false);\n /** Whether the checkbox column appears at the start or end of the table. */\n readonly selectionColumnPosition = input<SelectionColumnPosition>('start');\n /** Accessible label for each row's selection checkbox. */\n readonly selectionLabel = input<string>('Select row');\n\n // ===== EXPANSION =====\n // Opt-in via `rowDetailTemplate`. When present the table auto-injects\n // a chevron column at start (default) or end and renders the projected\n // template as a detail row beneath each expanded row.\n //\n // `expandedKeys` mirrors the selection contract: pass a Set to run in\n // controlled mode (parent owns state, table emits the new Set on every\n // toggle) or omit to let the engine manage state internally.\n //\n // `expandableRow` lets a host predicate-disable expansion per row —\n // the chevron renders as an inert spacer so columns stay aligned.\n /** Template rendered as the expansion detail row; presence enables the feature. */\n readonly rowDetailTemplate = input<TemplateRef<{\n $implicit: T;\n row: T;\n index: number;\n }> | null>(null);\n /** Whether the chevron column appears at the start or end of the table. */\n readonly expansionColumnPosition = input<ExpansionColumnPosition>('start');\n /** Controlled set of expanded row keys; null lets the engine manage state internally. */\n readonly expandedKeys = input<Set<unknown> | null>(null);\n /** Predicate that disables expansion for matching rows; default: every row is expandable. */\n readonly expandableRow = input<((row: T) => boolean) | null>(null);\n /** Accessible label for each row's expansion chevron. */\n readonly expansionLabel = input<string>('Toggle row details');\n\n // ===== GROUPING =====\n /**\n * Template rendered inside a group heading. Receives the group key and the\n * first row of the group, so a heading can show more than the key it was\n * grouped by. Omit it and the key is rendered as text.\n */\n readonly groupHeadingRenderer = input<TemplateRef<{\n $implicit: string;\n row: T;\n }> | null>(null);\n\n // ===== OUTPUTS =====\n /** Fires when the user clicks a sortable column header, emitting the new sort state. */\n readonly sortChange = output<SortState>();\n /** Fires when a filter changes, emitting the updated filter state. */\n readonly filterChange = output<FilterState>();\n /** Fires when the user navigates to a different page or changes page size. */\n readonly pageChange = output<PageState>();\n /** Fires when the user clicks a table row, emitting the row context. */\n readonly rowClick = output<TableRowContext<T>>();\n /** Fires when the selection set changes, emitting the full new set of selected keys. */\n readonly selectionChange = output<Set<unknown>>();\n /** Fires when the expansion set changes, emitting the full new set of expanded keys. */\n readonly expansionChange = output<Set<unknown>>();\n /** Fires when the user finishes resizing a column, emitting the column id and new width. */\n readonly columnResize = output<ColumnResizeEvent>();\n\n // ===== ENGINE =====\n protected readonly engine: TableEngineService<T>;\n protected readonly virtEngine: VirtualizationEngineService;\n protected readonly responsive = inject(ResponsiveStrategyService<T>);\n\n // ===== VIEW CHILDREN =====\n readonly virtualViewport =\n viewChild<ElementRef<HTMLElement>>('virtualViewport');\n\n // ===== COMPUTED =====\n readonly mergedConfig = computed<TableConfig<T>>(() => {\n return { ...DEFAULT_TABLE_CONFIG, ...this.config() } as TableConfig<T>;\n });\n\n readonly visibleColumns = computed(() => {\n const responsiveCols = this.responsive.responsiveColumns();\n\n return responsiveCols.filter((col) => col.visible !== false);\n });\n\n readonly activeMode = computed(() => {\n return this.responsive.activeMode();\n });\n\n readonly useVirtualization = computed(() => {\n const config = this.mergedConfig();\n const rowCount = this.rows().length;\n\n // Virtualization positions rows by multiplying an index by `rowHeight`.\n // A group heading is not that tall, so every row after the first heading\n // would be placed wrong. Grouping wins; the alternative is a table that\n // silently misplaces its own rows.\n if (config.groupBy) {\n return false;\n }\n\n if (config.virtualization === true) {\n return true;\n }\n\n if (config.virtualization === false) {\n return false;\n }\n\n return rowCount > config.virtualizationThreshold;\n });\n\n readonly virtualRows = computed(() => {\n const rows = this.engine.processedRows();\n const range = this.virtEngine.visibleRange();\n\n return rows.slice(range.start, range.end);\n });\n\n readonly virtualStartIndex = computed(() => {\n return this.virtEngine.visibleRange().start;\n });\n\n /**\n * How many cells a heading has to span — the visible columns plus whichever\n * of the selection and expansion cells the table is currently rendering.\n */\n readonly groupHeadingSpan = computed(() => {\n let span = this.visibleColumns().length;\n\n if (this.rowSelection()) {\n span += 1;\n }\n\n if (this.hasExpansion()) {\n span += 1;\n }\n\n return span;\n });\n\n readonly isEmpty = computed(() => {\n return this.engine.processedRows().length === 0 && !this.loading();\n });\n\n readonly classes = computed(() => {\n return [\n 'fk-data-table',\n this.loading() ? 'fk-data-table--loading' : '',\n this.isEmpty() ? 'fk-data-table--empty' : '',\n this.mergedConfig().stickyHeader ? 'fk-data-table--sticky-header' : '',\n this.useVirtualization() ? 'fk-data-table--virtual' : '',\n this.activeMode() === 'stack' ? 'fk-data-table--stack' : '',\n this.className(),\n ]\n .filter(Boolean)\n .join(' ');\n });\n\n @HostBinding('class')\n get hostClass() {\n return this.classes();\n }\n\n @HostBinding('attr.id')\n get hostId(): string | null {\n return this.id();\n }\n\n private readonly ngZone = inject(NgZone);\n /**\n * Optional group coordinator picked up via DI when this table is\n * wrapped in `<fk-data-table-group>`. Presence flips expansion to\n * single-open mode; absence keeps multi-expand behavior (the\n * default).\n */\n private readonly groupCoordinator = inject(DataTableGroupCoordinator, {\n optional: true,\n });\n\n constructor() {\n this.engine = new TableEngineService<T>();\n this.virtEngine = new VirtualizationEngineService();\n\n // Clean up the coordinator's active-pointer when this table is torn\n // down so a sibling expansion doesn't try to collapse a stale ref.\n inject(DestroyRef).onDestroy(() => {\n this.groupCoordinator?.unregister(this as DataTableComponent<unknown>);\n });\n\n effect(() => {\n this.engine.rows.set(this.rows());\n });\n\n effect(() => {\n this.engine.columns.set(this.columns());\n });\n\n effect(() => {\n const sort = this.sortState();\n\n this.engine.controlledSortState.set(sort === null ? undefined : sort);\n });\n\n effect(() => {\n const filter = this.filterState();\n\n this.engine.controlledFilterState.set(\n filter === null ? undefined : filter,\n );\n });\n\n effect(() => {\n const page = this.pageState();\n\n this.engine.controlledPageState.set(page === null ? undefined : page);\n });\n\n // Dev-mode: warn once per misconfiguration when selection is enabled\n // but no row id resolver is provided. Without it `getSelectionKey`\n // falls back to row reference which silently breaks across pagination\n // since each fetch returns brand-new objects.\n let warnedNoRowId = false;\n\n effect(() => {\n if (this.rowSelection() && this.getRowId() === null && !warnedNoRowId) {\n warnedNoRowId = true;\n console.error(\n '[fk-data-table] `rowSelection` is true but `getRowId` was not ' +\n 'provided. Selection requires a stable row identifier — set ' +\n \"`[getRowId]` to a function returning each row's unique key.\",\n );\n }\n });\n\n // Sync virtualization config\n effect(() => {\n const config = this.mergedConfig();\n\n this.virtEngine.rowHeight.set(config.rowHeight);\n this.virtEngine.overscan.set(config.overscan);\n });\n\n // Sync total row count into virtualization engine\n effect(() => {\n this.virtEngine.totalRows.set(this.engine.processedRows().length);\n });\n\n // Sync responsive strategy\n effect(() => {\n this.responsive.columns.set(this.columns());\n });\n\n effect(() => {\n this.responsive.config.set(this.mergedConfig());\n });\n\n // Initialize breakpoint observer\n effect(() => {\n const config = this.mergedConfig();\n\n this.responsive.init(config.breakpoints);\n });\n }\n\n // ===== TEMPLATE HELPERS =====\n /** The group heading to open before this row, if it starts a new group. */\n groupHeadingFor(row: T, index: number): string | null {\n return groupHeadingForRow(\n this.engine.processedRows(),\n row,\n index,\n this.mergedConfig().groupBy,\n );\n }\n\n /** Resolves the display value for a cell given its column definition and row data. */\n getCellValue(column: ColumnDef<T>, row: T): unknown {\n if (typeof column.accessor === 'function') {\n return column.accessor(row);\n }\n\n return row[column.accessor as keyof T];\n }\n\n /** Returns the trackBy function from the merged config for use in `*ngFor`. */\n getTrackBy(): (index: number, row: T) => unknown {\n return this.mergedConfig().trackBy;\n }\n\n // ===== SELECTION HELPERS =====\n\n /**\n * Source of truth for which keys are currently selected. Reads the\n * controlled `selectedKeys` input when the parent supplied one;\n * otherwise falls back to the engine's internal state (uncontrolled\n * mode). Computed so changes flow through Angular's signal graph\n * without effect-write timing surprises.\n */\n private readonly effectiveSelectedKeys = computed<Set<unknown>>(() => {\n const controlled = this.selectedKeys();\n\n if (controlled !== null) {\n return controlled;\n }\n\n return this.engine.selectedKeys();\n });\n\n /**\n * Public alias of `effectiveSelectedKeys` for the stack (mobile) child\n * binding. The private field stays private to discourage callers from\n * reaching past the API.\n */\n readonly effectiveSelectedKeysForTemplate = this.effectiveSelectedKeys;\n\n /**\n * Resolve a row's selection key. Uses the explicit `getRowId` input\n * when provided; otherwise falls back to the row reference itself\n * (which only works if rows are object-stable across renders — fine\n * for uncontrolled-mode demos, broken across server-side pagination).\n */\n /** Resolves a stable selection key for the given row using `getRowId` or falling back to the row reference. */\n getSelectionKey(row: T): unknown {\n const idFn = this.getRowId();\n\n if (idFn) {\n return idFn(row);\n }\n\n return row;\n }\n\n /** Returns true if the given row is currently in the selected keys set. */\n isRowSelected(row: T): boolean {\n return this.effectiveSelectedKeys().has(this.getSelectionKey(row));\n }\n\n /** Returns true if selection is disabled for the given row per the `selectionDisabled` input. */\n isRowSelectionDisabled(row: T): boolean {\n const disabled = this.selectionDisabled();\n\n if (typeof disabled === 'function') {\n return disabled(row);\n }\n\n return disabled;\n }\n\n /**\n * Selection state of the header checkbox, derived from visible rows ∩\n * `effectiveSelectedKeys`. Disabled rows are excluded — they can't\n * contribute to the all-selected check.\n */\n readonly headerSelectionState = computed<HeaderSelectionState>(() => {\n if (!this.rowSelection()) {\n return 'unchecked';\n }\n\n const selected = this.effectiveSelectedKeys();\n const visibleEligible = this.visibleSelectableRows();\n\n if (visibleEligible.length === 0) {\n return 'unchecked';\n }\n\n let hits = 0;\n\n for (const row of visibleEligible) {\n if (selected.has(this.getSelectionKey(row))) {\n hits++;\n }\n }\n\n if (hits === 0) {\n return 'unchecked';\n }\n\n if (hits === visibleEligible.length) {\n return 'checked';\n }\n\n return 'indeterminate';\n });\n\n /**\n * Rows currently visible in the body (post-pagination) excluding any\n * marked as selection-disabled. The header checkbox toggles only over\n * this set.\n */\n private readonly visibleSelectableRows = computed<T[]>(() => {\n return this.engine\n .processedRows()\n .filter((row) => !this.isRowSelectionDisabled(row));\n });\n\n // ===== SELECTION ACTIONS =====\n\n onToggleRow(row: T, event: Event): void {\n event.stopPropagation();\n\n if (this.isRowSelectionDisabled(row)) {\n return;\n }\n\n const key = this.getSelectionKey(row);\n const current = this.effectiveSelectedKeys();\n const next = new Set(current);\n\n if (next.has(key)) {\n next.delete(key);\n } else {\n next.add(key);\n }\n\n if (this.selectedKeys() === null) {\n this.engine.setSelectedKeys(next);\n }\n\n this.selectionChange.emit(next);\n }\n\n onToggleAllVisible(event: Event): void {\n event.stopPropagation();\n\n const visible = this.visibleSelectableRows();\n const visibleKeys = visible.map((row) => this.getSelectionKey(row));\n const current = this.effectiveSelectedKeys();\n const allSelected =\n visibleKeys.length > 0 && visibleKeys.every((key) => current.has(key));\n\n const next = new Set(current);\n\n if (allSelected) {\n for (const key of visibleKeys) {\n next.delete(key);\n }\n } else {\n for (const key of visibleKeys) {\n next.add(key);\n }\n }\n\n if (this.selectedKeys() === null) {\n this.engine.setSelectedKeys(next);\n }\n\n this.selectionChange.emit(next);\n }\n\n // ===== EXPANSION HELPERS =====\n\n /**\n * Source of truth for which row keys are currently expanded. Reads\n * the controlled `expandedKeys` input when the parent supplied one,\n * otherwise falls back to the engine's internal set.\n */\n private readonly effectiveExpandedKeys = computed<Set<unknown>>(() => {\n const controlled = this.expandedKeys();\n\n if (controlled !== null) {\n return controlled;\n }\n\n return this.engine.expandedKeys();\n });\n\n /** True when `rowDetailTemplate` is set — the feature is opt-in. */\n readonly hasExpansion = computed(() => this.rowDetailTemplate() !== null);\n\n /**\n * Whether the expand chevron column appears at the start. When the\n * expansion feature is off this returns false so the column doesn't\n * render. Selection takes priority when both are pinned to \"start\"\n * (selection comes first, then expand).\n */\n readonly hasExpansionStart = computed(\n () => this.hasExpansion() && this.expansionColumnPosition() === 'start',\n );\n\n readonly hasExpansionEnd = computed(\n () => this.hasExpansion() && this.expansionColumnPosition() === 'end',\n );\n\n /** Returns true if the given row is currently expanded. */\n isRowExpanded(row: T): boolean {\n return this.effectiveExpandedKeys().has(this.getSelectionKey(row));\n }\n\n /** Returns true unless an `expandableRow` predicate explicitly excludes the row. */\n isRowExpandable(row: T): boolean {\n const predicate = this.expandableRow();\n\n if (predicate) {\n return predicate(row);\n }\n\n return true;\n }\n\n /**\n * Total columns rendered per row (data columns + selection col + expand col).\n * Used as the colspan for the detail `<td>` so it spans the full row width.\n */\n readonly totalColumnCount = computed(() => {\n let count = this.visibleColumns().length;\n\n if (this.rowSelection()) {\n count += 1;\n }\n\n if (this.hasExpansion()) {\n count += 1;\n }\n\n return count;\n });\n\n /** Toggle a single row's expansion via chevron click or keyboard. */\n onToggleExpand(row: T, event: Event): void {\n event.stopPropagation();\n\n if (!this.isRowExpandable(row)) {\n return;\n }\n\n const key = this.getSelectionKey(row);\n const currentSet = this.effectiveExpandedKeys();\n const wasExpanded = currentSet.has(key);\n const nextExpanded = !wasExpanded;\n\n if (this.groupCoordinator) {\n // Single-expand mode — route through the coordinator so a\n // sibling row (or sibling table) gets collapsed atomically.\n const { keysForThisTable, siblingTableToClear } =\n this.groupCoordinator.resolveToggle(\n this as DataTableComponent<unknown>,\n key,\n nextExpanded,\n currentSet,\n );\n\n this.commitExpansion(keysForThisTable);\n\n if (siblingTableToClear) {\n siblingTableToClear.clearExpansion();\n }\n\n return;\n }\n\n // Multi-expand mode — default. Add or remove this key from the set.\n const next = new Set(currentSet);\n\n if (wasExpanded) {\n next.delete(key);\n } else {\n next.add(key);\n }\n\n this.commitExpansion(next);\n }\n\n /**\n * Public hook used by the group coordinator to force-clear this\n * table's expansion when a sibling table opens a row. Routes through\n * the same commit path so controlled-mode parents still see the\n * emission.\n */\n clearExpansion(): void {\n if (this.effectiveExpandedKeys().size === 0) {\n return;\n }\n\n this.commitExpansion(new Set());\n }\n\n private commitExpansion(next: Set<unknown>): void {\n if (this.expandedKeys() === null) {\n this.engine.setExpandedKeys(next);\n }\n\n this.expansionChange.emit(next);\n }\n\n // ===== ACTIONS =====\n onHeaderClick(column: ColumnDef<T>): void {\n if (!column.sortable) {\n return;\n }\n\n const next = this.engine.toggleSort(column.id);\n\n this.sortChange.emit(next);\n }\n\n /** Returns an inline style object for the row if a `rowStyleFn` is configured, otherwise null. */\n getRowStyle(row: T, index: number): Record<string, string> | null {\n const fn = this.mergedConfig().rowStyleFn;\n\n if (!fn) {\n return null;\n }\n\n return fn(row, index);\n }\n\n onRowClick(row: T, index: number): void {\n this.rowClick.emit({\n row,\n index,\n selected: false,\n expanded: false,\n });\n }\n\n onVirtualScroll(event: Event): void {\n const target = event.target as HTMLElement;\n\n this.virtEngine.onScroll(target.scrollTop);\n }\n\n onViewportInit(el: HTMLElement): void {\n this.virtEngine.onViewportResize(el.clientHeight);\n\n if (typeof ResizeObserver !== 'undefined') {\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n this.ngZone.run(() => {\n this.virtEngine.onViewportResize(entry.contentRect.height);\n });\n }\n });\n\n observer.observe(el);\n }\n }\n\n getPinOffset(column: ColumnDef<T>): string | null {\n if (!column.pinned) {\n return null;\n }\n\n const cols = this.visibleColumns();\n const side = column.pinned;\n\n let offset = 0;\n\n if (side === 'start') {\n for (const col of cols) {\n if (col.id === column.id) {\n break;\n }\n\n if (col.pinned === 'start') {\n offset += parseInt(col.width ?? col.minWidth ?? '0', 10) || 0;\n }\n }\n } else {\n for (let i = cols.length - 1; i >= 0; i--) {\n if (cols[i].id === column.id) {\n break;\n }\n\n if (cols[i].pinned === 'end') {\n offset += parseInt(cols[i].width ?? cols[i].minWidth ?? '0', 10) || 0;\n }\n }\n }\n\n return `${offset}px`;\n }\n\n onColumnResize(event: ColumnResizeEvent): void {\n this.columnResize.emit(event);\n }\n\n /** Returns the current sort direction for the given column id, or null if not sorted. */\n getSortDirection(columnId: string): 'asc' | 'desc' | null {\n const sort = this.engine.sortState();\n\n if (sort?.columnId !== columnId) {\n return null;\n }\n\n return sort.direction;\n }\n}\n","@if (activeMode() === 'stack') {\n <!-- Stack path: mobile card view -->\n <fk-data-table-stack\n [rows]=\"engine.processedRows()\"\n [columns]=\"columns()\"\n [config]=\"mergedConfig()\"\n [trackByFn]=\"mergedConfig().trackBy\"\n [rowSelection]=\"rowSelection()\"\n [selectedKeys]=\"effectiveSelectedKeysForTemplate()\"\n [getRowId]=\"getRowId()\"\n [selectionDisabled]=\"selectionDisabled()\"\n [selectionLabel]=\"selectionLabel()\"\n [groupHeadingRenderer]=\"groupHeadingRenderer()\"\n (rowClick)=\"rowClick.emit($event)\"\n (toggleRow)=\"onToggleRow($event.row, $event.event)\"\n />\n} @else if (useVirtualization()) {\n <!-- Virtual path: div/grid-based with virtual scrolling -->\n <div role=\"table\" [attr.aria-label]=\"ariaLabel()\">\n @if (mergedConfig().showHeader) {\n <div class=\"fk-data-table__head\" role=\"rowgroup\">\n <div class=\"fk-data-table__head-row\" role=\"row\">\n @if (rowSelection() && selectionColumnPosition() === 'start') {\n <div\n class=\"fk-data-table__th fk-data-table__selection-cell\"\n role=\"columnheader\"\n >\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"\n headerSelectionState() === 'checked'\n ? 'Deselect all on page'\n : 'Select all on page'\n \"\n [checked]=\"headerSelectionState() === 'checked'\"\n [indeterminate]=\"headerSelectionState() === 'indeterminate'\"\n (click)=\"onToggleAllVisible($event)\"\n />\n </div>\n }\n @for (column of visibleColumns(); track column.id) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div\n class=\"fk-data-table__th\"\n role=\"columnheader\"\n [fkColumnResize]=\"column.id\"\n [enabled]=\"column.resizable === true\"\n (columnResize)=\"onColumnResize($event)\"\n [class.fk-data-table__th--sortable]=\"column.sortable\"\n [class.fk-data-table__th--align-center]=\"\n column.align === 'center'\n \"\n [class.fk-data-table__th--align-end]=\"column.align === 'end'\"\n [class.fk-data-table__th--pinned-start]=\"\n column.pinned === 'start'\n \"\n [class.fk-data-table__th--pinned-end]=\"column.pinned === 'end'\"\n [style.width]=\"column.width ?? null\"\n [style.min-width]=\"column.minWidth ?? null\"\n [style.max-width]=\"column.maxWidth ?? null\"\n [style.flex]=\"column.flex ?? null\"\n [style.--fk-data-table-pin-offset]=\"getPinOffset(column)\"\n [attr.aria-sort]=\"\n getSortDirection(column.id) === 'asc'\n ? 'ascending'\n : getSortDirection(column.id) === 'desc'\n ? 'descending'\n : null\n \"\n (click)=\"onHeaderClick(column)\"\n >\n @if (column.headerRenderer) {\n <ng-container\n [ngTemplateOutlet]=\"column.headerRenderer\"\n [ngTemplateOutletContext]=\"{ $implicit: column }\"\n />\n } @else {\n {{ column.header }}\n }\n\n @if (column.sortable) {\n <span\n class=\"fk-data-table__sort-indicator\"\n [class.fk-data-table__sort-indicator--asc]=\"\n getSortDirection(column.id) === 'asc'\n \"\n [class.fk-data-table__sort-indicator--desc]=\"\n getSortDirection(column.id) === 'desc'\n \"\n aria-hidden=\"true\"\n >\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M5 2L8 6H2L5 2Z\" fill=\"currentColor\" />\n </svg>\n </span>\n }\n </div>\n }\n @if (rowSelection() && selectionColumnPosition() === 'end') {\n <div\n class=\"fk-data-table__th fk-data-table__selection-cell\"\n role=\"columnheader\"\n >\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"\n headerSelectionState() === 'checked'\n ? 'Deselect all on page'\n : 'Select all on page'\n \"\n [checked]=\"headerSelectionState() === 'checked'\"\n [indeterminate]=\"headerSelectionState() === 'indeterminate'\"\n (click)=\"onToggleAllVisible($event)\"\n />\n </div>\n }\n </div>\n </div>\n }\n\n <div\n #virtualViewport\n class=\"fk-data-table__viewport\"\n role=\"rowgroup\"\n (scroll)=\"onVirtualScroll($event)\"\n >\n <div\n class=\"fk-data-table__sentinel\"\n [style.height.px]=\"virtEngine.totalHeight()\"\n ></div>\n\n <div\n class=\"fk-data-table__virtual-body\"\n [style.transform]=\"'translateY(' + virtEngine.offsetY() + 'px)'\"\n >\n @for (\n row of virtualRows();\n track mergedConfig().trackBy(virtualStartIndex() + $index, row);\n let i = $index\n ) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div\n class=\"fk-data-table__row\"\n role=\"row\"\n [class.fk-data-table__row--selected]=\"isRowSelected(row)\"\n [style.height.px]=\"mergedConfig().rowHeight\"\n [ngStyle]=\"getRowStyle(row, virtualStartIndex() + i)\"\n (click)=\"onRowClick(row, virtualStartIndex() + i)\"\n >\n @if (rowSelection() && selectionColumnPosition() === 'start') {\n <div\n class=\"fk-data-table__td fk-data-table__selection-cell\"\n role=\"cell\"\n >\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"selectionLabel()\"\n [checked]=\"isRowSelected(row)\"\n [disabled]=\"isRowSelectionDisabled(row)\"\n (click)=\"onToggleRow(row, $event)\"\n />\n </div>\n }\n @for (column of visibleColumns(); track column.id) {\n <div\n class=\"fk-data-table__td\"\n role=\"cell\"\n [class.fk-data-table__td--truncate]=\"column.truncate\"\n [class.fk-data-table__td--align-center]=\"\n column.align === 'center'\n \"\n [class.fk-data-table__td--align-end]=\"column.align === 'end'\"\n [class.fk-data-table__td--pinned-start]=\"\n column.pinned === 'start'\n \"\n [class.fk-data-table__td--pinned-end]=\"column.pinned === 'end'\"\n [style.width]=\"column.width ?? null\"\n [style.min-width]=\"column.minWidth ?? null\"\n [style.max-width]=\"column.maxWidth ?? null\"\n [style.flex]=\"column.flex ?? null\"\n [style.--fk-data-table-pin-offset]=\"getPinOffset(column)\"\n >\n @if (column.cellRenderer) {\n <ng-container\n [ngTemplateOutlet]=\"column.cellRenderer\"\n [ngTemplateOutletContext]=\"{\n $implicit: getCellValue(column, row),\n row: row,\n }\"\n />\n } @else {\n {{ getCellValue(column, row) }}\n }\n </div>\n }\n @if (rowSelection() && selectionColumnPosition() === 'end') {\n <div\n class=\"fk-data-table__td fk-data-table__selection-cell\"\n role=\"cell\"\n >\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"selectionLabel()\"\n [checked]=\"isRowSelected(row)\"\n [disabled]=\"isRowSelectionDisabled(row)\"\n (click)=\"onToggleRow(row, $event)\"\n />\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n @if (isEmpty()) {\n <div class=\"fk-data-table__empty\" role=\"row\">\n <div role=\"cell\">{{ mergedConfig().emptyMessage }}</div>\n </div>\n }\n </div>\n} @else {\n <!-- Standard path: semantic table -->\n <div class=\"fk-data-table__scroll\">\n <table class=\"fk-data-table__table\" [attr.aria-label]=\"ariaLabel()\">\n @if (mergedConfig().showHeader) {\n <thead class=\"fk-data-table__head\">\n <tr class=\"fk-data-table__head-row\">\n @if (rowSelection() && selectionColumnPosition() === 'start') {\n <th class=\"fk-data-table__th fk-data-table__selection-cell\">\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"\n headerSelectionState() === 'checked'\n ? 'Deselect all on page'\n : 'Select all on page'\n \"\n [checked]=\"headerSelectionState() === 'checked'\"\n [indeterminate]=\"headerSelectionState() === 'indeterminate'\"\n (click)=\"onToggleAllVisible($event)\"\n />\n </th>\n }\n @if (hasExpansionStart()) {\n <th\n class=\"fk-data-table__th fk-data-table__expand-cell\"\n aria-hidden=\"true\"\n ></th>\n }\n @for (column of visibleColumns(); track column.id) {\n <th\n class=\"fk-data-table__th\"\n [fkColumnResize]=\"column.id\"\n [enabled]=\"column.resizable === true\"\n (columnResize)=\"onColumnResize($event)\"\n [class.fk-data-table__th--sortable]=\"column.sortable\"\n [class.fk-data-table__th--align-center]=\"\n column.align === 'center'\n \"\n [class.fk-data-table__th--align-end]=\"column.align === 'end'\"\n [class.fk-data-table__th--pinned-start]=\"\n column.pinned === 'start'\n \"\n [class.fk-data-table__th--pinned-end]=\"column.pinned === 'end'\"\n [style.width]=\"column.width ?? null\"\n [style.min-width]=\"column.minWidth ?? null\"\n [style.max-width]=\"column.maxWidth ?? null\"\n [style.--fk-data-table-pin-offset]=\"getPinOffset(column)\"\n [attr.aria-sort]=\"\n getSortDirection(column.id) === 'asc'\n ? 'ascending'\n : getSortDirection(column.id) === 'desc'\n ? 'descending'\n : null\n \"\n (click)=\"onHeaderClick(column)\"\n >\n @if (column.headerRenderer) {\n <ng-container\n [ngTemplateOutlet]=\"column.headerRenderer\"\n [ngTemplateOutletContext]=\"{ $implicit: column }\"\n />\n } @else {\n {{ column.header }}\n }\n\n @if (column.sortable) {\n <span\n class=\"fk-data-table__sort-indicator\"\n [class.fk-data-table__sort-indicator--asc]=\"\n getSortDirection(column.id) === 'asc'\n \"\n [class.fk-data-table__sort-indicator--desc]=\"\n getSortDirection(column.id) === 'desc'\n \"\n aria-hidden=\"true\"\n >\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M5 2L8 6H2L5 2Z\" fill=\"currentColor\" />\n </svg>\n </span>\n }\n </th>\n }\n @if (rowSelection() && selectionColumnPosition() === 'end') {\n <th class=\"fk-data-table__th fk-data-table__selection-cell\">\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"\n headerSelectionState() === 'checked'\n ? 'Deselect all on page'\n : 'Select all on page'\n \"\n [checked]=\"headerSelectionState() === 'checked'\"\n [indeterminate]=\"headerSelectionState() === 'indeterminate'\"\n (click)=\"onToggleAllVisible($event)\"\n />\n </th>\n }\n @if (hasExpansionEnd()) {\n <th\n class=\"fk-data-table__th fk-data-table__expand-cell\"\n aria-hidden=\"true\"\n ></th>\n }\n </tr>\n </thead>\n }\n\n <tbody class=\"fk-data-table__body\">\n @for (\n row of engine.processedRows();\n track mergedConfig().trackBy($index, row);\n let i = $index\n ) {\n <!--\n A heading opens each run of rows sharing a group key. Emitted from\n inside the row loop rather than by pre-grouping the rows, so the\n table still renders exactly the rows it was given, in the order it\n was given them.\n -->\n @if (groupHeadingFor(row, i); as heading) {\n <tr class=\"fk-data-table__group-heading\">\n <th\n scope=\"colgroup\"\n class=\"fk-data-table__group-heading-cell\"\n [attr.colspan]=\"groupHeadingSpan()\"\n >\n @if (groupHeadingRenderer()) {\n <ng-container\n [ngTemplateOutlet]=\"groupHeadingRenderer()!\"\n [ngTemplateOutletContext]=\"{ $implicit: heading, row: row }\"\n />\n } @else {\n {{ heading }}\n }\n </th>\n </tr>\n }\n\n <tr\n class=\"fk-data-table__row\"\n [class.fk-data-table__row--selected]=\"isRowSelected(row)\"\n [class.fk-data-table__row--expanded]=\"\n hasExpansion() && isRowExpanded(row)\n \"\n [ngStyle]=\"getRowStyle(row, i)\"\n (click)=\"onRowClick(row, i)\"\n >\n @if (rowSelection() && selectionColumnPosition() === 'start') {\n <td class=\"fk-data-table__td fk-data-table__selection-cell\">\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"selectionLabel()\"\n [checked]=\"isRowSelected(row)\"\n [disabled]=\"isRowSelectionDisabled(row)\"\n (click)=\"onToggleRow(row, $event)\"\n />\n </td>\n }\n @if (hasExpansionStart()) {\n <td class=\"fk-data-table__td fk-data-table__expand-cell\">\n @if (isRowExpandable(row)) {\n <button\n type=\"button\"\n class=\"fk-data-table__expand-button\"\n [class.fk-data-table__expand-button--expanded]=\"\n isRowExpanded(row)\n \"\n [attr.aria-label]=\"expansionLabel()\"\n [attr.aria-expanded]=\"isRowExpanded(row)\"\n (click)=\"onToggleExpand(row, $event)\"\n >\n <svg\n class=\"fk-data-table__expand-chevron\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n aria-hidden=\"true\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M3 1.5L6.5 5L3 8.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n }\n </td>\n }\n @for (column of visibleColumns(); track column.id) {\n <td\n class=\"fk-data-table__td\"\n [class.fk-data-table__td--truncate]=\"column.truncate\"\n [class.fk-data-table__td--align-center]=\"\n column.align === 'center'\n \"\n [class.fk-data-table__td--align-end]=\"column.align === 'end'\"\n [class.fk-data-table__td--pinned-start]=\"\n column.pinned === 'start'\n \"\n [class.fk-data-table__td--pinned-end]=\"column.pinned === 'end'\"\n [style.--fk-data-table-pin-offset]=\"getPinOffset(column)\"\n >\n @if (column.cellRenderer) {\n <ng-container\n [ngTemplateOutlet]=\"column.cellRenderer\"\n [ngTemplateOutletContext]=\"{\n $implicit: getCellValue(column, row),\n row: row,\n }\"\n />\n } @else {\n {{ getCellValue(column, row) }}\n }\n </td>\n }\n @if (rowSelection() && selectionColumnPosition() === 'end') {\n <td class=\"fk-data-table__td fk-data-table__selection-cell\">\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"selectionLabel()\"\n [checked]=\"isRowSelected(row)\"\n [disabled]=\"isRowSelectionDisabled(row)\"\n (click)=\"onToggleRow(row, $event)\"\n />\n </td>\n }\n @if (hasExpansionEnd()) {\n <td class=\"fk-data-table__td fk-data-table__expand-cell\">\n @if (isRowExpandable(row)) {\n <button\n type=\"button\"\n class=\"fk-data-table__expand-button\"\n [class.fk-data-table__expand-button--expanded]=\"\n isRowExpanded(row)\n \"\n [attr.aria-label]=\"expansionLabel()\"\n [attr.aria-expanded]=\"isRowExpanded(row)\"\n (click)=\"onToggleExpand(row, $event)\"\n >\n <svg\n class=\"fk-data-table__expand-chevron\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n aria-hidden=\"true\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M3 1.5L6.5 5L3 8.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n }\n </td>\n }\n </tr>\n @if (hasExpansion() && isRowExpanded(row)) {\n <tr class=\"fk-data-table__detail-row\">\n <td\n class=\"fk-data-table__detail-cell\"\n [attr.colspan]=\"totalColumnCount()\"\n >\n <ng-container\n [ngTemplateOutlet]=\"rowDetailTemplate()!\"\n [ngTemplateOutletContext]=\"{\n $implicit: row,\n row: row,\n index: i,\n }\"\n />\n </td>\n </tr>\n }\n }\n </tbody>\n </table>\n\n @if (isEmpty()) {\n <div class=\"fk-data-table__empty\">\n {{ mergedConfig().emptyMessage }}\n </div>\n }\n </div>\n}\n\n@if (loading()) {\n <div class=\"fk-data-table__loading-overlay\" aria-live=\"polite\">\n <span class=\"fk-data-table__loading-text\">Loading…</span>\n </div>\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n} from '@angular/core';\n\nimport { DataTableGroupCoordinator } from './data-table-group.service';\n\n/**\n * Single-expand wrapper for `<fk-data-table>`. Mirror of\n * `<fk-accordion-group>`: provides a coordinator scoped to itself, any\n * descendant data-table picks it up via DI and routes every expansion\n * toggle through it. The coordinator collapses the previously-active\n * row when a new one expands so only one detail panel is open.\n *\n * Wrap a data-table when you want exclusive expansion:\n *\n * ```html\n * <fk-data-table-group>\n * <fk-data-table [rowDetailTemplate]=\"detail\" ... />\n * </fk-data-table-group>\n * ```\n *\n * Omit the wrapper for multi-expand (the default).\n */\n@Component({\n selector: 'fk-data-table-group',\n standalone: true,\n imports: [],\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [DataTableGroupCoordinator],\n template: `<ng-content />`,\n})\nexport class DataTableGroupComponent {\n readonly className = input<string>('');\n\n readonly classes = computed(() => {\n return ['fk-data-table-group', this.className()].filter(Boolean).join(' ');\n });\n\n @HostBinding('class')\n get hostClass(): string {\n return this.classes();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"frame-kit-ui-ng-ui-data-table.mjs","sources":["../../../../packages/ui-ng/ui/data-table/column-resize.directive.ts","../../../../packages/ui-ng/ui/data-table/data-table.types.ts","../../../../packages/ui-ng/ui/data-table/data-table-group.service.ts","../../../../packages/ui-ng/ui/data-table/data-table-grouping.util.ts","../../../../packages/ui-ng/ui/data-table/data-table-stack.component.ts","../../../../packages/ui-ng/ui/data-table/data-table-stack.component.html","../../../../packages/ui-ng/ui/data-table/responsive-strategy.service.ts","../../../../packages/ui-ng/ui/data-table/table-engine.service.ts","../../../../packages/ui-ng/ui/data-table/virtualization-engine.service.ts","../../../../packages/ui-ng/ui/data-table/data-table.component.ts","../../../../packages/ui-ng/ui/data-table/data-table.component.html","../../../../packages/ui-ng/ui/data-table/data-table-group.component.ts","../../../../packages/ui-ng/ui/data-table/frame-kit-ui-ng-ui-data-table.ts"],"sourcesContent":["import {\n Directive,\n ElementRef,\n inject,\n input,\n NgZone,\n OnDestroy,\n OnInit,\n output,\n Renderer2,\n} from '@angular/core';\n\nimport type { ColumnResizeEvent } from './data-table.types';\n\n@Directive({\n selector: '[fkColumnResize]',\n standalone: true,\n})\nexport class ColumnResizeDirective implements OnInit, OnDestroy {\n readonly columnId = input.required<string>({ alias: 'fkColumnResize' });\n readonly enabled = input<boolean>(true);\n readonly minWidth = input<number>(50);\n readonly maxWidth = input<number | null>(null);\n\n readonly columnResize = output<ColumnResizeEvent>();\n\n private readonly el = inject(ElementRef<HTMLElement>);\n private readonly renderer = inject(Renderer2);\n private readonly ngZone = inject(NgZone);\n\n private handle: HTMLElement | null = null;\n private startX = 0;\n private startWidth = 0;\n private dragging = false;\n\n private moveListener: (() => void) | null = null;\n private upListener: (() => void) | null = null;\n\n ngOnInit(): void {\n if (!this.enabled()) {\n return;\n }\n\n this.handle = this.renderer.createElement('div');\n this.renderer.addClass(this.handle, 'fk-data-table__resize-handle');\n this.renderer.appendChild(this.el.nativeElement, this.handle);\n\n this.ngZone.runOutsideAngular(() => {\n this.handle?.addEventListener('mousedown', this.onMouseDown);\n this.handle?.addEventListener('touchstart', this.onTouchStart, {\n passive: false,\n });\n });\n }\n\n ngOnDestroy(): void {\n this.cleanupListeners();\n this.handle?.removeEventListener('mousedown', this.onMouseDown);\n this.handle?.removeEventListener('touchstart', this.onTouchStart);\n }\n\n private readonly onMouseDown = (event: MouseEvent): void => {\n event.preventDefault();\n\n this.startDrag(event.clientX);\n\n this.moveListener = this.renderer.listen(\n 'document',\n 'mousemove',\n (e: MouseEvent) => this.onDrag(e.clientX),\n );\n\n this.upListener = this.renderer.listen('document', 'mouseup', () =>\n this.endDrag(),\n );\n };\n\n private readonly onTouchStart = (event: TouchEvent): void => {\n event.preventDefault();\n\n const touch = event.touches[0];\n\n this.startDrag(touch.clientX);\n\n this.moveListener = this.renderer.listen(\n 'document',\n 'touchmove',\n (e: TouchEvent) => this.onDrag(e.touches[0].clientX),\n );\n\n this.upListener = this.renderer.listen('document', 'touchend', () =>\n this.endDrag(),\n );\n };\n\n private startDrag(clientX: number): void {\n this.dragging = true;\n this.startX = clientX;\n this.startWidth = this.el.nativeElement.offsetWidth;\n this.renderer.addClass(document.body, 'fk-data-table--resizing');\n }\n\n private onDrag(clientX: number): void {\n if (!this.dragging) {\n return;\n }\n\n const diff = clientX - this.startX;\n const min = this.minWidth();\n const max = this.maxWidth();\n\n let newWidth = this.startWidth + diff;\n\n if (newWidth < min) {\n newWidth = min;\n }\n\n if (max !== null && newWidth > max) {\n newWidth = max;\n }\n\n this.renderer.setStyle(this.el.nativeElement, 'width', `${newWidth}px`);\n }\n\n private endDrag(): void {\n if (!this.dragging) {\n return;\n }\n\n this.dragging = false;\n this.renderer.removeClass(document.body, 'fk-data-table--resizing');\n this.cleanupListeners();\n\n const finalWidth = this.el.nativeElement.offsetWidth;\n\n this.ngZone.run(() => {\n this.columnResize.emit({\n columnId: this.columnId(),\n width: finalWidth,\n });\n });\n }\n\n private cleanupListeners(): void {\n if (this.moveListener) {\n this.moveListener();\n this.moveListener = null;\n }\n\n if (this.upListener) {\n this.upListener();\n this.upListener = null;\n }\n }\n}\n","import type { TemplateRef } from '@angular/core';\n\n// ===== COLUMN DEFINITION =====\n\nexport interface ColumnDef<T = unknown> {\n id: string;\n header: string;\n accessor: keyof T | ((row: T) => unknown);\n sortAccessor?: (row: T) => unknown;\n width?: string;\n minWidth?: string;\n maxWidth?: string;\n flex?: number;\n sortable?: boolean;\n align?: 'start' | 'center' | 'end';\n truncate?: boolean;\n visible?: boolean;\n className?: string;\n headerClassName?: string;\n cellRenderer?: TemplateRef<{ $implicit: unknown; row: T }>;\n headerRenderer?: TemplateRef<{ $implicit: ColumnDef<T> }>;\n\n priority?: number;\n hideBelow?: 'sm' | 'md' | 'lg';\n mobileLabel?: string;\n\n resizable?: boolean;\n pinnable?: boolean;\n pinned?: 'start' | 'end' | null;\n}\n\n// ===== TABLE CONFIGURATION =====\n\nexport interface TableConfig<T = unknown> {\n responsiveMode: 'auto' | 'scroll' | 'stack' | 'priority';\n forceScroll: boolean;\n stickyHeader: boolean;\n showHeader: boolean;\n rowExpansion: boolean;\n emptyMessage: string;\n trackBy: (index: number, row: T) => unknown;\n rowStyleFn: ((row: T, index: number) => Record<string, string> | null) | null;\n /**\n * Groups consecutive rows under a heading. Returns the group key for a row,\n * or `null` to leave it ungrouped; a heading is emitted wherever the key\n * changes from the previous row.\n *\n * Grouping reads the rows in the order they are already sorted — it does not\n * reorder them. Sort by the same field you group on, or the same group will\n * open more than once.\n *\n * Mutually exclusive with virtualization, which assumes every row is\n * `rowHeight` tall; a heading is not. Setting this turns virtualization off.\n */\n groupBy: ((row: T) => string | null) | null;\n virtualization: boolean | 'auto';\n virtualizationThreshold: number;\n rowHeight: number;\n overscan: number;\n breakpoints: {\n sm: string;\n md: string;\n };\n}\n\nexport const DEFAULT_TABLE_CONFIG: TableConfig = {\n responsiveMode: 'auto',\n forceScroll: false,\n stickyHeader: true,\n showHeader: true,\n rowExpansion: false,\n emptyMessage: 'No data available',\n groupBy: null,\n trackBy: (index: number) => index,\n rowStyleFn: null,\n virtualization: 'auto',\n virtualizationThreshold: 200,\n rowHeight: 48,\n overscan: 10,\n breakpoints: {\n sm: '(max-width: 35.999em)',\n md: '(max-width: 47.999em)',\n },\n};\n\n// ===== ROW SELECTION =====\n\nexport type SelectionDisabled<T = unknown> = boolean | ((row: T) => boolean);\n\nexport type SelectionColumnPosition = 'start' | 'end';\n\nexport type HeaderSelectionState = 'checked' | 'unchecked' | 'indeterminate';\n\n// ===== ROW EXPANSION =====\n\nexport type ExpansionColumnPosition = 'start' | 'end';\n\n// ===== STATE =====\n\nexport type SortDirection = 'asc' | 'desc' | null;\n\nexport interface SortState {\n columnId: string;\n direction: SortDirection;\n}\n\nexport interface FilterState {\n query: string;\n columnFilters: Record<string, unknown>;\n}\n\nexport interface PageState {\n page: number;\n pageSize: number;\n totalRows: number;\n}\n\n// ===== COLUMN RESIZE =====\n\nexport interface ColumnResizeEvent {\n columnId: string;\n width: number;\n}\n\n// ===== ROW CONTEXT =====\n\nexport interface TableRowContext<T = unknown> {\n row: T;\n index: number;\n selected: boolean;\n expanded: boolean;\n}\n","import { Injectable } from '@angular/core';\n\nimport type { DataTableComponent } from './data-table.component';\n\n/**\n * Coordinator scoped to a single `<fk-data-table-group>`. Mirrors\n * `AccordionGroupCoordinator` — when a wrapped data-table expands a\n * row, the previously-active row is collapsed so only one detail\n * panel is open at a time.\n *\n * The wrapped data-table picks this up via `inject({ optional: true })`\n * and routes every expansion toggle through it. Absence of the\n * coordinator means multi-expand behavior — that's the default.\n */\n@Injectable()\nexport class DataTableGroupCoordinator {\n private activeTable: DataTableComponent<unknown> | null = null;\n private activeKey: unknown = null;\n\n /**\n * Resolve an expansion request. Caller passes the new expanded\n * state alongside the table + row key; coordinator returns the\n * Set the caller should commit. For multi-table groups this also\n * collapses any active row on a sibling table.\n */\n resolveToggle(\n table: DataTableComponent<unknown>,\n key: unknown,\n nextExpanded: boolean,\n currentKeysOnThisTable: ReadonlySet<unknown>,\n ): {\n keysForThisTable: Set<unknown>;\n /** Optional: a sibling table the host should clear by calling its `clearExpansion`. */\n siblingTableToClear: DataTableComponent<unknown> | null;\n } {\n if (!nextExpanded) {\n // Collapse: drop the key from this table's set. If it was the\n // active one, clear our pointer.\n const next = new Set(currentKeysOnThisTable);\n\n next.delete(key);\n\n if (this.activeTable === table && this.activeKey === key) {\n this.activeTable = null;\n this.activeKey = null;\n }\n\n return { keysForThisTable: next, siblingTableToClear: null };\n }\n\n // Expand: replace this table's set with just the new key, and\n // surface any sibling table that needs to drop its active row.\n const next = new Set<unknown>([key]);\n const sibling =\n this.activeTable && this.activeTable !== table ? this.activeTable : null;\n\n this.activeTable = table;\n this.activeKey = key;\n\n return { keysForThisTable: next, siblingTableToClear: sibling };\n }\n\n /**\n * Called when a data-table inside the group disconnects. Clears the\n * active pointer if it was tracking this table.\n */\n unregister(table: DataTableComponent<unknown>): void {\n if (this.activeTable === table) {\n this.activeTable = null;\n this.activeKey = null;\n }\n }\n}\n","import type { TableConfig } from './data-table.types';\n\n/**\n * The group heading to emit before a row, or null when the row continues the\n * group above it.\n *\n * Shared by the semantic-table and stack render paths so the two cannot answer\n * the question differently — a heading appearing on desktop and not on mobile\n * is the kind of drift that only shows up on someone's phone.\n *\n * Reads the rows in the order it is given rather than reordering, so a caller\n * sorting on one field while grouping by another sees the group open more than\n * once. That is deliberate: silently merging them would report a grouping the\n * data does not have.\n */\nexport function groupHeadingForRow<T>(\n rows: readonly T[],\n row: T,\n index: number,\n groupBy: TableConfig<T>['groupBy'],\n): string | null {\n if (!groupBy) {\n return null;\n }\n\n const key = groupBy(row);\n\n if (key === null) {\n return null;\n }\n\n if (index === 0) {\n return key;\n }\n\n const previous = rows[index - 1];\n\n return previous !== undefined && groupBy(previous) === key ? null : key;\n}\n","import { NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n output,\n signal,\n type TemplateRef,\n} from '@angular/core';\n\nimport { groupHeadingForRow } from './data-table-grouping.util';\nimport type {\n ColumnDef,\n SelectionDisabled,\n TableConfig,\n TableRowContext,\n} from './data-table.types';\n\nexport interface StackToggleRowEvent<T = unknown> {\n row: T;\n event: Event;\n}\n\n@Component({\n selector: 'fk-data-table-stack',\n standalone: true,\n imports: [NgTemplateOutlet],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './data-table-stack.component.html',\n styleUrl: './data-table-stack.component.scss',\n})\nexport class DataTableStackComponent<T = unknown> {\n /** Row data array rendered as stacked cards in mobile layout. */\n readonly rows = input<T[]>([]);\n /** Column definitions used to extract field labels and cell values. */\n readonly columns = input<ColumnDef<T>[]>([]);\n /** Merged table configuration passed down from the host data-table. */\n readonly config = input<TableConfig<T> | null>(null);\n /** TrackBy function used by the `@for` loop over rows. */\n readonly trackByFn = input<(index: number, row: T) => unknown>(\n (index: number) => index,\n );\n\n // ===== GROUPING =====\n /**\n * Template rendered inside a group heading. Mirrors the semantic-table path\n * so a grouped table looks grouped at every viewport.\n */\n readonly groupHeadingRenderer = input<TemplateRef<{\n $implicit: string;\n row: T;\n }> | null>(null);\n\n // ===== SELECTION =====\n // Mirrors the host data-table's selection inputs. The stack path renders a\n // checkbox at the top-left of each card when `rowSelection` is true and\n // bubbles toggle events up to the host so it can route them through the\n // shared engine.\n /** Mirrors the host table's `rowSelection` input to show checkboxes on each card. */\n readonly rowSelection = input<boolean>(false);\n /** Currently selected row keys forwarded from the host table engine. */\n readonly selectedKeys = input<Set<unknown>>(new Set());\n /** Row identity resolver forwarded from the host table. */\n readonly getRowId = input<((row: T) => unknown) | null>(null);\n /** Predicate (or static boolean) that disables selection for matching rows. */\n readonly selectionDisabled = input<SelectionDisabled<T>>(false);\n /** Accessible label for each card's selection checkbox. */\n readonly selectionLabel = input<string>('Select row');\n\n /** The group heading to open before this card, if it starts a new group. */\n groupHeadingFor(row: T, index: number): string | null {\n return groupHeadingForRow(\n this.rows(),\n row,\n index,\n this.config()?.groupBy ?? null,\n );\n }\n\n /** Fires when the user clicks a card row, emitting the row context. */\n readonly rowClick = output<TableRowContext<T>>();\n /** Fires when the user toggles a card's selection checkbox, bubbling up to the host. */\n readonly toggleRow = output<StackToggleRowEvent<T>>();\n\n readonly expandedRows = signal<Set<number>>(new Set());\n\n readonly visibleFieldCount = 3;\n\n readonly primaryColumns = computed(() => {\n return this.columns().slice(0, this.visibleFieldCount);\n });\n\n readonly secondaryColumns = computed(() => {\n return this.columns().slice(this.visibleFieldCount);\n });\n\n readonly hasSecondary = computed(() => {\n return this.secondaryColumns().length > 0;\n });\n\n getCellValue(column: ColumnDef<T>, row: T): unknown {\n if (typeof column.accessor === 'function') {\n return column.accessor(row);\n }\n\n return row[column.accessor as keyof T];\n }\n\n getLabel(column: ColumnDef<T>): string {\n return column.mobileLabel ?? column.header;\n }\n\n isExpanded(index: number): boolean {\n return this.expandedRows().has(index);\n }\n\n toggleExpand(index: number): void {\n const next = new Set(this.expandedRows());\n\n if (next.has(index)) {\n next.delete(index);\n } else {\n next.add(index);\n }\n\n this.expandedRows.set(next);\n }\n\n onRowClick(row: T, index: number): void {\n this.rowClick.emit({\n row,\n index,\n selected: this.isRowSelected(row),\n expanded: this.isExpanded(index),\n });\n }\n\n onToggleSelection(row: T, event: Event): void {\n event.stopPropagation();\n\n if (this.isRowSelectionDisabled(row)) {\n return;\n }\n\n this.toggleRow.emit({ row, event });\n }\n\n isRowSelected(row: T): boolean {\n if (!this.rowSelection()) {\n return false;\n }\n\n return this.selectedKeys().has(this.getSelectionKey(row));\n }\n\n isRowSelectionDisabled(row: T): boolean {\n const disabled = this.selectionDisabled();\n\n if (typeof disabled === 'function') {\n return disabled(row);\n }\n\n return disabled;\n }\n\n private getSelectionKey(row: T): unknown {\n const idFn = this.getRowId();\n\n if (idFn) {\n return idFn(row);\n }\n\n return row;\n }\n}\n","<div class=\"fk-data-table-stack\">\n @for (row of rows(); track trackByFn()($index, row); let i = $index) {\n @if (groupHeadingFor(row, i); as heading) {\n <div class=\"fk-data-table-stack__group-heading\">\n @if (groupHeadingRenderer()) {\n <ng-container\n [ngTemplateOutlet]=\"groupHeadingRenderer()!\"\n [ngTemplateOutletContext]=\"{ $implicit: heading, row: row }\"\n />\n } @else {\n {{ heading }}\n }\n </div>\n }\n\n <div\n class=\"fk-data-table-stack__card\"\n [class.fk-data-table-stack__card--selected]=\"isRowSelected(row)\"\n >\n @if (rowSelection()) {\n <div class=\"fk-data-table-stack__select\">\n <input\n type=\"checkbox\"\n class=\"fk-data-table-stack__checkbox\"\n [attr.aria-label]=\"selectionLabel()\"\n [checked]=\"isRowSelected(row)\"\n [disabled]=\"isRowSelectionDisabled(row)\"\n (click)=\"onToggleSelection(row, $event)\"\n />\n </div>\n }\n\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div class=\"fk-data-table-stack__primary\" (click)=\"onRowClick(row, i)\">\n @for (column of primaryColumns(); track column.id) {\n <div class=\"fk-data-table-stack__field\">\n <span class=\"fk-data-table-stack__label\">{{\n getLabel(column)\n }}</span>\n <span class=\"fk-data-table-stack__value\">\n @if (column.cellRenderer) {\n <ng-container\n [ngTemplateOutlet]=\"column.cellRenderer\"\n [ngTemplateOutletContext]=\"{\n $implicit: getCellValue(column, row),\n row: row,\n }\"\n />\n } @else {\n {{ getCellValue(column, row) }}\n }\n </span>\n </div>\n }\n </div>\n\n @if (hasSecondary()) {\n @if (isExpanded(i)) {\n <div class=\"fk-data-table-stack__secondary\">\n @for (column of secondaryColumns(); track column.id) {\n <div class=\"fk-data-table-stack__field\">\n <span class=\"fk-data-table-stack__label\">{{\n getLabel(column)\n }}</span>\n <span class=\"fk-data-table-stack__value\">\n @if (column.cellRenderer) {\n <ng-container\n [ngTemplateOutlet]=\"column.cellRenderer\"\n [ngTemplateOutletContext]=\"{\n $implicit: getCellValue(column, row),\n row: row,\n }\"\n />\n } @else {\n {{ getCellValue(column, row) }}\n }\n </span>\n </div>\n }\n </div>\n }\n\n <button\n class=\"fk-data-table-stack__toggle\"\n type=\"button\"\n [attr.aria-expanded]=\"isExpanded(i)\"\n (click)=\"toggleExpand(i)\"\n >\n {{ isExpanded(i) ? 'Show less' : 'Show more' }}\n </button>\n }\n </div>\n }\n\n @if (rows().length === 0) {\n <div class=\"fk-data-table-stack__empty\">\n {{ config()?.emptyMessage ?? 'No data available' }}\n </div>\n }\n</div>\n","import { BreakpointObserver } from '@angular/cdk/layout';\nimport {\n computed,\n DestroyRef,\n inject,\n Injectable,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport type { ColumnDef, TableConfig } from './data-table.types';\n\nexport type Breakpoint = 'sm' | 'md' | 'lg';\nexport type ActiveMode = 'table' | 'stack';\n\n@Injectable()\nexport class ResponsiveStrategyService<T = unknown> {\n // ===== INJECTIONS =====\n private readonly breakpointObserver = inject(BreakpointObserver);\n private readonly destroyRef = inject(DestroyRef);\n\n // ===== SOURCE DATA =====\n readonly columns = signal<ColumnDef<T>[]>([]);\n readonly config = signal<TableConfig<T> | null>(null);\n\n // ===== STATE =====\n readonly currentBreakpoint = signal<Breakpoint>('lg');\n\n // ===== COMPUTED =====\n readonly activeMode: ReturnType<typeof computed<ActiveMode>> = computed(\n () => {\n const cfg = this.config();\n\n if (!cfg) {\n return 'table';\n }\n\n if (cfg.forceScroll) {\n return 'table';\n }\n\n const mode = cfg.responsiveMode;\n const bp = this.currentBreakpoint();\n\n if (mode === 'scroll') {\n return 'table';\n }\n\n if (mode === 'stack') {\n return bp === 'sm' ? 'stack' : 'table';\n }\n\n if (mode === 'priority') {\n return 'table';\n }\n\n // mode === \"auto\"\n if (bp === 'sm') {\n return 'stack';\n }\n\n return 'table';\n },\n );\n\n readonly responsiveColumns = computed(() => {\n const cols = this.columns();\n const cfg = this.config();\n\n if (!cfg || cfg.forceScroll) {\n return cols;\n }\n\n const bp = this.currentBreakpoint();\n const mode = cfg.responsiveMode;\n\n if (bp === 'lg') {\n return cols;\n }\n\n if (mode === 'scroll') {\n return cols;\n }\n\n // For \"auto\", \"priority\", or \"stack\" at md breakpoint — apply priority hiding\n if (bp === 'md' && (mode === 'auto' || mode === 'priority')) {\n return cols.filter((col) => {\n if (col.hideBelow === 'md' || col.hideBelow === 'lg') {\n return false;\n }\n\n if (col.priority !== undefined && col.priority >= 2) {\n return false;\n }\n\n return true;\n });\n }\n\n return cols;\n });\n\n readonly hiddenColumns = computed(() => {\n const all = this.columns();\n const visible = this.responsiveColumns();\n const visibleIds = new Set(visible.map((c) => c.id));\n\n return all.filter((c) => !visibleIds.has(c.id));\n });\n\n // ===== INITIALIZATION =====\n private initialized = false;\n\n init(breakpoints: { sm: string; md: string }): void {\n if (this.initialized) {\n return;\n }\n\n this.initialized = true;\n\n this.breakpointObserver\n .observe([breakpoints.sm, breakpoints.md])\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((result) => {\n if (result.breakpoints[breakpoints.sm]) {\n this.currentBreakpoint.set('sm');\n } else if (result.breakpoints[breakpoints.md]) {\n this.currentBreakpoint.set('md');\n } else {\n this.currentBreakpoint.set('lg');\n }\n });\n }\n}\n","import { computed, Injectable, signal } from '@angular/core';\n\nimport type {\n ColumnDef,\n FilterState,\n PageState,\n SortDirection,\n SortState,\n} from './data-table.types';\n\n@Injectable()\nexport class TableEngineService<T = unknown> {\n // ===== SOURCE DATA =====\n readonly rows = signal<T[]>([]);\n readonly columns = signal<ColumnDef<T>[]>([]);\n\n // ===== INTERNAL STATE =====\n private readonly internalSortState = signal<SortState | null>(null);\n private readonly internalFilterState = signal<FilterState>({\n query: '',\n columnFilters: {},\n });\n private readonly internalPageState = signal<PageState | null>(null);\n\n // ===== CONTROLLED STATE =====\n readonly controlledSortState = signal<SortState | null | undefined>(\n undefined,\n );\n readonly controlledFilterState = signal<FilterState | null | undefined>(\n undefined,\n );\n readonly controlledPageState = signal<PageState | null | undefined>(\n undefined,\n );\n\n /**\n * When true the rows arrive already sorted (by a server, for the current\n * sort state) and are kept in the order given.\n */\n readonly manualSorting = signal(false);\n\n // ===== EFFECTIVE STATE =====\n readonly sortState = computed(() => {\n const controlled = this.controlledSortState();\n\n if (controlled !== undefined) {\n return controlled;\n }\n\n return this.internalSortState();\n });\n\n readonly filterState = computed(() => {\n const controlled = this.controlledFilterState();\n\n if (controlled !== undefined && controlled !== null) {\n return controlled;\n }\n\n return this.internalFilterState();\n });\n\n readonly pageState = computed(() => {\n const controlled = this.controlledPageState();\n\n if (controlled !== undefined) {\n return controlled;\n }\n\n return this.internalPageState();\n });\n\n // ===== SELECTION =====\n // Engine-owned (uncontrolled) selection state. The host data-table reads\n // from a controlled `selectedKeys` input when present and only writes\n // through `setSelectedKeys` here when running in uncontrolled mode.\n // Action methods stay pure — they compute the next Set from a current\n // Set and return it; they never mutate the input Set.\n readonly selectedKeys = signal<Set<unknown>>(new Set());\n\n // ===== EXPANSION =====\n // Mirror of selection: engine-owned Set of expanded row keys when the\n // host runs in uncontrolled mode. The host swaps to a controlled\n // `expandedKeys` input when supplied, the same way selection does.\n readonly expandedKeys = signal<Set<unknown>>(new Set());\n\n // ===== PROCESSED ROWS =====\n readonly sortedRows = computed(() => {\n const rows = this.rows();\n const sort = this.sortState();\n\n if (this.manualSorting() || !sort || !sort.direction) {\n return rows;\n }\n\n const column = this.columns().find((c) => c.id === sort.columnId);\n\n if (!column) {\n return rows;\n }\n\n const direction = sort.direction;\n\n return [...rows].sort((a, b) => {\n const valA = column.sortAccessor\n ? column.sortAccessor(a)\n : this.resolveAccessor(column.accessor, a);\n const valB = column.sortAccessor\n ? column.sortAccessor(b)\n : this.resolveAccessor(column.accessor, b);\n\n return this.compare(valA, valB, direction);\n });\n });\n\n readonly filteredRows = computed(() => {\n const rows = this.sortedRows();\n const filter = this.filterState();\n\n if (!filter.query && Object.keys(filter.columnFilters).length === 0) {\n return rows;\n }\n\n const columns = this.columns();\n const query = filter.query.toLowerCase();\n\n return rows.filter((row) => {\n if (query) {\n const matches = columns.some((col) => {\n const val = this.resolveAccessor(col.accessor, row);\n\n return String(val ?? '')\n .toLowerCase()\n .includes(query);\n });\n\n if (!matches) {\n return false;\n }\n }\n\n return true;\n });\n });\n\n readonly processedRows = computed(() => {\n const rows = this.filteredRows();\n const page = this.pageState();\n\n if (!page) {\n return rows;\n }\n\n const start = page.page * page.pageSize;\n\n return rows.slice(start, start + page.pageSize);\n });\n\n readonly totalFilteredRows = computed(() => {\n return this.filteredRows().length;\n });\n\n // ===== ACTIONS =====\n toggleSort(columnId: string): SortState {\n const current = this.sortState();\n\n let direction: SortDirection;\n\n if (current?.columnId === columnId) {\n if (current.direction === 'asc') {\n direction = 'desc';\n } else if (current.direction === 'desc') {\n direction = null;\n } else {\n direction = 'asc';\n }\n } else {\n direction = 'asc';\n }\n\n const next: SortState = { columnId, direction };\n\n if (this.controlledSortState() === undefined) {\n this.internalSortState.set(next);\n }\n\n return next;\n }\n\n setFilter(query: string): FilterState {\n const next: FilterState = {\n ...this.filterState(),\n query,\n };\n\n if (this.controlledFilterState() === undefined) {\n this.internalFilterState.set(next);\n }\n\n return next;\n }\n\n setPage(page: number, pageSize?: number): PageState {\n const current = this.pageState();\n const next: PageState = {\n page,\n pageSize: pageSize ?? current?.pageSize ?? 10,\n totalRows: this.totalFilteredRows(),\n };\n\n if (this.controlledPageState() === undefined) {\n this.internalPageState.set(next);\n }\n\n return next;\n }\n\n /**\n * Replace the engine's internal selection state. Used by the host\n * data-table when running in uncontrolled mode (controlled mode goes\n * through the parent and never touches the engine here).\n */\n setSelectedKeys(next: Set<unknown>): void {\n this.selectedKeys.set(next);\n }\n\n /**\n * Replace the engine's internal expansion state. Used by the host\n * data-table when running in uncontrolled mode.\n */\n setExpandedKeys(next: Set<unknown>): void {\n this.expandedKeys.set(next);\n }\n\n /**\n * Toggle a single key in a Set. Derives from `current` and returns a\n * brand-new Set — never mutates the input.\n */\n toggleSelection(\n key: unknown,\n current: ReadonlySet<unknown> = this.selectedKeys(),\n ): Set<unknown> {\n const next = new Set(current);\n\n if (next.has(key)) {\n next.delete(key);\n } else {\n next.add(key);\n }\n\n return next;\n }\n\n /**\n * Page-local select-all. Toggles every key in `visibleKeys`:\n * - if all visible keys are already selected → deselect them\n * - otherwise → select them all (existing selections outside the visible\n * range stay intact)\n *\n * `disabledKeys` is excluded from both the toggle target and the\n * \"all-selected\" check, so a row marked `selectionDisabled` never\n * blocks the header checkbox from going fully checked.\n */\n toggleVisibleRows(\n visibleKeys: Iterable<unknown>,\n disabledKeys: ReadonlySet<unknown> = new Set(),\n current: ReadonlySet<unknown> = this.selectedKeys(),\n ): Set<unknown> {\n const eligible: unknown[] = [];\n\n for (const key of visibleKeys) {\n if (!disabledKeys.has(key)) {\n eligible.push(key);\n }\n }\n\n const allSelected =\n eligible.length > 0 && eligible.every((key) => current.has(key));\n\n const next = new Set(current);\n\n if (allSelected) {\n for (const key of eligible) {\n next.delete(key);\n }\n } else {\n for (const key of eligible) {\n next.add(key);\n }\n }\n\n return next;\n }\n\n clearSelection(): Set<unknown> {\n return new Set<unknown>();\n }\n\n isSelected(key: unknown): boolean {\n return this.selectedKeys().has(key);\n }\n\n // ===== HELPERS =====\n private resolveAccessor(\n accessor: keyof T | ((row: T) => unknown),\n row: T,\n ): unknown {\n if (typeof accessor === 'function') {\n return accessor(row);\n }\n\n return row[accessor];\n }\n\n private compare(a: unknown, b: unknown, direction: 'asc' | 'desc'): number {\n const multiplier = direction === 'asc' ? 1 : -1;\n\n if (a == null && b == null) {\n return 0;\n }\n\n if (a == null) {\n return 1 * multiplier;\n }\n\n if (b == null) {\n return -1 * multiplier;\n }\n\n if (typeof a === 'string' && typeof b === 'string') {\n return a.localeCompare(b) * multiplier;\n }\n\n if (typeof a === 'number' && typeof b === 'number') {\n return (a - b) * multiplier;\n }\n\n return String(a).localeCompare(String(b)) * multiplier;\n }\n}\n","import { computed, Injectable, type Signal, signal } from '@angular/core';\n\n@Injectable()\nexport class VirtualizationEngineService {\n // ===== CONFIGURATION =====\n readonly rowHeight = signal<number>(48);\n readonly overscan = signal<number>(10);\n readonly totalRows = signal<number>(0);\n\n // ===== VIEWPORT STATE =====\n readonly viewportHeight = signal<number>(0);\n readonly scrollTop = signal<number>(0);\n\n // ===== COMPUTED =====\n readonly visibleRange: Signal<{ start: number; end: number }> = computed(\n () => {\n const height = this.viewportHeight();\n const scroll = this.scrollTop();\n const rh = this.rowHeight();\n const os = this.overscan();\n const total = this.totalRows();\n\n if (rh <= 0 || total === 0) {\n return { start: 0, end: 0 };\n }\n\n const visibleCount = Math.ceil(height / rh);\n const firstVisible = Math.floor(scroll / rh);\n\n const start = Math.max(0, firstVisible - os);\n const end = Math.min(total, firstVisible + visibleCount + os);\n\n return { start, end };\n },\n );\n\n readonly totalHeight: Signal<number> = computed(() => {\n return this.totalRows() * this.rowHeight();\n });\n\n readonly offsetY: Signal<number> = computed(() => {\n return this.visibleRange().start * this.rowHeight();\n });\n\n readonly visibleCount: Signal<number> = computed(() => {\n const range = this.visibleRange();\n\n return range.end - range.start;\n });\n\n // ===== ACTIONS =====\n onScroll(scrollTop: number): void {\n this.scrollTop.set(scrollTop);\n }\n\n onViewportResize(height: number): void {\n this.viewportHeight.set(height);\n }\n}\n","import { NgStyle, NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n effect,\n ElementRef,\n HostBinding,\n inject,\n input,\n NgZone,\n output,\n type TemplateRef,\n viewChild,\n} from '@angular/core';\n\nimport { ColumnResizeDirective } from './column-resize.directive';\nimport {\n type ColumnDef,\n type ColumnResizeEvent,\n DEFAULT_TABLE_CONFIG,\n type ExpansionColumnPosition,\n type FilterState,\n type HeaderSelectionState,\n type PageState,\n type SelectionColumnPosition,\n type SelectionDisabled,\n type SortState,\n type TableConfig,\n type TableRowContext,\n} from './data-table.types';\nimport { DataTableGroupCoordinator } from './data-table-group.service';\nimport { DataTableStackComponent } from './data-table-stack.component';\nimport { ResponsiveStrategyService } from './responsive-strategy.service';\nimport { TableEngineService } from './table-engine.service';\nimport { groupHeadingForRow } from './data-table-grouping.util';\nimport { VirtualizationEngineService } from './virtualization-engine.service';\n\n@Component({\n selector: 'fk-data-table',\n standalone: true,\n imports: [\n NgStyle,\n NgTemplateOutlet,\n DataTableStackComponent,\n ColumnResizeDirective,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n TableEngineService,\n VirtualizationEngineService,\n ResponsiveStrategyService,\n ],\n templateUrl: './data-table.component.html',\n styleUrl: './data-table.component.scss',\n})\nexport class DataTableComponent<T = unknown> {\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly id = input<string | null>(null);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== DATA =====\n /** Column definitions that describe the table schema, headers, and cell rendering. */\n readonly columns = input<ColumnDef<T>[]>([]);\n /** Array of row data objects rendered by the table. */\n readonly rows = input<T[]>([]);\n /** Partial table configuration merged with the defaults. */\n readonly config = input<Partial<TableConfig<T>>>({});\n /** When true, shows the loading overlay and suppresses the empty state. */\n readonly loading = input<boolean>(false);\n\n // ===== CONTROLLED STATE =====\n /** Controlled sort state; pass null to let the table manage sorting internally. */\n readonly sortState = input<SortState | null>(null);\n /**\n * When true the table never reorders `rows`: they arrive sorted by the\n * consumer (a server-paged list sorted by the server) and render as given.\n * Headers still show `sortState` and emit `sortChange`.\n */\n readonly manualSorting = input<boolean>(false);\n /** Controlled filter state; pass null to let the table manage filtering internally. */\n readonly filterState = input<FilterState | null>(null);\n /** Controlled page state; pass null to let the table manage pagination internally. */\n readonly pageState = input<PageState | null>(null);\n\n // ===== SELECTION =====\n // Opt-in via `rowSelection`. When the parent passes a `selectedKeys` Set the\n // table runs in controlled mode (parent owns state, table emits a new Set on\n // every change). When `selectedKeys` is null the table manages selection\n // internally — useful for Storybook and simple cases.\n //\n // `getRowId` is REQUIRED when `rowSelection` is true. Without a stable\n // row identity selection silently breaks across pagination. The constructor\n // logs a console error if it's missing in dev.\n /** Opt-in to row selection; requires `getRowId` for controlled mode across pagination. */\n readonly rowSelection = input<boolean>(false);\n /** Controlled set of selected row keys; null lets the table manage selection internally. */\n readonly selectedKeys = input<Set<unknown> | null>(null);\n /** Function that returns a stable unique key for each row, required when `rowSelection` is true. */\n readonly getRowId = input<((row: T) => unknown) | null>(null);\n /** Predicate (or static boolean) that disables selection for matching rows. */\n readonly selectionDisabled = input<SelectionDisabled<T>>(false);\n /** Whether the checkbox column appears at the start or end of the table. */\n readonly selectionColumnPosition = input<SelectionColumnPosition>('start');\n /** Accessible label for each row's selection checkbox. */\n readonly selectionLabel = input<string>('Select row');\n\n // ===== EXPANSION =====\n // Opt-in via `rowDetailTemplate`. When present the table auto-injects\n // a chevron column at start (default) or end and renders the projected\n // template as a detail row beneath each expanded row.\n //\n // `expandedKeys` mirrors the selection contract: pass a Set to run in\n // controlled mode (parent owns state, table emits the new Set on every\n // toggle) or omit to let the engine manage state internally.\n //\n // `expandableRow` lets a host predicate-disable expansion per row —\n // the chevron renders as an inert spacer so columns stay aligned.\n /** Template rendered as the expansion detail row; presence enables the feature. */\n readonly rowDetailTemplate = input<TemplateRef<{\n $implicit: T;\n row: T;\n index: number;\n }> | null>(null);\n /** Whether the chevron column appears at the start or end of the table. */\n readonly expansionColumnPosition = input<ExpansionColumnPosition>('start');\n /** Controlled set of expanded row keys; null lets the engine manage state internally. */\n readonly expandedKeys = input<Set<unknown> | null>(null);\n /** Predicate that disables expansion for matching rows; default: every row is expandable. */\n readonly expandableRow = input<((row: T) => boolean) | null>(null);\n /** Accessible label for each row's expansion chevron. */\n readonly expansionLabel = input<string>('Toggle row details');\n\n // ===== GROUPING =====\n /**\n * Template rendered inside a group heading. Receives the group key and the\n * first row of the group, so a heading can show more than the key it was\n * grouped by. Omit it and the key is rendered as text.\n */\n readonly groupHeadingRenderer = input<TemplateRef<{\n $implicit: string;\n row: T;\n }> | null>(null);\n\n // ===== OUTPUTS =====\n /** Fires when the user clicks a sortable column header, emitting the new sort state. */\n readonly sortChange = output<SortState>();\n /** Fires when a filter changes, emitting the updated filter state. */\n readonly filterChange = output<FilterState>();\n /** Fires when the user navigates to a different page or changes page size. */\n readonly pageChange = output<PageState>();\n /** Fires when the user clicks a table row, emitting the row context. */\n readonly rowClick = output<TableRowContext<T>>();\n /** Fires when the selection set changes, emitting the full new set of selected keys. */\n readonly selectionChange = output<Set<unknown>>();\n /** Fires when the expansion set changes, emitting the full new set of expanded keys. */\n readonly expansionChange = output<Set<unknown>>();\n /** Fires when the user finishes resizing a column, emitting the column id and new width. */\n readonly columnResize = output<ColumnResizeEvent>();\n\n // ===== ENGINE =====\n protected readonly engine: TableEngineService<T>;\n protected readonly virtEngine: VirtualizationEngineService;\n protected readonly responsive = inject(ResponsiveStrategyService<T>);\n\n // ===== VIEW CHILDREN =====\n readonly virtualViewport =\n viewChild<ElementRef<HTMLElement>>('virtualViewport');\n\n // ===== COMPUTED =====\n readonly mergedConfig = computed<TableConfig<T>>(() => {\n return { ...DEFAULT_TABLE_CONFIG, ...this.config() } as TableConfig<T>;\n });\n\n readonly visibleColumns = computed(() => {\n const responsiveCols = this.responsive.responsiveColumns();\n\n return responsiveCols.filter((col) => col.visible !== false);\n });\n\n readonly activeMode = computed(() => {\n return this.responsive.activeMode();\n });\n\n readonly useVirtualization = computed(() => {\n const config = this.mergedConfig();\n const rowCount = this.rows().length;\n\n // Virtualization positions rows by multiplying an index by `rowHeight`.\n // A group heading is not that tall, so every row after the first heading\n // would be placed wrong. Grouping wins; the alternative is a table that\n // silently misplaces its own rows.\n if (config.groupBy) {\n return false;\n }\n\n if (config.virtualization === true) {\n return true;\n }\n\n if (config.virtualization === false) {\n return false;\n }\n\n return rowCount > config.virtualizationThreshold;\n });\n\n readonly virtualRows = computed(() => {\n const rows = this.engine.processedRows();\n const range = this.virtEngine.visibleRange();\n\n return rows.slice(range.start, range.end);\n });\n\n readonly virtualStartIndex = computed(() => {\n return this.virtEngine.visibleRange().start;\n });\n\n /**\n * How many cells a heading has to span — the visible columns plus whichever\n * of the selection and expansion cells the table is currently rendering.\n */\n readonly groupHeadingSpan = computed(() => {\n let span = this.visibleColumns().length;\n\n if (this.rowSelection()) {\n span += 1;\n }\n\n if (this.hasExpansion()) {\n span += 1;\n }\n\n return span;\n });\n\n readonly isEmpty = computed(() => {\n return this.engine.processedRows().length === 0 && !this.loading();\n });\n\n readonly classes = computed(() => {\n return [\n 'fk-data-table',\n this.loading() ? 'fk-data-table--loading' : '',\n this.isEmpty() ? 'fk-data-table--empty' : '',\n this.mergedConfig().stickyHeader ? 'fk-data-table--sticky-header' : '',\n this.useVirtualization() ? 'fk-data-table--virtual' : '',\n this.activeMode() === 'stack' ? 'fk-data-table--stack' : '',\n this.className(),\n ]\n .filter(Boolean)\n .join(' ');\n });\n\n @HostBinding('class')\n get hostClass() {\n return this.classes();\n }\n\n @HostBinding('attr.id')\n get hostId(): string | null {\n return this.id();\n }\n\n private readonly ngZone = inject(NgZone);\n /**\n * Optional group coordinator picked up via DI when this table is\n * wrapped in `<fk-data-table-group>`. Presence flips expansion to\n * single-open mode; absence keeps multi-expand behavior (the\n * default).\n */\n private readonly groupCoordinator = inject(DataTableGroupCoordinator, {\n optional: true,\n });\n\n constructor() {\n this.engine = new TableEngineService<T>();\n this.virtEngine = new VirtualizationEngineService();\n\n // Clean up the coordinator's active-pointer when this table is torn\n // down so a sibling expansion doesn't try to collapse a stale ref.\n inject(DestroyRef).onDestroy(() => {\n this.groupCoordinator?.unregister(this as DataTableComponent<unknown>);\n });\n\n effect(() => {\n this.engine.rows.set(this.rows());\n });\n\n effect(() => {\n this.engine.columns.set(this.columns());\n });\n\n effect(() => {\n const sort = this.sortState();\n\n this.engine.controlledSortState.set(sort === null ? undefined : sort);\n });\n\n effect(() => {\n this.engine.manualSorting.set(this.manualSorting());\n });\n\n effect(() => {\n const filter = this.filterState();\n\n this.engine.controlledFilterState.set(\n filter === null ? undefined : filter,\n );\n });\n\n effect(() => {\n const page = this.pageState();\n\n this.engine.controlledPageState.set(page === null ? undefined : page);\n });\n\n // Dev-mode: warn once per misconfiguration when selection is enabled\n // but no row id resolver is provided. Without it `getSelectionKey`\n // falls back to row reference which silently breaks across pagination\n // since each fetch returns brand-new objects.\n let warnedNoRowId = false;\n\n effect(() => {\n if (this.rowSelection() && this.getRowId() === null && !warnedNoRowId) {\n warnedNoRowId = true;\n console.error(\n '[fk-data-table] `rowSelection` is true but `getRowId` was not ' +\n 'provided. Selection requires a stable row identifier — set ' +\n \"`[getRowId]` to a function returning each row's unique key.\",\n );\n }\n });\n\n // Sync virtualization config\n effect(() => {\n const config = this.mergedConfig();\n\n this.virtEngine.rowHeight.set(config.rowHeight);\n this.virtEngine.overscan.set(config.overscan);\n });\n\n // Sync total row count into virtualization engine\n effect(() => {\n this.virtEngine.totalRows.set(this.engine.processedRows().length);\n });\n\n // Sync responsive strategy\n effect(() => {\n this.responsive.columns.set(this.columns());\n });\n\n effect(() => {\n this.responsive.config.set(this.mergedConfig());\n });\n\n // Initialize breakpoint observer\n effect(() => {\n const config = this.mergedConfig();\n\n this.responsive.init(config.breakpoints);\n });\n }\n\n // ===== TEMPLATE HELPERS =====\n /** The group heading to open before this row, if it starts a new group. */\n groupHeadingFor(row: T, index: number): string | null {\n return groupHeadingForRow(\n this.engine.processedRows(),\n row,\n index,\n this.mergedConfig().groupBy,\n );\n }\n\n /** Resolves the display value for a cell given its column definition and row data. */\n getCellValue(column: ColumnDef<T>, row: T): unknown {\n if (typeof column.accessor === 'function') {\n return column.accessor(row);\n }\n\n return row[column.accessor as keyof T];\n }\n\n /** Returns the trackBy function from the merged config for use in `*ngFor`. */\n getTrackBy(): (index: number, row: T) => unknown {\n return this.mergedConfig().trackBy;\n }\n\n // ===== SELECTION HELPERS =====\n\n /**\n * Source of truth for which keys are currently selected. Reads the\n * controlled `selectedKeys` input when the parent supplied one;\n * otherwise falls back to the engine's internal state (uncontrolled\n * mode). Computed so changes flow through Angular's signal graph\n * without effect-write timing surprises.\n */\n private readonly effectiveSelectedKeys = computed<Set<unknown>>(() => {\n const controlled = this.selectedKeys();\n\n if (controlled !== null) {\n return controlled;\n }\n\n return this.engine.selectedKeys();\n });\n\n /**\n * Public alias of `effectiveSelectedKeys` for the stack (mobile) child\n * binding. The private field stays private to discourage callers from\n * reaching past the API.\n */\n readonly effectiveSelectedKeysForTemplate = this.effectiveSelectedKeys;\n\n /**\n * Resolve a row's selection key. Uses the explicit `getRowId` input\n * when provided; otherwise falls back to the row reference itself\n * (which only works if rows are object-stable across renders — fine\n * for uncontrolled-mode demos, broken across server-side pagination).\n */\n /** Resolves a stable selection key for the given row using `getRowId` or falling back to the row reference. */\n getSelectionKey(row: T): unknown {\n const idFn = this.getRowId();\n\n if (idFn) {\n return idFn(row);\n }\n\n return row;\n }\n\n /** Returns true if the given row is currently in the selected keys set. */\n isRowSelected(row: T): boolean {\n return this.effectiveSelectedKeys().has(this.getSelectionKey(row));\n }\n\n /** Returns true if selection is disabled for the given row per the `selectionDisabled` input. */\n isRowSelectionDisabled(row: T): boolean {\n const disabled = this.selectionDisabled();\n\n if (typeof disabled === 'function') {\n return disabled(row);\n }\n\n return disabled;\n }\n\n /**\n * Selection state of the header checkbox, derived from visible rows ∩\n * `effectiveSelectedKeys`. Disabled rows are excluded — they can't\n * contribute to the all-selected check.\n */\n readonly headerSelectionState = computed<HeaderSelectionState>(() => {\n if (!this.rowSelection()) {\n return 'unchecked';\n }\n\n const selected = this.effectiveSelectedKeys();\n const visibleEligible = this.visibleSelectableRows();\n\n if (visibleEligible.length === 0) {\n return 'unchecked';\n }\n\n let hits = 0;\n\n for (const row of visibleEligible) {\n if (selected.has(this.getSelectionKey(row))) {\n hits++;\n }\n }\n\n if (hits === 0) {\n return 'unchecked';\n }\n\n if (hits === visibleEligible.length) {\n return 'checked';\n }\n\n return 'indeterminate';\n });\n\n /**\n * Rows currently visible in the body (post-pagination) excluding any\n * marked as selection-disabled. The header checkbox toggles only over\n * this set.\n */\n private readonly visibleSelectableRows = computed<T[]>(() => {\n return this.engine\n .processedRows()\n .filter((row) => !this.isRowSelectionDisabled(row));\n });\n\n // ===== SELECTION ACTIONS =====\n\n onToggleRow(row: T, event: Event): void {\n event.stopPropagation();\n\n if (this.isRowSelectionDisabled(row)) {\n return;\n }\n\n const key = this.getSelectionKey(row);\n const current = this.effectiveSelectedKeys();\n const next = new Set(current);\n\n if (next.has(key)) {\n next.delete(key);\n } else {\n next.add(key);\n }\n\n if (this.selectedKeys() === null) {\n this.engine.setSelectedKeys(next);\n }\n\n this.selectionChange.emit(next);\n }\n\n onToggleAllVisible(event: Event): void {\n event.stopPropagation();\n\n const visible = this.visibleSelectableRows();\n const visibleKeys = visible.map((row) => this.getSelectionKey(row));\n const current = this.effectiveSelectedKeys();\n const allSelected =\n visibleKeys.length > 0 && visibleKeys.every((key) => current.has(key));\n\n const next = new Set(current);\n\n if (allSelected) {\n for (const key of visibleKeys) {\n next.delete(key);\n }\n } else {\n for (const key of visibleKeys) {\n next.add(key);\n }\n }\n\n if (this.selectedKeys() === null) {\n this.engine.setSelectedKeys(next);\n }\n\n this.selectionChange.emit(next);\n }\n\n // ===== EXPANSION HELPERS =====\n\n /**\n * Source of truth for which row keys are currently expanded. Reads\n * the controlled `expandedKeys` input when the parent supplied one,\n * otherwise falls back to the engine's internal set.\n */\n private readonly effectiveExpandedKeys = computed<Set<unknown>>(() => {\n const controlled = this.expandedKeys();\n\n if (controlled !== null) {\n return controlled;\n }\n\n return this.engine.expandedKeys();\n });\n\n /** True when `rowDetailTemplate` is set — the feature is opt-in. */\n readonly hasExpansion = computed(() => this.rowDetailTemplate() !== null);\n\n /**\n * Whether the expand chevron column appears at the start. When the\n * expansion feature is off this returns false so the column doesn't\n * render. Selection takes priority when both are pinned to \"start\"\n * (selection comes first, then expand).\n */\n readonly hasExpansionStart = computed(\n () => this.hasExpansion() && this.expansionColumnPosition() === 'start',\n );\n\n readonly hasExpansionEnd = computed(\n () => this.hasExpansion() && this.expansionColumnPosition() === 'end',\n );\n\n /** Returns true if the given row is currently expanded. */\n isRowExpanded(row: T): boolean {\n return this.effectiveExpandedKeys().has(this.getSelectionKey(row));\n }\n\n /** Returns true unless an `expandableRow` predicate explicitly excludes the row. */\n isRowExpandable(row: T): boolean {\n const predicate = this.expandableRow();\n\n if (predicate) {\n return predicate(row);\n }\n\n return true;\n }\n\n /**\n * Total columns rendered per row (data columns + selection col + expand col).\n * Used as the colspan for the detail `<td>` so it spans the full row width.\n */\n readonly totalColumnCount = computed(() => {\n let count = this.visibleColumns().length;\n\n if (this.rowSelection()) {\n count += 1;\n }\n\n if (this.hasExpansion()) {\n count += 1;\n }\n\n return count;\n });\n\n /** Toggle a single row's expansion via chevron click or keyboard. */\n onToggleExpand(row: T, event: Event): void {\n event.stopPropagation();\n\n if (!this.isRowExpandable(row)) {\n return;\n }\n\n const key = this.getSelectionKey(row);\n const currentSet = this.effectiveExpandedKeys();\n const wasExpanded = currentSet.has(key);\n const nextExpanded = !wasExpanded;\n\n if (this.groupCoordinator) {\n // Single-expand mode — route through the coordinator so a\n // sibling row (or sibling table) gets collapsed atomically.\n const { keysForThisTable, siblingTableToClear } =\n this.groupCoordinator.resolveToggle(\n this as DataTableComponent<unknown>,\n key,\n nextExpanded,\n currentSet,\n );\n\n this.commitExpansion(keysForThisTable);\n\n if (siblingTableToClear) {\n siblingTableToClear.clearExpansion();\n }\n\n return;\n }\n\n // Multi-expand mode — default. Add or remove this key from the set.\n const next = new Set(currentSet);\n\n if (wasExpanded) {\n next.delete(key);\n } else {\n next.add(key);\n }\n\n this.commitExpansion(next);\n }\n\n /**\n * Public hook used by the group coordinator to force-clear this\n * table's expansion when a sibling table opens a row. Routes through\n * the same commit path so controlled-mode parents still see the\n * emission.\n */\n clearExpansion(): void {\n if (this.effectiveExpandedKeys().size === 0) {\n return;\n }\n\n this.commitExpansion(new Set());\n }\n\n private commitExpansion(next: Set<unknown>): void {\n if (this.expandedKeys() === null) {\n this.engine.setExpandedKeys(next);\n }\n\n this.expansionChange.emit(next);\n }\n\n // ===== ACTIONS =====\n onHeaderClick(column: ColumnDef<T>): void {\n if (!column.sortable) {\n return;\n }\n\n const next = this.engine.toggleSort(column.id);\n\n this.sortChange.emit(next);\n }\n\n /** Returns an inline style object for the row if a `rowStyleFn` is configured, otherwise null. */\n getRowStyle(row: T, index: number): Record<string, string> | null {\n const fn = this.mergedConfig().rowStyleFn;\n\n if (!fn) {\n return null;\n }\n\n return fn(row, index);\n }\n\n onRowClick(row: T, index: number): void {\n this.rowClick.emit({\n row,\n index,\n selected: false,\n expanded: false,\n });\n }\n\n onVirtualScroll(event: Event): void {\n const target = event.target as HTMLElement;\n\n this.virtEngine.onScroll(target.scrollTop);\n }\n\n onViewportInit(el: HTMLElement): void {\n this.virtEngine.onViewportResize(el.clientHeight);\n\n if (typeof ResizeObserver !== 'undefined') {\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n this.ngZone.run(() => {\n this.virtEngine.onViewportResize(entry.contentRect.height);\n });\n }\n });\n\n observer.observe(el);\n }\n }\n\n getPinOffset(column: ColumnDef<T>): string | null {\n if (!column.pinned) {\n return null;\n }\n\n const cols = this.visibleColumns();\n const side = column.pinned;\n\n let offset = 0;\n\n if (side === 'start') {\n for (const col of cols) {\n if (col.id === column.id) {\n break;\n }\n\n if (col.pinned === 'start') {\n offset += parseInt(col.width ?? col.minWidth ?? '0', 10) || 0;\n }\n }\n } else {\n for (let i = cols.length - 1; i >= 0; i--) {\n if (cols[i].id === column.id) {\n break;\n }\n\n if (cols[i].pinned === 'end') {\n offset += parseInt(cols[i].width ?? cols[i].minWidth ?? '0', 10) || 0;\n }\n }\n }\n\n return `${offset}px`;\n }\n\n onColumnResize(event: ColumnResizeEvent): void {\n this.columnResize.emit(event);\n }\n\n /** Returns the current sort direction for the given column id, or null if not sorted. */\n getSortDirection(columnId: string): 'asc' | 'desc' | null {\n const sort = this.engine.sortState();\n\n if (sort?.columnId !== columnId) {\n return null;\n }\n\n return sort.direction;\n }\n}\n","@if (activeMode() === 'stack') {\n <!-- Stack path: mobile card view -->\n <fk-data-table-stack\n [rows]=\"engine.processedRows()\"\n [columns]=\"columns()\"\n [config]=\"mergedConfig()\"\n [trackByFn]=\"mergedConfig().trackBy\"\n [rowSelection]=\"rowSelection()\"\n [selectedKeys]=\"effectiveSelectedKeysForTemplate()\"\n [getRowId]=\"getRowId()\"\n [selectionDisabled]=\"selectionDisabled()\"\n [selectionLabel]=\"selectionLabel()\"\n [groupHeadingRenderer]=\"groupHeadingRenderer()\"\n (rowClick)=\"rowClick.emit($event)\"\n (toggleRow)=\"onToggleRow($event.row, $event.event)\"\n />\n} @else if (useVirtualization()) {\n <!-- Virtual path: div/grid-based with virtual scrolling -->\n <div role=\"table\" [attr.aria-label]=\"ariaLabel()\">\n @if (mergedConfig().showHeader) {\n <div class=\"fk-data-table__head\" role=\"rowgroup\">\n <div class=\"fk-data-table__head-row\" role=\"row\">\n @if (rowSelection() && selectionColumnPosition() === 'start') {\n <div\n class=\"fk-data-table__th fk-data-table__selection-cell\"\n role=\"columnheader\"\n >\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"\n headerSelectionState() === 'checked'\n ? 'Deselect all on page'\n : 'Select all on page'\n \"\n [checked]=\"headerSelectionState() === 'checked'\"\n [indeterminate]=\"headerSelectionState() === 'indeterminate'\"\n (click)=\"onToggleAllVisible($event)\"\n />\n </div>\n }\n @for (column of visibleColumns(); track column.id) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div\n class=\"fk-data-table__th\"\n role=\"columnheader\"\n [fkColumnResize]=\"column.id\"\n [enabled]=\"column.resizable === true\"\n (columnResize)=\"onColumnResize($event)\"\n [class.fk-data-table__th--sortable]=\"column.sortable\"\n [class.fk-data-table__th--align-center]=\"\n column.align === 'center'\n \"\n [class.fk-data-table__th--align-end]=\"column.align === 'end'\"\n [class.fk-data-table__th--pinned-start]=\"\n column.pinned === 'start'\n \"\n [class.fk-data-table__th--pinned-end]=\"column.pinned === 'end'\"\n [style.width]=\"column.width ?? null\"\n [style.min-width]=\"column.minWidth ?? null\"\n [style.max-width]=\"column.maxWidth ?? null\"\n [style.flex]=\"column.flex ?? null\"\n [style.--fk-data-table-pin-offset]=\"getPinOffset(column)\"\n [attr.aria-sort]=\"\n getSortDirection(column.id) === 'asc'\n ? 'ascending'\n : getSortDirection(column.id) === 'desc'\n ? 'descending'\n : null\n \"\n (click)=\"onHeaderClick(column)\"\n >\n @if (column.headerRenderer) {\n <ng-container\n [ngTemplateOutlet]=\"column.headerRenderer\"\n [ngTemplateOutletContext]=\"{ $implicit: column }\"\n />\n } @else {\n {{ column.header }}\n }\n\n @if (column.sortable) {\n <span\n class=\"fk-data-table__sort-indicator\"\n [class.fk-data-table__sort-indicator--asc]=\"\n getSortDirection(column.id) === 'asc'\n \"\n [class.fk-data-table__sort-indicator--desc]=\"\n getSortDirection(column.id) === 'desc'\n \"\n aria-hidden=\"true\"\n >\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M5 2L8 6H2L5 2Z\" fill=\"currentColor\" />\n </svg>\n </span>\n }\n </div>\n }\n @if (rowSelection() && selectionColumnPosition() === 'end') {\n <div\n class=\"fk-data-table__th fk-data-table__selection-cell\"\n role=\"columnheader\"\n >\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"\n headerSelectionState() === 'checked'\n ? 'Deselect all on page'\n : 'Select all on page'\n \"\n [checked]=\"headerSelectionState() === 'checked'\"\n [indeterminate]=\"headerSelectionState() === 'indeterminate'\"\n (click)=\"onToggleAllVisible($event)\"\n />\n </div>\n }\n </div>\n </div>\n }\n\n <div\n #virtualViewport\n class=\"fk-data-table__viewport\"\n role=\"rowgroup\"\n (scroll)=\"onVirtualScroll($event)\"\n >\n <div\n class=\"fk-data-table__sentinel\"\n [style.height.px]=\"virtEngine.totalHeight()\"\n ></div>\n\n <div\n class=\"fk-data-table__virtual-body\"\n [style.transform]=\"'translateY(' + virtEngine.offsetY() + 'px)'\"\n >\n @for (\n row of virtualRows();\n track mergedConfig().trackBy(virtualStartIndex() + $index, row);\n let i = $index\n ) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div\n class=\"fk-data-table__row\"\n role=\"row\"\n [class.fk-data-table__row--selected]=\"isRowSelected(row)\"\n [style.height.px]=\"mergedConfig().rowHeight\"\n [ngStyle]=\"getRowStyle(row, virtualStartIndex() + i)\"\n (click)=\"onRowClick(row, virtualStartIndex() + i)\"\n >\n @if (rowSelection() && selectionColumnPosition() === 'start') {\n <div\n class=\"fk-data-table__td fk-data-table__selection-cell\"\n role=\"cell\"\n >\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"selectionLabel()\"\n [checked]=\"isRowSelected(row)\"\n [disabled]=\"isRowSelectionDisabled(row)\"\n (click)=\"onToggleRow(row, $event)\"\n />\n </div>\n }\n @for (column of visibleColumns(); track column.id) {\n <div\n class=\"fk-data-table__td\"\n role=\"cell\"\n [class.fk-data-table__td--truncate]=\"column.truncate\"\n [class.fk-data-table__td--align-center]=\"\n column.align === 'center'\n \"\n [class.fk-data-table__td--align-end]=\"column.align === 'end'\"\n [class.fk-data-table__td--pinned-start]=\"\n column.pinned === 'start'\n \"\n [class.fk-data-table__td--pinned-end]=\"column.pinned === 'end'\"\n [style.width]=\"column.width ?? null\"\n [style.min-width]=\"column.minWidth ?? null\"\n [style.max-width]=\"column.maxWidth ?? null\"\n [style.flex]=\"column.flex ?? null\"\n [style.--fk-data-table-pin-offset]=\"getPinOffset(column)\"\n >\n @if (column.cellRenderer) {\n <ng-container\n [ngTemplateOutlet]=\"column.cellRenderer\"\n [ngTemplateOutletContext]=\"{\n $implicit: getCellValue(column, row),\n row: row,\n }\"\n />\n } @else {\n {{ getCellValue(column, row) }}\n }\n </div>\n }\n @if (rowSelection() && selectionColumnPosition() === 'end') {\n <div\n class=\"fk-data-table__td fk-data-table__selection-cell\"\n role=\"cell\"\n >\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"selectionLabel()\"\n [checked]=\"isRowSelected(row)\"\n [disabled]=\"isRowSelectionDisabled(row)\"\n (click)=\"onToggleRow(row, $event)\"\n />\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n @if (isEmpty()) {\n <div class=\"fk-data-table__empty\" role=\"row\">\n <div role=\"cell\">{{ mergedConfig().emptyMessage }}</div>\n </div>\n }\n </div>\n} @else {\n <!-- Standard path: semantic table -->\n <div class=\"fk-data-table__scroll\">\n <table class=\"fk-data-table__table\" [attr.aria-label]=\"ariaLabel()\">\n @if (mergedConfig().showHeader) {\n <thead class=\"fk-data-table__head\">\n <tr class=\"fk-data-table__head-row\">\n @if (rowSelection() && selectionColumnPosition() === 'start') {\n <th class=\"fk-data-table__th fk-data-table__selection-cell\">\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"\n headerSelectionState() === 'checked'\n ? 'Deselect all on page'\n : 'Select all on page'\n \"\n [checked]=\"headerSelectionState() === 'checked'\"\n [indeterminate]=\"headerSelectionState() === 'indeterminate'\"\n (click)=\"onToggleAllVisible($event)\"\n />\n </th>\n }\n @if (hasExpansionStart()) {\n <th\n class=\"fk-data-table__th fk-data-table__expand-cell\"\n aria-hidden=\"true\"\n ></th>\n }\n @for (column of visibleColumns(); track column.id) {\n <th\n class=\"fk-data-table__th\"\n [fkColumnResize]=\"column.id\"\n [enabled]=\"column.resizable === true\"\n (columnResize)=\"onColumnResize($event)\"\n [class.fk-data-table__th--sortable]=\"column.sortable\"\n [class.fk-data-table__th--align-center]=\"\n column.align === 'center'\n \"\n [class.fk-data-table__th--align-end]=\"column.align === 'end'\"\n [class.fk-data-table__th--pinned-start]=\"\n column.pinned === 'start'\n \"\n [class.fk-data-table__th--pinned-end]=\"column.pinned === 'end'\"\n [style.width]=\"column.width ?? null\"\n [style.min-width]=\"column.minWidth ?? null\"\n [style.max-width]=\"column.maxWidth ?? null\"\n [style.--fk-data-table-pin-offset]=\"getPinOffset(column)\"\n [attr.aria-sort]=\"\n getSortDirection(column.id) === 'asc'\n ? 'ascending'\n : getSortDirection(column.id) === 'desc'\n ? 'descending'\n : null\n \"\n (click)=\"onHeaderClick(column)\"\n >\n @if (column.headerRenderer) {\n <ng-container\n [ngTemplateOutlet]=\"column.headerRenderer\"\n [ngTemplateOutletContext]=\"{ $implicit: column }\"\n />\n } @else {\n {{ column.header }}\n }\n\n @if (column.sortable) {\n <span\n class=\"fk-data-table__sort-indicator\"\n [class.fk-data-table__sort-indicator--asc]=\"\n getSortDirection(column.id) === 'asc'\n \"\n [class.fk-data-table__sort-indicator--desc]=\"\n getSortDirection(column.id) === 'desc'\n \"\n aria-hidden=\"true\"\n >\n <svg\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M5 2L8 6H2L5 2Z\" fill=\"currentColor\" />\n </svg>\n </span>\n }\n </th>\n }\n @if (rowSelection() && selectionColumnPosition() === 'end') {\n <th class=\"fk-data-table__th fk-data-table__selection-cell\">\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"\n headerSelectionState() === 'checked'\n ? 'Deselect all on page'\n : 'Select all on page'\n \"\n [checked]=\"headerSelectionState() === 'checked'\"\n [indeterminate]=\"headerSelectionState() === 'indeterminate'\"\n (click)=\"onToggleAllVisible($event)\"\n />\n </th>\n }\n @if (hasExpansionEnd()) {\n <th\n class=\"fk-data-table__th fk-data-table__expand-cell\"\n aria-hidden=\"true\"\n ></th>\n }\n </tr>\n </thead>\n }\n\n <tbody class=\"fk-data-table__body\">\n @for (\n row of engine.processedRows();\n track mergedConfig().trackBy($index, row);\n let i = $index\n ) {\n <!--\n A heading opens each run of rows sharing a group key. Emitted from\n inside the row loop rather than by pre-grouping the rows, so the\n table still renders exactly the rows it was given, in the order it\n was given them.\n -->\n @if (groupHeadingFor(row, i); as heading) {\n <tr class=\"fk-data-table__group-heading\">\n <th\n scope=\"colgroup\"\n class=\"fk-data-table__group-heading-cell\"\n [attr.colspan]=\"groupHeadingSpan()\"\n >\n @if (groupHeadingRenderer()) {\n <ng-container\n [ngTemplateOutlet]=\"groupHeadingRenderer()!\"\n [ngTemplateOutletContext]=\"{ $implicit: heading, row: row }\"\n />\n } @else {\n {{ heading }}\n }\n </th>\n </tr>\n }\n\n <tr\n class=\"fk-data-table__row\"\n [class.fk-data-table__row--selected]=\"isRowSelected(row)\"\n [class.fk-data-table__row--expanded]=\"\n hasExpansion() && isRowExpanded(row)\n \"\n [ngStyle]=\"getRowStyle(row, i)\"\n (click)=\"onRowClick(row, i)\"\n >\n @if (rowSelection() && selectionColumnPosition() === 'start') {\n <td class=\"fk-data-table__td fk-data-table__selection-cell\">\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"selectionLabel()\"\n [checked]=\"isRowSelected(row)\"\n [disabled]=\"isRowSelectionDisabled(row)\"\n (click)=\"onToggleRow(row, $event)\"\n />\n </td>\n }\n @if (hasExpansionStart()) {\n <td class=\"fk-data-table__td fk-data-table__expand-cell\">\n @if (isRowExpandable(row)) {\n <button\n type=\"button\"\n class=\"fk-data-table__expand-button\"\n [class.fk-data-table__expand-button--expanded]=\"\n isRowExpanded(row)\n \"\n [attr.aria-label]=\"expansionLabel()\"\n [attr.aria-expanded]=\"isRowExpanded(row)\"\n (click)=\"onToggleExpand(row, $event)\"\n >\n <svg\n class=\"fk-data-table__expand-chevron\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n aria-hidden=\"true\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M3 1.5L6.5 5L3 8.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n }\n </td>\n }\n @for (column of visibleColumns(); track column.id) {\n <td\n class=\"fk-data-table__td\"\n [class.fk-data-table__td--truncate]=\"column.truncate\"\n [class.fk-data-table__td--align-center]=\"\n column.align === 'center'\n \"\n [class.fk-data-table__td--align-end]=\"column.align === 'end'\"\n [class.fk-data-table__td--pinned-start]=\"\n column.pinned === 'start'\n \"\n [class.fk-data-table__td--pinned-end]=\"column.pinned === 'end'\"\n [style.--fk-data-table-pin-offset]=\"getPinOffset(column)\"\n >\n @if (column.cellRenderer) {\n <ng-container\n [ngTemplateOutlet]=\"column.cellRenderer\"\n [ngTemplateOutletContext]=\"{\n $implicit: getCellValue(column, row),\n row: row,\n }\"\n />\n } @else {\n {{ getCellValue(column, row) }}\n }\n </td>\n }\n @if (rowSelection() && selectionColumnPosition() === 'end') {\n <td class=\"fk-data-table__td fk-data-table__selection-cell\">\n <input\n type=\"checkbox\"\n class=\"fk-data-table__checkbox\"\n [attr.aria-label]=\"selectionLabel()\"\n [checked]=\"isRowSelected(row)\"\n [disabled]=\"isRowSelectionDisabled(row)\"\n (click)=\"onToggleRow(row, $event)\"\n />\n </td>\n }\n @if (hasExpansionEnd()) {\n <td class=\"fk-data-table__td fk-data-table__expand-cell\">\n @if (isRowExpandable(row)) {\n <button\n type=\"button\"\n class=\"fk-data-table__expand-button\"\n [class.fk-data-table__expand-button--expanded]=\"\n isRowExpanded(row)\n \"\n [attr.aria-label]=\"expansionLabel()\"\n [attr.aria-expanded]=\"isRowExpanded(row)\"\n (click)=\"onToggleExpand(row, $event)\"\n >\n <svg\n class=\"fk-data-table__expand-chevron\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n aria-hidden=\"true\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M3 1.5L6.5 5L3 8.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n }\n </td>\n }\n </tr>\n @if (hasExpansion() && isRowExpanded(row)) {\n <tr class=\"fk-data-table__detail-row\">\n <td\n class=\"fk-data-table__detail-cell\"\n [attr.colspan]=\"totalColumnCount()\"\n >\n <ng-container\n [ngTemplateOutlet]=\"rowDetailTemplate()!\"\n [ngTemplateOutletContext]=\"{\n $implicit: row,\n row: row,\n index: i,\n }\"\n />\n </td>\n </tr>\n }\n }\n </tbody>\n </table>\n\n @if (isEmpty()) {\n <div class=\"fk-data-table__empty\">\n {{ mergedConfig().emptyMessage }}\n </div>\n }\n </div>\n}\n\n@if (loading()) {\n <div class=\"fk-data-table__loading-overlay\" aria-live=\"polite\">\n <span class=\"fk-data-table__loading-text\">Loading…</span>\n </div>\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n HostBinding,\n input,\n} from '@angular/core';\n\nimport { DataTableGroupCoordinator } from './data-table-group.service';\n\n/**\n * Single-expand wrapper for `<fk-data-table>`. Mirror of\n * `<fk-accordion-group>`: provides a coordinator scoped to itself, any\n * descendant data-table picks it up via DI and routes every expansion\n * toggle through it. The coordinator collapses the previously-active\n * row when a new one expands so only one detail panel is open.\n *\n * Wrap a data-table when you want exclusive expansion:\n *\n * ```html\n * <fk-data-table-group>\n * <fk-data-table [rowDetailTemplate]=\"detail\" ... />\n * </fk-data-table-group>\n * ```\n *\n * Omit the wrapper for multi-expand (the default).\n */\n@Component({\n selector: 'fk-data-table-group',\n standalone: true,\n imports: [],\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [DataTableGroupCoordinator],\n template: `<ng-content />`,\n})\nexport class DataTableGroupComponent {\n readonly className = input<string>('');\n\n readonly classes = computed(() => {\n return ['fk-data-table-group', this.className()].filter(Boolean).join(' ');\n });\n\n @HostBinding('class')\n get hostClass(): string {\n return this.classes();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;MAkBa,qBAAqB,CAAA;IACvB,QAAQ,GAAG,KAAK,CAAC,QAAQ,+EAAW,KAAK,EAAE,gBAAgB,EAAA,CAAG;AAC9D,IAAA,OAAO,GAAG,KAAK,CAAU,IAAI,8EAAC;AAC9B,IAAA,QAAQ,GAAG,KAAK,CAAS,EAAE,+EAAC;AAC5B,IAAA,QAAQ,GAAG,KAAK,CAAgB,IAAI,+EAAC;IAErC,YAAY,GAAG,MAAM,EAAqB;AAElC,IAAA,EAAE,GAAG,MAAM,EAAC,UAAuB,EAAC;AACpC,IAAA,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC;AAC5B,IAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAEhC,MAAM,GAAuB,IAAI;IACjC,MAAM,GAAG,CAAC;IACV,UAAU,GAAG,CAAC;IACd,QAAQ,GAAG,KAAK;IAEhB,YAAY,GAAwB,IAAI;IACxC,UAAU,GAAwB,IAAI;IAE9C,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE;YACnB;QACF;QAEA,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC;QAChD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,8BAA8B,CAAC;AACnE,QAAA,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC;AAE7D,QAAA,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,MAAK;YACjC,IAAI,CAAC,MAAM,EAAE,gBAAgB,CAAC,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC;YAC5D,IAAI,CAAC,MAAM,EAAE,gBAAgB,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE;AAC7D,gBAAA,OAAO,EAAE,KAAK;AACf,aAAA,CAAC;AACJ,QAAA,CAAC,CAAC;IACJ;IAEA,WAAW,GAAA;QACT,IAAI,CAAC,gBAAgB,EAAE;QACvB,IAAI,CAAC,MAAM,EAAE,mBAAmB,CAAC,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC;QAC/D,IAAI,CAAC,MAAM,EAAE,mBAAmB,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC;IACnE;AAEiB,IAAA,WAAW,GAAG,CAAC,KAAiB,KAAU;QACzD,KAAK,CAAC,cAAc,EAAE;AAEtB,QAAA,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC;QAE7B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CACtC,UAAU,EACV,WAAW,EACX,CAAC,CAAa,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAC1C;QAED,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,EAAE,MAC5D,IAAI,CAAC,OAAO,EAAE,CACf;AACH,IAAA,CAAC;AAEgB,IAAA,YAAY,GAAG,CAAC,KAAiB,KAAU;QAC1D,KAAK,CAAC,cAAc,EAAE;QAEtB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;AAE9B,QAAA,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC;AAE7B,QAAA,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CACtC,UAAU,EACV,WAAW,EACX,CAAC,CAAa,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CACrD;QAED,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,UAAU,EAAE,MAC7D,IAAI,CAAC,OAAO,EAAE,CACf;AACH,IAAA,CAAC;AAEO,IAAA,SAAS,CAAC,OAAe,EAAA;AAC/B,QAAA,IAAI,CAAC,QAAQ,GAAG,IAAI;AACpB,QAAA,IAAI,CAAC,MAAM,GAAG,OAAO;QACrB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,WAAW;QACnD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,yBAAyB,CAAC;IAClE;AAEQ,IAAA,MAAM,CAAC,OAAe,EAAA;AAC5B,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;YAClB;QACF;AAEA,QAAA,MAAM,IAAI,GAAG,OAAO,GAAG,IAAI,CAAC,MAAM;AAClC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC3B,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE;AAE3B,QAAA,IAAI,QAAQ,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI;AAErC,QAAA,IAAI,QAAQ,GAAG,GAAG,EAAE;YAClB,QAAQ,GAAG,GAAG;QAChB;QAEA,IAAI,GAAG,KAAK,IAAI,IAAI,QAAQ,GAAG,GAAG,EAAE;YAClC,QAAQ,GAAG,GAAG;QAChB;AAEA,QAAA,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAA,EAAA,CAAI,CAAC;IACzE;IAEQ,OAAO,GAAA;AACb,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;YAClB;QACF;AAEA,QAAA,IAAI,CAAC,QAAQ,GAAG,KAAK;QACrB,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,EAAE,yBAAyB,CAAC;QACnE,IAAI,CAAC,gBAAgB,EAAE;QAEvB,MAAM,UAAU,GAAG,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,WAAW;AAEpD,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAK;AACnB,YAAA,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;AACrB,gBAAA,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE;AACzB,gBAAA,KAAK,EAAE,UAAU;AAClB,aAAA,CAAC;AACJ,QAAA,CAAC,CAAC;IACJ;IAEQ,gBAAgB,GAAA;AACtB,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE;YACrB,IAAI,CAAC,YAAY,EAAE;AACnB,YAAA,IAAI,CAAC,YAAY,GAAG,IAAI;QAC1B;AAEA,QAAA,IAAI,IAAI,CAAC,UAAU,EAAE;YACnB,IAAI,CAAC,UAAU,EAAE;AACjB,YAAA,IAAI,CAAC,UAAU,GAAG,IAAI;QACxB;IACF;uGAvIW,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAArB,qBAAqB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,kBAAA,EAAA,MAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,YAAA,EAAA,cAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAArB,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBAJjC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,kBAAkB;AAC5B,oBAAA,UAAU,EAAE,IAAI;AACjB,iBAAA;;;ACgDM,MAAM,oBAAoB,GAAgB;AAC/C,IAAA,cAAc,EAAE,MAAM;AACtB,IAAA,WAAW,EAAE,KAAK;AAClB,IAAA,YAAY,EAAE,IAAI;AAClB,IAAA,UAAU,EAAE,IAAI;AAChB,IAAA,YAAY,EAAE,KAAK;AACnB,IAAA,YAAY,EAAE,mBAAmB;AACjC,IAAA,OAAO,EAAE,IAAI;AACb,IAAA,OAAO,EAAE,CAAC,KAAa,KAAK,KAAK;AACjC,IAAA,UAAU,EAAE,IAAI;AAChB,IAAA,cAAc,EAAE,MAAM;AACtB,IAAA,uBAAuB,EAAE,GAAG;AAC5B,IAAA,SAAS,EAAE,EAAE;AACb,IAAA,QAAQ,EAAE,EAAE;AACZ,IAAA,WAAW,EAAE;AACX,QAAA,EAAE,EAAE,uBAAuB;AAC3B,QAAA,EAAE,EAAE,uBAAuB;AAC5B,KAAA;;;AC9EH;;;;;;;;;AASG;MAEU,yBAAyB,CAAA;IAC5B,WAAW,GAAuC,IAAI;IACtD,SAAS,GAAY,IAAI;AAEjC;;;;;AAKG;AACH,IAAA,aAAa,CACX,KAAkC,EAClC,GAAY,EACZ,YAAqB,EACrB,sBAA4C,EAAA;QAM5C,IAAI,CAAC,YAAY,EAAE;;;AAGjB,YAAA,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,sBAAsB,CAAC;AAE5C,YAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;AAEhB,YAAA,IAAI,IAAI,CAAC,WAAW,KAAK,KAAK,IAAI,IAAI,CAAC,SAAS,KAAK,GAAG,EAAE;AACxD,gBAAA,IAAI,CAAC,WAAW,GAAG,IAAI;AACvB,gBAAA,IAAI,CAAC,SAAS,GAAG,IAAI;YACvB;YAEA,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE;QAC9D;;;QAIA,MAAM,IAAI,GAAG,IAAI,GAAG,CAAU,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,OAAO,GACX,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,WAAW,KAAK,KAAK,GAAG,IAAI,CAAC,WAAW,GAAG,IAAI;AAE1E,QAAA,IAAI,CAAC,WAAW,GAAG,KAAK;AACxB,QAAA,IAAI,CAAC,SAAS,GAAG,GAAG;QAEpB,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE;IACjE;AAEA;;;AAGG;AACH,IAAA,UAAU,CAAC,KAAkC,EAAA;AAC3C,QAAA,IAAI,IAAI,CAAC,WAAW,KAAK,KAAK,EAAE;AAC9B,YAAA,IAAI,CAAC,WAAW,GAAG,IAAI;AACvB,YAAA,IAAI,CAAC,SAAS,GAAG,IAAI;QACvB;IACF;uGAxDW,yBAAyB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;2GAAzB,yBAAyB,EAAA,CAAA;;2FAAzB,yBAAyB,EAAA,UAAA,EAAA,CAAA;kBADrC;;;ACZD;;;;;;;;;;;;AAYG;AACG,SAAU,kBAAkB,CAChC,IAAkB,EAClB,GAAM,EACN,KAAa,EACb,OAAkC,EAAA;IAElC,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,OAAO,IAAI;IACb;AAEA,IAAA,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;AAExB,IAAA,IAAI,GAAG,KAAK,IAAI,EAAE;AAChB,QAAA,OAAO,IAAI;IACb;AAEA,IAAA,IAAI,KAAK,KAAK,CAAC,EAAE;AACf,QAAA,OAAO,GAAG;IACZ;IAEA,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;AAEhC,IAAA,OAAO,QAAQ,KAAK,SAAS,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,GAAG,GAAG,IAAI,GAAG,GAAG;AACzE;;MCNa,uBAAuB,CAAA;;AAEzB,IAAA,IAAI,GAAG,KAAK,CAAM,EAAE,2EAAC;;AAErB,IAAA,OAAO,GAAG,KAAK,CAAiB,EAAE,8EAAC;;AAEnC,IAAA,MAAM,GAAG,KAAK,CAAwB,IAAI,6EAAC;;IAE3C,SAAS,GAAG,KAAK,CACxB,CAAC,KAAa,KAAK,KAAK,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,WAAA,EAAA,CAAA,8BAAA,EAAA,CAAA,CACzB;;AAGD;;;AAGG;AACM,IAAA,oBAAoB,GAAG,KAAK,CAG1B,IAAI,2FAAC;;;;;;;AAQP,IAAA,YAAY,GAAG,KAAK,CAAU,KAAK,mFAAC;;AAEpC,IAAA,YAAY,GAAG,KAAK,CAAe,IAAI,GAAG,EAAE,mFAAC;;AAE7C,IAAA,QAAQ,GAAG,KAAK,CAA+B,IAAI,+EAAC;;AAEpD,IAAA,iBAAiB,GAAG,KAAK,CAAuB,KAAK,wFAAC;;AAEtD,IAAA,cAAc,GAAG,KAAK,CAAS,YAAY,qFAAC;;IAGrD,eAAe,CAAC,GAAM,EAAE,KAAa,EAAA;QACnC,OAAO,kBAAkB,CACvB,IAAI,CAAC,IAAI,EAAE,EACX,GAAG,EACH,KAAK,EACL,IAAI,CAAC,MAAM,EAAE,EAAE,OAAO,IAAI,IAAI,CAC/B;IACH;;IAGS,QAAQ,GAAG,MAAM,EAAsB;;IAEvC,SAAS,GAAG,MAAM,EAA0B;AAE5C,IAAA,YAAY,GAAG,MAAM,CAAc,IAAI,GAAG,EAAE,mFAAC;IAE7C,iBAAiB,GAAG,CAAC;AAErB,IAAA,cAAc,GAAG,QAAQ,CAAC,MAAK;AACtC,QAAA,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC;AACxD,IAAA,CAAC,qFAAC;AAEO,IAAA,gBAAgB,GAAG,QAAQ,CAAC,MAAK;QACxC,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC;AACrD,IAAA,CAAC,uFAAC;AAEO,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAK;QACpC,OAAO,IAAI,CAAC,gBAAgB,EAAE,CAAC,MAAM,GAAG,CAAC;AAC3C,IAAA,CAAC,mFAAC;IAEF,YAAY,CAAC,MAAoB,EAAE,GAAM,EAAA;AACvC,QAAA,IAAI,OAAO,MAAM,CAAC,QAAQ,KAAK,UAAU,EAAE;AACzC,YAAA,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QAC7B;AAEA,QAAA,OAAO,GAAG,CAAC,MAAM,CAAC,QAAmB,CAAC;IACxC;AAEA,IAAA,QAAQ,CAAC,MAAoB,EAAA;AAC3B,QAAA,OAAO,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,MAAM;IAC5C;AAEA,IAAA,UAAU,CAAC,KAAa,EAAA;QACtB,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;IACvC;AAEA,IAAA,YAAY,CAAC,KAAa,EAAA;QACxB,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;AAEzC,QAAA,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AACnB,YAAA,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;QACpB;aAAO;AACL,YAAA,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;QACjB;AAEA,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;IAC7B;IAEA,UAAU,CAAC,GAAM,EAAE,KAAa,EAAA;AAC9B,QAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YACjB,GAAG;YACH,KAAK;AACL,YAAA,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;AACjC,YAAA,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;AACjC,SAAA,CAAC;IACJ;IAEA,iBAAiB,CAAC,GAAM,EAAE,KAAY,EAAA;QACpC,KAAK,CAAC,eAAe,EAAE;AAEvB,QAAA,IAAI,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,EAAE;YACpC;QACF;QAEA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;IACrC;AAEA,IAAA,aAAa,CAAC,GAAM,EAAA;AAClB,QAAA,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE;AACxB,YAAA,OAAO,KAAK;QACd;AAEA,QAAA,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IAC3D;AAEA,IAAA,sBAAsB,CAAC,GAAM,EAAA;AAC3B,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,iBAAiB,EAAE;AAEzC,QAAA,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE;AAClC,YAAA,OAAO,QAAQ,CAAC,GAAG,CAAC;QACtB;AAEA,QAAA,OAAO,QAAQ;IACjB;AAEQ,IAAA,eAAe,CAAC,GAAM,EAAA;AAC5B,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE;QAE5B,IAAI,IAAI,EAAE;AACR,YAAA,OAAO,IAAI,CAAC,GAAG,CAAC;QAClB;AAEA,QAAA,OAAO,GAAG;IACZ;uGA9IW,uBAAuB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAvB,uBAAuB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,qBAAA,EAAA,MAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,oBAAA,EAAA,EAAA,iBAAA,EAAA,sBAAA,EAAA,UAAA,EAAA,sBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,UAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,EAAA,iBAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,QAAA,EAAA,UAAA,EAAA,SAAA,EAAA,WAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EChCpC,47GAoGA,EAAA,MAAA,EAAA,CAAA,ojKAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDzEY,gBAAgB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,yBAAA,EAAA,kBAAA,EAAA,0BAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAKf,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBARnC,SAAS;+BACE,qBAAqB,EAAA,UAAA,EACnB,IAAI,EAAA,OAAA,EACP,CAAC,gBAAgB,CAAC,EAAA,eAAA,EACV,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,47GAAA,EAAA,MAAA,EAAA,CAAA,ojKAAA,CAAA,EAAA;;;MEZpC,yBAAyB,CAAA;;AAEnB,IAAA,kBAAkB,GAAG,MAAM,CAAC,kBAAkB,CAAC;AAC/C,IAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;;AAGvC,IAAA,OAAO,GAAG,MAAM,CAAiB,EAAE,8EAAC;AACpC,IAAA,MAAM,GAAG,MAAM,CAAwB,IAAI,6EAAC;;AAG5C,IAAA,iBAAiB,GAAG,MAAM,CAAa,IAAI,wFAAC;;AAG5C,IAAA,UAAU,GAA4C,QAAQ,CACrE,MAAK;AACH,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE;QAEzB,IAAI,CAAC,GAAG,EAAE;AACR,YAAA,OAAO,OAAO;QAChB;AAEA,QAAA,IAAI,GAAG,CAAC,WAAW,EAAE;AACnB,YAAA,OAAO,OAAO;QAChB;AAEA,QAAA,MAAM,IAAI,GAAG,GAAG,CAAC,cAAc;AAC/B,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,iBAAiB,EAAE;AAEnC,QAAA,IAAI,IAAI,KAAK,QAAQ,EAAE;AACrB,YAAA,OAAO,OAAO;QAChB;AAEA,QAAA,IAAI,IAAI,KAAK,OAAO,EAAE;YACpB,OAAO,EAAE,KAAK,IAAI,GAAG,OAAO,GAAG,OAAO;QACxC;AAEA,QAAA,IAAI,IAAI,KAAK,UAAU,EAAE;AACvB,YAAA,OAAO,OAAO;QAChB;;AAGA,QAAA,IAAI,EAAE,KAAK,IAAI,EAAE;AACf,YAAA,OAAO,OAAO;QAChB;AAEA,QAAA,OAAO,OAAO;AAChB,IAAA,CAAC,iFACF;AAEQ,IAAA,iBAAiB,GAAG,QAAQ,CAAC,MAAK;AACzC,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE;AAC3B,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE;AAEzB,QAAA,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,WAAW,EAAE;AAC3B,YAAA,OAAO,IAAI;QACb;AAEA,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,iBAAiB,EAAE;AACnC,QAAA,MAAM,IAAI,GAAG,GAAG,CAAC,cAAc;AAE/B,QAAA,IAAI,EAAE,KAAK,IAAI,EAAE;AACf,YAAA,OAAO,IAAI;QACb;AAEA,QAAA,IAAI,IAAI,KAAK,QAAQ,EAAE;AACrB,YAAA,OAAO,IAAI;QACb;;AAGA,QAAA,IAAI,EAAE,KAAK,IAAI,KAAK,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,UAAU,CAAC,EAAE;AAC3D,YAAA,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,KAAI;AACzB,gBAAA,IAAI,GAAG,CAAC,SAAS,KAAK,IAAI,IAAI,GAAG,CAAC,SAAS,KAAK,IAAI,EAAE;AACpD,oBAAA,OAAO,KAAK;gBACd;AAEA,gBAAA,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,GAAG,CAAC,QAAQ,IAAI,CAAC,EAAE;AACnD,oBAAA,OAAO,KAAK;gBACd;AAEA,gBAAA,OAAO,IAAI;AACb,YAAA,CAAC,CAAC;QACJ;AAEA,QAAA,OAAO,IAAI;AACb,IAAA,CAAC,wFAAC;AAEO,IAAA,aAAa,GAAG,QAAQ,CAAC,MAAK;AACrC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE;AAC1B,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,EAAE;AACxC,QAAA,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAEpD,QAAA,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AACjD,IAAA,CAAC,oFAAC;;IAGM,WAAW,GAAG,KAAK;AAE3B,IAAA,IAAI,CAAC,WAAuC,EAAA;AAC1C,QAAA,IAAI,IAAI,CAAC,WAAW,EAAE;YACpB;QACF;AAEA,QAAA,IAAI,CAAC,WAAW,GAAG,IAAI;AAEvB,QAAA,IAAI,CAAC;aACF,OAAO,CAAC,CAAC,WAAW,CAAC,EAAE,EAAE,WAAW,CAAC,EAAE,CAAC;AACxC,aAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC;AACxC,aAAA,SAAS,CAAC,CAAC,MAAM,KAAI;YACpB,IAAI,MAAM,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE;AACtC,gBAAA,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC;YAClC;iBAAO,IAAI,MAAM,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE;AAC7C,gBAAA,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC;YAClC;iBAAO;AACL,gBAAA,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC;YAClC;AACF,QAAA,CAAC,CAAC;IACN;uGApHW,yBAAyB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;2GAAzB,yBAAyB,EAAA,CAAA;;2FAAzB,yBAAyB,EAAA,UAAA,EAAA,CAAA;kBADrC;;;MCJY,kBAAkB,CAAA;;AAEpB,IAAA,IAAI,GAAG,MAAM,CAAM,EAAE,2EAAC;AACtB,IAAA,OAAO,GAAG,MAAM,CAAiB,EAAE,8EAAC;;AAG5B,IAAA,iBAAiB,GAAG,MAAM,CAAmB,IAAI,wFAAC;IAClD,mBAAmB,GAAG,MAAM,CAAc;AACzD,QAAA,KAAK,EAAE,EAAE;AACT,QAAA,aAAa,EAAE,EAAE;AAClB,KAAA,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,qBAAA,EAAA,CAAA,8BAAA,EAAA,CAAA,CAAC;AACe,IAAA,iBAAiB,GAAG,MAAM,CAAmB,IAAI,wFAAC;;AAG1D,IAAA,mBAAmB,GAAG,MAAM,CACnC,SAAS,0FACV;AACQ,IAAA,qBAAqB,GAAG,MAAM,CACrC,SAAS,4FACV;AACQ,IAAA,mBAAmB,GAAG,MAAM,CACnC,SAAS,0FACV;AAED;;;AAGG;AACM,IAAA,aAAa,GAAG,MAAM,CAAC,KAAK,oFAAC;;AAG7B,IAAA,SAAS,GAAG,QAAQ,CAAC,MAAK;AACjC,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,mBAAmB,EAAE;AAE7C,QAAA,IAAI,UAAU,KAAK,SAAS,EAAE;AAC5B,YAAA,OAAO,UAAU;QACnB;AAEA,QAAA,OAAO,IAAI,CAAC,iBAAiB,EAAE;AACjC,IAAA,CAAC,gFAAC;AAEO,IAAA,WAAW,GAAG,QAAQ,CAAC,MAAK;AACnC,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,qBAAqB,EAAE;QAE/C,IAAI,UAAU,KAAK,SAAS,IAAI,UAAU,KAAK,IAAI,EAAE;AACnD,YAAA,OAAO,UAAU;QACnB;AAEA,QAAA,OAAO,IAAI,CAAC,mBAAmB,EAAE;AACnC,IAAA,CAAC,kFAAC;AAEO,IAAA,SAAS,GAAG,QAAQ,CAAC,MAAK;AACjC,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,mBAAmB,EAAE;AAE7C,QAAA,IAAI,UAAU,KAAK,SAAS,EAAE;AAC5B,YAAA,OAAO,UAAU;QACnB;AAEA,QAAA,OAAO,IAAI,CAAC,iBAAiB,EAAE;AACjC,IAAA,CAAC,gFAAC;;;;;;;AAQO,IAAA,YAAY,GAAG,MAAM,CAAe,IAAI,GAAG,EAAE,mFAAC;;;;;AAM9C,IAAA,YAAY,GAAG,MAAM,CAAe,IAAI,GAAG,EAAE,mFAAC;;AAG9C,IAAA,UAAU,GAAG,QAAQ,CAAC,MAAK;AAClC,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE;AACxB,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE;AAE7B,QAAA,IAAI,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;AACpD,YAAA,OAAO,IAAI;QACb;QAEA,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,QAAQ,CAAC;QAEjE,IAAI,CAAC,MAAM,EAAE;AACX,YAAA,OAAO,IAAI;QACb;AAEA,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS;AAEhC,QAAA,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAI;AAC7B,YAAA,MAAM,IAAI,GAAG,MAAM,CAAC;AAClB,kBAAE,MAAM,CAAC,YAAY,CAAC,CAAC;kBACrB,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC5C,YAAA,MAAM,IAAI,GAAG,MAAM,CAAC;AAClB,kBAAE,MAAM,CAAC,YAAY,CAAC,CAAC;kBACrB,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;YAE5C,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC;AAC5C,QAAA,CAAC,CAAC;AACJ,IAAA,CAAC,iFAAC;AAEO,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAK;AACpC,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE;AAC9B,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE;AAEjC,QAAA,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE;AACnE,YAAA,OAAO,IAAI;QACb;AAEA,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE;QAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE;AAExC,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,KAAI;YACzB,IAAI,KAAK,EAAE;gBACT,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,KAAI;AACnC,oBAAA,MAAM,GAAG,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC;AAEnD,oBAAA,OAAO,MAAM,CAAC,GAAG,IAAI,EAAE;AACpB,yBAAA,WAAW;yBACX,QAAQ,CAAC,KAAK,CAAC;AACpB,gBAAA,CAAC,CAAC;gBAEF,IAAI,CAAC,OAAO,EAAE;AACZ,oBAAA,OAAO,KAAK;gBACd;YACF;AAEA,YAAA,OAAO,IAAI;AACb,QAAA,CAAC,CAAC;AACJ,IAAA,CAAC,mFAAC;AAEO,IAAA,aAAa,GAAG,QAAQ,CAAC,MAAK;AACrC,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE;AAChC,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE;QAE7B,IAAI,CAAC,IAAI,EAAE;AACT,YAAA,OAAO,IAAI;QACb;QAEA,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ;AAEvC,QAAA,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC;AACjD,IAAA,CAAC,oFAAC;AAEO,IAAA,iBAAiB,GAAG,QAAQ,CAAC,MAAK;AACzC,QAAA,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC,MAAM;AACnC,IAAA,CAAC,wFAAC;;AAGF,IAAA,UAAU,CAAC,QAAgB,EAAA;AACzB,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE;AAEhC,QAAA,IAAI,SAAwB;AAE5B,QAAA,IAAI,OAAO,EAAE,QAAQ,KAAK,QAAQ,EAAE;AAClC,YAAA,IAAI,OAAO,CAAC,SAAS,KAAK,KAAK,EAAE;gBAC/B,SAAS,GAAG,MAAM;YACpB;AAAO,iBAAA,IAAI,OAAO,CAAC,SAAS,KAAK,MAAM,EAAE;gBACvC,SAAS,GAAG,IAAI;YAClB;iBAAO;gBACL,SAAS,GAAG,KAAK;YACnB;QACF;aAAO;YACL,SAAS,GAAG,KAAK;QACnB;AAEA,QAAA,MAAM,IAAI,GAAc,EAAE,QAAQ,EAAE,SAAS,EAAE;AAE/C,QAAA,IAAI,IAAI,CAAC,mBAAmB,EAAE,KAAK,SAAS,EAAE;AAC5C,YAAA,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC;QAClC;AAEA,QAAA,OAAO,IAAI;IACb;AAEA,IAAA,SAAS,CAAC,KAAa,EAAA;AACrB,QAAA,MAAM,IAAI,GAAgB;YACxB,GAAG,IAAI,CAAC,WAAW,EAAE;YACrB,KAAK;SACN;AAED,QAAA,IAAI,IAAI,CAAC,qBAAqB,EAAE,KAAK,SAAS,EAAE;AAC9C,YAAA,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC;QACpC;AAEA,QAAA,OAAO,IAAI;IACb;IAEA,OAAO,CAAC,IAAY,EAAE,QAAiB,EAAA;AACrC,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE;AAChC,QAAA,MAAM,IAAI,GAAc;YACtB,IAAI;AACJ,YAAA,QAAQ,EAAE,QAAQ,IAAI,OAAO,EAAE,QAAQ,IAAI,EAAE;AAC7C,YAAA,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE;SACpC;AAED,QAAA,IAAI,IAAI,CAAC,mBAAmB,EAAE,KAAK,SAAS,EAAE;AAC5C,YAAA,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC;QAClC;AAEA,QAAA,OAAO,IAAI;IACb;AAEA;;;;AAIG;AACH,IAAA,eAAe,CAAC,IAAkB,EAAA;AAChC,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;IAC7B;AAEA;;;AAGG;AACH,IAAA,eAAe,CAAC,IAAkB,EAAA;AAChC,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;IAC7B;AAEA;;;AAGG;AACH,IAAA,eAAe,CACb,GAAY,EACZ,UAAgC,IAAI,CAAC,YAAY,EAAE,EAAA;AAEnD,QAAA,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC;AAE7B,QAAA,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AACjB,YAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;QAClB;aAAO;AACL,YAAA,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;QACf;AAEA,QAAA,OAAO,IAAI;IACb;AAEA;;;;;;;;;AASG;AACH,IAAA,iBAAiB,CACf,WAA8B,EAC9B,YAAA,GAAqC,IAAI,GAAG,EAAE,EAC9C,OAAA,GAAgC,IAAI,CAAC,YAAY,EAAE,EAAA;QAEnD,MAAM,QAAQ,GAAc,EAAE;AAE9B,QAAA,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE;YAC7B,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AAC1B,gBAAA,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;YACpB;QACF;QAEA,MAAM,WAAW,GACf,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAElE,QAAA,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC;QAE7B,IAAI,WAAW,EAAE;AACf,YAAA,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE;AAC1B,gBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;YAClB;QACF;aAAO;AACL,YAAA,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE;AAC1B,gBAAA,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YACf;QACF;AAEA,QAAA,OAAO,IAAI;IACb;IAEA,cAAc,GAAA;QACZ,OAAO,IAAI,GAAG,EAAW;IAC3B;AAEA,IAAA,UAAU,CAAC,GAAY,EAAA;QACrB,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;IACrC;;IAGQ,eAAe,CACrB,QAAyC,EACzC,GAAM,EAAA;AAEN,QAAA,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE;AAClC,YAAA,OAAO,QAAQ,CAAC,GAAG,CAAC;QACtB;AAEA,QAAA,OAAO,GAAG,CAAC,QAAQ,CAAC;IACtB;AAEQ,IAAA,OAAO,CAAC,CAAU,EAAE,CAAU,EAAE,SAAyB,EAAA;AAC/D,QAAA,MAAM,UAAU,GAAG,SAAS,KAAK,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;QAE/C,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE;AAC1B,YAAA,OAAO,CAAC;QACV;AAEA,QAAA,IAAI,CAAC,IAAI,IAAI,EAAE;YACb,OAAO,CAAC,GAAG,UAAU;QACvB;AAEA,QAAA,IAAI,CAAC,IAAI,IAAI,EAAE;AACb,YAAA,OAAO,CAAC,CAAC,GAAG,UAAU;QACxB;QAEA,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE;YAClD,OAAO,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,UAAU;QACxC;QAEA,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE;AAClD,YAAA,OAAO,CAAC,CAAC,GAAG,CAAC,IAAI,UAAU;QAC7B;AAEA,QAAA,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU;IACxD;uGAvUW,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;2GAAlB,kBAAkB,EAAA,CAAA;;2FAAlB,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAD9B;;;MCPY,2BAA2B,CAAA;;AAE7B,IAAA,SAAS,GAAG,MAAM,CAAS,EAAE,gFAAC;AAC9B,IAAA,QAAQ,GAAG,MAAM,CAAS,EAAE,+EAAC;AAC7B,IAAA,SAAS,GAAG,MAAM,CAAS,CAAC,gFAAC;;AAG7B,IAAA,cAAc,GAAG,MAAM,CAAS,CAAC,qFAAC;AAClC,IAAA,SAAS,GAAG,MAAM,CAAS,CAAC,gFAAC;;AAG7B,IAAA,YAAY,GAA2C,QAAQ,CACtE,MAAK;AACH,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,EAAE;AACpC,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE;AAC/B,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE;AAC3B,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC1B,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE;QAE9B,IAAI,EAAE,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC,EAAE;YAC1B,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;QAC7B;QAEA,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QAC3C,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC;AAE5C,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,GAAG,EAAE,CAAC;AAC5C,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,YAAY,GAAG,YAAY,GAAG,EAAE,CAAC;AAE7D,QAAA,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE;AACvB,IAAA,CAAC,mFACF;AAEQ,IAAA,WAAW,GAAmB,QAAQ,CAAC,MAAK;QACnD,OAAO,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE;AAC5C,IAAA,CAAC,kFAAC;AAEO,IAAA,OAAO,GAAmB,QAAQ,CAAC,MAAK;QAC/C,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE;AACrD,IAAA,CAAC,8EAAC;AAEO,IAAA,YAAY,GAAmB,QAAQ,CAAC,MAAK;AACpD,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE;AAEjC,QAAA,OAAO,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,KAAK;AAChC,IAAA,CAAC,mFAAC;;AAGF,IAAA,QAAQ,CAAC,SAAiB,EAAA;AACxB,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC;IAC/B;AAEA,IAAA,gBAAgB,CAAC,MAAc,EAAA;AAC7B,QAAA,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC;IACjC;uGAtDW,2BAA2B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;2GAA3B,2BAA2B,EAAA,CAAA;;2FAA3B,2BAA2B,EAAA,UAAA,EAAA,CAAA;kBADvC;;;MCuDY,kBAAkB,CAAA;;AAEpB,IAAA,SAAS,GAAG,KAAK,CAAS,EAAE,gFAAC;AAC7B,IAAA,EAAE,GAAG,KAAK,CAAgB,IAAI,yEAAC;AAC/B,IAAA,SAAS,GAAG,KAAK,CAAgB,IAAI,gFAAC;;;AAItC,IAAA,OAAO,GAAG,KAAK,CAAiB,EAAE,8EAAC;;AAEnC,IAAA,IAAI,GAAG,KAAK,CAAM,EAAE,2EAAC;;AAErB,IAAA,MAAM,GAAG,KAAK,CAA0B,EAAE,6EAAC;;AAE3C,IAAA,OAAO,GAAG,KAAK,CAAU,KAAK,8EAAC;;;AAI/B,IAAA,SAAS,GAAG,KAAK,CAAmB,IAAI,gFAAC;AAClD;;;;AAIG;AACM,IAAA,aAAa,GAAG,KAAK,CAAU,KAAK,oFAAC;;AAErC,IAAA,WAAW,GAAG,KAAK,CAAqB,IAAI,kFAAC;;AAE7C,IAAA,SAAS,GAAG,KAAK,CAAmB,IAAI,gFAAC;;;;;;;;;;;AAYzC,IAAA,YAAY,GAAG,KAAK,CAAU,KAAK,mFAAC;;AAEpC,IAAA,YAAY,GAAG,KAAK,CAAsB,IAAI,mFAAC;;AAE/C,IAAA,QAAQ,GAAG,KAAK,CAA+B,IAAI,+EAAC;;AAEpD,IAAA,iBAAiB,GAAG,KAAK,CAAuB,KAAK,wFAAC;;AAEtD,IAAA,uBAAuB,GAAG,KAAK,CAA0B,OAAO,8FAAC;;AAEjE,IAAA,cAAc,GAAG,KAAK,CAAS,YAAY,qFAAC;;;;;;;;;;;;;AAc5C,IAAA,iBAAiB,GAAG,KAAK,CAIvB,IAAI,wFAAC;;AAEP,IAAA,uBAAuB,GAAG,KAAK,CAA0B,OAAO,8FAAC;;AAEjE,IAAA,YAAY,GAAG,KAAK,CAAsB,IAAI,mFAAC;;AAE/C,IAAA,aAAa,GAAG,KAAK,CAA+B,IAAI,oFAAC;;AAEzD,IAAA,cAAc,GAAG,KAAK,CAAS,oBAAoB,qFAAC;;AAG7D;;;;AAIG;AACM,IAAA,oBAAoB,GAAG,KAAK,CAG1B,IAAI,2FAAC;;;IAIP,UAAU,GAAG,MAAM,EAAa;;IAEhC,YAAY,GAAG,MAAM,EAAe;;IAEpC,UAAU,GAAG,MAAM,EAAa;;IAEhC,QAAQ,GAAG,MAAM,EAAsB;;IAEvC,eAAe,GAAG,MAAM,EAAgB;;IAExC,eAAe,GAAG,MAAM,EAAgB;;IAExC,YAAY,GAAG,MAAM,EAAqB;;AAGhC,IAAA,MAAM;AACN,IAAA,UAAU;AACV,IAAA,UAAU,GAAG,MAAM,EAAC,yBAA4B,EAAC;;AAG3D,IAAA,eAAe,GACtB,SAAS,CAA0B,iBAAiB,sFAAC;;AAG9C,IAAA,YAAY,GAAG,QAAQ,CAAiB,MAAK;QACpD,OAAO,EAAE,GAAG,oBAAoB,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,EAAoB;AACxE,IAAA,CAAC,mFAAC;AAEO,IAAA,cAAc,GAAG,QAAQ,CAAC,MAAK;QACtC,MAAM,cAAc,GAAG,IAAI,CAAC,UAAU,CAAC,iBAAiB,EAAE;AAE1D,QAAA,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,OAAO,KAAK,KAAK,CAAC;AAC9D,IAAA,CAAC,qFAAC;AAEO,IAAA,UAAU,GAAG,QAAQ,CAAC,MAAK;AAClC,QAAA,OAAO,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE;AACrC,IAAA,CAAC,iFAAC;AAEO,IAAA,iBAAiB,GAAG,QAAQ,CAAC,MAAK;AACzC,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,EAAE;QAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM;;;;;AAMnC,QAAA,IAAI,MAAM,CAAC,OAAO,EAAE;AAClB,YAAA,OAAO,KAAK;QACd;AAEA,QAAA,IAAI,MAAM,CAAC,cAAc,KAAK,IAAI,EAAE;AAClC,YAAA,OAAO,IAAI;QACb;AAEA,QAAA,IAAI,MAAM,CAAC,cAAc,KAAK,KAAK,EAAE;AACnC,YAAA,OAAO,KAAK;QACd;AAEA,QAAA,OAAO,QAAQ,GAAG,MAAM,CAAC,uBAAuB;AAClD,IAAA,CAAC,wFAAC;AAEO,IAAA,WAAW,GAAG,QAAQ,CAAC,MAAK;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE;QACxC,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,YAAY,EAAE;AAE5C,QAAA,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC;AAC3C,IAAA,CAAC,kFAAC;AAEO,IAAA,iBAAiB,GAAG,QAAQ,CAAC,MAAK;QACzC,OAAO,IAAI,CAAC,UAAU,CAAC,YAAY,EAAE,CAAC,KAAK;AAC7C,IAAA,CAAC,wFAAC;AAEF;;;AAGG;AACM,IAAA,gBAAgB,GAAG,QAAQ,CAAC,MAAK;QACxC,IAAI,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC,MAAM;AAEvC,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE,EAAE;YACvB,IAAI,IAAI,CAAC;QACX;AAEA,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE,EAAE;YACvB,IAAI,IAAI,CAAC;QACX;AAEA,QAAA,OAAO,IAAI;AACb,IAAA,CAAC,uFAAC;AAEO,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAK;AAC/B,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;AACpE,IAAA,CAAC,8EAAC;AAEO,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAK;QAC/B,OAAO;YACL,eAAe;YACf,IAAI,CAAC,OAAO,EAAE,GAAG,wBAAwB,GAAG,EAAE;YAC9C,IAAI,CAAC,OAAO,EAAE,GAAG,sBAAsB,GAAG,EAAE;AAC5C,YAAA,IAAI,CAAC,YAAY,EAAE,CAAC,YAAY,GAAG,8BAA8B,GAAG,EAAE;YACtE,IAAI,CAAC,iBAAiB,EAAE,GAAG,wBAAwB,GAAG,EAAE;AACxD,YAAA,IAAI,CAAC,UAAU,EAAE,KAAK,OAAO,GAAG,sBAAsB,GAAG,EAAE;YAC3D,IAAI,CAAC,SAAS,EAAE;AACjB;aACE,MAAM,CAAC,OAAO;aACd,IAAI,CAAC,GAAG,CAAC;AACd,IAAA,CAAC,8EAAC;AAEF,IAAA,IACI,SAAS,GAAA;AACX,QAAA,OAAO,IAAI,CAAC,OAAO,EAAE;IACvB;AAEA,IAAA,IACI,MAAM,GAAA;AACR,QAAA,OAAO,IAAI,CAAC,EAAE,EAAE;IAClB;AAEiB,IAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AACxC;;;;;AAKG;AACc,IAAA,gBAAgB,GAAG,MAAM,CAAC,yBAAyB,EAAE;AACpE,QAAA,QAAQ,EAAE,IAAI;AACf,KAAA,CAAC;AAEF,IAAA,WAAA,GAAA;AACE,QAAA,IAAI,CAAC,MAAM,GAAG,IAAI,kBAAkB,EAAK;AACzC,QAAA,IAAI,CAAC,UAAU,GAAG,IAAI,2BAA2B,EAAE;;;AAInD,QAAA,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,MAAK;AAChC,YAAA,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,IAAmC,CAAC;AACxE,QAAA,CAAC,CAAC;QAEF,MAAM,CAAC,MAAK;AACV,YAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;AACnC,QAAA,CAAC,CAAC;QAEF,MAAM,CAAC,MAAK;AACV,YAAA,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;AACzC,QAAA,CAAC,CAAC;QAEF,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE;AAE7B,YAAA,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,KAAK,IAAI,GAAG,SAAS,GAAG,IAAI,CAAC;AACvE,QAAA,CAAC,CAAC;QAEF,MAAM,CAAC,MAAK;AACV,YAAA,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;AACrD,QAAA,CAAC,CAAC;QAEF,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE;AAEjC,YAAA,IAAI,CAAC,MAAM,CAAC,qBAAqB,CAAC,GAAG,CACnC,MAAM,KAAK,IAAI,GAAG,SAAS,GAAG,MAAM,CACrC;AACH,QAAA,CAAC,CAAC;QAEF,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE;AAE7B,YAAA,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,KAAK,IAAI,GAAG,SAAS,GAAG,IAAI,CAAC;AACvE,QAAA,CAAC,CAAC;;;;;QAMF,IAAI,aAAa,GAAG,KAAK;QAEzB,MAAM,CAAC,MAAK;AACV,YAAA,IAAI,IAAI,CAAC,YAAY,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE,KAAK,IAAI,IAAI,CAAC,aAAa,EAAE;gBACrE,aAAa,GAAG,IAAI;gBACpB,OAAO,CAAC,KAAK,CACX,gEAAgE;oBAC9D,6DAA6D;AAC7D,oBAAA,6DAA6D,CAChE;YACH;AACF,QAAA,CAAC,CAAC;;QAGF,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,EAAE;YAElC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC;YAC/C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC;AAC/C,QAAA,CAAC,CAAC;;QAGF,MAAM,CAAC,MAAK;AACV,YAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,MAAM,CAAC;AACnE,QAAA,CAAC,CAAC;;QAGF,MAAM,CAAC,MAAK;AACV,YAAA,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;AAC7C,QAAA,CAAC,CAAC;QAEF,MAAM,CAAC,MAAK;AACV,YAAA,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;AACjD,QAAA,CAAC,CAAC;;QAGF,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,EAAE;YAElC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;AAC1C,QAAA,CAAC,CAAC;IACJ;;;IAIA,eAAe,CAAC,GAAM,EAAE,KAAa,EAAA;QACnC,OAAO,kBAAkB,CACvB,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,EAC3B,GAAG,EACH,KAAK,EACL,IAAI,CAAC,YAAY,EAAE,CAAC,OAAO,CAC5B;IACH;;IAGA,YAAY,CAAC,MAAoB,EAAE,GAAM,EAAA;AACvC,QAAA,IAAI,OAAO,MAAM,CAAC,QAAQ,KAAK,UAAU,EAAE;AACzC,YAAA,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QAC7B;AAEA,QAAA,OAAO,GAAG,CAAC,MAAM,CAAC,QAAmB,CAAC;IACxC;;IAGA,UAAU,GAAA;AACR,QAAA,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC,OAAO;IACpC;;AAIA;;;;;;AAMG;AACc,IAAA,qBAAqB,GAAG,QAAQ,CAAe,MAAK;AACnE,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,EAAE;AAEtC,QAAA,IAAI,UAAU,KAAK,IAAI,EAAE;AACvB,YAAA,OAAO,UAAU;QACnB;AAEA,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;AACnC,IAAA,CAAC,4FAAC;AAEF;;;;AAIG;AACM,IAAA,gCAAgC,GAAG,IAAI,CAAC,qBAAqB;AAEtE;;;;;AAKG;;AAEH,IAAA,eAAe,CAAC,GAAM,EAAA;AACpB,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE;QAE5B,IAAI,IAAI,EAAE;AACR,YAAA,OAAO,IAAI,CAAC,GAAG,CAAC;QAClB;AAEA,QAAA,OAAO,GAAG;IACZ;;AAGA,IAAA,aAAa,CAAC,GAAM,EAAA;AAClB,QAAA,OAAO,IAAI,CAAC,qBAAqB,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IACpE;;AAGA,IAAA,sBAAsB,CAAC,GAAM,EAAA;AAC3B,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,iBAAiB,EAAE;AAEzC,QAAA,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE;AAClC,YAAA,OAAO,QAAQ,CAAC,GAAG,CAAC;QACtB;AAEA,QAAA,OAAO,QAAQ;IACjB;AAEA;;;;AAIG;AACM,IAAA,oBAAoB,GAAG,QAAQ,CAAuB,MAAK;AAClE,QAAA,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE;AACxB,YAAA,OAAO,WAAW;QACpB;AAEA,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,qBAAqB,EAAE;AAC7C,QAAA,MAAM,eAAe,GAAG,IAAI,CAAC,qBAAqB,EAAE;AAEpD,QAAA,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE;AAChC,YAAA,OAAO,WAAW;QACpB;QAEA,IAAI,IAAI,GAAG,CAAC;AAEZ,QAAA,KAAK,MAAM,GAAG,IAAI,eAAe,EAAE;AACjC,YAAA,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,EAAE;AAC3C,gBAAA,IAAI,EAAE;YACR;QACF;AAEA,QAAA,IAAI,IAAI,KAAK,CAAC,EAAE;AACd,YAAA,OAAO,WAAW;QACpB;AAEA,QAAA,IAAI,IAAI,KAAK,eAAe,CAAC,MAAM,EAAE;AACnC,YAAA,OAAO,SAAS;QAClB;AAEA,QAAA,OAAO,eAAe;AACxB,IAAA,CAAC,2FAAC;AAEF;;;;AAIG;AACc,IAAA,qBAAqB,GAAG,QAAQ,CAAM,MAAK;QAC1D,OAAO,IAAI,CAAC;AACT,aAAA,aAAa;AACb,aAAA,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC;AACvD,IAAA,CAAC,4FAAC;;IAIF,WAAW,CAAC,GAAM,EAAE,KAAY,EAAA;QAC9B,KAAK,CAAC,eAAe,EAAE;AAEvB,QAAA,IAAI,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,EAAE;YACpC;QACF;QAEA,MAAM,GAAG,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC;AACrC,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,qBAAqB,EAAE;AAC5C,QAAA,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC;AAE7B,QAAA,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AACjB,YAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;QAClB;aAAO;AACL,YAAA,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;QACf;AAEA,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;AAChC,YAAA,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC;QACnC;AAEA,QAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;IACjC;AAEA,IAAA,kBAAkB,CAAC,KAAY,EAAA;QAC7B,KAAK,CAAC,eAAe,EAAE;AAEvB,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,qBAAqB,EAAE;AAC5C,QAAA,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;AACnE,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,qBAAqB,EAAE;QAC5C,MAAM,WAAW,GACf,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAExE,QAAA,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC;QAE7B,IAAI,WAAW,EAAE;AACf,YAAA,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE;AAC7B,gBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;YAClB;QACF;aAAO;AACL,YAAA,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE;AAC7B,gBAAA,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YACf;QACF;AAEA,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;AAChC,YAAA,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC;QACnC;AAEA,QAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;IACjC;;AAIA;;;;AAIG;AACc,IAAA,qBAAqB,GAAG,QAAQ,CAAe,MAAK;AACnE,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,EAAE;AAEtC,QAAA,IAAI,UAAU,KAAK,IAAI,EAAE;AACvB,YAAA,OAAO,UAAU;QACnB;AAEA,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;AACnC,IAAA,CAAC,4FAAC;;AAGO,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,iBAAiB,EAAE,KAAK,IAAI,mFAAC;AAEzE;;;;;AAKG;AACM,IAAA,iBAAiB,GAAG,QAAQ,CACnC,MAAM,IAAI,CAAC,YAAY,EAAE,IAAI,IAAI,CAAC,uBAAuB,EAAE,KAAK,OAAO,wFACxE;AAEQ,IAAA,eAAe,GAAG,QAAQ,CACjC,MAAM,IAAI,CAAC,YAAY,EAAE,IAAI,IAAI,CAAC,uBAAuB,EAAE,KAAK,KAAK,sFACtE;;AAGD,IAAA,aAAa,CAAC,GAAM,EAAA;AAClB,QAAA,OAAO,IAAI,CAAC,qBAAqB,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IACpE;;AAGA,IAAA,eAAe,CAAC,GAAM,EAAA;AACpB,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,EAAE;QAEtC,IAAI,SAAS,EAAE;AACb,YAAA,OAAO,SAAS,CAAC,GAAG,CAAC;QACvB;AAEA,QAAA,OAAO,IAAI;IACb;AAEA;;;AAGG;AACM,IAAA,gBAAgB,GAAG,QAAQ,CAAC,MAAK;QACxC,IAAI,KAAK,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC,MAAM;AAExC,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE,EAAE;YACvB,KAAK,IAAI,CAAC;QACZ;AAEA,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE,EAAE;YACvB,KAAK,IAAI,CAAC;QACZ;AAEA,QAAA,OAAO,KAAK;AACd,IAAA,CAAC,uFAAC;;IAGF,cAAc,CAAC,GAAM,EAAE,KAAY,EAAA;QACjC,KAAK,CAAC,eAAe,EAAE;QAEvB,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE;YAC9B;QACF;QAEA,MAAM,GAAG,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC;AACrC,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,qBAAqB,EAAE;QAC/C,MAAM,WAAW,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC;AACvC,QAAA,MAAM,YAAY,GAAG,CAAC,WAAW;AAEjC,QAAA,IAAI,IAAI,CAAC,gBAAgB,EAAE;;;YAGzB,MAAM,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,GAC7C,IAAI,CAAC,gBAAgB,CAAC,aAAa,CACjC,IAAmC,EACnC,GAAG,EACH,YAAY,EACZ,UAAU,CACX;AAEH,YAAA,IAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC;YAEtC,IAAI,mBAAmB,EAAE;gBACvB,mBAAmB,CAAC,cAAc,EAAE;YACtC;YAEA;QACF;;AAGA,QAAA,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC;QAEhC,IAAI,WAAW,EAAE;AACf,YAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;QAClB;aAAO;AACL,YAAA,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;QACf;AAEA,QAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;IAC5B;AAEA;;;;;AAKG;IACH,cAAc,GAAA;QACZ,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC,IAAI,KAAK,CAAC,EAAE;YAC3C;QACF;AAEA,QAAA,IAAI,CAAC,eAAe,CAAC,IAAI,GAAG,EAAE,CAAC;IACjC;AAEQ,IAAA,eAAe,CAAC,IAAkB,EAAA;AACxC,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;AAChC,YAAA,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC;QACnC;AAEA,QAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;IACjC;;AAGA,IAAA,aAAa,CAAC,MAAoB,EAAA;AAChC,QAAA,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;YACpB;QACF;AAEA,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;AAE9C,QAAA,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;IAC5B;;IAGA,WAAW,CAAC,GAAM,EAAE,KAAa,EAAA;QAC/B,MAAM,EAAE,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,UAAU;QAEzC,IAAI,CAAC,EAAE,EAAE;AACP,YAAA,OAAO,IAAI;QACb;AAEA,QAAA,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC;IACvB;IAEA,UAAU,CAAC,GAAM,EAAE,KAAa,EAAA;AAC9B,QAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YACjB,GAAG;YACH,KAAK;AACL,YAAA,QAAQ,EAAE,KAAK;AACf,YAAA,QAAQ,EAAE,KAAK;AAChB,SAAA,CAAC;IACJ;AAEA,IAAA,eAAe,CAAC,KAAY,EAAA;AAC1B,QAAA,MAAM,MAAM,GAAG,KAAK,CAAC,MAAqB;QAE1C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC;IAC5C;AAEA,IAAA,cAAc,CAAC,EAAe,EAAA;QAC5B,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC,YAAY,CAAC;AAEjD,QAAA,IAAI,OAAO,cAAc,KAAK,WAAW,EAAE;YACzC,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,CAAC,OAAO,KAAI;AAC9C,gBAAA,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE;AAC3B,oBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAK;wBACnB,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC;AAC5D,oBAAA,CAAC,CAAC;gBACJ;AACF,YAAA,CAAC,CAAC;AAEF,YAAA,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACtB;IACF;AAEA,IAAA,YAAY,CAAC,MAAoB,EAAA;AAC/B,QAAA,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;AAClB,YAAA,OAAO,IAAI;QACb;AAEA,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE;AAClC,QAAA,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM;QAE1B,IAAI,MAAM,GAAG,CAAC;AAEd,QAAA,IAAI,IAAI,KAAK,OAAO,EAAE;AACpB,YAAA,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE;gBACtB,IAAI,GAAG,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,EAAE;oBACxB;gBACF;AAEA,gBAAA,IAAI,GAAG,CAAC,MAAM,KAAK,OAAO,EAAE;AAC1B,oBAAA,MAAM,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC;gBAC/D;YACF;QACF;aAAO;AACL,YAAA,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;gBACzC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,EAAE;oBAC5B;gBACF;gBAEA,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,KAAK,EAAE;oBAC5B,MAAM,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC;gBACvE;YACF;QACF;QAEA,OAAO,CAAA,EAAG,MAAM,CAAA,EAAA,CAAI;IACtB;AAEA,IAAA,cAAc,CAAC,KAAwB,EAAA;AACrC,QAAA,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;IAC/B;;AAGA,IAAA,gBAAgB,CAAC,QAAgB,EAAA;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE;AAEpC,QAAA,IAAI,IAAI,EAAE,QAAQ,KAAK,QAAQ,EAAE;AAC/B,YAAA,OAAO,IAAI;QACb;QAEA,OAAO,IAAI,CAAC,SAAS;IACvB;uGA1tBW,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAlB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,kBAAkB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,aAAA,EAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,UAAA,EAAA,eAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,UAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,uBAAA,EAAA,EAAA,iBAAA,EAAA,yBAAA,EAAA,UAAA,EAAA,yBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,EAAA,iBAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,UAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,uBAAA,EAAA,EAAA,iBAAA,EAAA,yBAAA,EAAA,UAAA,EAAA,yBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,aAAA,EAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,UAAA,EAAA,eAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,EAAA,iBAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,oBAAA,EAAA,EAAA,iBAAA,EAAA,sBAAA,EAAA,UAAA,EAAA,sBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,UAAA,EAAA,YAAA,EAAA,YAAA,EAAA,cAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,UAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,cAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,OAAA,EAAA,gBAAA,EAAA,SAAA,EAAA,aAAA,EAAA,EAAA,EAAA,SAAA,EARlB;YACT,kBAAkB;YAClB,2BAA2B;YAC3B,yBAAyB;SAC1B,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,iBAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,iBAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECrDH,o5qBA4hBA,qjUDjfI,OAAO,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACP,gBAAgB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,yBAAA,EAAA,kBAAA,EAAA,0BAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAChB,uBAAuB,mQACvB,qBAAqB,EAAA,QAAA,EAAA,kBAAA,EAAA,MAAA,EAAA,CAAA,gBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,UAAA,CAAA,EAAA,OAAA,EAAA,CAAA,cAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAWZ,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAlB9B,SAAS;+BACE,eAAe,EAAA,UAAA,EACb,IAAI,EAAA,OAAA,EACP;wBACP,OAAO;wBACP,gBAAgB;wBAChB,uBAAuB;wBACvB,qBAAqB;qBACtB,EAAA,eAAA,EACgB,uBAAuB,CAAC,MAAM,EAAA,SAAA,EACpC;wBACT,kBAAkB;wBAClB,2BAA2B;wBAC3B,yBAAyB;AAC1B,qBAAA,EAAA,QAAA,EAAA,o5qBAAA,EAAA,MAAA,EAAA,CAAA,6/TAAA,CAAA,EAAA;41FAoHoC,iBAAiB,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,SAAA,EAAA,CAAA;sBAuFrD,WAAW;uBAAC,OAAO;;sBAKnB,WAAW;uBAAC,SAAS;;;AE3PxB;;;;;;;;;;;;;;;;AAgBG;MASU,uBAAuB,CAAA;AACzB,IAAA,SAAS,GAAG,KAAK,CAAS,EAAE,gFAAC;AAE7B,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAK;AAC/B,QAAA,OAAO,CAAC,qBAAqB,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AAC5E,IAAA,CAAC,8EAAC;AAEF,IAAA,IACI,SAAS,GAAA;AACX,QAAA,OAAO,IAAI,CAAC,OAAO,EAAE;IACvB;uGAVW,uBAAuB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAvB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,uBAAuB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,qBAAA,EAAA,MAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,OAAA,EAAA,gBAAA,EAAA,EAAA,EAAA,SAAA,EAHvB,CAAC,yBAAyB,CAAC,0BAC5B,CAAA,cAAA,CAAgB,EAAA,QAAA,EAAA,IAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAEf,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBARnC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,qBAAqB;AAC/B,oBAAA,UAAU,EAAE,IAAI;AAChB,oBAAA,OAAO,EAAE,EAAE;oBACX,eAAe,EAAE,uBAAuB,CAAC,MAAM;oBAC/C,SAAS,EAAE,CAAC,yBAAyB,CAAC;AACtC,oBAAA,QAAQ,EAAE,CAAA,cAAA,CAAgB;AAC3B,iBAAA;;sBAQE,WAAW;uBAAC,OAAO;;;AC1CtB;;AAEG;;;;"}
|
|
@@ -2,8 +2,6 @@ import { moveItemInArray, CdkDropList, CdkDrag, CdkDragHandle, CdkDragPlaceholde
|
|
|
2
2
|
import { NgTemplateOutlet } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
4
|
import { inject, TemplateRef, Directive, model, input, output, contentChild, signal, computed, HostBinding, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
5
|
-
import * as i1 from '@angular/forms';
|
|
6
|
-
import { FormsModule } from '@angular/forms';
|
|
7
5
|
import { ButtonComponent, FkButtonIconStartDirective } from '@frame-kit/ui-ng/ui/button';
|
|
8
6
|
|
|
9
7
|
/**
|
|
@@ -154,12 +152,11 @@ class ListEditorComponent {
|
|
|
154
152
|
}
|
|
155
153
|
}
|
|
156
154
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ListEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
157
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: ListEditorComponent, isStandalone: true, selector: "fk-list-editor", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, addLabel: { classPropertyName: "addLabel", publicName: "addLabel", isSignal: true, isRequired: false, transformFunction: null }, orderable: { classPropertyName: "orderable", publicName: "orderable", isSignal: true, isRequired: false, transformFunction: null }, showOrder: { classPropertyName: "showOrder", publicName: "showOrder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, lockedItems: { classPropertyName: "lockedItems", publicName: "lockedItems", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { items: "itemsChange", itemsChange: "itemsChange", itemAdded: "itemAdded", itemRemoved: "itemRemoved" }, host: { properties: { "class": "this.hostClass" } }, queries: [{ propertyName: "itemTemplate", first: true, predicate: FkListEditorItemDirective, descendants: true, isSignal: true }], ngImport: i0, template: "<div\n cdkDropList\n [cdkDropListDisabled]=\"disabled() || !orderable()\"\n (cdkDropListDropped)=\"onDrop($event)\"\n class=\"fk-list-editor__list\"\n [attr.aria-label]=\"ariaLabel()\"\n>\n @for (item of items(); track $index) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"disabled() || !orderable()\"\n class=\"fk-list-editor__item\"\n >\n @if (orderable()) {\n <span class=\"fk-list-editor__handle\" cdkDragHandle>\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <circle cx=\"9\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n </svg>\n </span>\n }\n\n @if (showOrder()) {\n <span class=\"fk-list-editor__order\">{{ $index + 1 }}</span>\n }\n\n @if (itemTemplate(); as def) {\n <div class=\"fk-list-editor__item-custom\">\n <ng-container\n [ngTemplateOutlet]=\"def.templateRef\"\n [ngTemplateOutletContext]=\"contextFor(item, $index)\"\n />\n </div>\n } @else {\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [value]=\"item\"\n [disabled]=\"disabled() || isLocked(item)\"\n (input)=\"updateItem($index, $any($event.target).value)\"\n />\n\n <button\n class=\"fk-list-editor__remove\"\n type=\"button\"\n [disabled]=\"disabled() || isLocked(item)\"\n [title]=\"\n isLocked(item) ? 'This item cannot be removed' : 'Remove item'\n \"\n (click)=\"removeItem($index)\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n\n <div *cdkDragPlaceholder class=\"fk-list-editor__placeholder\"></div>\n </div>\n }\n</div>\n\n@if (items().length === 0 && emptyMessage()) {\n <p class=\"fk-list-editor__empty\">{{ emptyMessage() }}</p>\n}\n\n<div class=\"fk-list-editor__add\">\n <div class=\"fk-list-editor__add-input\">\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [ngModel]=\"newItemValue()\"\n (ngModelChange)=\"newItemValue.set($event)\"\n (keydown)=\"onKeydown($event)\"\n />\n\n @if (newItemValue() && !disabled()) {\n <button\n class=\"fk-list-editor__add-clear\"\n type=\"button\"\n aria-label=\"Clear input\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"newItemValue.set('')\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n </div>\n\n <fk-button\n variant=\"outline\"\n size=\"sm\"\n [disabled]=\"!canAdd() || disabled()\"\n (click)=\"addItem()\"\n >\n <svg\n fkButtonIconStart\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 5v14M5 12h14\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n {{ addLabel() }}\n </fk-button>\n</div>\n\n@if (hasDuplicates()) {\n <p class=\"fk-list-editor__error\">Item names must be unique.</p>\n}\n", styles: [":host{display:block}.fk-list-editor__list{display:flex;flex-direction:column;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem))}.fk-list-editor__item{display:flex;align-items:center;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-list-editor-item-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem));background:var(--fk-list-editor-item-bg, var(--fk-color-surface, #ffffff));border:1px solid var(--fk-list-editor-item-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-item-radius, var(--fk-radius-md, .5rem));transition:box-shadow .15s ease}.fk-list-editor__item:hover{box-shadow:var(--fk-list-editor-item-hover-shadow, 0 1px 3px rgba(0, 0, 0, .06))}.fk-list-editor__icon{width:var(--fk-list-editor-icon-size, 1rem);height:var(--fk-list-editor-icon-size, 1rem)}.fk-list-editor__handle{display:flex;cursor:grab;color:var(--fk-list-editor-handle-color, var(--fk-color-muted, #8a98a8));padding:var(--fk-list-editor-handle-padding, var(--fk-rhythm-1, .25rem))}.fk-list-editor__handle:active{cursor:grabbing}.fk-list-editor__order{display:flex;align-items:center;justify-content:center;width:var(--fk-list-editor-order-size, 1.5rem);height:var(--fk-list-editor-order-size, 1.5rem);border-radius:var(--fk-list-editor-order-radius, 50%);background:var(--fk-list-editor-order-bg, var(--fk-color-primary-light, #e0f2fe));color:var(--fk-list-editor-order-color, var(--fk-color-primary, #0a84ff));font-size:var(--fk-list-editor-order-font-size, .75rem);font-weight:var(--fk-list-editor-order-font-weight, var(--fk-font-weight-semibold, 600));flex-shrink:0}.fk-list-editor__item-custom{flex:1;min-width:0}.fk-list-editor__input{font-family:var(--fk-list-editor-input-font-family, inherit);flex:1;min-width:0;padding:var(--fk-list-editor-input-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem));border:1px solid var(--fk-list-editor-input-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-input-radius, var(--fk-radius-md, .5rem));font-size:var(--fk-list-editor-input-font-size, .875rem);color:var(--fk-list-editor-input-color, var(--fk-color-text, #1f2d3d));background:var(--fk-list-editor-input-bg, var(--fk-color-surface, #ffffff));outline:none;transition:border-color .15s ease}.fk-list-editor__input:focus{border-color:var(--fk-list-editor-input-focus-border-color, var(--fk-color-primary, #0a84ff))}.fk-list-editor__input:disabled{opacity:var(--fk-list-editor-disabled-opacity, var(--fk-input-disabled-opacity, .5));cursor:not-allowed}.fk-list-editor__remove{display:flex;align-items:center;padding:var(--fk-list-editor-remove-padding, var(--fk-rhythm-1, .25rem));border:none;background:transparent;cursor:pointer;color:var(--fk-list-editor-remove-color, var(--fk-color-muted, #8a98a8));transition:color .15s ease}.fk-list-editor__remove:hover:not(:disabled){color:var(--fk-list-editor-remove-hover-color, var(--fk-color-danger, #e02424))}.fk-list-editor__remove:focus-visible{outline:none;box-shadow:var(--fk-list-editor-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-list-editor__remove:disabled{opacity:.35;cursor:not-allowed}.fk-list-editor__placeholder{height:var(--fk-list-editor-placeholder-height, 3rem);border:2px dashed var(--fk-list-editor-placeholder-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-item-radius, var(--fk-radius-md, .5rem));background:var(--fk-list-editor-placeholder-bg, var(--fk-color-surface-muted, #f7f9fb))}.fk-list-editor__empty{padding:var(--fk-list-editor-empty-padding, var(--fk-rhythm-4, 1rem));text-align:var(--fk-list-editor-empty-text-align, left);color:var(--fk-list-editor-empty-color, var(--fk-color-muted, #8a98a8));font-size:var(--fk-list-editor-empty-font-size, var(--fk-typography-small-font-size, .875rem))}.fk-list-editor__add{display:flex;align-items:center;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem));margin-top:var(--fk-list-editor-add-gap, var(--fk-rhythm-3, .75rem))}.fk-list-editor__add-input{position:relative;display:flex;flex:1;min-width:0}.fk-list-editor__add-input .fk-list-editor__input{padding-right:var(--fk-list-editor-add-clear-reserve, var(--fk-rhythm-7, 1.75rem))}.fk-list-editor__add-clear{position:absolute;top:50%;right:var(--fk-list-editor-add-clear-offset, var(--fk-rhythm-2, .5rem));transform:translateY(-50%);display:flex;align-items:center;justify-content:center;padding:var(--fk-list-editor-add-clear-padding, .125rem);border:0;background:transparent;border-radius:var(--fk-list-editor-add-clear-radius, var(--fk-radius-sm, .25rem));color:var(--fk-list-editor-remove-color, var(--fk-color-muted, #8a98a8));cursor:pointer;transition:color .15s ease}.fk-list-editor__add-clear:hover{color:var(--fk-list-editor-remove-hover-color, var(--fk-color-danger, #e02424))}.fk-list-editor__add-clear:focus-visible{outline:none;box-shadow:var(--fk-list-editor-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-list-editor__error{margin-top:var(--fk-list-editor-error-gap, var(--fk-rhythm-2, .5rem));color:var(--fk-list-editor-error-color, var(--fk-color-danger, #e02424));font-size:var(--fk-list-editor-error-font-size, var(--fk-typography-small-font-size, .875rem))}:host.fk-list-editor--sm .fk-list-editor__input{font-size:var(--fk-list-editor-input-font-size-sm, .8125rem);padding:var(--fk-list-editor-input-padding-sm, var(--fk-rhythm-1, .25rem) var(--fk-rhythm-2, .5rem))}:host.fk-list-editor--sm .fk-list-editor__item{padding:var(--fk-list-editor-item-padding-sm, var(--fk-rhythm-1, .25rem) var(--fk-rhythm-2, .5rem))}:host.fk-list-editor--disabled{opacity:var(--fk-list-editor-disabled-opacity, var(--fk-input-disabled-opacity, .5));pointer-events:none}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.fk-list-editor__list.cdk-drop-list-dragging .fk-list-editor__item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drag-preview.fk-list-editor__item{box-shadow:var(--fk-list-editor-drag-shadow, 0 4px 12px rgba(0, 0, 0, .12));border-color:var(--fk-list-editor-drag-border-color, var(--fk-color-primary, #0a84ff))}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "component", type: ButtonComponent, selector: "fk-button", inputs: ["variant", "size", "loading", "disabled", "type", "fullWidth", "id", "className", "ariaLabel", "ariaDescribedBy"] }, { kind: "directive", type: FkButtonIconStartDirective, selector: "[fkButtonIconStart]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
155
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: ListEditorComponent, isStandalone: true, selector: "fk-list-editor", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, addLabel: { classPropertyName: "addLabel", publicName: "addLabel", isSignal: true, isRequired: false, transformFunction: null }, orderable: { classPropertyName: "orderable", publicName: "orderable", isSignal: true, isRequired: false, transformFunction: null }, showOrder: { classPropertyName: "showOrder", publicName: "showOrder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, lockedItems: { classPropertyName: "lockedItems", publicName: "lockedItems", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { items: "itemsChange", itemsChange: "itemsChange", itemAdded: "itemAdded", itemRemoved: "itemRemoved" }, host: { properties: { "class": "this.hostClass" } }, queries: [{ propertyName: "itemTemplate", first: true, predicate: FkListEditorItemDirective, descendants: true, isSignal: true }], ngImport: i0, template: "<div\n cdkDropList\n [cdkDropListDisabled]=\"disabled() || !orderable()\"\n (cdkDropListDropped)=\"onDrop($event)\"\n class=\"fk-list-editor__list\"\n [attr.aria-label]=\"ariaLabel()\"\n>\n @for (item of items(); track $index) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"disabled() || !orderable()\"\n class=\"fk-list-editor__item\"\n >\n @if (orderable()) {\n <span class=\"fk-list-editor__handle\" cdkDragHandle>\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <circle cx=\"9\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n </svg>\n </span>\n }\n\n @if (showOrder()) {\n <span class=\"fk-list-editor__order\">{{ $index + 1 }}</span>\n }\n\n @if (itemTemplate(); as def) {\n <div class=\"fk-list-editor__item-custom\">\n <ng-container\n [ngTemplateOutlet]=\"def.templateRef\"\n [ngTemplateOutletContext]=\"contextFor(item, $index)\"\n />\n </div>\n } @else {\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [value]=\"item\"\n [disabled]=\"disabled() || isLocked(item)\"\n (input)=\"updateItem($index, $any($event.target).value)\"\n />\n\n <button\n class=\"fk-list-editor__remove\"\n type=\"button\"\n [disabled]=\"disabled() || isLocked(item)\"\n [title]=\"\n isLocked(item) ? 'This item cannot be removed' : 'Remove item'\n \"\n (click)=\"removeItem($index)\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n\n <div *cdkDragPlaceholder class=\"fk-list-editor__placeholder\"></div>\n </div>\n }\n</div>\n\n@if (items().length === 0 && emptyMessage()) {\n <p class=\"fk-list-editor__empty\">{{ emptyMessage() }}</p>\n}\n\n<div class=\"fk-list-editor__add\">\n <div class=\"fk-list-editor__add-input\">\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [value]=\"newItemValue()\"\n (input)=\"newItemValue.set($any($event.target).value)\"\n (keydown)=\"onKeydown($event)\"\n />\n\n @if (newItemValue() && !disabled()) {\n <button\n class=\"fk-list-editor__add-clear\"\n type=\"button\"\n aria-label=\"Clear input\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"newItemValue.set('')\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n </div>\n\n <fk-button\n variant=\"outline\"\n size=\"sm\"\n [disabled]=\"!canAdd() || disabled()\"\n (click)=\"addItem()\"\n >\n <svg\n fkButtonIconStart\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 5v14M5 12h14\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n {{ addLabel() }}\n </fk-button>\n</div>\n\n@if (hasDuplicates()) {\n <p class=\"fk-list-editor__error\">Item names must be unique.</p>\n}\n", styles: [":host{display:block}.fk-list-editor__list{display:flex;flex-direction:column;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem))}.fk-list-editor__item{display:flex;align-items:center;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-list-editor-item-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem));background:var(--fk-list-editor-item-bg, var(--fk-color-surface, #ffffff));border:1px solid var(--fk-list-editor-item-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-item-radius, var(--fk-radius-md, .5rem));transition:box-shadow .15s ease}.fk-list-editor__item:hover{box-shadow:var(--fk-list-editor-item-hover-shadow, 0 1px 3px rgba(0, 0, 0, .06))}.fk-list-editor__icon{width:var(--fk-list-editor-icon-size, 1rem);height:var(--fk-list-editor-icon-size, 1rem)}.fk-list-editor__handle{display:flex;cursor:grab;color:var(--fk-list-editor-handle-color, var(--fk-color-muted, #8a98a8));padding:var(--fk-list-editor-handle-padding, var(--fk-rhythm-1, .25rem))}.fk-list-editor__handle:active{cursor:grabbing}.fk-list-editor__order{display:flex;align-items:center;justify-content:center;width:var(--fk-list-editor-order-size, 1.5rem);height:var(--fk-list-editor-order-size, 1.5rem);border-radius:var(--fk-list-editor-order-radius, 50%);background:var(--fk-list-editor-order-bg, var(--fk-color-primary-light, #e0f2fe));color:var(--fk-list-editor-order-color, var(--fk-color-primary, #0a84ff));font-size:var(--fk-list-editor-order-font-size, .75rem);font-weight:var(--fk-list-editor-order-font-weight, var(--fk-font-weight-semibold, 600));flex-shrink:0}.fk-list-editor__item-custom{flex:1;min-width:0}.fk-list-editor__input{font-family:var(--fk-list-editor-input-font-family, inherit);flex:1;min-width:0;padding:var(--fk-list-editor-input-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem));border:1px solid var(--fk-list-editor-input-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-input-radius, var(--fk-radius-md, .5rem));font-size:var(--fk-list-editor-input-font-size, .875rem);color:var(--fk-list-editor-input-color, var(--fk-color-text, #1f2d3d));background:var(--fk-list-editor-input-bg, var(--fk-color-surface, #ffffff));outline:none;transition:border-color .15s ease}.fk-list-editor__input:focus{border-color:var(--fk-list-editor-input-focus-border-color, var(--fk-color-primary, #0a84ff))}.fk-list-editor__input:disabled{opacity:var(--fk-list-editor-disabled-opacity, var(--fk-input-disabled-opacity, .5));cursor:not-allowed}.fk-list-editor__remove{display:flex;align-items:center;padding:var(--fk-list-editor-remove-padding, var(--fk-rhythm-1, .25rem));border:none;background:transparent;cursor:pointer;color:var(--fk-list-editor-remove-color, var(--fk-color-muted, #8a98a8));transition:color .15s ease}.fk-list-editor__remove:hover:not(:disabled){color:var(--fk-list-editor-remove-hover-color, var(--fk-color-danger, #e02424))}.fk-list-editor__remove:focus-visible{outline:none;box-shadow:var(--fk-list-editor-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-list-editor__remove:disabled{opacity:.35;cursor:not-allowed}.fk-list-editor__placeholder{height:var(--fk-list-editor-placeholder-height, 3rem);border:2px dashed var(--fk-list-editor-placeholder-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-item-radius, var(--fk-radius-md, .5rem));background:var(--fk-list-editor-placeholder-bg, var(--fk-color-surface-muted, #f7f9fb))}.fk-list-editor__empty{padding:var(--fk-list-editor-empty-padding, var(--fk-rhythm-4, 1rem));text-align:var(--fk-list-editor-empty-text-align, left);color:var(--fk-list-editor-empty-color, var(--fk-color-muted, #8a98a8));font-size:var(--fk-list-editor-empty-font-size, var(--fk-typography-small-font-size, .875rem))}.fk-list-editor__add{display:flex;align-items:center;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem));margin-top:var(--fk-list-editor-add-gap, var(--fk-rhythm-3, .75rem))}.fk-list-editor__add-input{position:relative;display:flex;flex:1;min-width:0}.fk-list-editor__add-input .fk-list-editor__input{padding-right:var(--fk-list-editor-add-clear-reserve, var(--fk-rhythm-7, 1.75rem))}.fk-list-editor__add-clear{position:absolute;top:50%;right:var(--fk-list-editor-add-clear-offset, var(--fk-rhythm-2, .5rem));transform:translateY(-50%);display:flex;align-items:center;justify-content:center;padding:var(--fk-list-editor-add-clear-padding, .125rem);border:0;background:transparent;border-radius:var(--fk-list-editor-add-clear-radius, var(--fk-radius-sm, .25rem));color:var(--fk-list-editor-remove-color, var(--fk-color-muted, #8a98a8));cursor:pointer;transition:color .15s ease}.fk-list-editor__add-clear:hover{color:var(--fk-list-editor-remove-hover-color, var(--fk-color-danger, #e02424))}.fk-list-editor__add-clear:focus-visible{outline:none;box-shadow:var(--fk-list-editor-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-list-editor__error{margin-top:var(--fk-list-editor-error-gap, var(--fk-rhythm-2, .5rem));color:var(--fk-list-editor-error-color, var(--fk-color-danger, #e02424));font-size:var(--fk-list-editor-error-font-size, var(--fk-typography-small-font-size, .875rem))}:host.fk-list-editor--sm .fk-list-editor__input{font-size:var(--fk-list-editor-input-font-size-sm, .8125rem);padding:var(--fk-list-editor-input-padding-sm, var(--fk-rhythm-1, .25rem) var(--fk-rhythm-2, .5rem))}:host.fk-list-editor--sm .fk-list-editor__item{padding:var(--fk-list-editor-item-padding-sm, var(--fk-rhythm-1, .25rem) var(--fk-rhythm-2, .5rem))}:host.fk-list-editor--disabled{opacity:var(--fk-list-editor-disabled-opacity, var(--fk-input-disabled-opacity, .5));pointer-events:none}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.fk-list-editor__list.cdk-drop-list-dragging .fk-list-editor__item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drag-preview.fk-list-editor__item{box-shadow:var(--fk-list-editor-drag-shadow, 0 4px 12px rgba(0, 0, 0, .12));border-color:var(--fk-list-editor-drag-border-color, var(--fk-color-primary, #0a84ff))}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "component", type: ButtonComponent, selector: "fk-button", inputs: ["variant", "size", "loading", "disabled", "type", "fullWidth", "id", "className", "ariaLabel", "ariaDescribedBy"] }, { kind: "directive", type: FkButtonIconStartDirective, selector: "[fkButtonIconStart]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
158
156
|
}
|
|
159
157
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ListEditorComponent, decorators: [{
|
|
160
158
|
type: Component,
|
|
161
159
|
args: [{ selector: 'fk-list-editor', standalone: true, imports: [
|
|
162
|
-
FormsModule,
|
|
163
160
|
NgTemplateOutlet,
|
|
164
161
|
CdkDropList,
|
|
165
162
|
CdkDrag,
|
|
@@ -167,7 +164,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
167
164
|
CdkDragPlaceholder,
|
|
168
165
|
ButtonComponent,
|
|
169
166
|
FkButtonIconStartDirective,
|
|
170
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n cdkDropList\n [cdkDropListDisabled]=\"disabled() || !orderable()\"\n (cdkDropListDropped)=\"onDrop($event)\"\n class=\"fk-list-editor__list\"\n [attr.aria-label]=\"ariaLabel()\"\n>\n @for (item of items(); track $index) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"disabled() || !orderable()\"\n class=\"fk-list-editor__item\"\n >\n @if (orderable()) {\n <span class=\"fk-list-editor__handle\" cdkDragHandle>\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <circle cx=\"9\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n </svg>\n </span>\n }\n\n @if (showOrder()) {\n <span class=\"fk-list-editor__order\">{{ $index + 1 }}</span>\n }\n\n @if (itemTemplate(); as def) {\n <div class=\"fk-list-editor__item-custom\">\n <ng-container\n [ngTemplateOutlet]=\"def.templateRef\"\n [ngTemplateOutletContext]=\"contextFor(item, $index)\"\n />\n </div>\n } @else {\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [value]=\"item\"\n [disabled]=\"disabled() || isLocked(item)\"\n (input)=\"updateItem($index, $any($event.target).value)\"\n />\n\n <button\n class=\"fk-list-editor__remove\"\n type=\"button\"\n [disabled]=\"disabled() || isLocked(item)\"\n [title]=\"\n isLocked(item) ? 'This item cannot be removed' : 'Remove item'\n \"\n (click)=\"removeItem($index)\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n\n <div *cdkDragPlaceholder class=\"fk-list-editor__placeholder\"></div>\n </div>\n }\n</div>\n\n@if (items().length === 0 && emptyMessage()) {\n <p class=\"fk-list-editor__empty\">{{ emptyMessage() }}</p>\n}\n\n<div class=\"fk-list-editor__add\">\n <div class=\"fk-list-editor__add-input\">\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [ngModel]=\"newItemValue()\"\n (ngModelChange)=\"newItemValue.set($event)\"\n (keydown)=\"onKeydown($event)\"\n />\n\n @if (newItemValue() && !disabled()) {\n <button\n class=\"fk-list-editor__add-clear\"\n type=\"button\"\n aria-label=\"Clear input\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"newItemValue.set('')\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n </div>\n\n <fk-button\n variant=\"outline\"\n size=\"sm\"\n [disabled]=\"!canAdd() || disabled()\"\n (click)=\"addItem()\"\n >\n <svg\n fkButtonIconStart\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 5v14M5 12h14\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n {{ addLabel() }}\n </fk-button>\n</div>\n\n@if (hasDuplicates()) {\n <p class=\"fk-list-editor__error\">Item names must be unique.</p>\n}\n", styles: [":host{display:block}.fk-list-editor__list{display:flex;flex-direction:column;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem))}.fk-list-editor__item{display:flex;align-items:center;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-list-editor-item-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem));background:var(--fk-list-editor-item-bg, var(--fk-color-surface, #ffffff));border:1px solid var(--fk-list-editor-item-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-item-radius, var(--fk-radius-md, .5rem));transition:box-shadow .15s ease}.fk-list-editor__item:hover{box-shadow:var(--fk-list-editor-item-hover-shadow, 0 1px 3px rgba(0, 0, 0, .06))}.fk-list-editor__icon{width:var(--fk-list-editor-icon-size, 1rem);height:var(--fk-list-editor-icon-size, 1rem)}.fk-list-editor__handle{display:flex;cursor:grab;color:var(--fk-list-editor-handle-color, var(--fk-color-muted, #8a98a8));padding:var(--fk-list-editor-handle-padding, var(--fk-rhythm-1, .25rem))}.fk-list-editor__handle:active{cursor:grabbing}.fk-list-editor__order{display:flex;align-items:center;justify-content:center;width:var(--fk-list-editor-order-size, 1.5rem);height:var(--fk-list-editor-order-size, 1.5rem);border-radius:var(--fk-list-editor-order-radius, 50%);background:var(--fk-list-editor-order-bg, var(--fk-color-primary-light, #e0f2fe));color:var(--fk-list-editor-order-color, var(--fk-color-primary, #0a84ff));font-size:var(--fk-list-editor-order-font-size, .75rem);font-weight:var(--fk-list-editor-order-font-weight, var(--fk-font-weight-semibold, 600));flex-shrink:0}.fk-list-editor__item-custom{flex:1;min-width:0}.fk-list-editor__input{font-family:var(--fk-list-editor-input-font-family, inherit);flex:1;min-width:0;padding:var(--fk-list-editor-input-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem));border:1px solid var(--fk-list-editor-input-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-input-radius, var(--fk-radius-md, .5rem));font-size:var(--fk-list-editor-input-font-size, .875rem);color:var(--fk-list-editor-input-color, var(--fk-color-text, #1f2d3d));background:var(--fk-list-editor-input-bg, var(--fk-color-surface, #ffffff));outline:none;transition:border-color .15s ease}.fk-list-editor__input:focus{border-color:var(--fk-list-editor-input-focus-border-color, var(--fk-color-primary, #0a84ff))}.fk-list-editor__input:disabled{opacity:var(--fk-list-editor-disabled-opacity, var(--fk-input-disabled-opacity, .5));cursor:not-allowed}.fk-list-editor__remove{display:flex;align-items:center;padding:var(--fk-list-editor-remove-padding, var(--fk-rhythm-1, .25rem));border:none;background:transparent;cursor:pointer;color:var(--fk-list-editor-remove-color, var(--fk-color-muted, #8a98a8));transition:color .15s ease}.fk-list-editor__remove:hover:not(:disabled){color:var(--fk-list-editor-remove-hover-color, var(--fk-color-danger, #e02424))}.fk-list-editor__remove:focus-visible{outline:none;box-shadow:var(--fk-list-editor-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-list-editor__remove:disabled{opacity:.35;cursor:not-allowed}.fk-list-editor__placeholder{height:var(--fk-list-editor-placeholder-height, 3rem);border:2px dashed var(--fk-list-editor-placeholder-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-item-radius, var(--fk-radius-md, .5rem));background:var(--fk-list-editor-placeholder-bg, var(--fk-color-surface-muted, #f7f9fb))}.fk-list-editor__empty{padding:var(--fk-list-editor-empty-padding, var(--fk-rhythm-4, 1rem));text-align:var(--fk-list-editor-empty-text-align, left);color:var(--fk-list-editor-empty-color, var(--fk-color-muted, #8a98a8));font-size:var(--fk-list-editor-empty-font-size, var(--fk-typography-small-font-size, .875rem))}.fk-list-editor__add{display:flex;align-items:center;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem));margin-top:var(--fk-list-editor-add-gap, var(--fk-rhythm-3, .75rem))}.fk-list-editor__add-input{position:relative;display:flex;flex:1;min-width:0}.fk-list-editor__add-input .fk-list-editor__input{padding-right:var(--fk-list-editor-add-clear-reserve, var(--fk-rhythm-7, 1.75rem))}.fk-list-editor__add-clear{position:absolute;top:50%;right:var(--fk-list-editor-add-clear-offset, var(--fk-rhythm-2, .5rem));transform:translateY(-50%);display:flex;align-items:center;justify-content:center;padding:var(--fk-list-editor-add-clear-padding, .125rem);border:0;background:transparent;border-radius:var(--fk-list-editor-add-clear-radius, var(--fk-radius-sm, .25rem));color:var(--fk-list-editor-remove-color, var(--fk-color-muted, #8a98a8));cursor:pointer;transition:color .15s ease}.fk-list-editor__add-clear:hover{color:var(--fk-list-editor-remove-hover-color, var(--fk-color-danger, #e02424))}.fk-list-editor__add-clear:focus-visible{outline:none;box-shadow:var(--fk-list-editor-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-list-editor__error{margin-top:var(--fk-list-editor-error-gap, var(--fk-rhythm-2, .5rem));color:var(--fk-list-editor-error-color, var(--fk-color-danger, #e02424));font-size:var(--fk-list-editor-error-font-size, var(--fk-typography-small-font-size, .875rem))}:host.fk-list-editor--sm .fk-list-editor__input{font-size:var(--fk-list-editor-input-font-size-sm, .8125rem);padding:var(--fk-list-editor-input-padding-sm, var(--fk-rhythm-1, .25rem) var(--fk-rhythm-2, .5rem))}:host.fk-list-editor--sm .fk-list-editor__item{padding:var(--fk-list-editor-item-padding-sm, var(--fk-rhythm-1, .25rem) var(--fk-rhythm-2, .5rem))}:host.fk-list-editor--disabled{opacity:var(--fk-list-editor-disabled-opacity, var(--fk-input-disabled-opacity, .5));pointer-events:none}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.fk-list-editor__list.cdk-drop-list-dragging .fk-list-editor__item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drag-preview.fk-list-editor__item{box-shadow:var(--fk-list-editor-drag-shadow, 0 4px 12px rgba(0, 0, 0, .12));border-color:var(--fk-list-editor-drag-border-color, var(--fk-color-primary, #0a84ff))}\n"] }]
|
|
167
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n cdkDropList\n [cdkDropListDisabled]=\"disabled() || !orderable()\"\n (cdkDropListDropped)=\"onDrop($event)\"\n class=\"fk-list-editor__list\"\n [attr.aria-label]=\"ariaLabel()\"\n>\n @for (item of items(); track $index) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"disabled() || !orderable()\"\n class=\"fk-list-editor__item\"\n >\n @if (orderable()) {\n <span class=\"fk-list-editor__handle\" cdkDragHandle>\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <circle cx=\"9\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n </svg>\n </span>\n }\n\n @if (showOrder()) {\n <span class=\"fk-list-editor__order\">{{ $index + 1 }}</span>\n }\n\n @if (itemTemplate(); as def) {\n <div class=\"fk-list-editor__item-custom\">\n <ng-container\n [ngTemplateOutlet]=\"def.templateRef\"\n [ngTemplateOutletContext]=\"contextFor(item, $index)\"\n />\n </div>\n } @else {\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [value]=\"item\"\n [disabled]=\"disabled() || isLocked(item)\"\n (input)=\"updateItem($index, $any($event.target).value)\"\n />\n\n <button\n class=\"fk-list-editor__remove\"\n type=\"button\"\n [disabled]=\"disabled() || isLocked(item)\"\n [title]=\"\n isLocked(item) ? 'This item cannot be removed' : 'Remove item'\n \"\n (click)=\"removeItem($index)\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n\n <div *cdkDragPlaceholder class=\"fk-list-editor__placeholder\"></div>\n </div>\n }\n</div>\n\n@if (items().length === 0 && emptyMessage()) {\n <p class=\"fk-list-editor__empty\">{{ emptyMessage() }}</p>\n}\n\n<div class=\"fk-list-editor__add\">\n <div class=\"fk-list-editor__add-input\">\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [value]=\"newItemValue()\"\n (input)=\"newItemValue.set($any($event.target).value)\"\n (keydown)=\"onKeydown($event)\"\n />\n\n @if (newItemValue() && !disabled()) {\n <button\n class=\"fk-list-editor__add-clear\"\n type=\"button\"\n aria-label=\"Clear input\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"newItemValue.set('')\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n </div>\n\n <fk-button\n variant=\"outline\"\n size=\"sm\"\n [disabled]=\"!canAdd() || disabled()\"\n (click)=\"addItem()\"\n >\n <svg\n fkButtonIconStart\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 5v14M5 12h14\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n {{ addLabel() }}\n </fk-button>\n</div>\n\n@if (hasDuplicates()) {\n <p class=\"fk-list-editor__error\">Item names must be unique.</p>\n}\n", styles: [":host{display:block}.fk-list-editor__list{display:flex;flex-direction:column;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem))}.fk-list-editor__item{display:flex;align-items:center;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem));padding:var(--fk-list-editor-item-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem));background:var(--fk-list-editor-item-bg, var(--fk-color-surface, #ffffff));border:1px solid var(--fk-list-editor-item-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-item-radius, var(--fk-radius-md, .5rem));transition:box-shadow .15s ease}.fk-list-editor__item:hover{box-shadow:var(--fk-list-editor-item-hover-shadow, 0 1px 3px rgba(0, 0, 0, .06))}.fk-list-editor__icon{width:var(--fk-list-editor-icon-size, 1rem);height:var(--fk-list-editor-icon-size, 1rem)}.fk-list-editor__handle{display:flex;cursor:grab;color:var(--fk-list-editor-handle-color, var(--fk-color-muted, #8a98a8));padding:var(--fk-list-editor-handle-padding, var(--fk-rhythm-1, .25rem))}.fk-list-editor__handle:active{cursor:grabbing}.fk-list-editor__order{display:flex;align-items:center;justify-content:center;width:var(--fk-list-editor-order-size, 1.5rem);height:var(--fk-list-editor-order-size, 1.5rem);border-radius:var(--fk-list-editor-order-radius, 50%);background:var(--fk-list-editor-order-bg, var(--fk-color-primary-light, #e0f2fe));color:var(--fk-list-editor-order-color, var(--fk-color-primary, #0a84ff));font-size:var(--fk-list-editor-order-font-size, .75rem);font-weight:var(--fk-list-editor-order-font-weight, var(--fk-font-weight-semibold, 600));flex-shrink:0}.fk-list-editor__item-custom{flex:1;min-width:0}.fk-list-editor__input{font-family:var(--fk-list-editor-input-font-family, inherit);flex:1;min-width:0;padding:var(--fk-list-editor-input-padding, var(--fk-rhythm-2, .5rem) var(--fk-rhythm-3, .75rem));border:1px solid var(--fk-list-editor-input-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-input-radius, var(--fk-radius-md, .5rem));font-size:var(--fk-list-editor-input-font-size, .875rem);color:var(--fk-list-editor-input-color, var(--fk-color-text, #1f2d3d));background:var(--fk-list-editor-input-bg, var(--fk-color-surface, #ffffff));outline:none;transition:border-color .15s ease}.fk-list-editor__input:focus{border-color:var(--fk-list-editor-input-focus-border-color, var(--fk-color-primary, #0a84ff))}.fk-list-editor__input:disabled{opacity:var(--fk-list-editor-disabled-opacity, var(--fk-input-disabled-opacity, .5));cursor:not-allowed}.fk-list-editor__remove{display:flex;align-items:center;padding:var(--fk-list-editor-remove-padding, var(--fk-rhythm-1, .25rem));border:none;background:transparent;cursor:pointer;color:var(--fk-list-editor-remove-color, var(--fk-color-muted, #8a98a8));transition:color .15s ease}.fk-list-editor__remove:hover:not(:disabled){color:var(--fk-list-editor-remove-hover-color, var(--fk-color-danger, #e02424))}.fk-list-editor__remove:focus-visible{outline:none;box-shadow:var(--fk-list-editor-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-list-editor__remove:disabled{opacity:.35;cursor:not-allowed}.fk-list-editor__placeholder{height:var(--fk-list-editor-placeholder-height, 3rem);border:2px dashed var(--fk-list-editor-placeholder-border-color, var(--fk-color-border, #d9e2ee));border-radius:var(--fk-list-editor-item-radius, var(--fk-radius-md, .5rem));background:var(--fk-list-editor-placeholder-bg, var(--fk-color-surface-muted, #f7f9fb))}.fk-list-editor__empty{padding:var(--fk-list-editor-empty-padding, var(--fk-rhythm-4, 1rem));text-align:var(--fk-list-editor-empty-text-align, left);color:var(--fk-list-editor-empty-color, var(--fk-color-muted, #8a98a8));font-size:var(--fk-list-editor-empty-font-size, var(--fk-typography-small-font-size, .875rem))}.fk-list-editor__add{display:flex;align-items:center;gap:var(--fk-list-editor-row-gap, var(--fk-rhythm-2, .5rem));margin-top:var(--fk-list-editor-add-gap, var(--fk-rhythm-3, .75rem))}.fk-list-editor__add-input{position:relative;display:flex;flex:1;min-width:0}.fk-list-editor__add-input .fk-list-editor__input{padding-right:var(--fk-list-editor-add-clear-reserve, var(--fk-rhythm-7, 1.75rem))}.fk-list-editor__add-clear{position:absolute;top:50%;right:var(--fk-list-editor-add-clear-offset, var(--fk-rhythm-2, .5rem));transform:translateY(-50%);display:flex;align-items:center;justify-content:center;padding:var(--fk-list-editor-add-clear-padding, .125rem);border:0;background:transparent;border-radius:var(--fk-list-editor-add-clear-radius, var(--fk-radius-sm, .25rem));color:var(--fk-list-editor-remove-color, var(--fk-color-muted, #8a98a8));cursor:pointer;transition:color .15s ease}.fk-list-editor__add-clear:hover{color:var(--fk-list-editor-remove-hover-color, var(--fk-color-danger, #e02424))}.fk-list-editor__add-clear:focus-visible{outline:none;box-shadow:var(--fk-list-editor-focus-ring, var(--fk-focus-ring, 0 0 0 3px rgba(10, 132, 255, .18)))}.fk-list-editor__error{margin-top:var(--fk-list-editor-error-gap, var(--fk-rhythm-2, .5rem));color:var(--fk-list-editor-error-color, var(--fk-color-danger, #e02424));font-size:var(--fk-list-editor-error-font-size, var(--fk-typography-small-font-size, .875rem))}:host.fk-list-editor--sm .fk-list-editor__input{font-size:var(--fk-list-editor-input-font-size-sm, .8125rem);padding:var(--fk-list-editor-input-padding-sm, var(--fk-rhythm-1, .25rem) var(--fk-rhythm-2, .5rem))}:host.fk-list-editor--sm .fk-list-editor__item{padding:var(--fk-list-editor-item-padding-sm, var(--fk-rhythm-1, .25rem) var(--fk-rhythm-2, .5rem))}:host.fk-list-editor--disabled{opacity:var(--fk-list-editor-disabled-opacity, var(--fk-input-disabled-opacity, .5));pointer-events:none}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.fk-list-editor__list.cdk-drop-list-dragging .fk-list-editor__item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drag-preview.fk-list-editor__item{box-shadow:var(--fk-list-editor-drag-shadow, 0 4px 12px rgba(0, 0, 0, .12));border-color:var(--fk-list-editor-drag-border-color, var(--fk-color-primary, #0a84ff))}\n"] }]
|
|
171
168
|
}], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }, { type: i0.Output, args: ["itemsChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], addLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "addLabel", required: false }] }], orderable: [{ type: i0.Input, args: [{ isSignal: true, alias: "orderable", required: false }] }], showOrder: [{ type: i0.Input, args: [{ isSignal: true, alias: "showOrder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], lockedItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "lockedItems", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], itemsChange: [{ type: i0.Output, args: ["itemsChange"] }], itemAdded: [{ type: i0.Output, args: ["itemAdded"] }], itemRemoved: [{ type: i0.Output, args: ["itemRemoved"] }], itemTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => FkListEditorItemDirective), { isSignal: true }] }], hostClass: [{
|
|
172
169
|
type: HostBinding,
|
|
173
170
|
args: ['class']
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frame-kit-ui-ng-ui-list-editor.mjs","sources":["../../../../packages/ui-ng/ui/list-editor/list-editor-item.directive.ts","../../../../packages/ui-ng/ui/list-editor/list-editor.component.ts","../../../../packages/ui-ng/ui/list-editor/list-editor.component.html","../../../../packages/ui-ng/ui/list-editor/frame-kit-ui-ng-ui-list-editor.ts"],"sourcesContent":["import { Directive, inject, TemplateRef } from '@angular/core';\n\nimport { ListEditorItemContext } from './list-editor.types';\n\n/**\n * Marks an `<ng-template>` as the per-row renderer for `fk-list-editor`. When\n * present, the editor renders this template for each item instead of its\n * default editable input + remove button, so the consumer owns the row markup\n * (scheme tag, status, custom actions, …). The add-input, empty state, and\n * optional drag/order chrome are still provided by the editor.\n *\n * ```html\n * <fk-list-editor [items]=\"origins\">\n * <ng-template fkListEditorItem let-origin let-remove=\"remove\">\n * <span>{{ origin }}</span>\n * <button (click)=\"remove()\">Remove</button>\n * </ng-template>\n * </fk-list-editor>\n * ```\n */\n@Directive({\n selector: '[fkListEditorItem]',\n standalone: true,\n})\nexport class FkListEditorItemDirective {\n readonly templateRef = inject(TemplateRef<ListEditorItemContext>);\n}\n","import {\n CdkDrag,\n CdkDragDrop,\n CdkDragHandle,\n CdkDragPlaceholder,\n CdkDropList,\n moveItemInArray,\n} from '@angular/cdk/drag-drop';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n HostBinding,\n input,\n model,\n output,\n signal,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { ButtonComponent } from '@frame-kit/ui-ng/ui/button';\nimport { FkButtonIconStartDirective } from '@frame-kit/ui-ng/ui/button';\nimport { FkListEditorItemDirective } from './list-editor-item.directive';\nimport type {\n ListEditorItemContext,\n ListEditorSize,\n} from './list-editor.types';\n\n@Component({\n selector: 'fk-list-editor',\n standalone: true,\n imports: [\n FormsModule,\n NgTemplateOutlet,\n CdkDropList,\n CdkDrag,\n CdkDragHandle,\n CdkDragPlaceholder,\n ButtonComponent,\n FkButtonIconStartDirective,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './list-editor.component.html',\n styleUrl: './list-editor.component.scss',\n})\nexport class ListEditorComponent {\n // ===== INPUTS =====\n /** The current list of string items; two-way bindable via `[(items)]`. */\n readonly items = model<string[]>([]);\n /** Placeholder text for the new-item input field. */\n readonly placeholder = input('Add an item...');\n /** Message displayed when the list is empty. */\n readonly emptyMessage = input('No items added yet.');\n /** Label for the add button. */\n readonly addLabel = input('Add');\n /** When true, items can be reordered via drag-and-drop. */\n readonly orderable = input(true);\n /** When true, shows a numeric position indicator next to each item. */\n readonly showOrder = input(true);\n /** Size variant controlling the spacing and font of the component. */\n readonly size = input<ListEditorSize>('md');\n /** Items that cannot be removed by the user (matched case-insensitively). */\n readonly lockedItems = input<string[]>([]);\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly disabled = input(false);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== OUTPUTS =====\n /** Fires whenever the items array changes, emitting the full updated array. */\n readonly itemsChange = output<string[]>();\n /** Fires when a new item is successfully added, emitting the added value. */\n readonly itemAdded = output<string>();\n /** Fires when an item is removed, emitting the removed value and its former index. */\n readonly itemRemoved = output<{ item: string; index: number }>();\n\n // ===== CONTENT =====\n /**\n * Optional custom row template (`*fkListEditorItem`). When provided, each\n * item renders through it instead of the default editable input + remove\n * button.\n */\n readonly itemTemplate = contentChild(FkListEditorItemDirective);\n\n // ===== LOCAL STATE =====\n readonly newItemValue = signal('');\n\n // ===== COMPUTED =====\n readonly canAdd = computed(() => {\n const value = this.newItemValue().trim();\n\n if (!value) {\n return false;\n }\n\n const existing = this.items().map((n) => n.trim().toLowerCase());\n\n return !existing.includes(value.toLowerCase());\n });\n\n readonly hasDuplicates = computed(() => {\n const names = this.items().map((n) => n.trim().toLowerCase());\n\n return new Set(names).size !== names.length;\n });\n\n readonly hasEmptyItems = computed(() => {\n return this.items().some((n) => n.trim() === '');\n });\n\n readonly classes = computed(() =>\n [\n 'fk-list-editor',\n `fk-list-editor--${this.size()}`,\n this.disabled() ? 'fk-list-editor--disabled' : '',\n this.className(),\n ]\n .filter(Boolean)\n .join(' '),\n );\n\n @HostBinding('class')\n get hostClass() {\n return this.classes();\n }\n\n // ===== ACTIONS =====\n\n /** Adds the current input value as a new item if it is non-empty and not a duplicate. */\n addItem(): void {\n const value = this.newItemValue().trim();\n\n if (!value || !this.canAdd() || this.disabled()) {\n return;\n }\n\n this.items.update((prev) => [...prev, value]);\n this.newItemValue.set('');\n this.itemsChange.emit(this.items());\n this.itemAdded.emit(value);\n }\n\n /** Removes the item at the given index unless it is locked or the component is disabled. */\n removeItem(index: number): void {\n const item = this.items()[index];\n\n if (this.disabled() || this.isLocked(item)) {\n return;\n }\n\n this.items.update((prev) => prev.filter((_, i) => i !== index));\n this.itemsChange.emit(this.items());\n this.itemRemoved.emit({ item, index });\n }\n\n /** Updates the item at the given index with a new value and emits the changed array. */\n updateItem(index: number, value: string): void {\n this.items.update((prev) =>\n prev.map((item, i) => (i === index ? value : item)),\n );\n this.itemsChange.emit(this.items());\n }\n\n onDrop(event: CdkDragDrop<string[]>): void {\n const updated = [...this.items()];\n\n moveItemInArray(updated, event.previousIndex, event.currentIndex);\n this.items.set(updated);\n this.itemsChange.emit(this.items());\n }\n\n /** Returns true if the given item matches any entry in `lockedItems`. */\n isLocked(item: string): boolean {\n return this.lockedItems().includes(item.trim().toLowerCase());\n }\n\n /** Builds the `let-` context for a custom row template. */\n contextFor(item: string, index: number): ListEditorItemContext {\n return {\n $implicit: item,\n index,\n locked: this.isLocked(item),\n remove: () => this.removeItem(index),\n update: (value: string) => this.updateItem(index, value),\n };\n }\n\n onKeydown(event: KeyboardEvent): void {\n if (event.key === 'Enter') {\n event.preventDefault();\n this.addItem();\n }\n }\n}\n","<div\n cdkDropList\n [cdkDropListDisabled]=\"disabled() || !orderable()\"\n (cdkDropListDropped)=\"onDrop($event)\"\n class=\"fk-list-editor__list\"\n [attr.aria-label]=\"ariaLabel()\"\n>\n @for (item of items(); track $index) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"disabled() || !orderable()\"\n class=\"fk-list-editor__item\"\n >\n @if (orderable()) {\n <span class=\"fk-list-editor__handle\" cdkDragHandle>\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <circle cx=\"9\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n </svg>\n </span>\n }\n\n @if (showOrder()) {\n <span class=\"fk-list-editor__order\">{{ $index + 1 }}</span>\n }\n\n @if (itemTemplate(); as def) {\n <div class=\"fk-list-editor__item-custom\">\n <ng-container\n [ngTemplateOutlet]=\"def.templateRef\"\n [ngTemplateOutletContext]=\"contextFor(item, $index)\"\n />\n </div>\n } @else {\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [value]=\"item\"\n [disabled]=\"disabled() || isLocked(item)\"\n (input)=\"updateItem($index, $any($event.target).value)\"\n />\n\n <button\n class=\"fk-list-editor__remove\"\n type=\"button\"\n [disabled]=\"disabled() || isLocked(item)\"\n [title]=\"\n isLocked(item) ? 'This item cannot be removed' : 'Remove item'\n \"\n (click)=\"removeItem($index)\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n\n <div *cdkDragPlaceholder class=\"fk-list-editor__placeholder\"></div>\n </div>\n }\n</div>\n\n@if (items().length === 0 && emptyMessage()) {\n <p class=\"fk-list-editor__empty\">{{ emptyMessage() }}</p>\n}\n\n<div class=\"fk-list-editor__add\">\n <div class=\"fk-list-editor__add-input\">\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [ngModel]=\"newItemValue()\"\n (ngModelChange)=\"newItemValue.set($event)\"\n (keydown)=\"onKeydown($event)\"\n />\n\n @if (newItemValue() && !disabled()) {\n <button\n class=\"fk-list-editor__add-clear\"\n type=\"button\"\n aria-label=\"Clear input\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"newItemValue.set('')\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n </div>\n\n <fk-button\n variant=\"outline\"\n size=\"sm\"\n [disabled]=\"!canAdd() || disabled()\"\n (click)=\"addItem()\"\n >\n <svg\n fkButtonIconStart\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 5v14M5 12h14\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n {{ addLabel() }}\n </fk-button>\n</div>\n\n@if (hasDuplicates()) {\n <p class=\"fk-list-editor__error\">Item names must be unique.</p>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"frame-kit-ui-ng-ui-list-editor.mjs","sources":["../../../../packages/ui-ng/ui/list-editor/list-editor-item.directive.ts","../../../../packages/ui-ng/ui/list-editor/list-editor.component.ts","../../../../packages/ui-ng/ui/list-editor/list-editor.component.html","../../../../packages/ui-ng/ui/list-editor/frame-kit-ui-ng-ui-list-editor.ts"],"sourcesContent":["import { Directive, inject, TemplateRef } from '@angular/core';\n\nimport { ListEditorItemContext } from './list-editor.types';\n\n/**\n * Marks an `<ng-template>` as the per-row renderer for `fk-list-editor`. When\n * present, the editor renders this template for each item instead of its\n * default editable input + remove button, so the consumer owns the row markup\n * (scheme tag, status, custom actions, …). The add-input, empty state, and\n * optional drag/order chrome are still provided by the editor.\n *\n * ```html\n * <fk-list-editor [items]=\"origins\">\n * <ng-template fkListEditorItem let-origin let-remove=\"remove\">\n * <span>{{ origin }}</span>\n * <button (click)=\"remove()\">Remove</button>\n * </ng-template>\n * </fk-list-editor>\n * ```\n */\n@Directive({\n selector: '[fkListEditorItem]',\n standalone: true,\n})\nexport class FkListEditorItemDirective {\n readonly templateRef = inject(TemplateRef<ListEditorItemContext>);\n}\n","import {\n CdkDrag,\n CdkDragDrop,\n CdkDragHandle,\n CdkDragPlaceholder,\n CdkDropList,\n moveItemInArray,\n} from '@angular/cdk/drag-drop';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n HostBinding,\n input,\n model,\n output,\n signal,\n} from '@angular/core';\n\nimport { ButtonComponent } from '@frame-kit/ui-ng/ui/button';\nimport { FkButtonIconStartDirective } from '@frame-kit/ui-ng/ui/button';\nimport { FkListEditorItemDirective } from './list-editor-item.directive';\nimport type {\n ListEditorItemContext,\n ListEditorSize,\n} from './list-editor.types';\n\n@Component({\n selector: 'fk-list-editor',\n standalone: true,\n imports: [\n NgTemplateOutlet,\n CdkDropList,\n CdkDrag,\n CdkDragHandle,\n CdkDragPlaceholder,\n ButtonComponent,\n FkButtonIconStartDirective,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './list-editor.component.html',\n styleUrl: './list-editor.component.scss',\n})\nexport class ListEditorComponent {\n // ===== INPUTS =====\n /** The current list of string items; two-way bindable via `[(items)]`. */\n readonly items = model<string[]>([]);\n /** Placeholder text for the new-item input field. */\n readonly placeholder = input('Add an item...');\n /** Message displayed when the list is empty. */\n readonly emptyMessage = input('No items added yet.');\n /** Label for the add button. */\n readonly addLabel = input('Add');\n /** When true, items can be reordered via drag-and-drop. */\n readonly orderable = input(true);\n /** When true, shows a numeric position indicator next to each item. */\n readonly showOrder = input(true);\n /** Size variant controlling the spacing and font of the component. */\n readonly size = input<ListEditorSize>('md');\n /** Items that cannot be removed by the user (matched case-insensitively). */\n readonly lockedItems = input<string[]>([]);\n\n // ===== BASE PROPS =====\n readonly className = input<string>('');\n readonly disabled = input(false);\n readonly ariaLabel = input<string | null>(null);\n\n // ===== OUTPUTS =====\n /** Fires whenever the items array changes, emitting the full updated array. */\n readonly itemsChange = output<string[]>();\n /** Fires when a new item is successfully added, emitting the added value. */\n readonly itemAdded = output<string>();\n /** Fires when an item is removed, emitting the removed value and its former index. */\n readonly itemRemoved = output<{ item: string; index: number }>();\n\n // ===== CONTENT =====\n /**\n * Optional custom row template (`*fkListEditorItem`). When provided, each\n * item renders through it instead of the default editable input + remove\n * button.\n */\n readonly itemTemplate = contentChild(FkListEditorItemDirective);\n\n // ===== LOCAL STATE =====\n readonly newItemValue = signal('');\n\n // ===== COMPUTED =====\n readonly canAdd = computed(() => {\n const value = this.newItemValue().trim();\n\n if (!value) {\n return false;\n }\n\n const existing = this.items().map((n) => n.trim().toLowerCase());\n\n return !existing.includes(value.toLowerCase());\n });\n\n readonly hasDuplicates = computed(() => {\n const names = this.items().map((n) => n.trim().toLowerCase());\n\n return new Set(names).size !== names.length;\n });\n\n readonly hasEmptyItems = computed(() => {\n return this.items().some((n) => n.trim() === '');\n });\n\n readonly classes = computed(() =>\n [\n 'fk-list-editor',\n `fk-list-editor--${this.size()}`,\n this.disabled() ? 'fk-list-editor--disabled' : '',\n this.className(),\n ]\n .filter(Boolean)\n .join(' '),\n );\n\n @HostBinding('class')\n get hostClass() {\n return this.classes();\n }\n\n // ===== ACTIONS =====\n\n /** Adds the current input value as a new item if it is non-empty and not a duplicate. */\n addItem(): void {\n const value = this.newItemValue().trim();\n\n if (!value || !this.canAdd() || this.disabled()) {\n return;\n }\n\n this.items.update((prev) => [...prev, value]);\n this.newItemValue.set('');\n this.itemsChange.emit(this.items());\n this.itemAdded.emit(value);\n }\n\n /** Removes the item at the given index unless it is locked or the component is disabled. */\n removeItem(index: number): void {\n const item = this.items()[index];\n\n if (this.disabled() || this.isLocked(item)) {\n return;\n }\n\n this.items.update((prev) => prev.filter((_, i) => i !== index));\n this.itemsChange.emit(this.items());\n this.itemRemoved.emit({ item, index });\n }\n\n /** Updates the item at the given index with a new value and emits the changed array. */\n updateItem(index: number, value: string): void {\n this.items.update((prev) =>\n prev.map((item, i) => (i === index ? value : item)),\n );\n this.itemsChange.emit(this.items());\n }\n\n onDrop(event: CdkDragDrop<string[]>): void {\n const updated = [...this.items()];\n\n moveItemInArray(updated, event.previousIndex, event.currentIndex);\n this.items.set(updated);\n this.itemsChange.emit(this.items());\n }\n\n /** Returns true if the given item matches any entry in `lockedItems`. */\n isLocked(item: string): boolean {\n return this.lockedItems().includes(item.trim().toLowerCase());\n }\n\n /** Builds the `let-` context for a custom row template. */\n contextFor(item: string, index: number): ListEditorItemContext {\n return {\n $implicit: item,\n index,\n locked: this.isLocked(item),\n remove: () => this.removeItem(index),\n update: (value: string) => this.updateItem(index, value),\n };\n }\n\n onKeydown(event: KeyboardEvent): void {\n if (event.key === 'Enter') {\n event.preventDefault();\n this.addItem();\n }\n }\n}\n","<div\n cdkDropList\n [cdkDropListDisabled]=\"disabled() || !orderable()\"\n (cdkDropListDropped)=\"onDrop($event)\"\n class=\"fk-list-editor__list\"\n [attr.aria-label]=\"ariaLabel()\"\n>\n @for (item of items(); track $index) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"disabled() || !orderable()\"\n class=\"fk-list-editor__item\"\n >\n @if (orderable()) {\n <span class=\"fk-list-editor__handle\" cdkDragHandle>\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <circle cx=\"9\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"6\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"12\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"9\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"15\" cy=\"18\" r=\"1.5\" fill=\"currentColor\" />\n </svg>\n </span>\n }\n\n @if (showOrder()) {\n <span class=\"fk-list-editor__order\">{{ $index + 1 }}</span>\n }\n\n @if (itemTemplate(); as def) {\n <div class=\"fk-list-editor__item-custom\">\n <ng-container\n [ngTemplateOutlet]=\"def.templateRef\"\n [ngTemplateOutletContext]=\"contextFor(item, $index)\"\n />\n </div>\n } @else {\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [value]=\"item\"\n [disabled]=\"disabled() || isLocked(item)\"\n (input)=\"updateItem($index, $any($event.target).value)\"\n />\n\n <button\n class=\"fk-list-editor__remove\"\n type=\"button\"\n [disabled]=\"disabled() || isLocked(item)\"\n [title]=\"\n isLocked(item) ? 'This item cannot be removed' : 'Remove item'\n \"\n (click)=\"removeItem($index)\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n\n <div *cdkDragPlaceholder class=\"fk-list-editor__placeholder\"></div>\n </div>\n }\n</div>\n\n@if (items().length === 0 && emptyMessage()) {\n <p class=\"fk-list-editor__empty\">{{ emptyMessage() }}</p>\n}\n\n<div class=\"fk-list-editor__add\">\n <div class=\"fk-list-editor__add-input\">\n <input\n class=\"fk-list-editor__input\"\n type=\"text\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [value]=\"newItemValue()\"\n (input)=\"newItemValue.set($any($event.target).value)\"\n (keydown)=\"onKeydown($event)\"\n />\n\n @if (newItemValue() && !disabled()) {\n <button\n class=\"fk-list-editor__add-clear\"\n type=\"button\"\n aria-label=\"Clear input\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"newItemValue.set('')\"\n >\n <svg\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6 6l12 12M18 6L6 18\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n </div>\n\n <fk-button\n variant=\"outline\"\n size=\"sm\"\n [disabled]=\"!canAdd() || disabled()\"\n (click)=\"addItem()\"\n >\n <svg\n fkButtonIconStart\n class=\"fk-list-editor__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 5v14M5 12h14\"\n stroke=\"currentColor\"\n stroke-width=\"1.9\"\n stroke-linecap=\"round\"\n />\n </svg>\n {{ addLabel() }}\n </fk-button>\n</div>\n\n@if (hasDuplicates()) {\n <p class=\"fk-list-editor__error\">Item names must be unique.</p>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;AAIA;;;;;;;;;;;;;;;AAeG;MAKU,yBAAyB,CAAA;AAC3B,IAAA,WAAW,GAAG,MAAM,EAAC,WAAkC,EAAC;uGADtD,yBAAyB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAzB,yBAAyB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,oBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAzB,yBAAyB,EAAA,UAAA,EAAA,CAAA;kBAJrC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,oBAAoB;AAC9B,oBAAA,UAAU,EAAE,IAAI;AACjB,iBAAA;;;MCsBY,mBAAmB,CAAA;;;AAGrB,IAAA,KAAK,GAAG,KAAK,CAAW,EAAE,4EAAC;;AAE3B,IAAA,WAAW,GAAG,KAAK,CAAC,gBAAgB,kFAAC;;AAErC,IAAA,YAAY,GAAG,KAAK,CAAC,qBAAqB,mFAAC;;AAE3C,IAAA,QAAQ,GAAG,KAAK,CAAC,KAAK,+EAAC;;AAEvB,IAAA,SAAS,GAAG,KAAK,CAAC,IAAI,gFAAC;;AAEvB,IAAA,SAAS,GAAG,KAAK,CAAC,IAAI,gFAAC;;AAEvB,IAAA,IAAI,GAAG,KAAK,CAAiB,IAAI,2EAAC;;AAElC,IAAA,WAAW,GAAG,KAAK,CAAW,EAAE,kFAAC;;AAGjC,IAAA,SAAS,GAAG,KAAK,CAAS,EAAE,gFAAC;AAC7B,IAAA,QAAQ,GAAG,KAAK,CAAC,KAAK,+EAAC;AACvB,IAAA,SAAS,GAAG,KAAK,CAAgB,IAAI,gFAAC;;;IAItC,WAAW,GAAG,MAAM,EAAY;;IAEhC,SAAS,GAAG,MAAM,EAAU;;IAE5B,WAAW,GAAG,MAAM,EAAmC;;AAGhE;;;;AAIG;AACM,IAAA,YAAY,GAAG,YAAY,CAAC,yBAAyB,mFAAC;;AAGtD,IAAA,YAAY,GAAG,MAAM,CAAC,EAAE,mFAAC;;AAGzB,IAAA,MAAM,GAAG,QAAQ,CAAC,MAAK;QAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE;QAExC,IAAI,CAAC,KAAK,EAAE;AACV,YAAA,OAAO,KAAK;QACd;QAEA,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAEhE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;AAChD,IAAA,CAAC,6EAAC;AAEO,IAAA,aAAa,GAAG,QAAQ,CAAC,MAAK;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAE7D,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM;AAC7C,IAAA,CAAC,oFAAC;AAEO,IAAA,aAAa,GAAG,QAAQ,CAAC,MAAK;AACrC,QAAA,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;AAClD,IAAA,CAAC,oFAAC;AAEO,IAAA,OAAO,GAAG,QAAQ,CAAC,MAC1B;QACE,gBAAgB;AAChB,QAAA,CAAA,gBAAA,EAAmB,IAAI,CAAC,IAAI,EAAE,CAAA,CAAE;QAChC,IAAI,CAAC,QAAQ,EAAE,GAAG,0BAA0B,GAAG,EAAE;QACjD,IAAI,CAAC,SAAS,EAAE;AACjB;SACE,MAAM,CAAC,OAAO;AACd,SAAA,IAAI,CAAC,GAAG,CAAC,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,SAAA,EAAA,CAAA,8BAAA,EAAA,CAAA,CACb;AAED,IAAA,IACI,SAAS,GAAA;AACX,QAAA,OAAO,IAAI,CAAC,OAAO,EAAE;IACvB;;;IAKA,OAAO,GAAA;QACL,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE;AAExC,QAAA,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;YAC/C;QACF;AAEA,QAAA,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,CAAC;AAC7C,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;AACnC,QAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC;IAC5B;;AAGA,IAAA,UAAU,CAAC,KAAa,EAAA;QACtB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC;AAEhC,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;YAC1C;QACF;QAEA,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,CAAC;QAC/D,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QACnC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACxC;;IAGA,UAAU,CAAC,KAAa,EAAE,KAAa,EAAA;AACrC,QAAA,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,KACrB,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,CACpD;QACD,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACrC;AAEA,IAAA,MAAM,CAAC,KAA4B,EAAA;QACjC,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAEjC,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,YAAY,CAAC;AACjE,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC;QACvB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACrC;;AAGA,IAAA,QAAQ,CAAC,IAAY,EAAA;AACnB,QAAA,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC/D;;IAGA,UAAU,CAAC,IAAY,EAAE,KAAa,EAAA;QACpC,OAAO;AACL,YAAA,SAAS,EAAE,IAAI;YACf,KAAK;AACL,YAAA,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YAC3B,MAAM,EAAE,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;AACpC,YAAA,MAAM,EAAE,CAAC,KAAa,KAAK,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC;SACzD;IACH;AAEA,IAAA,SAAS,CAAC,KAAoB,EAAA;AAC5B,QAAA,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,EAAE;YACzB,KAAK,CAAC,cAAc,EAAE;YACtB,IAAI,CAAC,OAAO,EAAE;QAChB;IACF;uGApJW,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAnB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,mBAAmB,wsDAsCO,yBAAyB,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECnFhE,m6IAyJA,EAAA,MAAA,EAAA,CAAA,ihMAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDxHI,gBAAgB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,yBAAA,EAAA,kBAAA,EAAA,0BAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAChB,WAAW,EAAA,QAAA,EAAA,8BAAA,EAAA,MAAA,EAAA,CAAA,wBAAA,EAAA,iBAAA,EAAA,wBAAA,EAAA,IAAA,EAAA,qBAAA,EAAA,qBAAA,EAAA,4BAAA,EAAA,2BAAA,EAAA,0BAAA,EAAA,+BAAA,EAAA,2BAAA,EAAA,6BAAA,EAAA,sBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,oBAAA,EAAA,oBAAA,EAAA,mBAAA,EAAA,mBAAA,CAAA,EAAA,QAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACX,OAAO,wcACP,aAAa,EAAA,QAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,CAAA,uBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACb,kBAAkB,EAAA,QAAA,EAAA,iCAAA,EAAA,MAAA,EAAA,CAAA,MAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAClB,eAAe,kLACf,0BAA0B,EAAA,QAAA,EAAA,qBAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAMjB,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAhB/B,SAAS;+BACE,gBAAgB,EAAA,UAAA,EACd,IAAI,EAAA,OAAA,EACP;wBACP,gBAAgB;wBAChB,WAAW;wBACX,OAAO;wBACP,aAAa;wBACb,kBAAkB;wBAClB,eAAe;wBACf,0BAA0B;qBAC3B,EAAA,eAAA,EACgB,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,m6IAAA,EAAA,MAAA,EAAA,CAAA,ihMAAA,CAAA,EAAA;w2CA0CV,yBAAyB,CAAA,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,SAAA,EAAA,CAAA;sBAuC7D,WAAW;uBAAC,OAAO;;;AE1HtB;;AAEG;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frame-kit/ui-ng",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.23",
|
|
4
4
|
"description": "Style-agnostic, token-driven Angular UI component library for FrameKit.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"@angular/forms": "^21.2.0",
|
|
18
18
|
"@angular/platform-browser": "^21.2.0",
|
|
19
19
|
"@angular/router": "^21.2.0",
|
|
20
|
-
"@frame-kit/utils": "0.2.
|
|
20
|
+
"@frame-kit/utils": "0.2.23",
|
|
21
21
|
"rxjs": "^7.0.0"
|
|
22
22
|
},
|
|
23
23
|
"sideEffects": false,
|
|
@@ -148,6 +148,11 @@ declare class TableEngineService<T = unknown> {
|
|
|
148
148
|
readonly controlledSortState: _angular_core.WritableSignal<SortState | null | undefined>;
|
|
149
149
|
readonly controlledFilterState: _angular_core.WritableSignal<FilterState | null | undefined>;
|
|
150
150
|
readonly controlledPageState: _angular_core.WritableSignal<PageState | null | undefined>;
|
|
151
|
+
/**
|
|
152
|
+
* When true the rows arrive already sorted (by a server, for the current
|
|
153
|
+
* sort state) and are kept in the order given.
|
|
154
|
+
*/
|
|
155
|
+
readonly manualSorting: _angular_core.WritableSignal<boolean>;
|
|
151
156
|
readonly sortState: _angular_core.Signal<SortState | null>;
|
|
152
157
|
readonly filterState: _angular_core.Signal<FilterState>;
|
|
153
158
|
readonly pageState: _angular_core.Signal<PageState | null>;
|
|
@@ -228,6 +233,12 @@ declare class DataTableComponent<T = unknown> {
|
|
|
228
233
|
readonly loading: _angular_core.InputSignal<boolean>;
|
|
229
234
|
/** Controlled sort state; pass null to let the table manage sorting internally. */
|
|
230
235
|
readonly sortState: _angular_core.InputSignal<SortState | null>;
|
|
236
|
+
/**
|
|
237
|
+
* When true the table never reorders `rows`: they arrive sorted by the
|
|
238
|
+
* consumer (a server-paged list sorted by the server) and render as given.
|
|
239
|
+
* Headers still show `sortState` and emit `sortChange`.
|
|
240
|
+
*/
|
|
241
|
+
readonly manualSorting: _angular_core.InputSignal<boolean>;
|
|
231
242
|
/** Controlled filter state; pass null to let the table manage filtering internally. */
|
|
232
243
|
readonly filterState: _angular_core.InputSignal<FilterState | null>;
|
|
233
244
|
/** Controlled page state; pass null to let the table manage pagination internally. */
|
|
@@ -401,7 +412,7 @@ declare class DataTableComponent<T = unknown> {
|
|
|
401
412
|
/** Returns the current sort direction for the given column id, or null if not sorted. */
|
|
402
413
|
getSortDirection(columnId: string): 'asc' | 'desc' | null;
|
|
403
414
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DataTableComponent<any>, never>;
|
|
404
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DataTableComponent<any>, "fk-data-table", never, { "className": { "alias": "className"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "columns": { "alias": "columns"; "required": false; "isSignal": true; }; "rows": { "alias": "rows"; "required": false; "isSignal": true; }; "config": { "alias": "config"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "sortState": { "alias": "sortState"; "required": false; "isSignal": true; }; "filterState": { "alias": "filterState"; "required": false; "isSignal": true; }; "pageState": { "alias": "pageState"; "required": false; "isSignal": true; }; "rowSelection": { "alias": "rowSelection"; "required": false; "isSignal": true; }; "selectedKeys": { "alias": "selectedKeys"; "required": false; "isSignal": true; }; "getRowId": { "alias": "getRowId"; "required": false; "isSignal": true; }; "selectionDisabled": { "alias": "selectionDisabled"; "required": false; "isSignal": true; }; "selectionColumnPosition": { "alias": "selectionColumnPosition"; "required": false; "isSignal": true; }; "selectionLabel": { "alias": "selectionLabel"; "required": false; "isSignal": true; }; "rowDetailTemplate": { "alias": "rowDetailTemplate"; "required": false; "isSignal": true; }; "expansionColumnPosition": { "alias": "expansionColumnPosition"; "required": false; "isSignal": true; }; "expandedKeys": { "alias": "expandedKeys"; "required": false; "isSignal": true; }; "expandableRow": { "alias": "expandableRow"; "required": false; "isSignal": true; }; "expansionLabel": { "alias": "expansionLabel"; "required": false; "isSignal": true; }; "groupHeadingRenderer": { "alias": "groupHeadingRenderer"; "required": false; "isSignal": true; }; }, { "sortChange": "sortChange"; "filterChange": "filterChange"; "pageChange": "pageChange"; "rowClick": "rowClick"; "selectionChange": "selectionChange"; "expansionChange": "expansionChange"; "columnResize": "columnResize"; }, never, never, true, never>;
|
|
415
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DataTableComponent<any>, "fk-data-table", never, { "className": { "alias": "className"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "columns": { "alias": "columns"; "required": false; "isSignal": true; }; "rows": { "alias": "rows"; "required": false; "isSignal": true; }; "config": { "alias": "config"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "sortState": { "alias": "sortState"; "required": false; "isSignal": true; }; "manualSorting": { "alias": "manualSorting"; "required": false; "isSignal": true; }; "filterState": { "alias": "filterState"; "required": false; "isSignal": true; }; "pageState": { "alias": "pageState"; "required": false; "isSignal": true; }; "rowSelection": { "alias": "rowSelection"; "required": false; "isSignal": true; }; "selectedKeys": { "alias": "selectedKeys"; "required": false; "isSignal": true; }; "getRowId": { "alias": "getRowId"; "required": false; "isSignal": true; }; "selectionDisabled": { "alias": "selectionDisabled"; "required": false; "isSignal": true; }; "selectionColumnPosition": { "alias": "selectionColumnPosition"; "required": false; "isSignal": true; }; "selectionLabel": { "alias": "selectionLabel"; "required": false; "isSignal": true; }; "rowDetailTemplate": { "alias": "rowDetailTemplate"; "required": false; "isSignal": true; }; "expansionColumnPosition": { "alias": "expansionColumnPosition"; "required": false; "isSignal": true; }; "expandedKeys": { "alias": "expandedKeys"; "required": false; "isSignal": true; }; "expandableRow": { "alias": "expandableRow"; "required": false; "isSignal": true; }; "expansionLabel": { "alias": "expansionLabel"; "required": false; "isSignal": true; }; "groupHeadingRenderer": { "alias": "groupHeadingRenderer"; "required": false; "isSignal": true; }; }, { "sortChange": "sortChange"; "filterChange": "filterChange"; "pageChange": "pageChange"; "rowClick": "rowClick"; "selectionChange": "selectionChange"; "expansionChange": "expansionChange"; "columnResize": "columnResize"; }, never, never, true, never>;
|
|
405
416
|
}
|
|
406
417
|
|
|
407
418
|
/**
|
package/ui/data-table/README.md
CHANGED
|
@@ -15,6 +15,7 @@ A token-driven, responsive data table component for Angular with sorting, virtua
|
|
|
15
15
|
| `config` | `Partial<TableConfig<T>>` | `{}` | Table configuration merged with defaults |
|
|
16
16
|
| `loading` | `boolean` | `false` | Shows a loading overlay |
|
|
17
17
|
| `sortState` | `SortState \| null` | `null` | Controlled sort state; `null` uses internal state |
|
|
18
|
+
| `manualSorting` | `boolean` | `false` | Rows arrive sorted by the consumer (a server); headers show and emit the sort, rows keep their order |
|
|
18
19
|
| `filterState` | `FilterState \| null` | `null` | Controlled filter state; `null` uses internal state |
|
|
19
20
|
| `pageState` | `PageState \| null` | `null` | Controlled page state; `null` uses internal state |
|
|
20
21
|
| `rowSelection` | `boolean` | `false` | Render a leading (or trailing) checkbox column with multi-row selection |
|
|
@@ -162,13 +163,21 @@ Mark columns as sortable in the column definition:
|
|
|
162
163
|
{ id: "price", header: "Price", accessor: "price", sortable: true }
|
|
163
164
|
```
|
|
164
165
|
|
|
165
|
-
### Controlled sort
|
|
166
|
+
### Controlled sort
|
|
166
167
|
|
|
167
168
|
```html
|
|
168
|
-
<fk-data-table [columns]="columns" [rows]="rows" [sortState]="currentSort" (sortChange)="
|
|
169
|
+
<fk-data-table [columns]="columns" [rows]="rows" [sortState]="currentSort" (sortChange)="currentSort = $event" />
|
|
169
170
|
```
|
|
170
171
|
|
|
171
|
-
When `sortState` is provided, the
|
|
172
|
+
When `sortState` is provided, the consumer owns the sort state: the headers show it and a click emits the next state through `sortChange`. The table still sorts the rows it holds by that state.
|
|
173
|
+
|
|
174
|
+
### Server-side sort
|
|
175
|
+
|
|
176
|
+
```html
|
|
177
|
+
<fk-data-table [columns]="columns" [rows]="page.items" [sortState]="currentSort" [manualSorting]="true" (sortChange)="fetchSorted($event)" />
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
For a server-paged list, add `manualSorting`. The server orders the whole result, so the table renders each page in the order it arrives and never re-sorts it by the column accessor, which could disagree with the server's key.
|
|
172
181
|
|
|
173
182
|
### Row selection — uncontrolled
|
|
174
183
|
|