@shival99/z-ui 2.2.0 → 2.2.2
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/shival99-z-ui-components-z-chat.mjs +102 -47
- package/fesm2022/shival99-z-ui-components-z-chat.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-table.mjs +353 -40
- package/fesm2022/shival99-z-ui-components-z-table.mjs.map +1 -1
- package/package.json +1 -1
- package/types/shival99-z-ui-components-z-chat.d.ts +26 -3
- package/types/shival99-z-ui-components-z-table.d.ts +99 -3
|
@@ -4,7 +4,7 @@ import { OverlayModule } from '@angular/cdk/overlay';
|
|
|
4
4
|
import { ScrollingModule } from '@angular/cdk/scrolling';
|
|
5
5
|
import { NgStyle, DOCUMENT, formatDate, NgTemplateOutlet } from '@angular/common';
|
|
6
6
|
import * as i0 from '@angular/core';
|
|
7
|
-
import { input, output, computed, ChangeDetectionStrategy, Component, signal, inject, ElementRef, effect, afterNextRender, DestroyRef, untracked, NgZone, Injectable, Directive, Renderer2, Pipe, TemplateRef, viewChild, viewChildren, linkedSignal } from '@angular/core';
|
|
7
|
+
import { input, output, computed, ChangeDetectionStrategy, Component, signal, inject, ElementRef, effect, afterNextRender, DestroyRef, untracked, NgZone, Injectable, Directive, Renderer2, Pipe, TemplateRef, viewChild, viewChildren, linkedSignal, afterRenderEffect } from '@angular/core';
|
|
8
8
|
import { TranslatePipe } from '@ngx-translate/core';
|
|
9
9
|
import { ZButtonComponent } from '@shival99/z-ui/components/z-button';
|
|
10
10
|
import { ZCheckboxComponent } from '@shival99/z-ui/components/z-checkbox';
|
|
@@ -21,7 +21,7 @@ import { ZSafeHtmlPipe, ZFormatNumPipe } from '@shival99/z-ui/pipes';
|
|
|
21
21
|
import { ZTranslateService, ZExcelService, ZCacheService } from '@shival99/z-ui/services';
|
|
22
22
|
import { zMergeClasses } from '@shival99/z-ui/utils';
|
|
23
23
|
import { tableFeatures, createSortedRowModel, createPaginatedRowModel, createFilteredRowModel, createFacetedUniqueValues, createFacetedRowModel, createFacetedMinMaxValues, createExpandedRowModel, stockFeatures, injectTable, FlexRenderDirective } from '@tanstack/angular-table';
|
|
24
|
-
import { injectVirtualizer, elementScroll } from '@tanstack/angular-virtual';
|
|
24
|
+
import { injectVirtualizer, defaultRangeExtractor, elementScroll } from '@tanstack/angular-virtual';
|
|
25
25
|
import { NgScrollbar } from 'ngx-scrollbar';
|
|
26
26
|
import { explicitEffect } from 'ngxtension/explicit-effect';
|
|
27
27
|
import { injectDestroy } from 'ngxtension/inject-destroy';
|
|
@@ -5502,6 +5502,8 @@ class ZTableComponent {
|
|
|
5502
5502
|
...(ngDevMode ? [{ debugName: "expandedRowTemplate" }] : /* istanbul ignore next */ []));
|
|
5503
5503
|
virtualRowElements = viewChildren('virtualRow', /* @ts-ignore */
|
|
5504
5504
|
...(ngDevMode ? [{ debugName: "virtualRowElements" }] : /* istanbul ignore next */ []));
|
|
5505
|
+
groupRowElements = viewChildren('groupRow', /* @ts-ignore */
|
|
5506
|
+
...(ngDevMode ? [{ debugName: "groupRowElements" }] : /* istanbul ignore next */ []));
|
|
5505
5507
|
// ─── TanStack Table State Signals ─────────────────────────────────────────
|
|
5506
5508
|
// These signals are the source of truth for table state. They are passed into
|
|
5507
5509
|
// createAngularTable() and updated via the on*Change callbacks.
|
|
@@ -5693,6 +5695,24 @@ class ZTableComponent {
|
|
|
5693
5695
|
/** True khi bottom-pinned rows đang đè lên nội dung body còn scroll xuống được */
|
|
5694
5696
|
hasScrollBottom = signal(false, /* @ts-ignore */
|
|
5695
5697
|
...(ngDevMode ? [{ debugName: "hasScrollBottom" }] : /* istanbul ignore next */ []));
|
|
5698
|
+
/**
|
|
5699
|
+
* Group header (non-virtual) đang ghim ở mép dưới cùng của chồng sticky — chỉ mình nó đổ shadow.
|
|
5700
|
+
* Nhiều header ghim chung một chỗ, mỗi cái một shadow thì alpha cộng dồn thành vệt đen đậm dần.
|
|
5701
|
+
* Chỉ dùng cho shadow: class này bám theo scroll nên luôn trễ một frame, chấp nhận được với shadow
|
|
5702
|
+
* nhưng không dùng được cho z-index (xem `tr.z-group-row-sticky`).
|
|
5703
|
+
*/
|
|
5704
|
+
shadowGroupRowId = signal(null, /* @ts-ignore */
|
|
5705
|
+
...(ngDevMode ? [{ debugName: "shadowGroupRowId" }] : /* istanbul ignore next */ []));
|
|
5706
|
+
/** Chiều cao thật của group header row (non-virtual), dùng để xếp chồng sticky theo depth. */
|
|
5707
|
+
_groupRowHeight = signal(Z_VIRTUAL_GROUP_HEADER_HEIGHT, /* @ts-ignore */
|
|
5708
|
+
...(ngDevMode ? [{ debugName: "_groupRowHeight" }] : /* istanbul ignore next */ []));
|
|
5709
|
+
/**
|
|
5710
|
+
* Tổng chiều cao khối pinned top rows (non-virtual), đo trực tiếp từ DOM sau mỗi render.
|
|
5711
|
+
* Không dùng `pinnedRowHeights` vì signal đó chỉ refresh trong `_checkScrollState`, nên có thể
|
|
5712
|
+
* còn giữ số đo cũ khi bảng vừa đổi cấu hình — sticky group header sẽ hở một khoảng vài px.
|
|
5713
|
+
*/
|
|
5714
|
+
_nonVirtualPinnedTopHeight = signal(0, /* @ts-ignore */
|
|
5715
|
+
...(ngDevMode ? [{ debugName: "_nonVirtualPinnedTopHeight" }] : /* istanbul ignore next */ []));
|
|
5696
5716
|
/** Maps row IDs to measured DOM heights for pinned row offset calculations */
|
|
5697
5717
|
pinnedRowHeights = signal({}, /* @ts-ignore */
|
|
5698
5718
|
...(ngDevMode ? [{ debugName: "pinnedRowHeights" }] : /* istanbul ignore next */ []));
|
|
@@ -6146,13 +6166,34 @@ class ZTableComponent {
|
|
|
6146
6166
|
groupingConfig = computed(() => {
|
|
6147
6167
|
const { enableGrouping: grouping } = this.zConfig();
|
|
6148
6168
|
if (grouping === false) {
|
|
6149
|
-
return {
|
|
6169
|
+
return {
|
|
6170
|
+
enabled: false,
|
|
6171
|
+
mode: 'local',
|
|
6172
|
+
allowHeaderMenu: true,
|
|
6173
|
+
defaultExpanded: true,
|
|
6174
|
+
showCount: true,
|
|
6175
|
+
stickyHeader: false,
|
|
6176
|
+
};
|
|
6150
6177
|
}
|
|
6151
6178
|
if (grouping === undefined) {
|
|
6152
|
-
return {
|
|
6179
|
+
return {
|
|
6180
|
+
enabled: true,
|
|
6181
|
+
mode: 'local',
|
|
6182
|
+
allowHeaderMenu: true,
|
|
6183
|
+
defaultExpanded: true,
|
|
6184
|
+
showCount: true,
|
|
6185
|
+
stickyHeader: false,
|
|
6186
|
+
};
|
|
6153
6187
|
}
|
|
6154
6188
|
if (typeof grouping === 'boolean') {
|
|
6155
|
-
return {
|
|
6189
|
+
return {
|
|
6190
|
+
enabled: grouping,
|
|
6191
|
+
mode: 'local',
|
|
6192
|
+
allowHeaderMenu: true,
|
|
6193
|
+
defaultExpanded: true,
|
|
6194
|
+
showCount: true,
|
|
6195
|
+
stickyHeader: false,
|
|
6196
|
+
};
|
|
6156
6197
|
}
|
|
6157
6198
|
return {
|
|
6158
6199
|
enabled: grouping.enabled !== false,
|
|
@@ -6162,6 +6203,7 @@ class ZTableComponent {
|
|
|
6162
6203
|
allowHeaderMenu: grouping.allowHeaderMenu !== false,
|
|
6163
6204
|
defaultExpanded: grouping.defaultExpanded !== false,
|
|
6164
6205
|
showCount: grouping.showCount !== false,
|
|
6206
|
+
stickyHeader: grouping.stickyHeader === true,
|
|
6165
6207
|
totals: grouping.totals,
|
|
6166
6208
|
serverGroupColumnId: grouping.serverGroupColumnId,
|
|
6167
6209
|
serverGroups: grouping.serverGroups,
|
|
@@ -6466,6 +6508,105 @@ class ZTableComponent {
|
|
|
6466
6508
|
return items;
|
|
6467
6509
|
}, /* @ts-ignore */
|
|
6468
6510
|
...(ngDevMode ? [{ debugName: "virtualGroupedFlatItems" }] : /* istanbul ignore next */ []));
|
|
6511
|
+
/** Sticky group header đang bật (config cho phép và đang thực sự group theo cột nào đó). */
|
|
6512
|
+
isStickyGroupHeaderEnabled = computed(() => this.groupingConfig().stickyHeader === true && this.activeGroupingColumnIds().length > 0, /* @ts-ignore */
|
|
6513
|
+
...(ngDevMode ? [{ debugName: "isStickyGroupHeaderEnabled" }] : /* istanbul ignore next */ []));
|
|
6514
|
+
/**
|
|
6515
|
+
* `top` (px) của sticky group header theo depth ở chế độ non-virtual.
|
|
6516
|
+
* Ở đây mọi group header đều là `<tr>` thật trong cùng một `<tbody>`, nên chỉ cần `position: sticky`:
|
|
6517
|
+
* header sau (đứng sau trong DOM) tự đè lên header trước khi trôi tới rồi lộ lại khi cuộn ngược —
|
|
6518
|
+
* không cần rangeExtractor như bên virtual (cơ chế đó chỉ để giữ row đã ra khỏi range).
|
|
6519
|
+
* Header con xếp chồng ngay dưới header cha nên cộng thêm `depth * chiều cao group row`.
|
|
6520
|
+
*/
|
|
6521
|
+
stickyGroupTopByDepth = computed(() => {
|
|
6522
|
+
if (this.isVirtual() || !this.isStickyGroupHeaderEnabled()) {
|
|
6523
|
+
return [];
|
|
6524
|
+
}
|
|
6525
|
+
const baseTop = this._nonVirtualPinnedTopHeight();
|
|
6526
|
+
const groupRowHeight = this._groupRowHeight();
|
|
6527
|
+
return Array.from({ length: this.activeGroupingColumnIds().length }, (_, depth) => baseTop + depth * groupRowHeight);
|
|
6528
|
+
}, /* @ts-ignore */
|
|
6529
|
+
...(ngDevMode ? [{ debugName: "stickyGroupTopByDepth" }] : /* istanbul ignore next */ []));
|
|
6530
|
+
/**
|
|
6531
|
+
* Lookup phục vụ sticky group header trong virtual scroll:
|
|
6532
|
+
* - `nearest[i]`: index group header gần nhất tại hoặc trước `i` (-1 nếu chưa có).
|
|
6533
|
+
* - `parent`: index group header cha của một header (multi-level grouping), -1 nếu là cấp gốc.
|
|
6534
|
+
* Trả `null` khi tắt sticky hoặc không ở chế độ virtual + grouping.
|
|
6535
|
+
*/
|
|
6536
|
+
_stickyGroupHeaderMeta = computed(() => {
|
|
6537
|
+
if (this.groupingConfig().stickyHeader !== true) {
|
|
6538
|
+
return null;
|
|
6539
|
+
}
|
|
6540
|
+
const items = this.virtualGroupedFlatItems();
|
|
6541
|
+
if (items.length === 0) {
|
|
6542
|
+
return null;
|
|
6543
|
+
}
|
|
6544
|
+
const nearest = new Int32Array(items.length).fill(-1);
|
|
6545
|
+
const parent = new Map();
|
|
6546
|
+
const openHeaders = [];
|
|
6547
|
+
let lastHeaderIndex = -1;
|
|
6548
|
+
for (let index = 0; index < items.length; index++) {
|
|
6549
|
+
const item = items[index];
|
|
6550
|
+
if (item.type === 'group-header') {
|
|
6551
|
+
const depth = item.groupItem.depth ?? 0;
|
|
6552
|
+
while (openHeaders.length > 0 && openHeaders[openHeaders.length - 1].depth >= depth) {
|
|
6553
|
+
openHeaders.pop();
|
|
6554
|
+
}
|
|
6555
|
+
parent.set(index, openHeaders.length > 0 ? openHeaders[openHeaders.length - 1].index : -1);
|
|
6556
|
+
openHeaders.push({ index, depth });
|
|
6557
|
+
lastHeaderIndex = index;
|
|
6558
|
+
}
|
|
6559
|
+
nearest[index] = lastHeaderIndex;
|
|
6560
|
+
}
|
|
6561
|
+
return { nearest, parent };
|
|
6562
|
+
}, /* @ts-ignore */
|
|
6563
|
+
...(ngDevMode ? [{ debugName: "_stickyGroupHeaderMeta" }] : /* istanbul ignore next */ []));
|
|
6564
|
+
/** Chuỗi header (gốc → sâu nhất) cần ghim khi viewport bắt đầu tại `startIndex`. */
|
|
6565
|
+
_buildStickyGroupChain(meta, startIndex) {
|
|
6566
|
+
const clampedIndex = Math.min(Math.max(startIndex, 0), meta.nearest.length - 1);
|
|
6567
|
+
const chain = [];
|
|
6568
|
+
let headerIndex = meta.nearest[clampedIndex];
|
|
6569
|
+
while (headerIndex >= 0) {
|
|
6570
|
+
chain.push(headerIndex);
|
|
6571
|
+
headerIndex = meta.parent.get(headerIndex) ?? -1;
|
|
6572
|
+
}
|
|
6573
|
+
return chain.reverse();
|
|
6574
|
+
}
|
|
6575
|
+
/**
|
|
6576
|
+
* Trạng thái sticky group header theo virtual index:
|
|
6577
|
+
* - `tops`: offset `top` (px) của từng header đang ghim; header cấp sâu hơn xếp chồng bên dưới
|
|
6578
|
+
* header cha nên cộng dồn chiều cao.
|
|
6579
|
+
* - `shadowIndex`: header cuối chuỗi mang shadow (giống pinned row), -1 khi chưa có row nào
|
|
6580
|
+
* cuộn xuống dưới nó — lúc đó header vẫn ở đúng vị trí thật nên không cần shadow.
|
|
6581
|
+
*/
|
|
6582
|
+
stickyGroupHeaderState = computed(() => {
|
|
6583
|
+
const empty = { tops: {}, shadowIndex: -1 };
|
|
6584
|
+
const meta = this._stickyGroupHeaderMeta();
|
|
6585
|
+
if (!meta) {
|
|
6586
|
+
return empty;
|
|
6587
|
+
}
|
|
6588
|
+
// Đọc virtual items trước để virtualizer tính xong `range` của chu kỳ hiện tại.
|
|
6589
|
+
const virtualItems = this.virtualizer.getVirtualItems();
|
|
6590
|
+
const range = this.virtualizer.range();
|
|
6591
|
+
if (!range) {
|
|
6592
|
+
return empty;
|
|
6593
|
+
}
|
|
6594
|
+
const chain = this._buildStickyGroupChain(meta, range.startIndex);
|
|
6595
|
+
if (chain.length === 0) {
|
|
6596
|
+
return empty;
|
|
6597
|
+
}
|
|
6598
|
+
const sizeByIndex = new Map(virtualItems.map(item => [item.index, item.size]));
|
|
6599
|
+
const fallbackSize = Math.max(this.virtualRowHeight(), Z_VIRTUAL_GROUP_HEADER_HEIGHT);
|
|
6600
|
+
const tops = {};
|
|
6601
|
+
let offset = this.virtualPinnedTopHeight();
|
|
6602
|
+
for (const headerIndex of chain) {
|
|
6603
|
+
tops[headerIndex] = offset;
|
|
6604
|
+
offset += sizeByIndex.get(headerIndex) ?? fallbackSize;
|
|
6605
|
+
}
|
|
6606
|
+
const deepestHeaderIndex = chain[chain.length - 1];
|
|
6607
|
+
return { tops, shadowIndex: range.startIndex > deepestHeaderIndex ? deepestHeaderIndex : -1 };
|
|
6608
|
+
}, /* @ts-ignore */
|
|
6609
|
+
...(ngDevMode ? [{ debugName: "stickyGroupHeaderState" }] : /* istanbul ignore next */ []));
|
|
6469
6610
|
_getVirtualGroupHeader(item) {
|
|
6470
6611
|
return item?.type === 'group-header' ? item.groupItem : null;
|
|
6471
6612
|
}
|
|
@@ -7076,6 +7217,26 @@ class ZTableComponent {
|
|
|
7076
7217
|
}
|
|
7077
7218
|
bottomRowsReversed = computed(() => [...this.table.getBottomRows()].reverse(), /* @ts-ignore */
|
|
7078
7219
|
...(ngDevMode ? [{ debugName: "bottomRowsReversed" }] : /* istanbul ignore next */ []));
|
|
7220
|
+
/**
|
|
7221
|
+
* Id row ở hai biên của mỗi khối pinned, theo THỨ TỰ HIỂN THỊ (pinned bottom render ngược lại).
|
|
7222
|
+
* Dùng signal thay cho `zTableRow` pipe: pipe là pure, chỉ chạy lại khi một tham số đổi reference.
|
|
7223
|
+
* Khi ghim thêm/bớt row thì `row` và `table` giữ nguyên reference, nên row từng là biên vẫn giữ
|
|
7224
|
+
* class cũ — pin bottom lộ rõ nhất vì shadow ở lại row cũ và row mới cũng có shadow.
|
|
7225
|
+
*/
|
|
7226
|
+
firstTopPinnedRowId = computed(() => this.table.getTopRows()[0]?.id ?? null, /* @ts-ignore */
|
|
7227
|
+
...(ngDevMode ? [{ debugName: "firstTopPinnedRowId" }] : /* istanbul ignore next */ []));
|
|
7228
|
+
lastTopPinnedRowId = computed(() => {
|
|
7229
|
+
const topRows = this.table.getTopRows();
|
|
7230
|
+
return topRows[topRows.length - 1]?.id ?? null;
|
|
7231
|
+
}, /* @ts-ignore */
|
|
7232
|
+
...(ngDevMode ? [{ debugName: "lastTopPinnedRowId" }] : /* istanbul ignore next */ []));
|
|
7233
|
+
firstBottomPinnedRowId = computed(() => this.bottomRowsReversed()[0]?.id ?? null, /* @ts-ignore */
|
|
7234
|
+
...(ngDevMode ? [{ debugName: "firstBottomPinnedRowId" }] : /* istanbul ignore next */ []));
|
|
7235
|
+
lastBottomPinnedRowId = computed(() => {
|
|
7236
|
+
const bottomRows = this.bottomRowsReversed();
|
|
7237
|
+
return bottomRows[bottomRows.length - 1]?.id ?? null;
|
|
7238
|
+
}, /* @ts-ignore */
|
|
7239
|
+
...(ngDevMode ? [{ debugName: "lastBottomPinnedRowId" }] : /* istanbul ignore next */ []));
|
|
7079
7240
|
leftHeaderRow = computed(() => {
|
|
7080
7241
|
void this.columnPinning();
|
|
7081
7242
|
void this._columnPinVersion();
|
|
@@ -7453,7 +7614,7 @@ class ZTableComponent {
|
|
|
7453
7614
|
if (!this.isVirtual()) {
|
|
7454
7615
|
return 0;
|
|
7455
7616
|
}
|
|
7456
|
-
const totalRows =
|
|
7617
|
+
const totalRows = this.table.getCenterRows().length;
|
|
7457
7618
|
return Math.ceil(totalRows / this.groupSize());
|
|
7458
7619
|
}, /* @ts-ignore */
|
|
7459
7620
|
...(ngDevMode ? [{ debugName: "_virtualGroupCount" }] : /* istanbul ignore next */ []));
|
|
@@ -7563,6 +7724,7 @@ class ZTableComponent {
|
|
|
7563
7724
|
const isGrouping = flatItems.length > 0;
|
|
7564
7725
|
const itemKeys = this._virtualItemKeys();
|
|
7565
7726
|
const isDynamic = this.effectiveDynamicRowSizing();
|
|
7727
|
+
const stickyGroupMeta = this._stickyGroupHeaderMeta();
|
|
7566
7728
|
// Estimate for not-yet-measured rows: learned height if available, else virtual.size.
|
|
7567
7729
|
const dynamicRowEstimate = isDynamic && this._dynamicEstimateHeight !== null ? this._dynamicEstimateHeight : rowHeight;
|
|
7568
7730
|
const itemCount = isGrouping ? flatItems.length : groups.length > 0 ? groups.length : this._virtualGroupCount();
|
|
@@ -7591,7 +7753,8 @@ class ZTableComponent {
|
|
|
7591
7753
|
instance.scrollOffset = offset;
|
|
7592
7754
|
elementScroll(offset, options, instance);
|
|
7593
7755
|
},
|
|
7594
|
-
measureElement:
|
|
7756
|
+
// No measureElement override: the built-in one rounds ResizeObserver sizes and short-circuits
|
|
7757
|
+
// to the cached size on manual calls, so re-measuring a settled row stays a no-op.
|
|
7595
7758
|
overscan: virtualConfig.overscan ?? Z_DEFAULT_VIRTUAL_OVERSCAN,
|
|
7596
7759
|
paddingStart: this.virtualPinnedTopHeight(),
|
|
7597
7760
|
paddingEnd: this.virtualPinnedBottomHeight(),
|
|
@@ -7600,48 +7763,187 @@ class ZTableComponent {
|
|
|
7600
7763
|
initialOffset: virtualConfig.initialOffset ?? 0,
|
|
7601
7764
|
useApplicationRefTick: false,
|
|
7602
7765
|
...pickDefined(virtualConfig, ['gap', 'isScrollingResetDelay', 'useScrollendEvent', 'getItemKey']),
|
|
7603
|
-
|
|
7604
|
-
|
|
7766
|
+
// Sticky group header cần header đang ghim luôn nằm trong tập render, kể cả khi nó đã
|
|
7767
|
+
// cuộn ra ngoài range tự nhiên — nên chèn cả chuỗi header cha vào range.
|
|
7768
|
+
rangeExtractor: rangeExtractor || stickyGroupMeta
|
|
7769
|
+
? (range) => {
|
|
7770
|
+
const baseIndexes = rangeExtractor ? rangeExtractor(range) : defaultRangeExtractor(range);
|
|
7771
|
+
if (!stickyGroupMeta) {
|
|
7772
|
+
return baseIndexes;
|
|
7773
|
+
}
|
|
7774
|
+
const chain = this._buildStickyGroupChain(stickyGroupMeta, range.startIndex);
|
|
7775
|
+
if (chain.length === 0) {
|
|
7776
|
+
return baseIndexes;
|
|
7777
|
+
}
|
|
7778
|
+
return [...new Set([...chain, ...baseIndexes])].sort((a, b) => a - b);
|
|
7779
|
+
}
|
|
7605
7780
|
: undefined,
|
|
7606
7781
|
};
|
|
7607
7782
|
});
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
|
|
7783
|
+
/**
|
|
7784
|
+
* Nhận diện group header đang ghim sau MỖI render, không chỉ khi scroll.
|
|
7785
|
+
* Đổi virtual/non-virtual, đổi cột group hay pin/unpin row đều giữ nguyên scrollOffset nhưng dựng
|
|
7786
|
+
* lại DOM và đổi đường sticky — nếu chỉ trông vào scroll handler thì header đang ghim sẽ thiếu
|
|
7787
|
+
* class `z-group-row-stuck` cho tới lần cuộn kế tiếp, và bị data row đè trong khoảng đó.
|
|
7788
|
+
* `_refreshStuckGroupRows` đọc `groupRowElements` + `stickyGroupTopByDepth` trước mọi early-return
|
|
7789
|
+
* nên effect này tự chạy lại khi hai nguồn đó đổi (kể cả khi số đo tới muộn hơn một pass).
|
|
7790
|
+
*/
|
|
7791
|
+
_trackStuckGroupRows = afterRenderEffect({
|
|
7792
|
+
read: () => this._refreshStuckGroupRows(),
|
|
7793
|
+
});
|
|
7794
|
+
/** Measures in the render `read` phase so corrected offsets land before paint, not a frame later. */
|
|
7795
|
+
_measureVirtualItems = afterRenderEffect({
|
|
7796
|
+
read: () => {
|
|
7797
|
+
const elements = this.virtualRowElements();
|
|
7798
|
+
const isDynamic = this.effectiveDynamicRowSizing();
|
|
7799
|
+
this._refreshStickyGroupMetrics();
|
|
7800
|
+
// `_trackStuckGroupRows` chạy trước effect này trong cùng một phase nên nó thấy đường sticky
|
|
7801
|
+
// của lần render trước. Hẹn thêm một lượt sau frame để đọc lại số đo vừa cập nhật ở trên.
|
|
7802
|
+
this._scheduleStuckGroupRowsRefresh();
|
|
7803
|
+
if (!isDynamic) {
|
|
7804
|
+
this._warnOnOverflowingFixedRows(elements);
|
|
7805
|
+
return;
|
|
7806
|
+
}
|
|
7807
|
+
for (const el of elements) {
|
|
7808
|
+
this.virtualizer.measureElement(el.nativeElement);
|
|
7809
|
+
}
|
|
7810
|
+
this._refreshDynamicEstimate();
|
|
7811
|
+
},
|
|
7812
|
+
});
|
|
7813
|
+
_stuckGroupRowsFrame = null;
|
|
7814
|
+
/** Gom nhiều lần scroll trong cùng một frame — mỗi lần chạy đều đọc rect nên phải giới hạn tần suất. */
|
|
7815
|
+
_scheduleStuckGroupRowsRefresh() {
|
|
7816
|
+
if (this._stuckGroupRowsFrame !== null) {
|
|
7817
|
+
return;
|
|
7818
|
+
}
|
|
7819
|
+
this._stuckGroupRowsFrame = requestAnimationFrame(() => {
|
|
7820
|
+
this._stuckGroupRowsFrame = null;
|
|
7821
|
+
this._refreshStuckGroupRows();
|
|
7822
|
+
});
|
|
7823
|
+
}
|
|
7824
|
+
_cancelStuckGroupRowsRefresh() {
|
|
7825
|
+
if (this._stuckGroupRowsFrame === null) {
|
|
7612
7826
|
return;
|
|
7613
7827
|
}
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
|
|
7617
|
-
|
|
7828
|
+
cancelAnimationFrame(this._stuckGroupRowsFrame);
|
|
7829
|
+
this._stuckGroupRowsFrame = null;
|
|
7830
|
+
}
|
|
7831
|
+
/**
|
|
7832
|
+
* Tìm group header (non-virtual) đang ghim ở mép dưới cùng của chồng sticky để trao shadow.
|
|
7833
|
+
* Header đã ghim có `rect.top` đúng bằng đường sticky của depth đó; header chưa tới thì lớn hơn.
|
|
7834
|
+
* Ưu tiên đường sticky thấp nhất (multi-level: header con), tie thì lấy cái sau cùng trong DOM vì
|
|
7835
|
+
* đó là cái đang nằm trên khi nhiều header chồng nhau.
|
|
7836
|
+
*/
|
|
7837
|
+
_refreshStuckGroupRows() {
|
|
7838
|
+
const groupRows = this.groupRowElements();
|
|
7839
|
+
const viewportEl = this._getTbodyViewportElement();
|
|
7840
|
+
const stickyTops = this.stickyGroupTopByDepth();
|
|
7841
|
+
// Ở đỉnh bảng, header đầu tiên nằm sẵn đúng đường sticky nhưng chưa có row nào cuộn xuống dưới
|
|
7842
|
+
// nó — chưa tính là đang ghim, nếu không sẽ đổ shadow ngay khi vừa mở bảng.
|
|
7843
|
+
if (groupRows.length === 0 || !viewportEl || stickyTops.length === 0 || viewportEl.scrollTop <= 0.5) {
|
|
7844
|
+
this.shadowGroupRowId.set(null);
|
|
7845
|
+
return;
|
|
7846
|
+
}
|
|
7847
|
+
const viewportTop = viewportEl.getBoundingClientRect().top;
|
|
7848
|
+
let shadowId = null;
|
|
7849
|
+
let shadowTop = -1;
|
|
7850
|
+
for (const groupRow of groupRows) {
|
|
7851
|
+
const element = groupRow.nativeElement;
|
|
7852
|
+
const groupId = element.dataset['groupId'];
|
|
7853
|
+
if (!groupId) {
|
|
7854
|
+
continue;
|
|
7855
|
+
}
|
|
7856
|
+
const stickyTop = stickyTops[Number(element.dataset['groupDepth'] ?? 0)] ?? stickyTops[0];
|
|
7857
|
+
if (element.getBoundingClientRect().top - viewportTop > stickyTop + 0.5) {
|
|
7858
|
+
continue;
|
|
7859
|
+
}
|
|
7860
|
+
if (stickyTop >= shadowTop) {
|
|
7861
|
+
shadowTop = stickyTop;
|
|
7862
|
+
shadowId = groupId;
|
|
7863
|
+
}
|
|
7618
7864
|
}
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
queueMicrotask(() => this._learnDynamicEstimate());
|
|
7865
|
+
if (this.shadowGroupRowId() !== shadowId) {
|
|
7866
|
+
this.shadowGroupRowId.set(shadowId);
|
|
7622
7867
|
}
|
|
7623
|
-
}
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
if (
|
|
7868
|
+
}
|
|
7869
|
+
/** Đo các mốc mà `stickyGroupTopByDepth` cần (non-virtual): chiều cao group row và khối pinned top. */
|
|
7870
|
+
_refreshStickyGroupMetrics() {
|
|
7871
|
+
const groupRows = this.groupRowElements();
|
|
7872
|
+
if (groupRows.length === 0) {
|
|
7628
7873
|
return;
|
|
7629
7874
|
}
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7875
|
+
// Mọi group header dùng chung style nên chỉ cần đo row đầu tiên.
|
|
7876
|
+
const measuredHeight = groupRows[0].nativeElement.getBoundingClientRect().height;
|
|
7877
|
+
if (measuredHeight > 0 && Math.abs(measuredHeight - this._groupRowHeight()) > 0.5) {
|
|
7878
|
+
this._groupRowHeight.set(measuredHeight);
|
|
7879
|
+
}
|
|
7880
|
+
const tbodyWrapperEl = this.tbodyWrapper()?.nativeElement;
|
|
7881
|
+
if (!tbodyWrapperEl) {
|
|
7882
|
+
return;
|
|
7883
|
+
}
|
|
7884
|
+
let pinnedTopHeight = 0;
|
|
7885
|
+
for (const pinnedRow of tbodyWrapperEl.querySelectorAll('tbody tr.z-pinned-top')) {
|
|
7886
|
+
pinnedTopHeight += pinnedRow.getBoundingClientRect().height;
|
|
7887
|
+
}
|
|
7888
|
+
if (Math.abs(pinnedTopHeight - this._nonVirtualPinnedTopHeight()) > 0.5) {
|
|
7889
|
+
this._nonVirtualPinnedTopHeight.set(pinnedTopHeight);
|
|
7890
|
+
}
|
|
7891
|
+
}
|
|
7892
|
+
_hasWarnedOverflowingFixedRows = false;
|
|
7893
|
+
/**
|
|
7894
|
+
* Cảnh báo một lần mỗi bảng khi body row cao hơn `virtual.size`.
|
|
7895
|
+
* CSS table layout coi `height` trên `<tr>`/`<td>` là min-height, nên nội dung cell không nén được
|
|
7896
|
+
* (tag, button, nhiều dòng…) sẽ đẩy row vượt slot của virtualizer; row kế tiếp định vị tuyệt đối
|
|
7897
|
+
* đúng theo `virtual.size` nên đè lên phần dôi ra — nhìn như mỗi row bị hụt mất vài px.
|
|
7898
|
+
* Không tự sửa: chiều cao đúng phụ thuộc dữ liệu, chọn tăng `size` hay bật `dynamicSize` là của app.
|
|
7899
|
+
*/
|
|
7900
|
+
_warnOnOverflowingFixedRows(elements) {
|
|
7901
|
+
if (this._hasWarnedOverflowingFixedRows || elements.length === 0 || this.hasBodyRowSpan()) {
|
|
7902
|
+
return;
|
|
7903
|
+
}
|
|
7904
|
+
const configuredHeight = this._virtualConfig().size ?? Z_DEFAULT_ROW_HEIGHT;
|
|
7905
|
+
for (const element of elements) {
|
|
7906
|
+
for (const row of element.nativeElement.querySelectorAll('tr')) {
|
|
7907
|
+
// Group header có chiều cao riêng (Z_VIRTUAL_GROUP_HEADER_HEIGHT), không so với virtual.size.
|
|
7908
|
+
if (row.classList.contains('z-group-row')) {
|
|
7909
|
+
continue;
|
|
7910
|
+
}
|
|
7911
|
+
const rowHeight = row.getBoundingClientRect().height;
|
|
7912
|
+
if (rowHeight - configuredHeight < 1) {
|
|
7913
|
+
continue;
|
|
7914
|
+
}
|
|
7915
|
+
this._hasWarnedOverflowingFixedRows = true;
|
|
7916
|
+
console.warn(`[z-table] Row renders at ${Math.ceil(rowHeight)}px but virtual.size is ${configuredHeight}px, so each row is ` +
|
|
7917
|
+
`overlapped by the next one. Raise virtual.size to at least ${Math.ceil(rowHeight)} or set virtual.dynamicSize: true.`);
|
|
7918
|
+
return;
|
|
7638
7919
|
}
|
|
7639
7920
|
}
|
|
7640
|
-
|
|
7921
|
+
}
|
|
7922
|
+
_dynamicEstimateSampleCount = 0;
|
|
7923
|
+
/** Averages the rows measured so far to estimate the ones not yet rendered. */
|
|
7924
|
+
_refreshDynamicEstimate() {
|
|
7925
|
+
const sizeCache = this.virtualizer.itemSizeCache;
|
|
7926
|
+
const measuredCount = sizeCache.size;
|
|
7927
|
+
if (measuredCount === 0 || measuredCount === this._dynamicEstimateSampleCount) {
|
|
7641
7928
|
return;
|
|
7642
7929
|
}
|
|
7643
|
-
this.
|
|
7644
|
-
|
|
7930
|
+
this._dynamicEstimateSampleCount = measuredCount;
|
|
7931
|
+
let measuredSum = 0;
|
|
7932
|
+
for (const size of sizeCache.values()) {
|
|
7933
|
+
measuredSum += size;
|
|
7934
|
+
}
|
|
7935
|
+
const nextEstimate = Math.round(measuredSum / measuredCount);
|
|
7936
|
+
const currentEstimate = this._dynamicEstimateHeight;
|
|
7937
|
+
if (currentEstimate === null) {
|
|
7938
|
+
this._dynamicEstimateHeight = nextEstimate;
|
|
7939
|
+
this.virtualizer.measure();
|
|
7940
|
+
return;
|
|
7941
|
+
}
|
|
7942
|
+
// measure() rebuilds every offset, so never re-broadcast mid-scroll.
|
|
7943
|
+
if (Math.abs(nextEstimate - currentEstimate) >= 1 && !this.virtualizer.isScrolling) {
|
|
7944
|
+
this._dynamicEstimateHeight = nextEstimate;
|
|
7945
|
+
this.virtualizer.measure();
|
|
7946
|
+
}
|
|
7645
7947
|
}
|
|
7646
7948
|
_rowDragAutoScroll = effect(onCleanup => {
|
|
7647
7949
|
const scrollbar = this.tbodyScrollbar();
|
|
@@ -7781,7 +8083,14 @@ class ZTableComponent {
|
|
|
7781
8083
|
this.pagination.set(initial.pagination);
|
|
7782
8084
|
}
|
|
7783
8085
|
}
|
|
7784
|
-
|
|
8086
|
+
// Virtual scroll windows the rows itself, so it needs the full row model — otherwise the
|
|
8087
|
+
// default pageSize of 10 leaves the paginated row model truncating the data it ever sees.
|
|
8088
|
+
const isVirtualConfig = !!cfg.virtual && (typeof cfg.virtual === 'boolean' ? cfg.virtual : cfg.virtual.enabled);
|
|
8089
|
+
const configuredPageSize = cfg.pagination?.enabled
|
|
8090
|
+
? cfg.pagination.pageSize
|
|
8091
|
+
: isVirtualConfig
|
|
8092
|
+
? Number.MAX_SAFE_INTEGER
|
|
8093
|
+
: undefined;
|
|
7785
8094
|
const initialPageSize = cfg.initialState?.pagination?.pageSize;
|
|
7786
8095
|
const paginationSchemaKey = `${this._getConfigCacheKey(key || 'initial-pagination')}:${configuredPageSize ?? ''}:${initialPageSize ?? ''}`;
|
|
7787
8096
|
if (!cfg.initialState?.pagination &&
|
|
@@ -7870,6 +8179,7 @@ class ZTableComponent {
|
|
|
7870
8179
|
}
|
|
7871
8180
|
this._cancelPinnedRowHeightsRefresh();
|
|
7872
8181
|
this._cancelVirtualSpacerWidthRefresh();
|
|
8182
|
+
this._cancelStuckGroupRowsRefresh();
|
|
7873
8183
|
this._cellDragCleanup?.();
|
|
7874
8184
|
});
|
|
7875
8185
|
}
|
|
@@ -7919,6 +8229,7 @@ class ZTableComponent {
|
|
|
7919
8229
|
explicitEffect([this.columnFilters, this.globalFilter, this.pagination, this.sorting, this._data], () => {
|
|
7920
8230
|
// New dataset may have different row heights -> relearn the estimate.
|
|
7921
8231
|
this._dynamicEstimateHeight = null;
|
|
8232
|
+
this._dynamicEstimateSampleCount = 0;
|
|
7922
8233
|
queueMicrotask(() => {
|
|
7923
8234
|
this._checkVerticalScroll();
|
|
7924
8235
|
this._checkHorizontalScroll();
|
|
@@ -8004,6 +8315,7 @@ class ZTableComponent {
|
|
|
8004
8315
|
this._destroy$.subscribe(() => {
|
|
8005
8316
|
this._cancelPinnedRowHeightsRefresh();
|
|
8006
8317
|
this._cancelVirtualSpacerWidthRefresh();
|
|
8318
|
+
this._cancelStuckGroupRowsRefresh();
|
|
8007
8319
|
});
|
|
8008
8320
|
this._listenCellInteractionOutside();
|
|
8009
8321
|
this.zControl.emit({
|
|
@@ -8681,6 +8993,7 @@ class ZTableComponent {
|
|
|
8681
8993
|
this._updateScrollShadowState(viewport);
|
|
8682
8994
|
this._updateVerticalScrollShadowState(viewport);
|
|
8683
8995
|
this._scheduleVirtualSpacerWidthRefresh();
|
|
8996
|
+
this._scheduleStuckGroupRowsRefresh();
|
|
8684
8997
|
this._host.nativeElement.style.setProperty('--z-scroll-x', `${viewport.scrollLeft}px`);
|
|
8685
8998
|
}
|
|
8686
8999
|
/** Chặn wheel trực tiếp trên header; header chỉ nhận scrollLeft từ body. */
|
|
@@ -10804,7 +11117,7 @@ class ZTableComponent {
|
|
|
10804
11117
|
return result;
|
|
10805
11118
|
}
|
|
10806
11119
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: ZTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10807
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: ZTableComponent, isStandalone: true, selector: "z-table", inputs: { zClass: { classPropertyName: "zClass", publicName: "zClass", isSignal: true, isRequired: false, transformFunction: null }, zConfig: { classPropertyName: "zConfig", publicName: "zConfig", isSignal: true, isRequired: false, transformFunction: null }, zLoading: { classPropertyName: "zLoading", publicName: "zLoading", isSignal: true, isRequired: false, transformFunction: null }, zKey: { classPropertyName: "zKey", publicName: "zKey", isSignal: true, isRequired: false, transformFunction: null }, zVariant: { classPropertyName: "zVariant", publicName: "zVariant", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { zChange: "zChange", zControl: "zControl" }, host: { classAttribute: "z-table block relative py-1" }, providers: [TranslatePipe, ZTableDragService], viewQueries: [{ propertyName: "theadWrapper", first: true, predicate: ["theadWrapper"], descendants: true, isSignal: true }, { propertyName: "tableContainer", first: true, predicate: ["tableContainer"], descendants: true, isSignal: true }, { propertyName: "tbodyContainer", first: true, predicate: ["tbodyContainer"], descendants: true, isSignal: true }, { propertyName: "tbodyWrapper", first: true, predicate: ["tbodyWrapper"], descendants: true, isSignal: true }, { propertyName: "tbodyScrollbar", first: true, predicate: ["tbodyWrapper"], descendants: true, isSignal: true }, { propertyName: "tfootWrapper", first: true, predicate: ["tfootWrapper"], descendants: true, isSignal: true }, { propertyName: "expandedRowTemplate", first: true, predicate: ["expandedRowTemplate"], descendants: true, isSignal: true }, { propertyName: "virtualRowElements", predicate: ["virtualRow"], descendants: true, isSignal: true }], exportAs: ["zTable"], ngImport: i0, template: "<!-- Toolbar: Search & Settings -->\n@if (isSearchEnabled() || zConfig().enableSettings) {\n <div class=\"z-table-toolbar mb-2 flex items-center justify-between gap-4\">\n <!-- Search -->\n @if (isSearchEnabled()) {\n @let config = searchConfig();\n <z-input\n [class]=\"config?.width ?? 'w-64'\"\n [zSize]=\"config?.size ?? 'sm'\"\n [zPlaceholder]=\"config?.placeholder ?? 'i18n_z_ui_table_search' | translate\"\n [zSearch]=\"true\"\n [zDebounce]=\"config?.debounceTime ?? 300\"\n (zOnSearch)=\"onSearchChange($event)\" />\n } @else {\n <div></div>\n }\n\n <!-- Settings Button -->\n @if (zConfig().enableSettings) {\n <z-button zType=\"outline\" zSize=\"sm\" zTypeIcon=\"lucideSettings\" (click)=\"openSettingsDrawer()\">\n {{ 'i18n_z_ui_table_settings' | translate }}\n </z-button>\n }\n </div>\n}\n\n@if (zConfig().enableFilterHeader && appliedFilterChips().length > 0) {\n <div class=\"z-table-filter-header mb-2 flex min-w-0 items-center gap-2\">\n <div class=\"flex min-w-0 flex-1 flex-wrap items-center gap-1.5\">\n @for (chip of visibleAppliedFilterChips(); track chip.id) {\n <span\n class=\"border-border bg-muted/60 text-foreground inline-flex max-w-80 min-w-0 shrink-0 items-center gap-1 rounded-sm border px-2 py-1 text-[0.8125rem] shadow-xs\">\n <span class=\"font-medium whitespace-nowrap\">{{ chip.label }}</span>\n <span class=\"text-muted-foreground\">:</span>\n <span class=\"truncate\" z-tooltip [zContent]=\"chip.value\" zTooltipTrigger=\"hover\" zTooltipPosition=\"top\">\n {{ chip.value }}\n </span>\n <button\n type=\"button\"\n class=\"hover:bg-destructive/10 hover:text-destructive focus-visible:ring-ring -mr-1 inline-flex size-5 cursor-pointer items-center justify-center rounded-sm outline-none focus-visible:ring-2\"\n [attr.aria-label]=\"'i18n_z_ui_table_filter_remove' | translate\"\n (click)=\"clearAppliedFilterChip(chip)\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </span>\n }\n @if (hiddenAppliedFilterChipCount() > 0 && isFilterHeaderExpanded()) {\n @for (chip of overflowAppliedFilterChips(); track chip.id) {\n <span\n class=\"z-table-filter-header-overflow-chip border-border bg-muted/60 text-foreground inline-flex max-w-80 min-w-0 shrink-0 items-center gap-1 rounded-sm border px-2 py-1 text-[0.8125rem] shadow-xs\"\n [attr.aria-hidden]=\"!isFilterHeaderExpanded()\">\n <span class=\"font-medium whitespace-nowrap\">{{ chip.label }}</span>\n <span class=\"text-muted-foreground\">:</span>\n <span class=\"truncate\" z-tooltip [zContent]=\"chip.value\" zTooltipTrigger=\"hover\" zTooltipPosition=\"top\">\n {{ chip.value }}\n </span>\n <button\n type=\"button\"\n class=\"hover:bg-destructive/10 hover:text-destructive focus-visible:ring-ring -mr-1 inline-flex size-5 cursor-pointer items-center justify-center rounded-sm outline-none focus-visible:ring-2\"\n [attr.aria-label]=\"'i18n_z_ui_table_filter_remove' | translate\"\n (click)=\"clearAppliedFilterChip(chip)\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </span>\n }\n }\n @if (hiddenAppliedFilterChipCount() > 0) {\n <button\n type=\"button\"\n class=\"text-primary hover:bg-primary/10 focus-visible:ring-ring inline-flex h-7 cursor-pointer items-center rounded-sm px-2 text-xs font-medium outline-none focus-visible:ring-2\"\n (click)=\"toggleFilterHeaderExpanded()\">\n {{\n isFilterHeaderExpanded()\n ? ('i18n_z_ui_table_show_less' | translate)\n : ('i18n_z_ui_table_show_more' | translate: { count: hiddenAppliedFilterChipCount() })\n }}\n </button>\n }\n <button\n type=\"button\"\n class=\"bg-destructive/10 text-destructive hover:bg-destructive/20 dark:bg-destructive/15 dark:text-destructive-foreground dark:hover:bg-destructive/25 focus-visible:ring-destructive inline-flex h-7 cursor-pointer items-center gap-1 rounded-sm px-2 text-xs font-medium shadow-xs outline-none focus-visible:ring-2\"\n (click)=\"clearAppliedFilters()\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_clear_filter' | translate }}</span>\n </button>\n </div>\n </div>\n}\n\n<div\n #tableContainer\n [class]=\"classTable()\"\n [class.z-pinning-overflow]=\"!isPinnedLayoutWithinContainer()\"\n [class.z-hide-horizontal-border]=\"!showHorizontalBorder()\"\n [class.z-hide-vertical-border]=\"!showVerticalBorder()\"\n [class.z-hide-pinned-top-border]=\"hasScrollTop()\"\n [class.z-hide-pinned-bottom-border]=\"hasScrollBottom()\"\n [style.width]=\"zConfig().width\"\n [style.height]=\"zConfig().height\"\n [style.max-height]=\"zConfig().maxHeight\"\n [style.min-height]=\"zConfig().minHeight\"\n [attr.tabindex]=\"canUseContentRowInsert() || canUseCellSelection() ? 0 : null\"\n (keydown)=\"onContentTableKeydown($event)\">\n @let isColumnPinningActive = isPinnedLayoutWithinContainer();\n <ng-template #contentRowMenuContent>\n <div class=\"flex min-w-36 flex-col gap-0.5 p-1\">\n @if (contentRowMenu()?.columnId) {\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"copyContentCell()\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_cell' | translate }}</span>\n </button>\n <div class=\"border-border my-0 border-t\"></div>\n }\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (click)=\"copyContentRows()\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_row' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"contentRowClipboard().length === 0\"\n (click)=\"pasteContentRows('below')\">\n <z-icon zType=\"lucideClipboardPaste\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_paste_row_below' | translate }}</span>\n </button>\n <div class=\"border-border my-0 border-t\"></div>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canMoveContentRowUp()\"\n (click)=\"moveContentRow('up')\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_move_row_up' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canMoveContentRowDown()\"\n (click)=\"moveContentRow('down')\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_move_row_down' | translate }}</span>\n </button>\n <div class=\"border-border my-0 border-t\"></div>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (click)=\"insertContentRow('above')\">\n <z-icon zType=\"lucideArrowUpToLine\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_insert_row_above' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (click)=\"insertContentRow('below')\">\n <z-icon zType=\"lucideArrowDownToLine\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_insert_row_below' | translate }}</span>\n </button>\n <div class=\"border-border my-0 border-t\"></div>\n <button\n type=\"button\"\n class=\"text-destructive hover:bg-destructive/10 focus:bg-destructive/10 flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (click)=\"deleteContentRows()\">\n <z-icon zType=\"lucideTrash2\" zSize=\"12\" />\n <span>\n {{\n contentRowDeleteCount() > 1\n ? ('i18n_z_ui_table_delete_selected_rows' | translate)\n : ('i18n_z_ui_table_delete_row' | translate)\n }}\n </span>\n </button>\n </div>\n </ng-template>\n\n <ng-template #cellMenuContent>\n <div class=\"flex min-w-36 flex-col gap-0.5 p-1\">\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canCopyCellMenuSelection()\"\n (click)=\"copySelectedCells(false)\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_cell' | translate }}</span>\n </button>\n @if (cellSelectionOptions().copyWithHeaders) {\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canCopyCellMenuSelection()\"\n (click)=\"copySelectedCells(true)\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_cell_with_headers' | translate }}</span>\n </button>\n }\n </div>\n </ng-template>\n\n <div\n class=\"pointer-events-none fixed size-px opacity-0\"\n z-popover\n [zPopoverContent]=\"contentRowMenuContent\"\n zTrigger=\"manual\"\n zPosition=\"bottom-left\"\n zClass=\"z-table-content-row-menu\"\n [zOffset]=\"0\"\n [zManualClose]=\"true\"\n [zScrollClose]=\"true\"\n [style.left.px]=\"contentRowMenu()?.left ?? -9999\"\n [style.top.px]=\"contentRowMenu()?.top ?? -9999\"\n (zControl)=\"setContentRowMenuControl($event)\"\n (zHide)=\"clearContentRowMenu()\"></div>\n\n <div\n class=\"pointer-events-none fixed size-px opacity-0\"\n z-popover\n [zPopoverContent]=\"cellMenuContent\"\n zTrigger=\"manual\"\n zPosition=\"bottom-left\"\n zClass=\"z-table-cell-menu\"\n [zOffset]=\"0\"\n [zManualClose]=\"true\"\n [zScrollClose]=\"true\"\n [style.left.px]=\"cellMenu()?.left ?? -9999\"\n [style.top.px]=\"cellMenu()?.top ?? -9999\"\n (zControl)=\"setCellMenuControl($event)\"\n (zHide)=\"clearCellMenu()\"></div>\n\n <!-- Shared colgroup template -->\n <ng-template #colGroupTpl>\n <colgroup>\n @if (canUseVirtualColumns()) {\n @for (column of leftLeafColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <col [style.width.px]=\"virtualRenderedLeftSpacerWidth()\" />\n }\n @for (column of virtualCenterColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n @if (virtualRightSpacerWidth() > 0) {\n <col [style.width.px]=\"virtualRenderedRightSpacerWidth()\" />\n }\n @for (column of rightLeafColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n } @else {\n @for (column of orderedLeafColumns(); track column.id) {\n @if (column.getIsVisible()) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n }\n }\n </colgroup>\n </ng-template>\n\n <!-- Header table -->\n <div\n class=\"z-thead-wrapper shadow-card\"\n [class.z-shadow-header]=\"shouldHeaderShowShadow()\"\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\"\n (wheel)=\"onTheadWheel($event)\"\n #theadWrapper>\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <thead>\n @if (canUseVirtualColumns()) {\n <tr>\n @for (header of leftHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: leftHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (effectiveEnableOrdering) {\n <button\n type=\"button\"\n [disabled]=\"isFirstMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnLeft(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_left' | translate }}</span>\n </button>\n <button\n type=\"button\"\n [disabled]=\"isLastMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnRight(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideChevronsLeftRight\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_column' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeAllColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_all_columns' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"resetColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRotateCcw\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_reset_columns' | translate }}</span>\n </button>\n @if (hideableColumns().length > 0) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover)\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded px-1.5 py-1\"\n [class.cursor-pointer]=\"hasColumnOptions\"\n [class.z-has-options]=\"hasColumnOptions\"\n [attr.z-popover]=\"hasColumnOptions ? '' : null\"\n #colOptionsPopover=\"zPopover\"\n #headerTextWrapper\n z-popover\n [zPopoverContent]=\"hasColumnOptions ? colOptionsPopoverContent : null\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <th\n class=\"z-virtual-column-spacer z-virtual-header-spacer z-virtual-left-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></th>\n }\n @for (header of virtualCenterHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: virtualCenterHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (effectiveEnableOrdering) {\n <button\n type=\"button\"\n [disabled]=\"isFirstMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnLeft(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_left' | translate }}</span>\n </button>\n <button\n type=\"button\"\n [disabled]=\"isLastMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnRight(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideChevronsLeftRight\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_column' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeAllColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_all_columns' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"resetColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRotateCcw\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_reset_columns' | translate }}</span>\n </button>\n @if (hideableColumns().length > 0) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover)\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded px-1.5 py-1\"\n [class.cursor-pointer]=\"hasColumnOptions\"\n [class.z-has-options]=\"hasColumnOptions\"\n [attr.z-popover]=\"hasColumnOptions ? '' : null\"\n #colOptionsPopover=\"zPopover\"\n #headerTextWrapper\n z-popover\n [zPopoverContent]=\"hasColumnOptions ? colOptionsPopoverContent : null\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualRightSpacerWidth() > 0) {\n <th\n class=\"z-virtual-column-spacer z-virtual-header-spacer z-virtual-right-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></th>\n }\n @for (header of rightHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: rightHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <!-- Header Checkbox -->\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <!-- Expand All Button -->\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <!-- Header Content with Sort and Pin -->\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <!-- Column Options Popover Template -->\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (effectiveEnableOrdering) {\n <button\n type=\"button\"\n [disabled]=\"isFirstMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnLeft(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_left' | translate }}</span>\n </button>\n <button\n type=\"button\"\n [disabled]=\"isLastMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnRight(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideChevronsLeftRight\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_column' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeAllColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_all_columns' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"resetColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRotateCcw\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_reset_columns' | translate }}</span>\n </button>\n @if (hideableColumns().length > 0) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover)\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded px-1.5 py-1\"\n [class.cursor-pointer]=\"hasColumnOptions\"\n [class.z-has-options]=\"hasColumnOptions\"\n [attr.z-popover]=\"hasColumnOptions ? '' : null\"\n #colOptionsPopover=\"zPopover\"\n #headerTextWrapper\n z-popover\n [zPopoverContent]=\"hasColumnOptions ? colOptionsPopoverContent : null\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n <!-- Dropdown indicator when has options (between text and sort icon) -->\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n <!-- Sort Icon (outside wrapper, no hover background) -->\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n <!-- Column Resizer -->\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n </tr>\n } @else {\n @for (headerGroup of orderedHeaderGroups(); track headerGroup.id) {\n <tr>\n @for (header of headerGroup.headers; track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: headerGroup.headers : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (effectiveEnableOrdering) {\n <button\n type=\"button\"\n [disabled]=\"isFirstMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnLeft(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_move_left' | translate }}</span>\n </button>\n <button\n type=\"button\"\n [disabled]=\"isLastMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnRight(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"15\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"\n handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\n \"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"15\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon\n zType=\"lucideChevronsLeftRight\"\n zSize=\"14\"\n class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_column' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeAllColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_all_columns' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"resetColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRotateCcw\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_reset_columns' | translate }}</span>\n </button>\n @if (hideableColumns().length > 0) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover)\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded px-1.5 py-1\"\n [class.cursor-pointer]=\"hasColumnOptions\"\n [class.z-has-options]=\"hasColumnOptions\"\n [attr.z-popover]=\"hasColumnOptions ? '' : null\"\n #colOptionsPopover=\"zPopover\"\n #headerTextWrapper\n z-popover\n [zPopoverContent]=\"hasColumnOptions ? colOptionsPopoverContent : null\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"\n header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\n \"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n </tr>\n }\n }\n </thead>\n </table>\n </div>\n\n <!-- Body table -->\n <div\n class=\"z-tbody-wrapper relative\"\n #tbodyContainer\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\">\n @if (isLoading() || isProcessing()) {\n <!-- Loading State -->\n @if (zConfig().useSkeleton) {\n <!-- Skeleton Loading -->\n <div class=\"animate-in fade-in flex h-full flex-col duration-200\">\n @for (i of skeletonRows(); track $index; let last = $last) {\n <div\n class=\"border-border box-border flex flex-1 flex-col items-start justify-center gap-1.5 px-2\"\n [class.border-b]=\"!last\">\n <z-skeleton zType=\"bar\" zWidth=\"100%\" zHeight=\"22px\" zRadius=\"4px\" />\n <z-skeleton zType=\"bar\" zWidth=\"50%\" zHeight=\"14px\" zRadius=\"4px\" />\n </div>\n }\n </div>\n } @else {\n <!-- Spinner Loading -->\n <div class=\"z-loading-state\">\n <z-loading [zLoading]=\"true\" zSize=\"lg\" [zText]=\"'i18n_z_ui_table_loading' | translate\" />\n </div>\n }\n } @else if (isEmpty()) {\n <div class=\"z-empty-state\">\n @if (isNoSearchResults()) {\n <z-empty zIcon=\"lucideSearchX\" zSize=\"sm\" [zMessage]=\"'i18n_z_ui_table_no_results' | translate\" />\n } @else {\n <z-empty zIcon=\"lucidePackageOpen\" zSize=\"sm\" [zMessage]=\"'i18n_z_ui_table_no_data' | translate\" />\n }\n </div>\n } @else {\n <ng-scrollbar class=\"z-tbody-scrollbar\" #tbodyWrapper (scroll)=\"onTbodyScroll($event)\">\n @if (isVirtual()) {\n <!-- Virtual Scroll Mode -->\n\n <div\n class=\"z-virtual-scroll-inner\"\n [style.height.px]=\"virtualizer.getTotalSize()\"\n [style.min-width.px]=\"table.getTotalSize()\">\n <!-- Pinned rows v\u00E0 center rows d\u00F9ng chung m\u1ED9t virtual canvas. -->\n @if (virtualPinnedTopRows().length > 0) {\n <div class=\"z-virtual-pinned-top\" [style.min-width.px]=\"table.getTotalSize()\">\n @for (row of virtualPinnedTopRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"virtualPinnedRowTpl; context: { $implicit: row }\" />\n }\n </div>\n }\n\n @for (virtualItem of virtualizer.getVirtualItems(); track virtualItem.index) {\n @let groupRows = dynamicGroupRows()[virtualItem.index] || [];\n @let virtualFlatItem = virtualGroupedFlatItems()[virtualItem.index];\n <div\n #virtualRow\n class=\"z-virtual-row\"\n z-table-draggable=\"row\"\n z-table-drop-target=\"row\"\n [z-table-drag-table-id]=\"dragInstanceId\"\n [z-table-drop-table-id]=\"dragInstanceId\"\n [z-table-drag-item-id]=\"groupRows.length > 0 ? groupRows[0].id : ''\"\n [z-table-drop-item-id]=\"groupRows.length > 0 ? groupRows[0].id : ''\"\n [z-table-drag-disabled]=\"!isVirtualRowDragEnabled() || groupRows.length !== 1\"\n [z-table-drop-disabled]=\"!isVirtualRowDragEnabled() || groupRows.length !== 1\"\n (zTableDropped)=\"_handleDragDrop($event)\"\n [attr.data-index]=\"virtualItem.index\"\n [style.height.px]=\"\n effectiveDynamicRowSizing()\n ? null\n : (dynamicGroupHeights()[virtualItem.index] ?? groupSize() * virtualRowHeight())\n \"\n [style.transform]=\"'translate3d(0,' + virtualItem.start + 'px,0)'\">\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-has-bottom-pinned]=\"table.getBottomRows().length > 0\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n @let groupHeaderItem = _getVirtualGroupHeader(virtualFlatItem);\n @if (groupHeaderItem) {\n <tr\n class=\"z-group-row\"\n [class.z-group-row-has-totals]=\"groupHeaderItem.totals\"\n [class.z-group-row-expanded]=\"groupHeaderItem.expanded\"\n [attr.data-group-id]=\"groupHeaderItem.id\"\n [attr.data-group-depth]=\"groupHeaderItem.depth\">\n @if (groupHeaderItem.totals) {\n @let totalColumnMap = groupTotalColumnMap();\n @for (column of orderedLeafColumns(); track column.id; let isFirstGroupCell = $first) {\n <td\n [class.z-group-row-label-cell]=\"isFirstGroupCell\"\n [class.z-group-row-total-cell]=\"!isFirstGroupCell && totalColumnMap[column.id]\"\n [attr.data-column-id]=\"column.id\">\n @if (isFirstGroupCell) {\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + groupHeaderItem.depth * 0.75\"\n [attr.aria-expanded]=\"groupHeaderItem.expanded\"\n (click)=\"toggleGroupRow(groupHeaderItem.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"groupHeaderItem.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"\n (groupHeaderItem.columnLabel ? groupHeaderItem.columnLabel + ': ' : '') +\n groupHeaderItem.label\n \">\n @if (groupHeaderItem.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ groupHeaderItem.columnLabel }}:</span>\n }\n {{ groupHeaderItem.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ groupHeaderItem.count }}</span>\n }\n @if (groupHeaderItem.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n [zWave]=\"false\"\n z-tooltip\n zSizeIcon=\"14\"\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(groupHeaderItem.columnId)\"></button>\n }\n </div>\n }\n @if (!isFirstGroupCell && totalColumnMap[column.id]) {\n @let totalConfig = groupTotalConfigMap()[column.id];\n @let totalTooltip = totalConfig.tooltip;\n @let totalPopover = totalConfig.popover;\n @let totalPopoverContent = totalPopover | zTablePopoverConfig: 'content';\n <ng-template #groupTotalPopoverTpl>\n @if (totalPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(totalPopoverContent)\" />\n }\n @if (!(totalPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(totalPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n <span\n class=\"z-group-row-total\"\n z-tooltip\n z-popover\n [class]=\"totalConfig.class\"\n [zContent]=\"\n $any(\n (totalTooltip | zTableTooltipConfig: 'content') ||\n groupHeaderItem.totals[column.id]\n )\n \"\n [zTooltipPosition]=\"$any(totalTooltip | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(totalTooltip | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(totalTooltip | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(totalTooltip | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(totalTooltip | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'showDelay')\"\n [zTooltipHideDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'hideDelay')\"\n [zTooltipArrow]=\"$any(totalTooltip | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(totalTooltip | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(totalTooltip | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(totalTooltip | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(totalTooltip | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"totalPopoverContent ? groupTotalPopoverTpl : null\"\n [zPosition]=\"$any(totalPopover | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(totalPopover | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(totalPopover | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(totalPopover | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(totalPopover | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(totalPopover | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(totalPopover | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(totalPopover | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(totalPopover | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"$any(totalPopover | zTablePopoverConfig: 'outsideClickClose')\"\n [zScrollClose]=\"$any(totalPopover | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(totalPopover | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(totalPopover | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(totalPopover | zTablePopoverConfig: 'keyboardSafe')\">\n {{ groupHeaderItem.totals[column.id] }}\n </span>\n }\n </td>\n }\n } @else {\n <td [attr.colspan]=\"renderedColumnCount()\">\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + groupHeaderItem.depth * 0.75\"\n [attr.aria-expanded]=\"groupHeaderItem.expanded\"\n (click)=\"toggleGroupRow(groupHeaderItem.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"groupHeaderItem.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"\n (groupHeaderItem.columnLabel ? groupHeaderItem.columnLabel + ': ' : '') +\n groupHeaderItem.label\n \">\n @if (groupHeaderItem.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ groupHeaderItem.columnLabel }}:</span>\n }\n {{ groupHeaderItem.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ groupHeaderItem.count }}</span>\n }\n @if (groupHeaderItem.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n [zWave]=\"false\"\n z-tooltip\n zSizeIcon=\"14\"\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(groupHeaderItem.columnId)\"></button>\n }\n </div>\n </td>\n }\n </tr>\n }\n @for (row of groupRows; track row.id) {\n @let virtualGroupDepth = _getVirtualGroupDepth(virtualFlatItem);\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <tr\n z-table-row-hover\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"effectiveDynamicRowSizing() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"effectiveDynamicRowSizing() ? virtualRowHeight() : null\"\n [style.--z-row-height]=\"effectiveDynamicRowSizing() ? 'auto' : virtualRowHeight() + 'px'\"\n [class.z-child-row]=\"row.depth > 0\"\n [class.z-group-child-row]=\"_isVirtualGroupChild(virtualFlatItem)\"\n [style.--z-group-content-indent]=\"\n virtualGroupDepth > 0 ? 1.75 + (virtualGroupDepth - 1) * 0.75 + 'rem' : null\n \"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"\n rowPinned === 'top' && (row | zTableRow: table : 'isFirstTopPinned')\n \"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"\n rowPinned === 'bottom' && (row | zTableRow: table : 'isLastBottomPinned')\n \"\n [class.z-pinned-bottom-first]=\"\n rowPinned === 'bottom' && (row | zTableRow: table : 'isFirstBottomPinned')\n \"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n (row | zTableRow: table : 'isLastTopPinned')\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n (row | zTableRow: table : 'isFirstBottomPinned')\n \"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : bodyRowSpanRows();\n @let shouldRenderColSpan = cell | zTableCellRender: visibleCells : zConfig().columns : 'body';\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (shouldRenderRowSpan && shouldRenderColSpan && isVirtualColumnVisible) {\n @let cellSelectionId = row.id + '::' + cell.column.id;\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"isColumnPinningActive && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActive && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"cell.column.id === actionColumnInfo()?.columnId\"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [class.z-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"cell | zTableCellBottom: zConfig().columns : renderedBodyRows()\"\n [attr.rowspan]=\"cell | zTableSpan: zConfig().columns : 'cellRowSpan' : bodyRowSpanRows()\"\n [attr.colspan]=\"cell | zTableSpan: zConfig().columns : 'cellColSpan'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n [style.--z-cell-range-top]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\n \"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\n \"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <button\n data-z-table-drag-handle\n type=\"button\"\n class=\"text-muted-foreground inline-flex size-7 items-center justify-center rounded-md\"\n [class.cursor-grab]=\"isRowDragEnabled()\"\n [class.opacity-40]=\"!isRowDragEnabled()\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === 'select') {\n <!-- Row Checkbox -->\n <div class=\"flex items-center justify-center\">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && cell.row.getIsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && cell.row.getIsSomeSelected() && !cell.row.getIsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection() || !cell.row.getCanSelect()\"\n (zChange)=\"canUseRowSelection() && cell.row.toggleSelected()\" />\n </div>\n } @else if (cell.column.id === 'expand') {\n <!-- Expand Button -->\n <div class=\"flex items-center justify-center\">\n @if (cell.row.getCanExpand()) {\n <button\n type=\"button\"\n (click)=\"cell.row.toggleExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"cell.row.getIsExpanded()\" />\n </button>\n }\n </div>\n } @else if (\n (cell.column.id === 'actionRowPin' || cell.column.id === 'actions') &&\n cell.column.id !== actionColumnInfo()?.columnId\n ) {\n @if (cell.row.depth === 0 && !hasBodyRowSpan()) {\n <div class=\"flex items-center justify-center\">\n <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (cell.row.getIsPinned() !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cell.row.getIsPinned() !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cell.row.getIsPinned()) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded p-1 outline-none\"\n [class.text-primary]=\"cell.row.getIsPinned()\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n </div>\n }\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisible = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisible) {\n @let editInfoVirtual = cell.getContext() | zTableCellEdit: zConfig().columns;\n @if (editInfoVirtual.enabled) {\n <!-- Editable Cell (Virtual) -->\n <z-table-edit-cell\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n [zRowIndex]=\"cell.row.index\"\n [zColumnId]=\"cell.column.id\"\n [zValue]=\"cell.getValue()\"\n [zRowUpdate]=\"_rowUpdate()\"\n [zEditConfig]=\"$any(editInfoVirtual.config)\"\n (zChange)=\"onCellEdit($any($event))\" />\n } @else if (editInfoVirtual.contentEnabled) {\n @let contentConfigVirtual = editInfoVirtual.contentConfig!;\n @if (\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n ) {\n <z-table-content-editor\n [zValue]=\"cell.getValue()\"\n [zConfig]=\"contentConfigVirtual\"\n (zCommit)=\"onContentEditCommit($event, row, cell.column.id, cell.getValue())\"\n (zCancel)=\"onContentEditCancel()\" />\n } @else {\n <button\n type=\"button\"\n class=\"z-table-content-trigger\"\n [attr.data-z-table-edit-row]=\"row.id\"\n [attr.data-z-table-edit-column]=\"cell.column.id\"\n (keydown)=\"onContentEditKeydown($event, row.id, cell.column.id)\"\n (click)=\"onContentEditStart($event, row.id, cell.column.id)\">\n {{ contentConfigVirtual.displayValue }}\n </button>\n }\n } @else {\n <ng-container\n *flexRender=\"\n cell.column.columnDef.cell;\n props: cell.getContext();\n let cellContent\n \">\n @if (cellContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n @let isClickable = cell.column.id | zTableCellClickable: zConfig().columns;\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickable && onCellClick(row, cell.column.id, cell.getValue())\">\n <ng-container\n *ngTemplateOutlet=\"\n cellContent;\n context: { $implicit: cell.getContext() }\n \" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n @let isClickableIcon = cell.column.id | zTableCellClickable: zConfig().columns;\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"\n isClickableIcon && onCellClick(row, cell.column.id, cell.getValue())\n \" />\n } @else {\n <!-- Default/innerHTML rendering -->\n @let isClickableDefault =\n cell.column.id | zTableCellClickable: zConfig().columns;\n @let cellTooltipConfig = cell | zTableCellConfig: zConfig() : 'contentTooltip';\n @let cellPopoverConfig = cell | zTableCellConfig: zConfig() : 'contentPopover';\n @let cellPopoverContent = cellPopoverConfig | zTablePopoverConfig: 'content';\n <ng-template #cellPopoverTpl>\n @if (cellPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(cellPopoverContent)\" />\n }\n @if (!(cellPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(cellPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n @if (cellPopoverContent) {\n <div\n class=\"z-table-cell-text\"\n z-popover\n z-tooltip\n [zTriggerElement]=\"cellOverlayContent\"\n [zTriggerRef]=\"cellOverlayContent\"\n [zContent]=\"\n (cellTooltipConfig | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'position')\n \"\n [zTooltipTrigger]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"cellPopoverTpl\"\n [zPosition]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'manualClose')\n \"\n [zOutsideClickClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'outsideClickClose')\n \"\n [zScrollClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'scrollClose')\n \"\n [zSticky]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'keyboardSafe')\n \"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellOverlayContent\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n } @else {\n <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zTriggerElement]=\"cellTooltipContent\"\n [zContent]=\"\n (cellTooltipConfig | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'position')\n \"\n [zTooltipTrigger]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'maxWidth')\"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellTooltipContent\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n }\n }\n </ng-container>\n }\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n\n <!--\n Bottom pinned rows: sibling AFTER the virtual canvas (not absolute like the\n center rows). The virtualizer reserves their height inside getTotalSize() via\n `paddingEnd`, leaving an empty band at the canvas bottom. `margin-top: -bottomHeight`\n pulls this real flow element back over that band, and `position: sticky; bottom: 0`\n floats it to the viewport bottom while scrolling.\n -->\n @if (virtualPinnedBottomRows().length > 0) {\n <div\n class=\"z-virtual-pinned-bottom\"\n [style.min-width.px]=\"table.getTotalSize()\"\n [style.margin-top.px]=\"-virtualPinnedBottomHeight()\">\n @for (row of virtualPinnedBottomRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"virtualPinnedRowTpl; context: { $implicit: row }\" />\n }\n </div>\n }\n\n <!-- Template for rendering pinned rows in virtual scroll mode -->\n <ng-template #virtualPinnedRowTpl let-row>\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody [class.z-has-vertical-scroll]=\"hasVerticalScroll()\">\n <tr\n z-table-row-hover\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"effectiveDynamicRowSizing() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"effectiveDynamicRowSizing() ? virtualRowHeight() : null\"\n [style.--z-row-height]=\"effectiveDynamicRowSizing() ? 'auto' : virtualRowHeight() + 'px'\"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && (row | zTableRow: table : 'isFirstTopPinned')\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"\n rowPinned === 'bottom' && (row | zTableRow: table : 'isLastBottomPinned')\n \"\n [class.z-pinned-bottom-first]=\"\n rowPinned === 'bottom' && (row | zTableRow: table : 'isFirstBottomPinned')\n \"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n (row | zTableRow: table : 'isLastTopPinned')\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n (row | zTableRow: table : 'isFirstBottomPinned')\n \"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @let isColumnPinningActivePinned = isPinnedLayoutWithinContainer();\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @let cellSelectionId = row.id + '::' + cell.column.id;\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (isVirtualColumnVisible) {\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActivePinned\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"isColumnPinningActivePinned && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActivePinned && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"cell.column.id === actionColumnInfo()?.columnId\"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [style.--z-cell-range-top]=\"(selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"(selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'select') {\n <z-checkbox\n [zChecked]=\"rowSelected\"\n [zIndeterminate]=\"rowSomeSelected && !rowSelected\"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && row.toggleSelected()\" />\n } @else if (cell.column.id === 'expand') {\n <button\n type=\"button\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"row.toggleExpanded()\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"row.getIsExpanded()\" />\n </button>\n } @else if (cell.column.id === 'actionRowPin') {\n <div class=\"flex items-center justify-center\">\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisible = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisible) {\n <ng-container\n *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let cellContent\">\n @if (cellContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { $implicit: cell.getContext() }\" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"(cell | zTableCellConfig: zConfig() : 'contentTooltip') || cellContent\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"></span>\n }\n </ng-container>\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n </tbody>\n </table>\n </ng-template>\n } @else {\n <!-- Normal Scroll Mode -->\n\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n class=\"z-table-drag-body\"\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-has-bottom-pinned]=\"table.getBottomRows().length > 0\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n <!-- Row Template -->\n <ng-template #rowTemplate let-row let-isGroupChild=\"isGroupChild\" let-groupDepth=\"groupDepth\">\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <tr\n z-table-row-hover\n z-table-draggable=\"row\"\n z-table-drop-target=\"row\"\n [z-table-drag-table-id]=\"dragInstanceId\"\n [z-table-drop-table-id]=\"dragInstanceId\"\n [z-table-drag-item-id]=\"row.id\"\n [z-table-drop-item-id]=\"row.id\"\n [z-table-drag-disabled]=\"!isRowDragEnabled()\"\n [z-table-drop-disabled]=\"!isRowDragEnabled()\"\n (zTableDropped)=\"_handleDragDrop($event)\"\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [ngStyle]=\"row | zTableRow: table : 'pinningStyles' : pinnedRowHeights() : virtualRowHeight()\"\n [class.z-child-row]=\"row.depth > 0\"\n [class.z-group-child-row]=\"isGroupChild\"\n [style.--z-group-content-indent]=\"groupDepth > 0 ? 1.75 + (groupDepth - 1) * 0.75 + 'rem' : null\"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && (row | zTableRow: table : 'isFirstTopPinned')\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"\n rowPinned === 'bottom' && (row | zTableRow: table : 'isLastBottomPinned')\n \"\n [class.z-pinned-bottom-first]=\"\n rowPinned === 'bottom' && (row | zTableRow: table : 'isFirstBottomPinned')\n \"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n (row | zTableRow: table : 'isLastTopPinned')\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n (row | zTableRow: table : 'isFirstBottomPinned')\n \"\n [attr.data-depth]=\"row.depth\"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @let cellRowPinned = cell.row.getIsPinned();\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : bodyRowSpanRows();\n @let shouldRenderColSpan = cell | zTableCellRender: visibleCells : zConfig().columns : 'body';\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (shouldRenderRowSpan && shouldRenderColSpan && isVirtualColumnVisible) {\n @let cellSelectionId = row.id + '::' + cell.column.id;\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n [class.z-sticky-left]=\"isColumnPinningActive && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActive && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"\n cell.column.id === 'actions' || cell.column.id === actionColumnInfo()?.columnId\n \"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [class.z-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"cell | zTableCellBottom: zConfig().columns : renderedBodyRows()\"\n [attr.rowspan]=\"cell | zTableSpan: zConfig().columns : 'cellRowSpan' : bodyRowSpanRows()\"\n [attr.colspan]=\"cell | zTableSpan: zConfig().columns : 'cellColSpan'\"\n [style.--z-cell-range-top]=\"(selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"(selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <button\n data-z-table-drag-handle\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground inline-flex size-7 items-center justify-center rounded-md transition-colors\"\n [class.cursor-grab]=\"isRowDragEnabled()\"\n [class.cursor-not-allowed]=\"!isRowDragEnabled()\"\n [class.opacity-40]=\"!isRowDragEnabled()\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === 'select') {\n <!-- Row Checkbox with Pin Button -->\n <div class=\"flex items-center justify-center gap-1\">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && cell.row.getIsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && cell.row.getIsSomeSelected() && !cell.row.getIsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection() || !cell.row.getCanSelect()\"\n (zChange)=\"canUseRowSelection() && cell.row.toggleSelected()\" />\n @if (zConfig().enableRowPinning && cell.row.depth === 0 && !hasBodyRowSpan()) {\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n }\n </div>\n } @else if (cell.column.id === 'expand') {\n <!-- Expand Button with Row Pin Popover -->\n <div class=\"flex items-center justify-center gap-1\">\n @if (cell.row.getCanExpand()) {\n <button\n type=\"button\"\n (click)=\"cell.row.toggleExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"cell.row.getIsExpanded()\" />\n </button>\n }\n @if (\n zConfig().enableRowPinning &&\n cell.row.depth === 0 &&\n !(cell.row.subRows && cell.row.subRows.length > 0) &&\n !hasBodyRowSpan()\n ) {\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n }\n </div>\n } @else if (\n (cell.column.id === 'actionRowPin' || cell.column.id === 'actions') &&\n cell.column.id !== actionColumnInfo()?.columnId\n ) {\n <!-- Actions Column - Row Pin Only (for parent rows) -->\n @if (cell.row.depth === 0 && !hasBodyRowSpan()) {\n <div class=\"flex items-center justify-center\">\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n </div>\n }\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisibleNormal = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisibleNormal) {\n @let editInfo = cell.getContext() | zTableCellEdit: zConfig().columns;\n @if (editInfo.enabled) {\n <!-- Editable Cell -->\n <z-table-edit-cell\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n [zRowIndex]=\"cell.row.index\"\n [zColumnId]=\"cell.column.id\"\n [zValue]=\"cell.getValue()\"\n [zRowUpdate]=\"_rowUpdate()\"\n [zEditConfig]=\"$any(editInfo.config)\"\n (zChange)=\"onCellEdit($any($event))\" />\n } @else if (editInfo.contentEnabled) {\n @let contentConfig = editInfo.contentConfig!;\n @if (\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n ) {\n <z-table-content-editor\n [zValue]=\"cell.getValue()\"\n [zConfig]=\"contentConfig\"\n (zCommit)=\"onContentEditCommit($event, row, cell.column.id, cell.getValue())\"\n (zCancel)=\"onContentEditCancel()\" />\n } @else {\n <button\n type=\"button\"\n class=\"z-table-content-trigger\"\n [attr.data-z-table-edit-row]=\"row.id\"\n [attr.data-z-table-edit-column]=\"cell.column.id\"\n (keydown)=\"onContentEditKeydown($event, row.id, cell.column.id)\"\n (click)=\"onContentEditStart($event, row.id, cell.column.id)\">\n {{ contentConfig.displayValue }}\n </button>\n }\n } @else {\n <ng-container\n *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let cellContent\">\n @if (cellContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n @let isClickableTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickableTpl && onCellClick(row, cell.column.id, cell.getValue())\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { $implicit: cell.getContext() }\" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n @let isClickableIconTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickableIconTpl && onCellClick(row, cell.column.id, cell.getValue())\" />\n } @else {\n <!-- Default/innerHTML rendering -->\n @let isClickableDefaultTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n @let cellTooltipConfigTpl = cell | zTableCellConfig: zConfig() : 'contentTooltip';\n @let cellPopoverConfigTpl = cell | zTableCellConfig: zConfig() : 'contentPopover';\n @let cellPopoverContentTpl = cellPopoverConfigTpl | zTablePopoverConfig: 'content';\n <ng-template #cellPopoverTplNormal>\n @if (cellPopoverContentTpl | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(cellPopoverContentTpl)\" />\n }\n @if (!(cellPopoverContentTpl | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(cellPopoverContentTpl) | zSafeHtml\"></div>\n }\n </ng-template>\n @if (cellPopoverContentTpl) {\n <div\n class=\"z-table-cell-text\"\n z-popover\n z-tooltip\n [zTriggerElement]=\"cellOverlayContentTpl\"\n [zTriggerRef]=\"cellOverlayContentTpl\"\n [zContent]=\"\n (cellTooltipConfigTpl | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"cellPopoverTplNormal\"\n [zPosition]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"\n $any(cellPopoverConfigTpl | zTablePopoverConfig: 'outsideClickClose')\n \"\n [zScrollClose]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'keyboardSafe')\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellOverlayContentTpl\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n } @else {\n <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zTriggerElement]=\"cellTooltipContentTpl\"\n [zContent]=\"\n (cellTooltipConfigTpl | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'maxWidth')\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellTooltipContentTpl\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n }\n }\n </ng-container>\n }\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n\n <!-- Expanded Row Detail -->\n @if (row.getIsExpanded() && row.depth === 0 && !row.subRows?.length) {\n @let resolvedSubTableConfig = row | zTableSubTableConfig: zConfig();\n <tr class=\"z-expanded-row\">\n <td [attr.colspan]=\"renderedColumnCount()\" class=\"p-0\">\n @if (zConfig().expandedRowTemplate) {\n <ng-container *ngTemplateOutlet=\"zConfig().expandedRowTemplate!; context: { $implicit: row }\" />\n } @else if (resolvedSubTableConfig) {\n <div class=\"z-sub-table-container\">\n <z-table [zConfig]=\"$any(resolvedSubTableConfig)\" zVariant=\"borderless\" />\n </div>\n }\n </td>\n </tr>\n }\n </ng-template>\n\n <!-- Render Top Pinned Rows (hidden when filtered data is empty) -->\n @if (!isEmpty()) {\n @for (row of table.getTopRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\n }\n }\n\n <!-- Render Center Rows -->\n @for (item of groupedCenterRowItems(); track item.type === 'group' ? item.id : item.row.id) {\n @if (item.type === 'group') {\n <tr\n class=\"z-group-row\"\n [class.z-group-row-has-totals]=\"item.totals\"\n [class.z-group-row-expanded]=\"item.expanded\"\n [attr.data-group-id]=\"item.id\"\n [attr.data-group-depth]=\"item.depth\">\n @if (item.totals) {\n @let totalColumnMap = groupTotalColumnMap();\n @for (column of orderedLeafColumns(); track column.id; let isFirstGroupCell = $first) {\n <td\n [class.z-group-row-label-cell]=\"isFirstGroupCell\"\n [class.z-group-row-total-cell]=\"!isFirstGroupCell && totalColumnMap[column.id]\"\n [attr.data-column-id]=\"column.id\">\n @if (isFirstGroupCell) {\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + item.depth * 0.75\"\n [attr.aria-expanded]=\"item.expanded\"\n (click)=\"toggleGroupRow(item.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"item.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"(item.columnLabel ? item.columnLabel + ': ' : '') + item.label\">\n @if (item.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ item.columnLabel }}:</span>\n }\n {{ item.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ item.count }}</span>\n }\n @if (item.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n zSizeIcon=\"14\"\n [zWave]=\"false\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(item.columnId)\"></button>\n }\n </div>\n }\n @if (!isFirstGroupCell && totalColumnMap[column.id]) {\n @let totalConfig = groupTotalConfigMap()[column.id];\n @let totalTooltip = totalConfig.tooltip;\n @let totalPopover = totalConfig.popover;\n @let totalPopoverContent = totalPopover | zTablePopoverConfig: 'content';\n <ng-template #groupTotalPopoverTpl>\n @if (totalPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(totalPopoverContent)\" />\n }\n @if (!(totalPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(totalPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n <span\n class=\"z-group-row-total\"\n z-tooltip\n z-popover\n [class]=\"totalConfig.class\"\n [zContent]=\"\n $any((totalTooltip | zTableTooltipConfig: 'content') || item.totals[column.id])\n \"\n [zTooltipPosition]=\"$any(totalTooltip | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(totalTooltip | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(totalTooltip | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(totalTooltip | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(totalTooltip | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'showDelay')\"\n [zTooltipHideDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'hideDelay')\"\n [zTooltipArrow]=\"$any(totalTooltip | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(totalTooltip | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(totalTooltip | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(totalTooltip | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(totalTooltip | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"totalPopoverContent ? groupTotalPopoverTpl : null\"\n [zPosition]=\"$any(totalPopover | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(totalPopover | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(totalPopover | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(totalPopover | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(totalPopover | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(totalPopover | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(totalPopover | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(totalPopover | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(totalPopover | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"$any(totalPopover | zTablePopoverConfig: 'outsideClickClose')\"\n [zScrollClose]=\"$any(totalPopover | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(totalPopover | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(totalPopover | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(totalPopover | zTablePopoverConfig: 'keyboardSafe')\">\n {{ item.totals[column.id] }}\n </span>\n }\n </td>\n }\n } @else {\n <td [attr.colspan]=\"renderedColumnCount()\">\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + item.depth * 0.75\"\n [attr.aria-expanded]=\"item.expanded\"\n (click)=\"toggleGroupRow(item.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"item.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"(item.columnLabel ? item.columnLabel + ': ' : '') + item.label\">\n @if (item.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ item.columnLabel }}:</span>\n }\n {{ item.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ item.count }}</span>\n }\n @if (item.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n zSizeIcon=\"14\"\n [zWave]=\"false\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(item.columnId)\"></button>\n }\n </div>\n </td>\n }\n </tr>\n }\n @if (item.type === 'row') {\n <ng-container\n *ngTemplateOutlet=\"\n rowTemplate;\n context: {\n $implicit: item.row,\n isGroupChild: item.isGroupChild,\n groupDepth: item.groupDepth,\n }\n \" />\n }\n }\n\n <!-- Render Bottom Pinned Rows (hidden when filtered data is empty) -->\n @if (!isEmpty()) {\n @for (row of bottomRowsReversed(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\n }\n }\n </tbody>\n </table>\n }\n </ng-scrollbar>\n }\n <!-- end @else -->\n </div>\n\n <!-- Footer table -->\n @if (hasFooter()) {\n <div\n class=\"z-tfoot-wrapper\"\n [class.z-shadow-footer]=\"shouldFooterShowShadow()\"\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\"\n #tfootWrapper>\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tfoot>\n @for (footerGroup of orderedFooterGroups(); track footerGroup.id; let footerRowIndex = $index) {\n @if (footerGroup | zTableFooterContent: zConfig().columns : footerRowIndex) {\n <tr>\n @for (footer of footerGroup.headers; track footer.id) {\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n footer.column.id === firstVirtualCenterColumnId()\n ) {\n <th\n class=\"z-virtual-column-spacer z-virtual-footer-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></th>\n }\n @let rowSpan = footer | zTableSpan: zConfig().columns : 'footerRowSpan' : footerRowIndex;\n @let shouldRender =\n footer\n | zTableCellRender\n : footerGroup.headers\n : zConfig().columns\n : 'footer'\n : footerRowIndex\n : orderedFooterGroups();\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n footer.column.getIsPinned() !== false ||\n virtualCenterColumnVisibilityMap()[footer.column.id];\n @if (rowSpan && shouldRender && isVirtualColumnVisible) {\n <th\n [attr.data-column-id]=\"footer.column.id\"\n [ngStyle]=\"\n footer.column\n | zTablePinningStyles\n : footer\n : 'footer'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerClass' : footerRowIndex) +\n ' ' +\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex)\n \"\n [style]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerStyle' : footerRowIndex\n \"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (footer | zTableCellPin: 'isLeftPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-at-left-edge]=\"footer | zTableCellOffset: orderedLeafColumns()\"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"footer | zTableSpan: zConfig().columns : 'footerColSpan' : footerRowIndex\">\n @let configFooterContent =\n footer.column.id | zTableFooterRender: zConfig().columns : footerRowIndex;\n @if (configFooterContent !== undefined && configFooterContent !== '') {\n <ng-container *flexRender=\"configFooterContent; props: footer.getContext(); let footerContent\">\n <div\n class=\"flex w-full items-center\"\n [class.justify-center]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex) ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex) ===\n 'text-right'\n \">\n @if (footerContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n <div\n class=\"z-template-content\"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \">\n <ng-container\n *ngTemplateOutlet=\"footerContent; context: { $implicit: footer.getContext() }\" />\n </div>\n } @else if (footerContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n <z-table-icon-text\n [zText]=\"footerContent\"\n [zTooltip]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerTooltip' : footerRowIndex\n \"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \" />\n } @else {\n <!-- Default/string rendering -->\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerTooltip' : footerRowIndex) ||\n footerContent\n \"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \">\n {{ footerContent | translate }}\n </span>\n }\n </div>\n </ng-container>\n }\n </th>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n footer.column.id === lastVirtualCenterColumnId()\n ) {\n <th\n class=\"z-virtual-column-spacer z-virtual-footer-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></th>\n }\n }\n </tr>\n }\n }\n </tfoot>\n </table>\n </div>\n }\n</div>\n\n<!-- Pagination -->\n@if (zConfig().pagination?.enabled !== false) {\n <div class=\"mt-4 flex items-center justify-between gap-4\">\n <div class=\"truncate text-sm text-gray-500\">\n {{ 'i18n_z_ui_table_total_rows' | translate: { total: (paginationTotal() | zFormatNum) } }}\n </div>\n <z-pagination\n [zTotal]=\"paginationTotal()\"\n [(zPageIndex)]=\"pagination().pageIndex\"\n [(zPageSize)]=\"pagination().pageSize\"\n [zPageSizeOptions]=\"zConfig().pagination?.pageSizeOptions ?? [10, 20, 50, 100]\"\n [zShowSizeChanger]=\"zConfig().pagination?.showSizeChanger ?? true\"\n [zShowQuickJumper]=\"zConfig().pagination?.showQuickJumper ?? false\"\n [zShowTotal]=\"false\"\n [zDisabled]=\"zConfig().pagination?.disabled || isLoading() || isProcessing()\"\n (zOnPageChange)=\"onPageChange($event)\" />\n </div>\n}\n\n<!-- Floating Bulk Action Bar -->\n<div class=\"z-bulk-action-bar-origin\" cdkOverlayOrigin #bulkBarOrigin=\"cdkOverlayOrigin\"></div>\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"bulkBarOrigin\"\n [cdkConnectedOverlayOpen]=\"bulkBarMounted()\"\n [cdkConnectedOverlayPositions]=\"bulkBarPositions\"\n [cdkConnectedOverlayHasBackdrop]=\"false\"\n cdkConnectedOverlayPanelClass=\"z-bulk-action-bar-overlay\">\n @if (bulkBarConfig(); as config) {\n <div class=\"z-bulk-action-bar-inner\" [class.z-leaving]=\"bulkBarClosing()\">\n <div class=\"z-bulk-action-bar-count\">\n {{ bulkBarContext()?.selectedRowIds?.length ?? 0 | zFormatNum }}\n {{ config.selectedLabel ?? ('i18n_z_ui_table_selected' | translate) }}\n </div>\n\n <div class=\"z-bulk-action-bar-divider\"></div>\n\n @for (item of bulkBarItems(); track item.action.key) {\n <button\n type=\"button\"\n z-button\n zSize=\"sm\"\n [zType]=\"item.buttonType\"\n [zDisabled]=\"item.disabled\"\n class=\"z-bulk-action-bar-button\"\n [disabled]=\"item.disabled\"\n (click)=\"onBulkActionClick(item.action)\">\n @if (item.action.icon) {\n <z-icon [zType]=\"item.action.icon\" [zSize]=\"item.action.iconSize ?? '14'\" />\n }\n @if (item.action.label) {\n <span>{{ item.action.label | translate }}</span>\n }\n </button>\n }\n </div>\n }\n</ng-template>\n\n<!-- Settings Drawer -->\n<z-drawer\n [(zVisible)]=\"showSettingsDrawer\"\n [zTitle]=\"'i18n_z_ui_table_settings_title' | translate\"\n zPlacement=\"right\"\n zWidth=\"500px\"\n [zShadow]=\"true\"\n [zOkText]=\"null\"\n [zCancelText]=\"'i18n_z_ui_drawer_close' | translate\">\n <div class=\"z-table-settings-drawer px-4\">\n <!-- Display Settings -->\n <div class=\"mb-4\">\n <h4 class=\"text-foreground mb-2 text-sm font-semibold\">{{ 'i18n_z_ui_table_display_settings' | translate }}</h4>\n <p class=\"text-muted-foreground mb-3 text-xs\">{{ 'i18n_z_ui_table_display_settings_desc' | translate }}</p>\n <div class=\"grid grid-cols-2 gap-x-4 gap-y-3\">\n <z-checkbox\n [zChecked]=\"showHorizontalBorder()\"\n [zText]=\"'i18n_z_ui_table_horizontal_border' | translate\"\n (zChange)=\"showHorizontalBorder.set(!showHorizontalBorder())\" />\n <z-checkbox\n [zChecked]=\"showVerticalBorder()\"\n [zText]=\"'i18n_z_ui_table_vertical_border' | translate\"\n (zChange)=\"showVerticalBorder.set(!showVerticalBorder())\" />\n <z-checkbox\n [zChecked]=\"showHeaderFooterShadow()\"\n [zText]=\"'i18n_z_ui_table_header_footer_shadow' | translate\"\n (zChange)=\"showHeaderFooterShadow.set(!showHeaderFooterShadow())\" />\n </div>\n </div>\n\n <!-- Divider -->\n <div class=\"border-border my-4 border-t\"></div>\n\n <!-- Unified Column Settings -->\n <!-- T\u1EA1m t\u1EAFt \u0111i\u1EC1u ki\u1EC7n: @if (zConfig().enableSettings) -->\n <div class=\"mb-4\">\n <h4 class=\"text-foreground mb-2 text-sm font-semibold\">{{ 'i18n_z_ui_table_column_settings' | translate }}</h4>\n <p class=\"text-muted-foreground mb-3 text-xs\">{{ 'i18n_z_ui_table_column_settings_desc' | translate }}</p>\n\n <!-- Unpinned Columns (Draggable) -->\n <div\n cdkDropList\n #columnDropList=\"cdkDropList\"\n [cdkDropListAutoScrollDisabled]=\"true\"\n (cdkDropListDropped)=\"onPendingColumnDrop($event)\"\n class=\"z-column-drop-list space-y-1.5\">\n @for (columnId of columnOrder(); track columnId; let i = $index) {\n @if (columnId !== 'expand' && columnId !== 'select' && columnId !== 'rowDrag') {\n @let column = table.getColumn(columnId);\n @let isPinned = column?.getIsPinned();\n @let isVisible = pendingVisibleColumns().includes(columnId);\n @let isVisibilityDisabled = pendingColumnVisibilityDisabledMap()[columnId];\n @let isGroupedColumn = groupingColumnMap()[columnId];\n @let columnEnablePinningConfig = columnId | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let canPin =\n (columnEnablePinningConfig ?? zConfig().enableColumnPinning ?? true) && column?.getCanPin() !== false;\n @if (!isPinned) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"isGroupedColumn\"\n [cdkDragData]=\"columnId\"\n cdkDragLockAxis=\"y\"\n cdkDragPreviewContainer=\"global\"\n cdkDragPreviewClass=\"z-drag-preview\"\n class=\"z-drag-item border-border bg-card hover:border-primary flex cursor-default items-center gap-2 rounded border px-2 py-1.5 text-sm\"\n [class.opacity-60]=\"!isVisible\">\n <!-- Drag Handle -->\n <z-icon\n cdkDragHandle\n zType=\"lucideGripVertical\"\n zSize=\"14\"\n class=\"text-muted-foreground shrink-0\"\n [class.cursor-pointer]=\"!isGroupedColumn\"\n [class.cursor-default]=\"isGroupedColumn\"\n [class.opacity-40]=\"isGroupedColumn\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n [disabled]=\"isVisibilityDisabled\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n (mousedown)=\"$event.stopPropagation()\"\n class=\"border-input h-4 w-4 shrink-0 cursor-default rounded disabled:opacity-50\" />\n\n <!-- Column Name -->\n <span class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\" [class.text-muted-foreground]=\"!isVisible\">\n {{ columnId | zTableColumnHeader: zConfig().columns | translate }}\n </span>\n @let parents = columnId | zTableColumnParents: zConfig().columns;\n @if (parents) {\n <span class=\"text-muted-foreground truncate text-[0.625rem]\">({{ parents | translate }})</span>\n }\n </span>\n\n <!-- Pin Buttons -->\n @if (canPin) {\n <div class=\"flex shrink-0 items-center gap-0.5\" (mousedown)=\"$event.stopPropagation()\">\n <button\n type=\"button\"\n [disabled]=\"!isVisible || isGroupedColumn || !pinAvailabilityMap()[columnId]?.left\"\n (click)=\"onToggleColumnPin(columnId, 'left')\"\n class=\"text-muted-foreground hover:bg-muted cursor-pointer rounded p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Pin Left\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"12\" />\n </button>\n <button\n type=\"button\"\n [disabled]=\"!isVisible || isGroupedColumn || !pinAvailabilityMap()[columnId]?.right\"\n (click)=\"onToggleColumnPin(columnId, 'right')\"\n class=\"text-muted-foreground hover:bg-muted cursor-pointer rounded p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Pin Right\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"12\" />\n </button>\n </div>\n }\n </div>\n }\n }\n }\n </div>\n\n <!-- Pinned Columns Section -->\n @if (zConfig().enableColumnPinning ?? true) {\n @if (pinnedColumnIds().length > 0) {\n <div class=\"border-border mt-4 border-t pt-4\">\n <h5 class=\"text-muted-foreground mb-2 text-xs font-medium\">\n {{ 'i18n_z_ui_table_pinned_columns' | translate }}\n </h5>\n <div class=\"space-y-1.5\">\n @for (columnId of pinnedColumnIds(); track columnId) {\n @let column = table.getColumn(columnId);\n @let isPinned = column?.getIsPinned();\n @let isVisible = pendingVisibleColumns().includes(columnId);\n @let isVisibilityDisabled = pendingColumnVisibilityDisabledMap()[columnId];\n @let isGroupedColumn = groupingColumnMap()[columnId];\n <div\n class=\"border-border bg-muted/30 flex items-center gap-2 rounded border px-2 py-1.5 text-sm\"\n [class.opacity-60]=\"!isVisible\">\n <!-- Pin Icon -->\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"text-primary shrink-0\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n [disabled]=\"isVisibilityDisabled\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n class=\"border-input h-4 w-4 shrink-0 cursor-default rounded disabled:opacity-50\" />\n\n <!-- Column Name -->\n <span class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\" [class.text-muted-foreground]=\"!isVisible\">\n {{ columnId | zTableColumnHeader: zConfig().columns | translate }}\n </span>\n @let pinnedParents = columnId | zTableColumnParents: zConfig().columns;\n @if (pinnedParents) {\n <span class=\"text-muted-foreground truncate text-[0.625rem]\">\n ({{ pinnedParents | translate }})\n </span>\n }\n </span>\n\n <!-- Position Badge -->\n <span class=\"bg-primary/10 text-primary shrink-0 rounded px-1.5 py-0.5 text-[0.625rem] font-medium\">\n {{\n isPinned === 'start'\n ? ('i18n_z_ui_table_left' | translate)\n : ('i18n_z_ui_table_right' | translate)\n }}\n </span>\n\n <!-- Unpin Button -->\n <button\n type=\"button\"\n [disabled]=\"isGroupedColumn\"\n (click)=\"onToggleColumnPin(columnId, isPinned === 'start' ? 'left' : 'right')\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground cursor-pointer rounded p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Unpin\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </div>\n }\n </div>\n </div>\n }\n }\n </div>\n </div>\n</z-drawer>\n", styles: [":host{display:flex;flex-direction:column;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;overflow-x:visible;--scrollbar-track-thickness: 7px;--scrollbar-track-color: transparent;--scrollbar-thumb-shape: 3px;--z-shadow-left-right: -1.875rem;--z-shadow-left-width: 1.875rem;--z-shadow-left-opacity: 0;--z-shadow-right-left: -1.875rem;--z-shadow-right-width: 1.875rem;--z-shadow-right-opacity: 0;--z-sticky-left-border-color: transparent;--z-sticky-right-border-color: var(--border);--z-cell-selection-background: color-mix(in srgb, var(--primary) 12%, transparent);--z-cell-selection-background-opaque: color-mix(in srgb, var(--primary) 12%, var(--card))}.z-table-container{display:flex;flex-direction:column;position:relative;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;overflow:hidden;border-radius:.3125rem;border:thin solid var(--border);background-color:var(--card)}.z-table-container:focus{outline:none}.z-table-container.z-table-borderless{border:none;border-radius:0;box-shadow:none!important;background-color:transparent}.z-table-container.z-hide-horizontal-border th,.z-table-container.z-hide-horizontal-border td{border-bottom:none!important;border-top:none!important}.z-table-container.z-hide-vertical-border th,.z-table-container.z-hide-vertical-border td{border-left:none!important}.z-table-container.z-hide-pinned-top-border tbody tr.z-pinned-top.z-shadow-bottom>td{border-bottom-color:var(--border)!important}.z-table-container.z-hide-pinned-bottom-border tbody.z-has-bottom-pinned td.z-at-bottom{border-bottom-color:transparent}table{width:fit-content;min-width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed;font-size:.875rem}.z-table-container.z-column-resizing table,.z-table-toolbar{min-width:0}.z-table-toolbar .z-settings-btn{transition:all .15s ease}.z-table-toolbar .z-settings-btn:hover{border-color:var(--muted-foreground)}.z-table-filter-header{min-width:0}.z-table-filter-header button{flex:none}.z-table-filter-header-overflow-chip{animation:z-table-filter-chip-enter .16s ease}@media(prefers-reduced-motion:reduce){.z-table-filter-header-overflow-chip{animation:none}}@keyframes z-table-filter-chip-enter{0%{opacity:0;transform:translate(-.25rem)}to{opacity:1;transform:translate(0)}}.z-bulk-action-bar-origin{position:fixed;left:50%;bottom:1rem;width:1px;height:1px;pointer-events:none}:host ::ng-deep .z-bulk-action-bar-overlay{max-width:calc(100vw - 2rem);margin-bottom:1rem;transform-origin:center bottom}.z-bulk-action-bar-inner{border:thin solid color-mix(in srgb,var(--border) 88%,transparent);border-radius:.4rem;background:color-mix(in srgb,var(--card) 96%,var(--background));color:var(--foreground);box-shadow:0 1rem 2.5rem color-mix(in srgb,var(--foreground) 20%,transparent),0 .25rem .75rem color-mix(in srgb,var(--foreground) 12%,transparent),0 0 0 1px color-mix(in srgb,var(--background) 65%,transparent) inset;display:flex;align-items:center;gap:.5rem;width:max-content;min-height:2.25rem;max-width:calc(100vw - 2rem);padding:.5rem;transform-origin:center bottom;animation:z-bulk-action-bar-enter .18s cubic-bezier(.16,1,.3,1);will-change:opacity,transform}.z-bulk-action-bar-inner.z-leaving{pointer-events:none;animation:z-bulk-action-bar-exit .14s ease-in forwards}.z-bulk-action-bar-count{padding:0 .25rem;white-space:nowrap;font-size:.8125rem;font-weight:500;color:var(--foreground)}.z-bulk-action-bar-divider{width:1px;height:1.5rem;flex:none;background:color-mix(in srgb,var(--border) 88%,transparent)}.z-bulk-action-bar-button{flex:none}@keyframes z-bulk-action-bar-enter{0%{opacity:0;transform:translateY(.875rem)}to{opacity:1;transform:translateY(0)}}@keyframes z-bulk-action-bar-exit{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(.875rem)}}@media(prefers-reduced-motion:reduce){.z-bulk-action-bar-inner{animation:none}}:host ::ng-deep .z-table-cell-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;min-width:0;-webkit-user-select:text;user-select:text}:host ::ng-deep .z-table-cell-text>*,:host ::ng-deep .z-table-cell-text *{display:inline-block;max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}:host ::ng-deep .z-table-cell-content-trigger{display:inline-block;max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}.z-template-content{display:block;width:100%;min-width:0;max-width:100%;overflow:hidden}.z-template-content>*{min-width:0;max-width:100%}.z-template-content>[class*=flex]{min-width:0;max-width:100%}.z-template-content>[class*=flex]>*{min-width:0;flex-shrink:1}.z-template-content>[class*=grid]{min-width:0;max-width:100%}.z-thead-wrapper{flex-shrink:0;background:var(--muted);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;position:relative;z-index:4}.z-thead-wrapper::-webkit-scrollbar{display:none}.z-thead-wrapper th{height:auto;padding:.5rem;text-align:left;vertical-align:middle;font-weight:500;color:var(--foreground);white-space:nowrap;overflow:hidden;background:var(--muted);border-left:thin solid var(--border);border-bottom:thin solid var(--border);-webkit-user-select:none;user-select:none}.z-thead-wrapper th.z-at-left-edge{border-left:none}.z-thead-wrapper th[colspan]{text-align:center;background:var(--muted);font-weight:500;color:var(--foreground)}.z-thead-wrapper.z-shadow-header{box-shadow:0 1px 3px #00000014;position:relative;z-index:15}.z-thead-wrapper.z-shadow-header:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}.z-tbody-wrapper{flex:1;width:100%;max-width:100%;min-width:0;min-height:6.25rem;display:flex;flex-direction:column;overflow:hidden}.z-tbody-scrollbar{flex:1;width:100%;max-width:100%;min-width:0;height:100%}.z-empty-state,.z-loading-state{flex:1 1 0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;min-height:6.25rem;height:100%;color:var(--muted-foreground);font-size:.875rem;animation:z-fade-in .2s ease-out}.z-tbody-scrollbar,.z-tbody-scrollbar table{animation:z-fade-in .2s ease-out}@keyframes z-fade-in{0%{opacity:0;transform:translateY(.25rem)}to{opacity:1;transform:translateY(0)}}.z-tbody-wrapper tr{transition:background-color .15s ease}.z-tbody-wrapper tr:hover,.z-tbody-wrapper tr:hover td[style*=sticky]{background-color:var(--muted)}.z-tbody-wrapper tr.z-pinned-top td.z-sticky-left,.z-tbody-wrapper tr.z-pinned-top td.z-sticky-right,.z-tbody-wrapper tr.z-pinned-bottom td.z-sticky-left,.z-tbody-wrapper tr.z-pinned-bottom td.z-sticky-right{z-index:3}.z-tbody-wrapper tr.z-shadow-bottom{box-shadow:0 1px 3px #00000014!important;position:relative;z-index:15}.z-tbody-wrapper tr.z-shadow-bottom:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d!important}.z-tbody-wrapper tr.z-shadow-top{box-shadow:0 -2px 4px #0000000d!important;position:relative;z-index:15}.z-tbody-wrapper tr.z-shadow-top:where(.dark,.dark *){box-shadow:0 -2px 4px #0003!important}.z-tbody-wrapper td{padding:.5rem 12px;height:var(--z-row-height, 2.375rem);vertical-align:middle;color:var(--foreground);white-space:nowrap;overflow:hidden;background:var(--card);border-left:thin solid var(--border);border-bottom:thin solid var(--border);box-sizing:border-box}.z-tbody-wrapper tbody.z-has-vertical-scroll td.z-at-bottom,.z-tbody-wrapper tbody.z-last-row-touches-bottom td.z-at-bottom{border-bottom-color:transparent}.z-tbody-wrapper tbody.z-has-bottom-pinned td.z-at-bottom{border-bottom-color:var(--border)}.z-tbody-wrapper td.z-at-left-edge{border-left:none}.z-tbody-wrapper td i{color:var(--muted-foreground);font-style:italic}.z-tbody-wrapper td[rowspan]{vertical-align:top;padding-top:.75rem}.z-tbody-wrapper td.z-row-hover{background-color:var(--muted)!important}.z-tbody-wrapper td.z-col-select,.z-tbody-wrapper td.z-col-expand,.z-tbody-wrapper td.z-col-actions{padding:.5rem 4px!important;text-align:center}.z-tbody-wrapper tr.z-child-row td.z-col-select:first-child,.z-tbody-wrapper tr.z-child-row td.z-col-expand:first-child,.z-tbody-wrapper tr.z-child-row td.z-col-actions:first-child{padding-left:0!important}.z-virtual-scroll-inner{position:relative;box-sizing:border-box;width:100%}.z-virtual-row{position:absolute;top:0;left:0;width:100%}tr.z-child-row td:first-child{border-left:.125rem solid var(--primary)!important;padding-left:.75rem!important}tbody tr.z-context-menu-active,tbody tr.z-context-menu-active td{background-color:var(--muted)!important}tbody tr.z-selected,tbody tr.z-selected td{background-color:color-mix(in srgb,var(--primary) 15%,var(--background))!important}tbody tr.z-selected:hover,tbody tr.z-selected:hover td{background-color:color-mix(in srgb,var(--primary) 20%,var(--background))!important}tbody tr.z-indeterminate-selected,tbody tr.z-indeterminate-selected td{background-color:color-mix(in srgb,var(--primary) 10%,var(--background))!important}tbody tr.z-indeterminate-selected:hover,tbody tr.z-indeterminate-selected:hover td{background-color:color-mix(in srgb,var(--primary) 15%,var(--background))!important}tbody tr.z-pinned-top td{background-color:var(--card)!important}tbody tr.z-pinned-top:hover{background-color:var(--muted)}tbody tr.z-pinned-top:hover td{background-color:var(--muted)!important}tbody tr.z-pinned-bottom td{background-color:var(--card)!important}tbody tr.z-pinned-bottom:hover{background-color:var(--muted)}tbody tr.z-pinned-bottom:hover td{background-color:var(--muted)!important}tbody tr.z-pinned-bottom-last>td{border-bottom-color:transparent!important}tbody tr.z-pinned-bottom-first>td{border-top:thin solid var(--border)}:host .z-tbody-wrapper tbody tr:not(.z-pinned-top):not(.z-pinned-bottom):has(+tr.z-pinned-bottom)>td{border-bottom-color:transparent}tr.z-expanded-row>td{border-left:.125rem solid var(--primary);background-color:var(--background)!important}.z-sub-table-container{padding:.75rem 1rem .75rem 3rem;background-color:var(--background)}.z-table-content-trigger{display:block;width:100%;min-width:0;min-height:1.5rem;padding:0;border:0;border-radius:0;background:transparent;color:inherit;font:inherit;line-height:1.5rem;text-align:inherit;outline:0;cursor:text}.z-table-content-trigger:hover{color:var(--primary)}.z-content-edit-active{position:relative;z-index:2}td:has(>.z-table-content-trigger:focus-visible){position:relative;z-index:2}td:has(>.z-table-content-trigger:focus-visible):after{position:absolute;z-index:3;inset:0;border:1px solid var(--primary);content:\"\";pointer-events:none}td.z-cell-selectable{-webkit-user-select:none;user-select:none}td.z-cell-range-selected{position:relative;isolation:isolate}td.z-cell-range-selected:before{position:absolute;z-index:0;box-sizing:border-box;top:var(--z-cell-range-top, 0);right:var(--z-cell-range-right, 0);bottom:var(--z-cell-range-bottom, 0);left:var(--z-cell-range-left, 0);background-color:var(--z-cell-selection-background);content:\"\";pointer-events:none}td.z-cell-range-selected>*{position:relative;z-index:1}td.z-cell-range-top:before{border-top:1px solid var(--primary)}td.z-cell-range-right:before{border-right:1px solid var(--primary)}td.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}td.z-cell-range-left:before{border-left:1px solid var(--primary)}td.z-cell-active{position:relative;z-index:3;background-color:var(--z-cell-selection-background)!important}td.z-cell-active:after{position:absolute;z-index:4;inset:0;border:1px solid var(--primary);content:\"\";pointer-events:none}td.z-content-edit-active{-webkit-user-select:text;user-select:text}td.z-cell-active.z-row-hover,td.z-content-edit-active.z-row-hover{background-color:var(--card)!important}thead th{position:relative}thead th .z-resizer{position:absolute;right:0;top:0;height:100%;width:.5rem;background:transparent;cursor:col-resize;-webkit-user-select:none;user-select:none;touch-action:none;z-index:5}thead th .z-resizer:after{content:\"\";position:absolute;right:0;top:0;height:100%;width:.1875rem;background:#0000001a;opacity:0;transition:opacity .2s ease}thead th .z-resizer:after:where(.dark,.dark *){background:#ffffff1a}thead th .z-resizer:hover:after{opacity:1;background:var(--primary);width:.1875rem}thead th .z-resizer.z-is-resizing:after{opacity:1;background:var(--primary);width:.1875rem}thead th .z-resizer.z-resizer-left{right:auto;left:0}thead th .z-resizer.z-resizer-left:after{right:auto;left:0}.z-thead-wrapper th.z-sticky-left,.z-thead-wrapper th.z-sticky-right,.z-tbody-wrapper th.z-sticky-left,.z-tbody-wrapper th.z-sticky-right,.z-tfoot-wrapper th.z-sticky-left,.z-tfoot-wrapper th.z-sticky-right{background-color:var(--muted);z-index:1;transform:translateZ(0);backface-visibility:hidden}.z-thead-wrapper td.z-sticky-left,.z-thead-wrapper td.z-sticky-right,.z-tbody-wrapper td.z-sticky-left,.z-tbody-wrapper td.z-sticky-right,.z-tfoot-wrapper td.z-sticky-left,.z-tfoot-wrapper td.z-sticky-right{background-color:var(--card);z-index:1;transform:translateZ(0);backface-visibility:hidden}.z-thead-wrapper th.z-sticky-left-last,.z-thead-wrapper td.z-sticky-left-last,.z-tbody-wrapper th.z-sticky-left-last,.z-tbody-wrapper td.z-sticky-left-last,.z-tfoot-wrapper th.z-sticky-left-last,.z-tfoot-wrapper td.z-sticky-left-last{position:relative;overflow:visible;border-right:thin solid var(--z-sticky-left-border-color)}.z-thead-wrapper th.z-sticky-left-last:after,.z-thead-wrapper td.z-sticky-left-last:after,.z-tbody-wrapper th.z-sticky-left-last:after,.z-tbody-wrapper td.z-sticky-left-last:after,.z-tfoot-wrapper th.z-sticky-left-last:after,.z-tfoot-wrapper td.z-sticky-left-last:after{content:\"\";position:absolute;top:0;bottom:0;right:var(--z-shadow-left-right);width:var(--z-shadow-left-width);pointer-events:none;box-shadow:inset 10px 0 8px -8px #0000001a;z-index:10;opacity:var(--z-shadow-left-opacity)}:host-context(.dark) .z-thead-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-thead-wrapper td.z-sticky-left-last:after,:host-context(.dark) .z-tbody-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-tbody-wrapper td.z-sticky-left-last:after,:host-context(.dark) .z-tfoot-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-tfoot-wrapper td.z-sticky-left-last:after{box-shadow:inset 10px 0 10px -8px #0000004d}.z-thead-wrapper.z-scroll-left,.z-tbody-wrapper.z-scroll-left,.z-tfoot-wrapper.z-scroll-left{--z-shadow-left-opacity: 1}.z-thead-wrapper.z-scroll-left:where(.dark,.dark *),.z-tbody-wrapper.z-scroll-left:where(.dark,.dark *),.z-tfoot-wrapper.z-scroll-left:where(.dark,.dark *){--z-sticky-left-border-color: var(--border)}.z-thead-wrapper th.z-sticky-right-first,.z-thead-wrapper td.z-sticky-right-first,.z-tbody-wrapper th.z-sticky-right-first,.z-tbody-wrapper td.z-sticky-right-first,.z-tfoot-wrapper th.z-sticky-right-first,.z-tfoot-wrapper td.z-sticky-right-first{position:relative;overflow:visible;border-left:thin solid var(--z-sticky-right-border-color)}.z-thead-wrapper th.z-sticky-right-first:before,.z-thead-wrapper td.z-sticky-right-first:before,.z-tbody-wrapper th.z-sticky-right-first:before,.z-tbody-wrapper td.z-sticky-right-first:before,.z-tfoot-wrapper th.z-sticky-right-first:before,.z-tfoot-wrapper td.z-sticky-right-first:before{content:\"\";position:absolute;top:0;bottom:0;left:var(--z-shadow-right-left);width:var(--z-shadow-right-width);pointer-events:none;box-shadow:inset -10px 0 8px -8px #0000001a;z-index:10;opacity:var(--z-shadow-right-opacity)}:host-context(.dark) .z-thead-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-thead-wrapper td.z-sticky-right-first:before,:host-context(.dark) .z-tbody-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-tbody-wrapper td.z-sticky-right-first:before,:host-context(.dark) .z-tfoot-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-tfoot-wrapper td.z-sticky-right-first:before{box-shadow:inset -10px 0 10px -8px #0000004d}.z-thead-wrapper.z-scroll-right,.z-tbody-wrapper.z-scroll-right,.z-tfoot-wrapper.z-scroll-right{--z-shadow-right-opacity: 1}.z-thead-wrapper.z-scroll-right:not(:where(.dark,.dark *)),.z-tbody-wrapper.z-scroll-right:not(:where(.dark,.dark *)),.z-tfoot-wrapper.z-scroll-right:not(:where(.dark,.dark *)){--z-sticky-right-border-color: transparent}.z-pinning-overflow{--z-shadow-left-opacity: 0 !important;--z-shadow-right-opacity: 0 !important;--z-sticky-left-border-color: transparent !important;--z-sticky-right-border-color: transparent !important}.z-pinning-overflow .z-sticky-left,.z-pinning-overflow .z-sticky-right{position:relative!important;right:auto!important;left:auto!important}.z-pinning-overflow .z-sticky-left-last:after,.z-pinning-overflow .z-sticky-right-first:before,.z-pinning-overflow .z-sticky-right-last:after{display:none!important}.z-thead-wrapper th.z-sticky-right-last,.z-tfoot-wrapper th.z-sticky-right-last{position:relative}.z-thead-wrapper th.z-sticky-right-last:after,.z-tfoot-wrapper th.z-sticky-right-last:after{content:\"\";position:absolute;top:0;bottom:0;right:-1.875rem;width:1.875rem;background:var(--muted);pointer-events:none}.z-tfoot-wrapper{flex-shrink:0;width:100%;max-width:100%;min-width:0;background:var(--muted);overflow-x:hidden;overflow-y:hidden;touch-action:pan-y pinch-zoom}.z-tfoot-wrapper th{height:auto;padding:.5rem 12px;text-align:left;vertical-align:middle;font-weight:500;font-size:.75rem;color:var(--muted-foreground);text-transform:uppercase;letter-spacing:.5px;background:var(--muted);border-left:thin solid var(--border);border-top:thin solid var(--border)}.z-tfoot-wrapper th.z-at-left-edge{border-left:none}.z-tfoot-wrapper.z-shadow-footer{box-shadow:0 -2px 4px #0000000d;position:relative;z-index:15}.z-tfoot-wrapper.z-shadow-footer:where(.dark,.dark *){box-shadow:0 -2px 4px #0003}.z-pin-btn{padding:.125rem 4px;border-radius:.25rem;color:var(--muted-foreground);transition:all .15s ease}.z-pin-btn:hover{background-color:var(--muted);color:var(--foreground)}.z-pin-btn.z-pin-btn-active{color:var(--primary);background-color:var(--primary)}.z-pin-btn.z-pin-btn-active:hover{background-color:var(--primary);opacity:.8}.z-row-pin-trigger{opacity:1}.z-row-pin-trigger:focus-visible,.z-row-pin-trigger.z-popover-open{background-color:color-mix(in srgb,var(--foreground) 8%,transparent);color:var(--foreground)}.z-row-pin-trigger:active{background-color:color-mix(in srgb,var(--foreground) 12%,transparent)}.z-row-pin-trigger.text-primary{color:var(--primary)}.z-row-pin-unpin-trigger{color:var(--muted-foreground);outline:none}.z-row-pin-unpin-trigger:hover{color:var(--destructive);background-color:color-mix(in srgb,var(--destructive) 10%,transparent)}.z-row-pin-unpin-trigger:focus,.z-row-pin-unpin-trigger:focus-visible{color:var(--muted-foreground);background-color:transparent;outline:none;box-shadow:none}.z-row-pin-unpin-trigger:active{color:var(--destructive);background-color:color-mix(in srgb,var(--destructive) 14%,transparent)}.z-header-pin-trigger{opacity:1}.z-header-pin-trigger.text-primary{color:var(--primary)}th{overflow:hidden}th .z-header-content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}th .z-header-text-wrapper{transition:background-color .15s ease;border-radius:.25rem;min-width:0;overflow:hidden;flex-shrink:1}th .z-header-text-wrapper.z-has-options:hover,th .z-header-text-wrapper.z-has-options:focus-visible,th .z-header-text-wrapper.z-has-options.z-popover-open{background-color:color-mix(in srgb,var(--foreground) 8%,transparent);outline:none}th .z-header-text-wrapper.z-has-options:active{background-color:color-mix(in srgb,var(--foreground) 12%,transparent)}.z-column-menu-item{line-height:1.25rem}.z-column-menu-item:focus-visible,.z-column-menu-item.z-popover-open{background-color:var(--muted);outline:none}.cdk-drag-preview,.z-drag-preview{box-sizing:border-box;border:1px solid var(--primary);border-radius:.375rem;background-color:var(--card);box-shadow:0 5px 20px #0003;overflow:hidden;pointer-events:none;z-index:10000!important}.cdk-drag-preview:where(.dark,.dark *),.z-drag-preview:where(.dark,.dark *){box-shadow:0 5px 20px #00000080}.cdk-drag-placeholder{box-sizing:border-box;border:2px dashed var(--primary);border-radius:.375rem;background-color:color-mix(in srgb,var(--primary) 10%,var(--background))}.cdk-drag-animating,.cdk-drop-list-dragging .cdk-drag:not(.cdk-drag-placeholder){transition:transform .1s cubic-bezier(0,0,.2,1)}.z-drag-item.cdk-drag-dragging{transition:none!important}.z-table-drag-preview{box-sizing:border-box;border-radius:.375rem;background-color:var(--card);border:1px solid var(--primary);box-shadow:0 10px 24px #00000029;overflow:hidden;z-index:10000!important;pointer-events:none}.z-table-drag-preview:where(.dark,.dark *){box-shadow:0 5px 20px #00000080}.z-table-drag-preview-row{border:0;border-radius:.125rem;background-color:var(--background);box-shadow:0 8px 20px #0000001f,inset 0 0 0 1px color-mix(in srgb,var(--primary) 45%,var(--border))}.z-table-drag-preview-row table,.z-table-drag-preview-row tbody,.z-table-drag-preview-row tr{height:100%}.z-table-drag-preview-row td{vertical-align:middle!important;background-color:var(--background)}.z-table-drag-source{display:none!important}.z-virtual-row.z-table-drag-source{display:block!important;pointer-events:none;outline:1px solid var(--border);outline-offset:-1px}.z-virtual-row.z-table-drag-source td{color:color-mix(in srgb,var(--foreground) 45%,transparent);border-color:var(--border)!important;background-color:var(--card)!important}.z-virtual-row.z-table-drag-source td>*{opacity:.45}[data-z-table-drag-handle]{touch-action:none;-webkit-user-select:none;user-select:none}.z-column-drop-list{min-height:3.125rem;overscroll-behavior:contain}.z-column-drop-list.cdk-drop-list-dragging{overflow:clip}.z-table-drag-placeholder{width:100%;min-height:2.625rem;box-sizing:border-box;border:2px dashed var(--primary);border-radius:.375rem;background-color:color-mix(in srgb,var(--primary) 10%,var(--background));pointer-events:none}.z-table-drag-placeholder-row>td{padding:0!important;border:0!important;background:transparent!important}.z-table-drag-placeholder-row .z-table-drag-placeholder{border-radius:0;background-color:color-mix(in srgb,var(--primary) 10%,transparent)}.z-table-drag-placeholder-virtual{position:absolute;top:0;left:0;z-index:20;border-radius:0}.z-tbody-wrapper tr.z-group-row td{background:var(--card);border-top:none;border-bottom:1px solid var(--border)}.z-virtual-row tr.z-group-row td{background:var(--card);border-top:none;border-bottom:none}.z-group-row-sticky-wrapper{display:inline-flex;align-items:center;translate:var(--z-scroll-x, 0px) 0}.z-table-container:not(.z-hide-horizontal-border) .z-virtual-row:after{content:\"\";position:absolute;right:0;bottom:0;left:0;z-index:3;height:1px;background:var(--border);pointer-events:none}.z-tbody-wrapper tr.z-group-child-row td.z-at-left-edge,.z-virtual-row tr.z-group-child-row td.z-at-left-edge{border-left:2px solid var(--primary)!important;padding-left:var(--z-group-content-indent, .75rem)}.z-group-row-trigger{display:inline-flex;min-height:2rem;max-width:100%;align-items:center;gap:.5rem;padding:.25rem .5rem .25rem .75rem;color:var(--primary);font-size:.8125rem;font-weight:600;vertical-align:middle;cursor:pointer}.z-group-row-remove{margin-left:.125rem;color:var(--muted-foreground);vertical-align:middle}.z-group-row-remove:hover,.z-group-row-remove:focus-visible{color:var(--destructive);background:color-mix(in srgb,var(--destructive) 10%,transparent);outline:none}.z-group-row-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-column-label{color:color-mix(in srgb,var(--primary) 65%,var(--foreground));font-weight:500;margin-right:.25rem}.z-group-row-count{display:inline-flex;min-width:1.25rem;height:1.25rem;align-items:center;justify-content:center;padding:0 .375rem;border-radius:999px;background:var(--primary);color:var(--primary-foreground);font-size:.6875rem;font-weight:600}.z-group-row-loading{display:inline-flex;align-items:center;margin-left:.25rem}.z-group-row-has-totals td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-has-totals .z-group-row-label-cell{position:sticky;left:0;z-index:2;background:var(--card)}.z-group-row-has-totals .z-group-row-label-cell .z-group-row-sticky-wrapper{max-width:100%;translate:none}.z-group-row-total{display:inline-block;max-width:100%;color:var(--foreground);font-size:.8125rem;font-weight:600;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-total-cell{text-align:right}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-selected:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:before{position:absolute!important;z-index:0!important;box-sizing:border-box!important;top:var(--z-cell-range-top, 0)!important;right:var(--z-cell-range-right, 0)!important;bottom:var(--z-cell-range-bottom, 0)!important;left:var(--z-cell-range-left, 0)!important;width:auto!important;background-color:var(--z-cell-selection-background-opaque)!important;box-shadow:none!important;content:\"\"!important;pointer-events:none!important;opacity:1!important}:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:after{display:none!important}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-top:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-top:before{border-top:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-right:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-right:before{border-right:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-bottom:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-left:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-left:before{border-left:1px solid var(--primary)}:host-context(.z-table-pointer-dragging) .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-selected:before,:host-context(.z-table-pointer-dragging) .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:before{background-color:transparent!important}:host td.z-cell-range-selected:before{position:absolute;z-index:0;box-sizing:border-box;top:var(--z-cell-range-top, 0);right:var(--z-cell-range-right, 0);bottom:var(--z-cell-range-bottom, 0);left:var(--z-cell-range-left, 0);background-color:var(--z-cell-selection-background);box-shadow:none;content:\"\";pointer-events:none;opacity:1}:host td.z-cell-range-top:before{border-top:1px solid var(--primary)}:host td.z-cell-range-right:before{border-right:1px solid var(--primary)}:host td.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}:host td.z-cell-range-left:before{border-left:1px solid var(--primary)}:host-context(.z-table-pointer-dragging) td.z-row-hover{background-color:var(--background)!important}:host td.z-cell-active,:host td.z-cell-active.z-row-hover{background-color:var(--z-cell-selection-background)!important}:host td.z-content-edit-active.z-row-hover{background-color:var(--card)!important}:host tr.z-pinned-top td.z-cell-active,:host tr.z-pinned-top td.z-cell-active.z-row-hover,:host tr.z-pinned-bottom td.z-cell-active,:host tr.z-pinned-bottom td.z-cell-active.z-row-hover,:host td.z-cell-active.z-sticky-left,:host td.z-cell-active.z-sticky-left.z-row-hover,:host td.z-cell-active.z-sticky-right,:host td.z-cell-active.z-sticky-right.z-row-hover{background-color:var(--z-cell-selection-background-opaque)!important}:host tr.z-pinned-top td.z-cell-range-selected,:host tr.z-pinned-bottom td.z-cell-range-selected,:host td.z-cell-range-selected.z-sticky-left,:host td.z-cell-range-selected.z-sticky-right{background-color:var(--card)}:host tr.z-pinned-top td.z-cell-range-selected:before,:host tr.z-pinned-bottom td.z-cell-range-selected:before,:host td.z-cell-range-selected.z-sticky-left:before,:host td.z-cell-range-selected.z-sticky-right:before{background-color:var(--z-cell-selection-background-opaque)}:host-context(.z-table-pointer-dragging) td.z-cell-range-selected,:host-context(.z-table-pointer-dragging) td.z-cell-range-selected.z-row-hover,:host-context(.z-table-pointer-dragging) td.z-cell-active,:host-context(.z-table-pointer-dragging) td.z-cell-active.z-row-hover{background-color:var(--card)!important}:host-context(.z-table-pointer-dragging) td.z-cell-range-selected:before{background-color:transparent}:host .z-tbody-wrapper tbody tr.z-group-child-row:has(+tr.z-group-row)>td.z-at-bottom{border-bottom-color:var(--border)}:host .z-virtual-row:has(tr.z-group-child-row):has(+.z-virtual-row tr.z-group-row) tr.z-group-child-row>td.z-at-bottom{border-bottom-color:var(--border)}.z-thead-wrapper th.z-virtual-column-spacer,.z-tfoot-wrapper th.z-virtual-column-spacer{box-sizing:border-box;padding:0!important;background:var(--muted);border-left:thin solid var(--border)}.z-thead-wrapper th.z-virtual-header-spacer{border-bottom:thin solid var(--border)}.z-tfoot-wrapper th.z-virtual-footer-spacer{border-top:thin solid var(--border)}.z-tbody-wrapper td.z-virtual-column-spacer{box-sizing:border-box;height:auto;padding:0!important;background:var(--card);border-left:thin solid var(--border);border-bottom:thin solid var(--border)}.z-tbody-wrapper tr:hover td.z-virtual-column-spacer{background-color:var(--muted)}.z-table-settings-drawer input[type=checkbox]{appearance:none;-webkit-appearance:none;-moz-appearance:none;width:1rem;height:1rem;border:thin solid var(--input);border-radius:.25rem;background-color:var(--background);cursor:pointer;position:relative;transition:all .2s ease}.z-table-settings-drawer input[type=checkbox]:hover{border-color:var(--primary)}.z-table-settings-drawer input[type=checkbox]:checked{background-color:var(--primary);border-color:var(--primary)}.z-table-settings-drawer input[type=checkbox]:checked:after{content:\"\";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:.375rem;height:.625rem;border:solid var(--primary-foreground);border-width:0 .125rem .125rem 0;transform:translate(-50%,-60%) rotate(45deg)}.z-table-settings-drawer input[type=checkbox]:disabled{opacity:.5;cursor:not-allowed}.z-virtual-pinned-top{position:sticky;top:0;left:0;z-index:3;width:100%}.z-virtual-pinned-bottom{position:sticky;bottom:0;left:0;z-index:3;width:100%}\n"], dependencies: [{ kind: "component", type: ZTableComponent, selector: "z-table", inputs: ["zClass", "zConfig", "zLoading", "zKey", "zVariant"], outputs: ["zChange", "zControl"], exportAs: ["zTable"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "component", type: NgScrollbar, selector: "ng-scrollbar:not([externalViewport]), [ngScrollbar]", exportAs: ["ngScrollbar"] }, { kind: "directive", type: FlexRenderDirective, selector: "ng-template[flexRender]", inputs: ["flexRender", "flexRenderProps", "flexRenderInjector"] }, { 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: ZTableDraggableDirective, selector: "[z-table-draggable]", inputs: ["z-table-draggable", "z-table-drag-table-id", "z-table-drag-item-id", "z-table-drag-disabled", "z-table-drag-handle"] }, { kind: "directive", type: ZTableDropTargetDirective, selector: "[z-table-drop-target]", inputs: ["z-table-drop-target", "z-table-drop-table-id", "z-table-drop-item-id", "z-table-drop-disabled"], outputs: ["zTableDropped"] }, { kind: "component", type: ZCheckboxComponent, selector: "z-checkbox", inputs: ["class", "zType", "zSize", "zLabel", "zText", "zDisabled", "zIndeterminate", "zValue", "zOptions", "zOrientation", "zCheckAll", "zCheckAllText", "zChecked", "zGroupValue"], outputs: ["zChange", "zGroupChange", "zOnBlur", "zOnFocus", "zControl", "zEvent", "zCheckedChange", "zGroupValueChange"] }, { kind: "component", type: ZEmptyComponent, selector: "z-empty", inputs: ["class", "zType", "zIcon", "zIconSize", "zSize", "zMessage", "zDescription"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zAnimatedType", "zAnimate", "zAnimationTrigger", "zSize", "zStrokeWidth", "zSvg"] }, { kind: "component", type: ZInputComponent, selector: "z-input", inputs: ["class", "zType", "zSize", "zAlign", "zLabel", "zLabelClass", "zPlaceholder", "zRequired", "zDisabled", "zReadonly", "zLoading", "zLoadingOutline", "zPrefix", "zSuffix", "zMin", "zMax", "zStep", "zShowArrows", "zMask", "zDecimalPlaces", "zAllowNegative", "zThousandSeparator", "zDecimalMarker", "zValidators", "zAsyncValidators", "zAsyncDebounce", "zAsyncValidateOn", "zShowPasswordToggle", "zSearch", "zDebounce", "zAutofocus", "zAutoComplete", "zAllowClear", "zAutoSizeContent", "zRows", "zResize", "zMaxLength", "zAutoSuggest", "zColorConfig"], outputs: ["zOnSearch", "zOnChange", "zOnBlur", "zOnFocus", "zOnKeydown", "zOnEnter", "zOnColorCollapse", "zControl", "zEvent"], exportAs: ["zInput"] }, { kind: "component", type: ZLoadingComponent, selector: "z-loading", inputs: ["class", "zSpinner", "zSize", "zColor", "zText", "zOverlay", "zOverlayType", "zFullscreen", "zLoading"] }, { kind: "component", type: ZSkeletonComponent, selector: "z-skeleton", inputs: ["class", "zType", "zSize", "zWidth", "zHeight", "zRows", "zGap", "zAnimated", "zRadius"] }, { kind: "component", type: ZDrawerComponent, selector: "z-drawer", inputs: ["class", "zBodyClass", "zVisible", "zTitle", "zDescription", "zWidth", "zHeight", "zPlacement", "zClosable", "zMaskClosable", "zDisableShadow", "zHeaderBorder", "zFooterBorder", "zHideFooter", "zHideHeader", "zOkText", "zCancelText", "zOkDestructive", "zOkDisabled", "zLoading", "zOverlay", "zShadow", "zShape", "zContentLoading", "zSkeletonRows", "zExpand"], outputs: ["zOnOk", "zOnCancel", "zAfterClose", "zScrollbar", "zVisibleChange"], exportAs: ["zDrawer"] }, { kind: "component", type: ZPaginationComponent, selector: "z-pagination", inputs: ["zPageIndex", "zPageSize", "zTotal", "zPageSizeOptions", "zShowSizeChanger", "zShowQuickJumper", "zShowTotal", "zSimple", "zSize", "zDisabled", "zTotalLabel", "zPerPageLabel", "zGoToLabel"], outputs: ["zOnPageChange", "zPageIndexChange", "zPageSizeChange"] }, { kind: "component", type: ZTableFilterComponent, selector: "z-table-filter", inputs: ["zColumn", "zTable", "zResetVersion", "zSortingState", "zEnableMultiSort"] }, { kind: "component", type: ZTableEditCellComponent, selector: "z-table-edit-cell", inputs: ["zRow", "zRowId", "zRowIndex", "zColumnId", "zValue", "zEditConfig", "zRowUpdate"], outputs: ["zChange"] }, { kind: "directive", type: ZPopoverDirective, selector: "[z-popover]", inputs: ["zPopoverContent", "zPosition", "zTrigger", "zPopoverTrigger", "zClass", "zShowDelay", "zHideDelay", "zDisabled", "zOffset", "zPopoverWidth", "zTriggerRef", "zManualClose", "zOutsideClickClose", "zScrollClose", "zSticky", "zShowArrow", "zKeyboardSafe"], outputs: ["zShow", "zHide", "zHideStart", "zControl", "zPositionChange", "zOutsideClick"], exportAs: ["zPopover"] }, { kind: "component", type: ZButtonComponent, selector: "z-button, button[z-button], a[z-button]", inputs: ["class", "zType", "zSize", "zShape", "zLabel", "zLoading", "zDisabled", "zTypeIcon", "zAnimatedTypeIcon", "zAnimateIcon", "zAnimationTriggerIcon", "zSizeIcon", "zStrokeWidthIcon", "zWave"], exportAs: ["zButton"] }, { kind: "directive", type: ZTooltipDirective, selector: "[z-tooltip], [zTooltip]", inputs: ["zContent", "zPosition", "zTooltipPosition", "zTrigger", "zTooltipTrigger", "zTooltipType", "zTooltipSize", "zClass", "zTooltipClass", "zShowDelay", "zTooltipShowDelay", "zHideDelay", "zTooltipHideDelay", "zArrow", "zTooltipArrow", "zDisabled", "zTooltipDisabled", "zOffset", "zTooltipOffset", "zAutoDetect", "zTriggerElement", "zAlwaysShow", "zMaxWidth"], outputs: ["zShow", "zHide"], exportAs: ["zTooltip"] }, { kind: "directive", type: ZTableResizeDirective, selector: "[z-table-resize],[zTableResize]", inputs: ["zTableResize"] }, { kind: "directive", type: ZTableRowHoverDirective, selector: "[z-table-row-hover], [zTableRowHover]", inputs: ["zTableRowHover"] }, { kind: "component", type: ZTableIconTextComponent, selector: "z-table-icon-text", inputs: ["zText", "zTooltip", "zTriggerElement"] }, { kind: "component", type: ZTableActionsComponent, selector: "z-table-actions", inputs: ["zConfig", "zRow", "zRowId", "zDropdownButtonSize"], outputs: ["zActionClick"] }, { kind: "component", type: ZTableContentEditorComponent, selector: "z-table-content-editor", inputs: ["zValue", "zConfig"], outputs: ["zCommit", "zCancel"] }, { kind: "pipe", type: ZTableIsTemplateRefPipe, name: "zTableIsTemplateRef" }, { kind: "pipe", type: ZTableHasIconPipe, name: "zTableHasIcon" }, { kind: "pipe", type: ZTableCellBottomPipe, name: "zTableCellBottom" }, { kind: "pipe", type: ZTableCellClickablePipe, name: "zTableCellClickable" }, { kind: "pipe", type: ZTableCellConfigPipe, name: "zTableCellConfig" }, { kind: "pipe", type: ZTableCellEditPipe, name: "zTableCellEdit" }, { kind: "pipe", type: ZTableCellOffsetPipe, name: "zTableCellOffset" }, { kind: "pipe", type: ZTableCellPinPipe, name: "zTableCellPin" }, { kind: "pipe", type: ZTableCellVisiblePipe, name: "zTableCellVisible" }, { kind: "pipe", type: ZTableColumnConfigPipe, name: "zTableColumnConfig" }, { kind: "pipe", type: ZTableColumnHeaderPipe, name: "zTableColumnHeader" }, { kind: "pipe", type: ZTableColumnParentsPipe, name: "zTableColumnParents" }, { kind: "pipe", type: ZTableFooterContentPipe, name: "zTableFooterContent" }, { kind: "pipe", type: ZTableFooterRenderPipe, name: "zTableFooterRender" }, { kind: "pipe", type: ZTablePinningStylesPipe, name: "zTablePinningStyles" }, { kind: "pipe", type: ZTablePopoverConfigPipe, name: "zTablePopoverConfig" }, { kind: "pipe", type: ZTableRowPipe, name: "zTableRow" }, { kind: "pipe", type: ZTableRowConfigPipe, name: "zTableRowConfig" }, { kind: "pipe", type: ZTableSpanPipe, name: "zTableSpan" }, { kind: "pipe", type: ZTableSubTableConfigPipe, name: "zTableSubTableConfig" }, { kind: "pipe", type: ZTableTooltipConfigPipe, name: "zTableTooltipConfig" }, { kind: "pipe", type: ZTableCellRenderPipe, name: "zTableCellRender" }, { kind: "pipe", type: ZFormatNumPipe, name: "zFormatNum" }, { kind: "pipe", type: ZSafeHtmlPipe, name: "zSafeHtml" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
11120
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: ZTableComponent, isStandalone: true, selector: "z-table", inputs: { zClass: { classPropertyName: "zClass", publicName: "zClass", isSignal: true, isRequired: false, transformFunction: null }, zConfig: { classPropertyName: "zConfig", publicName: "zConfig", isSignal: true, isRequired: false, transformFunction: null }, zLoading: { classPropertyName: "zLoading", publicName: "zLoading", isSignal: true, isRequired: false, transformFunction: null }, zKey: { classPropertyName: "zKey", publicName: "zKey", isSignal: true, isRequired: false, transformFunction: null }, zVariant: { classPropertyName: "zVariant", publicName: "zVariant", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { zChange: "zChange", zControl: "zControl" }, host: { classAttribute: "z-table block relative py-1" }, providers: [TranslatePipe, ZTableDragService], viewQueries: [{ propertyName: "theadWrapper", first: true, predicate: ["theadWrapper"], descendants: true, isSignal: true }, { propertyName: "tableContainer", first: true, predicate: ["tableContainer"], descendants: true, isSignal: true }, { propertyName: "tbodyContainer", first: true, predicate: ["tbodyContainer"], descendants: true, isSignal: true }, { propertyName: "tbodyWrapper", first: true, predicate: ["tbodyWrapper"], descendants: true, isSignal: true }, { propertyName: "tbodyScrollbar", first: true, predicate: ["tbodyWrapper"], descendants: true, isSignal: true }, { propertyName: "tfootWrapper", first: true, predicate: ["tfootWrapper"], descendants: true, isSignal: true }, { propertyName: "expandedRowTemplate", first: true, predicate: ["expandedRowTemplate"], descendants: true, isSignal: true }, { propertyName: "virtualRowElements", predicate: ["virtualRow"], descendants: true, isSignal: true }, { propertyName: "groupRowElements", predicate: ["groupRow"], descendants: true, isSignal: true }], exportAs: ["zTable"], ngImport: i0, template: "<!-- Toolbar: Search & Settings -->\n@if (isSearchEnabled() || zConfig().enableSettings) {\n <div class=\"z-table-toolbar mb-2 flex items-center justify-between gap-4\">\n <!-- Search -->\n @if (isSearchEnabled()) {\n @let config = searchConfig();\n <z-input\n [class]=\"config?.width ?? 'w-64'\"\n [zSize]=\"config?.size ?? 'sm'\"\n [zPlaceholder]=\"config?.placeholder ?? 'i18n_z_ui_table_search' | translate\"\n [zSearch]=\"true\"\n [zDebounce]=\"config?.debounceTime ?? 300\"\n (zOnSearch)=\"onSearchChange($event)\" />\n } @else {\n <div></div>\n }\n\n <!-- Settings Button -->\n @if (zConfig().enableSettings) {\n <z-button zType=\"outline\" zSize=\"sm\" zTypeIcon=\"lucideSettings\" (click)=\"openSettingsDrawer()\">\n {{ 'i18n_z_ui_table_settings' | translate }}\n </z-button>\n }\n </div>\n}\n\n@if (zConfig().enableFilterHeader && appliedFilterChips().length > 0) {\n <div class=\"z-table-filter-header mb-2 flex min-w-0 items-center gap-2\">\n <div class=\"flex min-w-0 flex-1 flex-wrap items-center gap-1.5\">\n @for (chip of visibleAppliedFilterChips(); track chip.id) {\n <span\n class=\"border-border bg-muted/60 text-foreground inline-flex max-w-80 min-w-0 shrink-0 items-center gap-1 rounded-sm border px-2 py-1 text-[0.8125rem] shadow-xs\">\n <span class=\"font-medium whitespace-nowrap\">{{ chip.label }}</span>\n <span class=\"text-muted-foreground\">:</span>\n <span class=\"truncate\" z-tooltip [zContent]=\"chip.value\" zTooltipTrigger=\"hover\" zTooltipPosition=\"top\">\n {{ chip.value }}\n </span>\n <button\n type=\"button\"\n class=\"hover:bg-destructive/10 hover:text-destructive focus-visible:ring-ring -mr-1 inline-flex size-5 cursor-pointer items-center justify-center rounded-sm outline-none focus-visible:ring-2\"\n [attr.aria-label]=\"'i18n_z_ui_table_filter_remove' | translate\"\n (click)=\"clearAppliedFilterChip(chip)\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </span>\n }\n @if (hiddenAppliedFilterChipCount() > 0 && isFilterHeaderExpanded()) {\n @for (chip of overflowAppliedFilterChips(); track chip.id) {\n <span\n class=\"z-table-filter-header-overflow-chip border-border bg-muted/60 text-foreground inline-flex max-w-80 min-w-0 shrink-0 items-center gap-1 rounded-sm border px-2 py-1 text-[0.8125rem] shadow-xs\"\n [attr.aria-hidden]=\"!isFilterHeaderExpanded()\">\n <span class=\"font-medium whitespace-nowrap\">{{ chip.label }}</span>\n <span class=\"text-muted-foreground\">:</span>\n <span class=\"truncate\" z-tooltip [zContent]=\"chip.value\" zTooltipTrigger=\"hover\" zTooltipPosition=\"top\">\n {{ chip.value }}\n </span>\n <button\n type=\"button\"\n class=\"hover:bg-destructive/10 hover:text-destructive focus-visible:ring-ring -mr-1 inline-flex size-5 cursor-pointer items-center justify-center rounded-sm outline-none focus-visible:ring-2\"\n [attr.aria-label]=\"'i18n_z_ui_table_filter_remove' | translate\"\n (click)=\"clearAppliedFilterChip(chip)\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </span>\n }\n }\n @if (hiddenAppliedFilterChipCount() > 0) {\n <button\n type=\"button\"\n class=\"text-primary hover:bg-primary/10 focus-visible:ring-ring inline-flex h-7 cursor-pointer items-center rounded-sm px-2 text-xs font-medium outline-none focus-visible:ring-2\"\n (click)=\"toggleFilterHeaderExpanded()\">\n {{\n isFilterHeaderExpanded()\n ? ('i18n_z_ui_table_show_less' | translate)\n : ('i18n_z_ui_table_show_more' | translate: { count: hiddenAppliedFilterChipCount() })\n }}\n </button>\n }\n <button\n type=\"button\"\n class=\"bg-destructive/10 text-destructive hover:bg-destructive/20 dark:bg-destructive/15 dark:text-destructive-foreground dark:hover:bg-destructive/25 focus-visible:ring-destructive inline-flex h-7 cursor-pointer items-center gap-1 rounded-sm px-2 text-xs font-medium shadow-xs outline-none focus-visible:ring-2\"\n (click)=\"clearAppliedFilters()\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_clear_filter' | translate }}</span>\n </button>\n </div>\n </div>\n}\n\n<div\n #tableContainer\n [class]=\"classTable()\"\n [class.z-pinning-overflow]=\"!isPinnedLayoutWithinContainer()\"\n [class.z-hide-horizontal-border]=\"!showHorizontalBorder()\"\n [class.z-hide-vertical-border]=\"!showVerticalBorder()\"\n [class.z-hide-pinned-top-border]=\"hasScrollTop()\"\n [class.z-hide-pinned-bottom-border]=\"hasScrollBottom()\"\n [style.width]=\"zConfig().width\"\n [style.height]=\"zConfig().height\"\n [style.max-height]=\"zConfig().maxHeight\"\n [style.min-height]=\"zConfig().minHeight\"\n [attr.tabindex]=\"canUseContentRowInsert() || canUseCellSelection() ? 0 : null\"\n (keydown)=\"onContentTableKeydown($event)\">\n @let isColumnPinningActive = isPinnedLayoutWithinContainer();\n <ng-template #contentRowMenuContent>\n <div class=\"flex min-w-36 flex-col gap-0.5 p-1\">\n @if (contentRowMenu()?.columnId) {\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"copyContentCell()\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_cell' | translate }}</span>\n </button>\n <div class=\"border-border my-0 border-t\"></div>\n }\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (click)=\"copyContentRows()\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_row' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"contentRowClipboard().length === 0\"\n (click)=\"pasteContentRows('below')\">\n <z-icon zType=\"lucideClipboardPaste\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_paste_row_below' | translate }}</span>\n </button>\n <div class=\"border-border my-0 border-t\"></div>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canMoveContentRowUp()\"\n (click)=\"moveContentRow('up')\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_move_row_up' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canMoveContentRowDown()\"\n (click)=\"moveContentRow('down')\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_move_row_down' | translate }}</span>\n </button>\n <div class=\"border-border my-0 border-t\"></div>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (click)=\"insertContentRow('above')\">\n <z-icon zType=\"lucideArrowUpToLine\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_insert_row_above' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (click)=\"insertContentRow('below')\">\n <z-icon zType=\"lucideArrowDownToLine\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_insert_row_below' | translate }}</span>\n </button>\n <div class=\"border-border my-0 border-t\"></div>\n <button\n type=\"button\"\n class=\"text-destructive hover:bg-destructive/10 focus:bg-destructive/10 flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (click)=\"deleteContentRows()\">\n <z-icon zType=\"lucideTrash2\" zSize=\"12\" />\n <span>\n {{\n contentRowDeleteCount() > 1\n ? ('i18n_z_ui_table_delete_selected_rows' | translate)\n : ('i18n_z_ui_table_delete_row' | translate)\n }}\n </span>\n </button>\n </div>\n </ng-template>\n\n <ng-template #cellMenuContent>\n <div class=\"flex min-w-36 flex-col gap-0.5 p-1\">\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canCopyCellMenuSelection()\"\n (click)=\"copySelectedCells(false)\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_cell' | translate }}</span>\n </button>\n @if (cellSelectionOptions().copyWithHeaders) {\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canCopyCellMenuSelection()\"\n (click)=\"copySelectedCells(true)\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_cell_with_headers' | translate }}</span>\n </button>\n }\n </div>\n </ng-template>\n\n <div\n class=\"pointer-events-none fixed size-px opacity-0\"\n z-popover\n [zPopoverContent]=\"contentRowMenuContent\"\n zTrigger=\"manual\"\n zPosition=\"bottom-left\"\n zClass=\"z-table-content-row-menu\"\n [zOffset]=\"0\"\n [zManualClose]=\"true\"\n [zScrollClose]=\"true\"\n [style.left.px]=\"contentRowMenu()?.left ?? -9999\"\n [style.top.px]=\"contentRowMenu()?.top ?? -9999\"\n (zControl)=\"setContentRowMenuControl($event)\"\n (zHide)=\"clearContentRowMenu()\"></div>\n\n <div\n class=\"pointer-events-none fixed size-px opacity-0\"\n z-popover\n [zPopoverContent]=\"cellMenuContent\"\n zTrigger=\"manual\"\n zPosition=\"bottom-left\"\n zClass=\"z-table-cell-menu\"\n [zOffset]=\"0\"\n [zManualClose]=\"true\"\n [zScrollClose]=\"true\"\n [style.left.px]=\"cellMenu()?.left ?? -9999\"\n [style.top.px]=\"cellMenu()?.top ?? -9999\"\n (zControl)=\"setCellMenuControl($event)\"\n (zHide)=\"clearCellMenu()\"></div>\n\n <!-- Shared colgroup template -->\n <ng-template #colGroupTpl>\n <colgroup>\n @if (canUseVirtualColumns()) {\n @for (column of leftLeafColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <col [style.width.px]=\"virtualRenderedLeftSpacerWidth()\" />\n }\n @for (column of virtualCenterColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n @if (virtualRightSpacerWidth() > 0) {\n <col [style.width.px]=\"virtualRenderedRightSpacerWidth()\" />\n }\n @for (column of rightLeafColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n } @else {\n @for (column of orderedLeafColumns(); track column.id) {\n @if (column.getIsVisible()) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n }\n }\n </colgroup>\n </ng-template>\n\n <!-- Header table -->\n <div\n class=\"z-thead-wrapper shadow-card\"\n [class.z-shadow-header]=\"shouldHeaderShowShadow()\"\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\"\n (wheel)=\"onTheadWheel($event)\"\n #theadWrapper>\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <thead>\n @if (canUseVirtualColumns()) {\n <tr>\n @for (header of leftHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: leftHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (effectiveEnableOrdering) {\n <button\n type=\"button\"\n [disabled]=\"isFirstMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnLeft(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_left' | translate }}</span>\n </button>\n <button\n type=\"button\"\n [disabled]=\"isLastMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnRight(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideChevronsLeftRight\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_column' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeAllColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_all_columns' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"resetColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRotateCcw\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_reset_columns' | translate }}</span>\n </button>\n @if (hideableColumns().length > 0) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover)\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded px-1.5 py-1\"\n [class.cursor-pointer]=\"hasColumnOptions\"\n [class.z-has-options]=\"hasColumnOptions\"\n [attr.z-popover]=\"hasColumnOptions ? '' : null\"\n #colOptionsPopover=\"zPopover\"\n #headerTextWrapper\n z-popover\n [zPopoverContent]=\"hasColumnOptions ? colOptionsPopoverContent : null\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <th\n class=\"z-virtual-column-spacer z-virtual-header-spacer z-virtual-left-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></th>\n }\n @for (header of virtualCenterHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: virtualCenterHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (effectiveEnableOrdering) {\n <button\n type=\"button\"\n [disabled]=\"isFirstMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnLeft(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_left' | translate }}</span>\n </button>\n <button\n type=\"button\"\n [disabled]=\"isLastMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnRight(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideChevronsLeftRight\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_column' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeAllColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_all_columns' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"resetColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRotateCcw\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_reset_columns' | translate }}</span>\n </button>\n @if (hideableColumns().length > 0) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover)\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded px-1.5 py-1\"\n [class.cursor-pointer]=\"hasColumnOptions\"\n [class.z-has-options]=\"hasColumnOptions\"\n [attr.z-popover]=\"hasColumnOptions ? '' : null\"\n #colOptionsPopover=\"zPopover\"\n #headerTextWrapper\n z-popover\n [zPopoverContent]=\"hasColumnOptions ? colOptionsPopoverContent : null\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualRightSpacerWidth() > 0) {\n <th\n class=\"z-virtual-column-spacer z-virtual-header-spacer z-virtual-right-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></th>\n }\n @for (header of rightHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: rightHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <!-- Header Checkbox -->\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <!-- Expand All Button -->\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <!-- Header Content with Sort and Pin -->\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <!-- Column Options Popover Template -->\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (effectiveEnableOrdering) {\n <button\n type=\"button\"\n [disabled]=\"isFirstMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnLeft(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_left' | translate }}</span>\n </button>\n <button\n type=\"button\"\n [disabled]=\"isLastMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnRight(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideChevronsLeftRight\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_column' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeAllColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_all_columns' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"resetColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRotateCcw\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_reset_columns' | translate }}</span>\n </button>\n @if (hideableColumns().length > 0) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover)\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded px-1.5 py-1\"\n [class.cursor-pointer]=\"hasColumnOptions\"\n [class.z-has-options]=\"hasColumnOptions\"\n [attr.z-popover]=\"hasColumnOptions ? '' : null\"\n #colOptionsPopover=\"zPopover\"\n #headerTextWrapper\n z-popover\n [zPopoverContent]=\"hasColumnOptions ? colOptionsPopoverContent : null\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n <!-- Dropdown indicator when has options (between text and sort icon) -->\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n <!-- Sort Icon (outside wrapper, no hover background) -->\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n <!-- Column Resizer -->\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n </tr>\n } @else {\n @for (headerGroup of orderedHeaderGroups(); track headerGroup.id) {\n <tr>\n @for (header of headerGroup.headers; track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: headerGroup.headers : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (effectiveEnableOrdering) {\n <button\n type=\"button\"\n [disabled]=\"isFirstMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnLeft(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_move_left' | translate }}</span>\n </button>\n <button\n type=\"button\"\n [disabled]=\"isLastMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnRight(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"15\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"\n handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\n \"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"15\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon\n zType=\"lucideChevronsLeftRight\"\n zSize=\"14\"\n class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_column' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeAllColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_all_columns' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"resetColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRotateCcw\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_reset_columns' | translate }}</span>\n </button>\n @if (hideableColumns().length > 0) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover)\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded px-1.5 py-1\"\n [class.cursor-pointer]=\"hasColumnOptions\"\n [class.z-has-options]=\"hasColumnOptions\"\n [attr.z-popover]=\"hasColumnOptions ? '' : null\"\n #colOptionsPopover=\"zPopover\"\n #headerTextWrapper\n z-popover\n [zPopoverContent]=\"hasColumnOptions ? colOptionsPopoverContent : null\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"\n header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\n \"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n </tr>\n }\n }\n </thead>\n </table>\n </div>\n\n <!-- Body table -->\n <div\n class=\"z-tbody-wrapper relative\"\n #tbodyContainer\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\">\n @if (isLoading() || isProcessing()) {\n <!-- Loading State -->\n @if (zConfig().useSkeleton) {\n <!-- Skeleton Loading -->\n <div class=\"animate-in fade-in flex h-full flex-col duration-200\">\n @for (i of skeletonRows(); track $index; let last = $last) {\n <div\n class=\"border-border box-border flex flex-1 flex-col items-start justify-center gap-1.5 px-2\"\n [class.border-b]=\"!last\">\n <z-skeleton zType=\"bar\" zWidth=\"100%\" zHeight=\"22px\" zRadius=\"4px\" />\n <z-skeleton zType=\"bar\" zWidth=\"50%\" zHeight=\"14px\" zRadius=\"4px\" />\n </div>\n }\n </div>\n } @else {\n <!-- Spinner Loading -->\n <div class=\"z-loading-state\">\n <z-loading [zLoading]=\"true\" zSize=\"lg\" [zText]=\"'i18n_z_ui_table_loading' | translate\" />\n </div>\n }\n } @else if (isEmpty()) {\n <div class=\"z-empty-state\">\n @if (isNoSearchResults()) {\n <z-empty zIcon=\"lucideSearchX\" zSize=\"sm\" [zMessage]=\"'i18n_z_ui_table_no_results' | translate\" />\n } @else {\n <z-empty zIcon=\"lucidePackageOpen\" zSize=\"sm\" [zMessage]=\"'i18n_z_ui_table_no_data' | translate\" />\n }\n </div>\n } @else {\n <ng-scrollbar class=\"z-tbody-scrollbar\" #tbodyWrapper (scroll)=\"onTbodyScroll($event)\">\n @if (isVirtual()) {\n <!-- Virtual Scroll Mode -->\n\n <div\n class=\"z-virtual-scroll-inner\"\n [style.height.px]=\"virtualizer.getTotalSize()\"\n [style.min-width.px]=\"table.getTotalSize()\">\n <!-- Pinned rows v\u00E0 center rows d\u00F9ng chung m\u1ED9t virtual canvas. -->\n @if (virtualPinnedTopRows().length > 0) {\n <div class=\"z-virtual-pinned-top\" [style.min-width.px]=\"table.getTotalSize()\">\n @for (row of virtualPinnedTopRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"virtualPinnedRowTpl; context: { $implicit: row }\" />\n }\n </div>\n }\n\n @for (virtualItem of virtualizer.getVirtualItems(); track virtualItem.index) {\n @let groupRows = dynamicGroupRows()[virtualItem.index] || [];\n @let virtualFlatItem = virtualGroupedFlatItems()[virtualItem.index];\n @let stickyGroupState = stickyGroupHeaderState();\n @let stickyGroupTop = stickyGroupState.tops[virtualItem.index];\n @let isStickyGroupHeader = stickyGroupTop !== undefined;\n <div\n #virtualRow\n class=\"z-virtual-row\"\n [class.z-virtual-row-group-header]=\"virtualFlatItem?.type === 'group-header'\"\n [class.z-virtual-row-sticky-group]=\"isStickyGroupHeader\"\n [class.z-virtual-row-sticky-group-shadow]=\"stickyGroupState.shadowIndex === virtualItem.index\"\n [style.top.px]=\"stickyGroupTop\"\n z-table-draggable=\"row\"\n z-table-drop-target=\"row\"\n [z-table-drag-table-id]=\"dragInstanceId\"\n [z-table-drop-table-id]=\"dragInstanceId\"\n [z-table-drag-item-id]=\"groupRows.length > 0 ? groupRows[0].id : ''\"\n [z-table-drop-item-id]=\"groupRows.length > 0 ? groupRows[0].id : ''\"\n [z-table-drag-disabled]=\"!isVirtualRowDragEnabled() || groupRows.length !== 1\"\n [z-table-drop-disabled]=\"!isVirtualRowDragEnabled() || groupRows.length !== 1\"\n (zTableDropped)=\"_handleDragDrop($event)\"\n [attr.data-index]=\"virtualItem.index\"\n [style.height.px]=\"\n effectiveDynamicRowSizing()\n ? null\n : (dynamicGroupHeights()[virtualItem.index] ?? groupSize() * virtualRowHeight())\n \"\n [style.transform]=\"isStickyGroupHeader ? null : 'translate3d(0,' + virtualItem.start + 'px,0)'\">\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-has-bottom-pinned]=\"table.getBottomRows().length > 0\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n @let groupHeaderItem = _getVirtualGroupHeader(virtualFlatItem);\n @if (groupHeaderItem) {\n <tr\n class=\"z-group-row\"\n [class.z-group-row-has-totals]=\"groupHeaderItem.totals\"\n [class.z-group-row-expanded]=\"groupHeaderItem.expanded\"\n [attr.data-group-id]=\"groupHeaderItem.id\"\n [attr.data-group-depth]=\"groupHeaderItem.depth\">\n @if (groupHeaderItem.totals) {\n @let totalColumnMap = groupTotalColumnMap();\n @for (column of orderedLeafColumns(); track column.id; let isFirstGroupCell = $first) {\n <td\n [class.z-group-row-label-cell]=\"isFirstGroupCell\"\n [class.z-group-row-total-cell]=\"!isFirstGroupCell && totalColumnMap[column.id]\"\n [attr.data-column-id]=\"column.id\">\n @if (isFirstGroupCell) {\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + groupHeaderItem.depth * 0.75\"\n [attr.aria-expanded]=\"groupHeaderItem.expanded\"\n (click)=\"toggleGroupRow(groupHeaderItem.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"groupHeaderItem.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"\n (groupHeaderItem.columnLabel ? groupHeaderItem.columnLabel + ': ' : '') +\n groupHeaderItem.label\n \">\n @if (groupHeaderItem.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ groupHeaderItem.columnLabel }}:</span>\n }\n {{ groupHeaderItem.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ groupHeaderItem.count }}</span>\n }\n @if (groupHeaderItem.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n [zWave]=\"false\"\n z-tooltip\n zSizeIcon=\"14\"\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(groupHeaderItem.columnId)\"></button>\n }\n </div>\n }\n @if (!isFirstGroupCell && totalColumnMap[column.id]) {\n @let totalConfig = groupTotalConfigMap()[column.id];\n @let totalTooltip = totalConfig.tooltip;\n @let totalPopover = totalConfig.popover;\n @let totalPopoverContent = totalPopover | zTablePopoverConfig: 'content';\n <ng-template #groupTotalPopoverTpl>\n @if (totalPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(totalPopoverContent)\" />\n }\n @if (!(totalPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(totalPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n <span\n class=\"z-group-row-total\"\n z-tooltip\n z-popover\n [class]=\"totalConfig.class\"\n [zContent]=\"\n $any(\n (totalTooltip | zTableTooltipConfig: 'content') ||\n groupHeaderItem.totals[column.id]\n )\n \"\n [zTooltipPosition]=\"$any(totalTooltip | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(totalTooltip | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(totalTooltip | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(totalTooltip | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(totalTooltip | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'showDelay')\"\n [zTooltipHideDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'hideDelay')\"\n [zTooltipArrow]=\"$any(totalTooltip | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(totalTooltip | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(totalTooltip | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(totalTooltip | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(totalTooltip | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"totalPopoverContent ? groupTotalPopoverTpl : null\"\n [zPosition]=\"$any(totalPopover | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(totalPopover | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(totalPopover | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(totalPopover | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(totalPopover | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(totalPopover | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(totalPopover | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(totalPopover | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(totalPopover | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"$any(totalPopover | zTablePopoverConfig: 'outsideClickClose')\"\n [zScrollClose]=\"$any(totalPopover | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(totalPopover | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(totalPopover | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(totalPopover | zTablePopoverConfig: 'keyboardSafe')\">\n {{ groupHeaderItem.totals[column.id] }}\n </span>\n }\n </td>\n }\n } @else {\n <td [attr.colspan]=\"renderedColumnCount()\">\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + groupHeaderItem.depth * 0.75\"\n [attr.aria-expanded]=\"groupHeaderItem.expanded\"\n (click)=\"toggleGroupRow(groupHeaderItem.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"groupHeaderItem.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"\n (groupHeaderItem.columnLabel ? groupHeaderItem.columnLabel + ': ' : '') +\n groupHeaderItem.label\n \">\n @if (groupHeaderItem.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ groupHeaderItem.columnLabel }}:</span>\n }\n {{ groupHeaderItem.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ groupHeaderItem.count }}</span>\n }\n @if (groupHeaderItem.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n [zWave]=\"false\"\n z-tooltip\n zSizeIcon=\"14\"\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(groupHeaderItem.columnId)\"></button>\n }\n </div>\n </td>\n }\n </tr>\n }\n @for (row of groupRows; track row.id) {\n @let virtualGroupDepth = _getVirtualGroupDepth(virtualFlatItem);\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <tr\n z-table-row-hover\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"effectiveDynamicRowSizing() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"effectiveDynamicRowSizing() ? virtualRowHeight() : null\"\n [style.--z-row-height]=\"effectiveDynamicRowSizing() ? 'auto' : virtualRowHeight() + 'px'\"\n [class.z-child-row]=\"row.depth > 0\"\n [class.z-group-child-row]=\"_isVirtualGroupChild(virtualFlatItem)\"\n [style.--z-group-content-indent]=\"\n virtualGroupDepth > 0 ? 1.75 + (virtualGroupDepth - 1) * 0.75 + 'rem' : null\n \"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && row.id === firstTopPinnedRowId()\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"rowPinned === 'bottom' && row.id === lastBottomPinnedRowId()\"\n [class.z-pinned-bottom-first]=\"rowPinned === 'bottom' && row.id === firstBottomPinnedRowId()\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n row.id === lastTopPinnedRowId()\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n row.id === firstBottomPinnedRowId()\n \"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : bodyRowSpanRows();\n @let shouldRenderColSpan = cell | zTableCellRender: visibleCells : zConfig().columns : 'body';\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (shouldRenderRowSpan && shouldRenderColSpan && isVirtualColumnVisible) {\n @let cellSelectionId = row.id + '::' + cell.column.id;\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"isColumnPinningActive && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActive && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"cell.column.id === actionColumnInfo()?.columnId\"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [class.z-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"cell | zTableCellBottom: zConfig().columns : renderedBodyRows()\"\n [attr.rowspan]=\"cell | zTableSpan: zConfig().columns : 'cellRowSpan' : bodyRowSpanRows()\"\n [attr.colspan]=\"cell | zTableSpan: zConfig().columns : 'cellColSpan'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n [style.--z-cell-range-top]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\n \"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\n \"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <button\n data-z-table-drag-handle\n type=\"button\"\n class=\"text-muted-foreground inline-flex size-7 items-center justify-center rounded-md\"\n [class.cursor-grab]=\"isRowDragEnabled()\"\n [class.opacity-40]=\"!isRowDragEnabled()\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === 'select') {\n <!-- Row Checkbox -->\n <div class=\"flex items-center justify-center\">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && cell.row.getIsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && cell.row.getIsSomeSelected() && !cell.row.getIsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection() || !cell.row.getCanSelect()\"\n (zChange)=\"canUseRowSelection() && cell.row.toggleSelected()\" />\n </div>\n } @else if (cell.column.id === 'expand') {\n <!-- Expand Button -->\n <div class=\"flex items-center justify-center\">\n @if (cell.row.getCanExpand()) {\n <button\n type=\"button\"\n (click)=\"cell.row.toggleExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"cell.row.getIsExpanded()\" />\n </button>\n }\n </div>\n } @else if (\n (cell.column.id === 'actionRowPin' || cell.column.id === 'actions') &&\n cell.column.id !== actionColumnInfo()?.columnId\n ) {\n @if (cell.row.depth === 0 && !hasBodyRowSpan()) {\n <div class=\"flex items-center justify-center\">\n <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (cell.row.getIsPinned() !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cell.row.getIsPinned() !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cell.row.getIsPinned()) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded p-1 outline-none\"\n [class.text-primary]=\"cell.row.getIsPinned()\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n </div>\n }\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisible = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisible) {\n @let editInfoVirtual = cell.getContext() | zTableCellEdit: zConfig().columns;\n @if (editInfoVirtual.enabled) {\n <!-- Editable Cell (Virtual) -->\n <z-table-edit-cell\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n [zRowIndex]=\"cell.row.index\"\n [zColumnId]=\"cell.column.id\"\n [zValue]=\"cell.getValue()\"\n [zRowUpdate]=\"_rowUpdate()\"\n [zEditConfig]=\"$any(editInfoVirtual.config)\"\n (zChange)=\"onCellEdit($any($event))\" />\n } @else if (editInfoVirtual.contentEnabled) {\n @let contentConfigVirtual = editInfoVirtual.contentConfig!;\n @if (\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n ) {\n <z-table-content-editor\n [zValue]=\"cell.getValue()\"\n [zConfig]=\"contentConfigVirtual\"\n (zCommit)=\"onContentEditCommit($event, row, cell.column.id, cell.getValue())\"\n (zCancel)=\"onContentEditCancel()\" />\n } @else {\n <button\n type=\"button\"\n class=\"z-table-content-trigger\"\n [attr.data-z-table-edit-row]=\"row.id\"\n [attr.data-z-table-edit-column]=\"cell.column.id\"\n (keydown)=\"onContentEditKeydown($event, row.id, cell.column.id)\"\n (click)=\"onContentEditStart($event, row.id, cell.column.id)\">\n {{ contentConfigVirtual.displayValue }}\n </button>\n }\n } @else {\n <ng-container\n *flexRender=\"\n cell.column.columnDef.cell;\n props: cell.getContext();\n let cellContent\n \">\n @if (cellContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n @let isClickable = cell.column.id | zTableCellClickable: zConfig().columns;\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickable && onCellClick(row, cell.column.id, cell.getValue())\">\n <ng-container\n *ngTemplateOutlet=\"\n cellContent;\n context: { $implicit: cell.getContext() }\n \" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n @let isClickableIcon = cell.column.id | zTableCellClickable: zConfig().columns;\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"\n isClickableIcon && onCellClick(row, cell.column.id, cell.getValue())\n \" />\n } @else {\n <!-- Default/innerHTML rendering -->\n @let isClickableDefault =\n cell.column.id | zTableCellClickable: zConfig().columns;\n @let cellTooltipConfig = cell | zTableCellConfig: zConfig() : 'contentTooltip';\n @let cellPopoverConfig = cell | zTableCellConfig: zConfig() : 'contentPopover';\n @let cellPopoverContent = cellPopoverConfig | zTablePopoverConfig: 'content';\n <ng-template #cellPopoverTpl>\n @if (cellPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(cellPopoverContent)\" />\n }\n @if (!(cellPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(cellPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n @if (cellPopoverContent) {\n <div\n class=\"z-table-cell-text\"\n z-popover\n z-tooltip\n [zTriggerElement]=\"cellOverlayContent\"\n [zTriggerRef]=\"cellOverlayContent\"\n [zContent]=\"\n (cellTooltipConfig | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'position')\n \"\n [zTooltipTrigger]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"cellPopoverTpl\"\n [zPosition]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'manualClose')\n \"\n [zOutsideClickClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'outsideClickClose')\n \"\n [zScrollClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'scrollClose')\n \"\n [zSticky]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'keyboardSafe')\n \"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellOverlayContent\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n } @else {\n <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zTriggerElement]=\"cellTooltipContent\"\n [zContent]=\"\n (cellTooltipConfig | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'position')\n \"\n [zTooltipTrigger]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'maxWidth')\"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellTooltipContent\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n }\n }\n </ng-container>\n }\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n\n <!--\n Bottom pinned rows: sibling AFTER the virtual canvas (not absolute like the\n center rows). The virtualizer reserves their height inside getTotalSize() via\n `paddingEnd`, leaving an empty band at the canvas bottom. `margin-top: -bottomHeight`\n pulls this real flow element back over that band, and `position: sticky; bottom: 0`\n floats it to the viewport bottom while scrolling.\n -->\n @if (virtualPinnedBottomRows().length > 0) {\n <div\n class=\"z-virtual-pinned-bottom\"\n [style.min-width.px]=\"table.getTotalSize()\"\n [style.margin-top.px]=\"-virtualPinnedBottomHeight()\">\n @for (row of virtualPinnedBottomRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"virtualPinnedRowTpl; context: { $implicit: row }\" />\n }\n </div>\n }\n\n <!-- Template for rendering pinned rows in virtual scroll mode -->\n <ng-template #virtualPinnedRowTpl let-row>\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody [class.z-has-vertical-scroll]=\"hasVerticalScroll()\">\n <tr\n z-table-row-hover\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"effectiveDynamicRowSizing() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"effectiveDynamicRowSizing() ? virtualRowHeight() : null\"\n [style.--z-row-height]=\"effectiveDynamicRowSizing() ? 'auto' : virtualRowHeight() + 'px'\"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && row.id === firstTopPinnedRowId()\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"rowPinned === 'bottom' && row.id === lastBottomPinnedRowId()\"\n [class.z-pinned-bottom-first]=\"rowPinned === 'bottom' && row.id === firstBottomPinnedRowId()\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() && hasScrollTop() && rowPinned === 'top' && row.id === lastTopPinnedRowId()\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n row.id === firstBottomPinnedRowId()\n \"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @let isColumnPinningActivePinned = isPinnedLayoutWithinContainer();\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @let cellSelectionId = row.id + '::' + cell.column.id;\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (isVirtualColumnVisible) {\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActivePinned\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"isColumnPinningActivePinned && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActivePinned && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"cell.column.id === actionColumnInfo()?.columnId\"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [style.--z-cell-range-top]=\"(selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"(selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'select') {\n <z-checkbox\n [zChecked]=\"rowSelected\"\n [zIndeterminate]=\"rowSomeSelected && !rowSelected\"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && row.toggleSelected()\" />\n } @else if (cell.column.id === 'expand') {\n <button\n type=\"button\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"row.toggleExpanded()\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"row.getIsExpanded()\" />\n </button>\n } @else if (cell.column.id === 'actionRowPin') {\n <div class=\"flex items-center justify-center\">\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisible = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisible) {\n <ng-container\n *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let cellContent\">\n @if (cellContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { $implicit: cell.getContext() }\" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"(cell | zTableCellConfig: zConfig() : 'contentTooltip') || cellContent\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"></span>\n }\n </ng-container>\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n </tbody>\n </table>\n </ng-template>\n } @else {\n <!-- Normal Scroll Mode -->\n\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n class=\"z-table-drag-body\"\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-has-bottom-pinned]=\"table.getBottomRows().length > 0\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n <!-- Row Template -->\n <ng-template #rowTemplate let-row let-isGroupChild=\"isGroupChild\" let-groupDepth=\"groupDepth\">\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <tr\n z-table-row-hover\n z-table-draggable=\"row\"\n z-table-drop-target=\"row\"\n [animate.enter]=\"row.depth > 0 || isGroupChild ? 'z-row-enter' : ''\"\n [z-table-drag-table-id]=\"dragInstanceId\"\n [z-table-drop-table-id]=\"dragInstanceId\"\n [z-table-drag-item-id]=\"row.id\"\n [z-table-drop-item-id]=\"row.id\"\n [z-table-drag-disabled]=\"!isRowDragEnabled()\"\n [z-table-drop-disabled]=\"!isRowDragEnabled()\"\n (zTableDropped)=\"_handleDragDrop($event)\"\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [ngStyle]=\"row | zTableRow: table : 'pinningStyles' : pinnedRowHeights() : virtualRowHeight()\"\n [class.z-child-row]=\"row.depth > 0\"\n [class.z-group-child-row]=\"isGroupChild\"\n [style.--z-group-content-indent]=\"groupDepth > 0 ? 1.75 + (groupDepth - 1) * 0.75 + 'rem' : null\"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && row.id === firstTopPinnedRowId()\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"rowPinned === 'bottom' && row.id === lastBottomPinnedRowId()\"\n [class.z-pinned-bottom-first]=\"rowPinned === 'bottom' && row.id === firstBottomPinnedRowId()\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() && hasScrollTop() && rowPinned === 'top' && row.id === lastTopPinnedRowId()\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n row.id === firstBottomPinnedRowId()\n \"\n [attr.data-depth]=\"row.depth\"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @let cellRowPinned = cell.row.getIsPinned();\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : bodyRowSpanRows();\n @let shouldRenderColSpan = cell | zTableCellRender: visibleCells : zConfig().columns : 'body';\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (shouldRenderRowSpan && shouldRenderColSpan && isVirtualColumnVisible) {\n @let cellSelectionId = row.id + '::' + cell.column.id;\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n [class.z-sticky-left]=\"isColumnPinningActive && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActive && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"\n cell.column.id === 'actions' || cell.column.id === actionColumnInfo()?.columnId\n \"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [class.z-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"cell | zTableCellBottom: zConfig().columns : renderedBodyRows()\"\n [attr.rowspan]=\"cell | zTableSpan: zConfig().columns : 'cellRowSpan' : bodyRowSpanRows()\"\n [attr.colspan]=\"cell | zTableSpan: zConfig().columns : 'cellColSpan'\"\n [style.--z-cell-range-top]=\"(selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"(selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <button\n data-z-table-drag-handle\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground inline-flex size-7 items-center justify-center rounded-md transition-colors\"\n [class.cursor-grab]=\"isRowDragEnabled()\"\n [class.cursor-not-allowed]=\"!isRowDragEnabled()\"\n [class.opacity-40]=\"!isRowDragEnabled()\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === 'select') {\n <!-- Row Checkbox with Pin Button -->\n <div class=\"flex items-center justify-center gap-1\">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && cell.row.getIsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && cell.row.getIsSomeSelected() && !cell.row.getIsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection() || !cell.row.getCanSelect()\"\n (zChange)=\"canUseRowSelection() && cell.row.toggleSelected()\" />\n @if (zConfig().enableRowPinning && cell.row.depth === 0 && !hasBodyRowSpan()) {\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n }\n </div>\n } @else if (cell.column.id === 'expand') {\n <!-- Expand Button with Row Pin Popover -->\n <div class=\"flex items-center justify-center gap-1\">\n @if (cell.row.getCanExpand()) {\n <button\n type=\"button\"\n (click)=\"cell.row.toggleExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"cell.row.getIsExpanded()\" />\n </button>\n }\n @if (\n zConfig().enableRowPinning &&\n cell.row.depth === 0 &&\n !(cell.row.subRows && cell.row.subRows.length > 0) &&\n !hasBodyRowSpan()\n ) {\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n }\n </div>\n } @else if (\n (cell.column.id === 'actionRowPin' || cell.column.id === 'actions') &&\n cell.column.id !== actionColumnInfo()?.columnId\n ) {\n <!-- Actions Column - Row Pin Only (for parent rows) -->\n @if (cell.row.depth === 0 && !hasBodyRowSpan()) {\n <div class=\"flex items-center justify-center\">\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n </div>\n }\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisibleNormal = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisibleNormal) {\n @let editInfo = cell.getContext() | zTableCellEdit: zConfig().columns;\n @if (editInfo.enabled) {\n <!-- Editable Cell -->\n <z-table-edit-cell\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n [zRowIndex]=\"cell.row.index\"\n [zColumnId]=\"cell.column.id\"\n [zValue]=\"cell.getValue()\"\n [zRowUpdate]=\"_rowUpdate()\"\n [zEditConfig]=\"$any(editInfo.config)\"\n (zChange)=\"onCellEdit($any($event))\" />\n } @else if (editInfo.contentEnabled) {\n @let contentConfig = editInfo.contentConfig!;\n @if (\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n ) {\n <z-table-content-editor\n [zValue]=\"cell.getValue()\"\n [zConfig]=\"contentConfig\"\n (zCommit)=\"onContentEditCommit($event, row, cell.column.id, cell.getValue())\"\n (zCancel)=\"onContentEditCancel()\" />\n } @else {\n <button\n type=\"button\"\n class=\"z-table-content-trigger\"\n [attr.data-z-table-edit-row]=\"row.id\"\n [attr.data-z-table-edit-column]=\"cell.column.id\"\n (keydown)=\"onContentEditKeydown($event, row.id, cell.column.id)\"\n (click)=\"onContentEditStart($event, row.id, cell.column.id)\">\n {{ contentConfig.displayValue }}\n </button>\n }\n } @else {\n <ng-container\n *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let cellContent\">\n @if (cellContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n @let isClickableTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickableTpl && onCellClick(row, cell.column.id, cell.getValue())\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { $implicit: cell.getContext() }\" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n @let isClickableIconTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickableIconTpl && onCellClick(row, cell.column.id, cell.getValue())\" />\n } @else {\n <!-- Default/innerHTML rendering -->\n @let isClickableDefaultTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n @let cellTooltipConfigTpl = cell | zTableCellConfig: zConfig() : 'contentTooltip';\n @let cellPopoverConfigTpl = cell | zTableCellConfig: zConfig() : 'contentPopover';\n @let cellPopoverContentTpl = cellPopoverConfigTpl | zTablePopoverConfig: 'content';\n <ng-template #cellPopoverTplNormal>\n @if (cellPopoverContentTpl | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(cellPopoverContentTpl)\" />\n }\n @if (!(cellPopoverContentTpl | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(cellPopoverContentTpl) | zSafeHtml\"></div>\n }\n </ng-template>\n @if (cellPopoverContentTpl) {\n <div\n class=\"z-table-cell-text\"\n z-popover\n z-tooltip\n [zTriggerElement]=\"cellOverlayContentTpl\"\n [zTriggerRef]=\"cellOverlayContentTpl\"\n [zContent]=\"\n (cellTooltipConfigTpl | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"cellPopoverTplNormal\"\n [zPosition]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"\n $any(cellPopoverConfigTpl | zTablePopoverConfig: 'outsideClickClose')\n \"\n [zScrollClose]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'keyboardSafe')\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellOverlayContentTpl\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n } @else {\n <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zTriggerElement]=\"cellTooltipContentTpl\"\n [zContent]=\"\n (cellTooltipConfigTpl | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'maxWidth')\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellTooltipContentTpl\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n }\n }\n </ng-container>\n }\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n\n <!-- Expanded Row Detail -->\n @if (row.getIsExpanded() && row.depth === 0 && !row.subRows?.length) {\n @let resolvedSubTableConfig = row | zTableSubTableConfig: zConfig();\n <tr class=\"z-expanded-row\" animate.enter=\"z-expanded-row-enter\">\n <td [attr.colspan]=\"renderedColumnCount()\" class=\"p-0\">\n <!-- Animate \u1EDF wrapper n\u00E0y b\u1EB1ng clip-path/translate/opacity \u2014 xem z-expanded-row-reveal. -->\n <div class=\"z-expanded-row-content\">\n @if (zConfig().expandedRowTemplate) {\n <ng-container\n *ngTemplateOutlet=\"zConfig().expandedRowTemplate!; context: { $implicit: row }\" />\n } @else if (resolvedSubTableConfig) {\n <div class=\"z-sub-table-container\">\n <z-table [zConfig]=\"$any(resolvedSubTableConfig)\" zVariant=\"borderless\" />\n </div>\n }\n </div>\n </td>\n </tr>\n }\n </ng-template>\n\n <!-- Render Top Pinned Rows (hidden when filtered data is empty) -->\n @if (!isEmpty()) {\n @for (row of table.getTopRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\n }\n }\n\n <!-- Render Center Rows -->\n @for (item of groupedCenterRowItems(); track item.type === 'group' ? item.id : item.row.id) {\n @if (item.type === 'group') {\n <tr\n #groupRow\n class=\"z-group-row\"\n [class.z-group-row-has-totals]=\"item.totals\"\n [class.z-group-row-expanded]=\"item.expanded\"\n [class.z-group-row-sticky]=\"isStickyGroupHeaderEnabled()\"\n [class.z-group-row-sticky-shadow]=\"shadowGroupRowId() === item.id\"\n [style.top.px]=\"stickyGroupTopByDepth()[item.depth]\"\n [attr.data-group-id]=\"item.id\"\n [attr.data-group-depth]=\"item.depth\">\n @if (item.totals) {\n @let totalColumnMap = groupTotalColumnMap();\n @for (column of orderedLeafColumns(); track column.id; let isFirstGroupCell = $first) {\n <td\n [class.z-group-row-label-cell]=\"isFirstGroupCell\"\n [class.z-group-row-total-cell]=\"!isFirstGroupCell && totalColumnMap[column.id]\"\n [attr.data-column-id]=\"column.id\">\n @if (isFirstGroupCell) {\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + item.depth * 0.75\"\n [attr.aria-expanded]=\"item.expanded\"\n (click)=\"toggleGroupRow(item.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"item.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"(item.columnLabel ? item.columnLabel + ': ' : '') + item.label\">\n @if (item.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ item.columnLabel }}:</span>\n }\n {{ item.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ item.count }}</span>\n }\n @if (item.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n zSizeIcon=\"14\"\n [zWave]=\"false\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(item.columnId)\"></button>\n }\n </div>\n }\n @if (!isFirstGroupCell && totalColumnMap[column.id]) {\n @let totalConfig = groupTotalConfigMap()[column.id];\n @let totalTooltip = totalConfig.tooltip;\n @let totalPopover = totalConfig.popover;\n @let totalPopoverContent = totalPopover | zTablePopoverConfig: 'content';\n <ng-template #groupTotalPopoverTpl>\n @if (totalPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(totalPopoverContent)\" />\n }\n @if (!(totalPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(totalPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n <span\n class=\"z-group-row-total\"\n z-tooltip\n z-popover\n [class]=\"totalConfig.class\"\n [zContent]=\"\n $any((totalTooltip | zTableTooltipConfig: 'content') || item.totals[column.id])\n \"\n [zTooltipPosition]=\"$any(totalTooltip | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(totalTooltip | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(totalTooltip | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(totalTooltip | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(totalTooltip | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'showDelay')\"\n [zTooltipHideDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'hideDelay')\"\n [zTooltipArrow]=\"$any(totalTooltip | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(totalTooltip | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(totalTooltip | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(totalTooltip | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(totalTooltip | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"totalPopoverContent ? groupTotalPopoverTpl : null\"\n [zPosition]=\"$any(totalPopover | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(totalPopover | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(totalPopover | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(totalPopover | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(totalPopover | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(totalPopover | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(totalPopover | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(totalPopover | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(totalPopover | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"$any(totalPopover | zTablePopoverConfig: 'outsideClickClose')\"\n [zScrollClose]=\"$any(totalPopover | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(totalPopover | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(totalPopover | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(totalPopover | zTablePopoverConfig: 'keyboardSafe')\">\n {{ item.totals[column.id] }}\n </span>\n }\n </td>\n }\n } @else {\n <td [attr.colspan]=\"renderedColumnCount()\">\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + item.depth * 0.75\"\n [attr.aria-expanded]=\"item.expanded\"\n (click)=\"toggleGroupRow(item.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"item.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"(item.columnLabel ? item.columnLabel + ': ' : '') + item.label\">\n @if (item.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ item.columnLabel }}:</span>\n }\n {{ item.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ item.count }}</span>\n }\n @if (item.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n zSizeIcon=\"14\"\n [zWave]=\"false\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(item.columnId)\"></button>\n }\n </div>\n </td>\n }\n </tr>\n }\n @if (item.type === 'row') {\n <ng-container\n *ngTemplateOutlet=\"\n rowTemplate;\n context: {\n $implicit: item.row,\n isGroupChild: item.isGroupChild,\n groupDepth: item.groupDepth,\n }\n \" />\n }\n }\n\n <!-- Render Bottom Pinned Rows (hidden when filtered data is empty) -->\n @if (!isEmpty()) {\n @for (row of bottomRowsReversed(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\n }\n }\n </tbody>\n </table>\n }\n </ng-scrollbar>\n }\n <!-- end @else -->\n </div>\n\n <!-- Footer table -->\n @if (hasFooter()) {\n <div\n class=\"z-tfoot-wrapper\"\n [class.z-shadow-footer]=\"shouldFooterShowShadow()\"\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\"\n #tfootWrapper>\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tfoot>\n @for (footerGroup of orderedFooterGroups(); track footerGroup.id; let footerRowIndex = $index) {\n @if (footerGroup | zTableFooterContent: zConfig().columns : footerRowIndex) {\n <tr>\n @for (footer of footerGroup.headers; track footer.id) {\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n footer.column.id === firstVirtualCenterColumnId()\n ) {\n <th\n class=\"z-virtual-column-spacer z-virtual-footer-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></th>\n }\n @let rowSpan = footer | zTableSpan: zConfig().columns : 'footerRowSpan' : footerRowIndex;\n @let shouldRender =\n footer\n | zTableCellRender\n : footerGroup.headers\n : zConfig().columns\n : 'footer'\n : footerRowIndex\n : orderedFooterGroups();\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n footer.column.getIsPinned() !== false ||\n virtualCenterColumnVisibilityMap()[footer.column.id];\n @if (rowSpan && shouldRender && isVirtualColumnVisible) {\n <th\n [attr.data-column-id]=\"footer.column.id\"\n [ngStyle]=\"\n footer.column\n | zTablePinningStyles\n : footer\n : 'footer'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerClass' : footerRowIndex) +\n ' ' +\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex)\n \"\n [style]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerStyle' : footerRowIndex\n \"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (footer | zTableCellPin: 'isLeftPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-at-left-edge]=\"footer | zTableCellOffset: orderedLeafColumns()\"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"footer | zTableSpan: zConfig().columns : 'footerColSpan' : footerRowIndex\">\n @let configFooterContent =\n footer.column.id | zTableFooterRender: zConfig().columns : footerRowIndex;\n @if (configFooterContent !== undefined && configFooterContent !== '') {\n <ng-container *flexRender=\"configFooterContent; props: footer.getContext(); let footerContent\">\n <div\n class=\"flex w-full items-center\"\n [class.justify-center]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex) ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex) ===\n 'text-right'\n \">\n @if (footerContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n <div\n class=\"z-template-content\"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \">\n <ng-container\n *ngTemplateOutlet=\"footerContent; context: { $implicit: footer.getContext() }\" />\n </div>\n } @else if (footerContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n <z-table-icon-text\n [zText]=\"footerContent\"\n [zTooltip]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerTooltip' : footerRowIndex\n \"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \" />\n } @else {\n <!-- Default/string rendering -->\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerTooltip' : footerRowIndex) ||\n footerContent\n \"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \">\n {{ footerContent | translate }}\n </span>\n }\n </div>\n </ng-container>\n }\n </th>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n footer.column.id === lastVirtualCenterColumnId()\n ) {\n <th\n class=\"z-virtual-column-spacer z-virtual-footer-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></th>\n }\n }\n </tr>\n }\n }\n </tfoot>\n </table>\n </div>\n }\n</div>\n\n<!-- Pagination -->\n@if (zConfig().pagination?.enabled !== false) {\n <div class=\"mt-4 flex items-center justify-between gap-4\">\n <div class=\"truncate text-sm text-gray-500\">\n {{ 'i18n_z_ui_table_total_rows' | translate: { total: (paginationTotal() | zFormatNum) } }}\n </div>\n <z-pagination\n [zTotal]=\"paginationTotal()\"\n [(zPageIndex)]=\"pagination().pageIndex\"\n [(zPageSize)]=\"pagination().pageSize\"\n [zPageSizeOptions]=\"zConfig().pagination?.pageSizeOptions ?? [10, 20, 50, 100]\"\n [zShowSizeChanger]=\"zConfig().pagination?.showSizeChanger ?? true\"\n [zShowQuickJumper]=\"zConfig().pagination?.showQuickJumper ?? false\"\n [zShowTotal]=\"false\"\n [zDisabled]=\"zConfig().pagination?.disabled || isLoading() || isProcessing()\"\n (zOnPageChange)=\"onPageChange($event)\" />\n </div>\n}\n\n<!-- Floating Bulk Action Bar -->\n<div class=\"z-bulk-action-bar-origin\" cdkOverlayOrigin #bulkBarOrigin=\"cdkOverlayOrigin\"></div>\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"bulkBarOrigin\"\n [cdkConnectedOverlayOpen]=\"bulkBarMounted()\"\n [cdkConnectedOverlayPositions]=\"bulkBarPositions\"\n [cdkConnectedOverlayHasBackdrop]=\"false\"\n cdkConnectedOverlayPanelClass=\"z-bulk-action-bar-overlay\">\n @if (bulkBarConfig(); as config) {\n <div class=\"z-bulk-action-bar-inner\" [class.z-leaving]=\"bulkBarClosing()\">\n <div class=\"z-bulk-action-bar-count\">\n {{ bulkBarContext()?.selectedRowIds?.length ?? 0 | zFormatNum }}\n {{ config.selectedLabel ?? ('i18n_z_ui_table_selected' | translate) }}\n </div>\n\n <div class=\"z-bulk-action-bar-divider\"></div>\n\n @for (item of bulkBarItems(); track item.action.key) {\n <button\n type=\"button\"\n z-button\n zSize=\"sm\"\n [zType]=\"item.buttonType\"\n [zDisabled]=\"item.disabled\"\n class=\"z-bulk-action-bar-button\"\n [disabled]=\"item.disabled\"\n (click)=\"onBulkActionClick(item.action)\">\n @if (item.action.icon) {\n <z-icon [zType]=\"item.action.icon\" [zSize]=\"item.action.iconSize ?? '14'\" />\n }\n @if (item.action.label) {\n <span>{{ item.action.label | translate }}</span>\n }\n </button>\n }\n </div>\n }\n</ng-template>\n\n<!-- Settings Drawer -->\n<z-drawer\n [(zVisible)]=\"showSettingsDrawer\"\n [zTitle]=\"'i18n_z_ui_table_settings_title' | translate\"\n zPlacement=\"right\"\n zWidth=\"500px\"\n [zShadow]=\"true\"\n [zOkText]=\"null\"\n [zCancelText]=\"'i18n_z_ui_drawer_close' | translate\">\n <div class=\"z-table-settings-drawer px-4\">\n <!-- Display Settings -->\n <div class=\"mb-4\">\n <h4 class=\"text-foreground mb-2 text-sm font-semibold\">{{ 'i18n_z_ui_table_display_settings' | translate }}</h4>\n <p class=\"text-muted-foreground mb-3 text-xs\">{{ 'i18n_z_ui_table_display_settings_desc' | translate }}</p>\n <div class=\"grid grid-cols-2 gap-x-4 gap-y-3\">\n <z-checkbox\n [zChecked]=\"showHorizontalBorder()\"\n [zText]=\"'i18n_z_ui_table_horizontal_border' | translate\"\n (zChange)=\"showHorizontalBorder.set(!showHorizontalBorder())\" />\n <z-checkbox\n [zChecked]=\"showVerticalBorder()\"\n [zText]=\"'i18n_z_ui_table_vertical_border' | translate\"\n (zChange)=\"showVerticalBorder.set(!showVerticalBorder())\" />\n <z-checkbox\n [zChecked]=\"showHeaderFooterShadow()\"\n [zText]=\"'i18n_z_ui_table_header_footer_shadow' | translate\"\n (zChange)=\"showHeaderFooterShadow.set(!showHeaderFooterShadow())\" />\n </div>\n </div>\n\n <!-- Divider -->\n <div class=\"border-border my-4 border-t\"></div>\n\n <!-- Unified Column Settings -->\n <!-- T\u1EA1m t\u1EAFt \u0111i\u1EC1u ki\u1EC7n: @if (zConfig().enableSettings) -->\n <div class=\"mb-4\">\n <h4 class=\"text-foreground mb-2 text-sm font-semibold\">{{ 'i18n_z_ui_table_column_settings' | translate }}</h4>\n <p class=\"text-muted-foreground mb-3 text-xs\">{{ 'i18n_z_ui_table_column_settings_desc' | translate }}</p>\n\n <!-- Unpinned Columns (Draggable) -->\n <div\n cdkDropList\n #columnDropList=\"cdkDropList\"\n [cdkDropListAutoScrollDisabled]=\"true\"\n (cdkDropListDropped)=\"onPendingColumnDrop($event)\"\n class=\"z-column-drop-list space-y-1.5\">\n @for (columnId of columnOrder(); track columnId; let i = $index) {\n @if (columnId !== 'expand' && columnId !== 'select' && columnId !== 'rowDrag') {\n @let column = table.getColumn(columnId);\n @let isPinned = column?.getIsPinned();\n @let isVisible = pendingVisibleColumns().includes(columnId);\n @let isVisibilityDisabled = pendingColumnVisibilityDisabledMap()[columnId];\n @let isGroupedColumn = groupingColumnMap()[columnId];\n @let columnEnablePinningConfig = columnId | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let canPin =\n (columnEnablePinningConfig ?? zConfig().enableColumnPinning ?? true) && column?.getCanPin() !== false;\n @if (!isPinned) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"isGroupedColumn\"\n [cdkDragData]=\"columnId\"\n cdkDragLockAxis=\"y\"\n cdkDragPreviewContainer=\"global\"\n cdkDragPreviewClass=\"z-drag-preview\"\n class=\"z-drag-item border-border bg-card hover:border-primary flex cursor-default items-center gap-2 rounded border px-2 py-1.5 text-sm\"\n [class.opacity-60]=\"!isVisible\">\n <!-- Drag Handle -->\n <z-icon\n cdkDragHandle\n zType=\"lucideGripVertical\"\n zSize=\"14\"\n class=\"text-muted-foreground shrink-0\"\n [class.cursor-pointer]=\"!isGroupedColumn\"\n [class.cursor-default]=\"isGroupedColumn\"\n [class.opacity-40]=\"isGroupedColumn\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n [disabled]=\"isVisibilityDisabled\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n (mousedown)=\"$event.stopPropagation()\"\n class=\"border-input h-4 w-4 shrink-0 cursor-default rounded disabled:opacity-50\" />\n\n <!-- Column Name -->\n <span class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\" [class.text-muted-foreground]=\"!isVisible\">\n {{ columnId | zTableColumnHeader: zConfig().columns | translate }}\n </span>\n @let parents = columnId | zTableColumnParents: zConfig().columns;\n @if (parents) {\n <span class=\"text-muted-foreground truncate text-[0.625rem]\">({{ parents | translate }})</span>\n }\n </span>\n\n <!-- Pin Buttons -->\n @if (canPin) {\n <div class=\"flex shrink-0 items-center gap-0.5\" (mousedown)=\"$event.stopPropagation()\">\n <button\n type=\"button\"\n [disabled]=\"!isVisible || isGroupedColumn || !pinAvailabilityMap()[columnId]?.left\"\n (click)=\"onToggleColumnPin(columnId, 'left')\"\n class=\"text-muted-foreground hover:bg-muted cursor-pointer rounded p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Pin Left\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"12\" />\n </button>\n <button\n type=\"button\"\n [disabled]=\"!isVisible || isGroupedColumn || !pinAvailabilityMap()[columnId]?.right\"\n (click)=\"onToggleColumnPin(columnId, 'right')\"\n class=\"text-muted-foreground hover:bg-muted cursor-pointer rounded p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Pin Right\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"12\" />\n </button>\n </div>\n }\n </div>\n }\n }\n }\n </div>\n\n <!-- Pinned Columns Section -->\n @if (zConfig().enableColumnPinning ?? true) {\n @if (pinnedColumnIds().length > 0) {\n <div class=\"border-border mt-4 border-t pt-4\">\n <h5 class=\"text-muted-foreground mb-2 text-xs font-medium\">\n {{ 'i18n_z_ui_table_pinned_columns' | translate }}\n </h5>\n <div class=\"space-y-1.5\">\n @for (columnId of pinnedColumnIds(); track columnId) {\n @let column = table.getColumn(columnId);\n @let isPinned = column?.getIsPinned();\n @let isVisible = pendingVisibleColumns().includes(columnId);\n @let isVisibilityDisabled = pendingColumnVisibilityDisabledMap()[columnId];\n @let isGroupedColumn = groupingColumnMap()[columnId];\n <div\n class=\"border-border bg-muted/30 flex items-center gap-2 rounded border px-2 py-1.5 text-sm\"\n [class.opacity-60]=\"!isVisible\">\n <!-- Pin Icon -->\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"text-primary shrink-0\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n [disabled]=\"isVisibilityDisabled\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n class=\"border-input h-4 w-4 shrink-0 cursor-default rounded disabled:opacity-50\" />\n\n <!-- Column Name -->\n <span class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\" [class.text-muted-foreground]=\"!isVisible\">\n {{ columnId | zTableColumnHeader: zConfig().columns | translate }}\n </span>\n @let pinnedParents = columnId | zTableColumnParents: zConfig().columns;\n @if (pinnedParents) {\n <span class=\"text-muted-foreground truncate text-[0.625rem]\">\n ({{ pinnedParents | translate }})\n </span>\n }\n </span>\n\n <!-- Position Badge -->\n <span class=\"bg-primary/10 text-primary shrink-0 rounded px-1.5 py-0.5 text-[0.625rem] font-medium\">\n {{\n isPinned === 'start'\n ? ('i18n_z_ui_table_left' | translate)\n : ('i18n_z_ui_table_right' | translate)\n }}\n </span>\n\n <!-- Unpin Button -->\n <button\n type=\"button\"\n [disabled]=\"isGroupedColumn\"\n (click)=\"onToggleColumnPin(columnId, isPinned === 'start' ? 'left' : 'right')\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground cursor-pointer rounded p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Unpin\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </div>\n }\n </div>\n </div>\n }\n }\n </div>\n </div>\n</z-drawer>\n", styles: [":host{display:flex;flex-direction:column;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;overflow-x:visible;--scrollbar-track-thickness: 7px;--scrollbar-track-color: transparent;--scrollbar-thumb-shape: 3px;--z-shadow-left-right: -1.875rem;--z-shadow-left-width: 1.875rem;--z-shadow-left-opacity: 0;--z-shadow-right-left: -1.875rem;--z-shadow-right-width: 1.875rem;--z-shadow-right-opacity: 0;--z-sticky-left-border-color: transparent;--z-sticky-right-border-color: var(--border);--z-cell-selection-background: color-mix(in srgb, var(--primary) 12%, transparent);--z-cell-selection-background-opaque: color-mix(in srgb, var(--primary) 12%, var(--card))}.z-table-container{display:flex;flex-direction:column;position:relative;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;overflow:hidden;border-radius:.3125rem;border:thin solid var(--border);background-color:var(--card)}.z-table-container:focus{outline:none}.z-table-container.z-table-borderless{border:none;border-radius:0;box-shadow:none!important;background-color:transparent}.z-table-container.z-hide-horizontal-border th,.z-table-container.z-hide-horizontal-border td{border-bottom:none!important;border-top:none!important}.z-table-container.z-hide-vertical-border th,.z-table-container.z-hide-vertical-border td{border-left:none!important}.z-table-container.z-hide-pinned-top-border tbody tr.z-pinned-top.z-shadow-bottom>td{border-bottom-color:var(--border)!important}.z-table-container.z-hide-pinned-bottom-border tbody.z-has-bottom-pinned td.z-at-bottom{border-bottom-color:transparent}table{width:fit-content;min-width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed;font-size:.875rem}.z-table-container.z-column-resizing table,.z-table-toolbar{min-width:0}.z-table-toolbar .z-settings-btn{transition:all .15s ease}.z-table-toolbar .z-settings-btn:hover{border-color:var(--muted-foreground)}.z-table-filter-header{min-width:0}.z-table-filter-header button{flex:none}.z-table-filter-header-overflow-chip{animation:z-table-filter-chip-enter .16s ease}@media(prefers-reduced-motion:reduce){.z-table-filter-header-overflow-chip{animation:none}}@keyframes z-table-filter-chip-enter{0%{opacity:0;transform:translate(-.25rem)}to{opacity:1;transform:translate(0)}}.z-bulk-action-bar-origin{position:fixed;left:50%;bottom:1rem;width:1px;height:1px;pointer-events:none}:host ::ng-deep .z-bulk-action-bar-overlay{max-width:calc(100vw - 2rem);margin-bottom:1rem;transform-origin:center bottom}.z-bulk-action-bar-inner{border:thin solid color-mix(in srgb,var(--border) 88%,transparent);border-radius:.4rem;background:color-mix(in srgb,var(--card) 96%,var(--background));color:var(--foreground);box-shadow:0 1rem 2.5rem color-mix(in srgb,var(--foreground) 20%,transparent),0 .25rem .75rem color-mix(in srgb,var(--foreground) 12%,transparent),0 0 0 1px color-mix(in srgb,var(--background) 65%,transparent) inset;display:flex;align-items:center;gap:.5rem;width:max-content;min-height:2.25rem;max-width:calc(100vw - 2rem);padding:.5rem;transform-origin:center bottom;animation:z-bulk-action-bar-enter .18s cubic-bezier(.16,1,.3,1);will-change:opacity,transform}.z-bulk-action-bar-inner.z-leaving{pointer-events:none;animation:z-bulk-action-bar-exit .14s ease-in forwards}.z-bulk-action-bar-count{padding:0 .25rem;white-space:nowrap;font-size:.8125rem;font-weight:500;color:var(--foreground)}.z-bulk-action-bar-divider{width:1px;height:1.5rem;flex:none;background:color-mix(in srgb,var(--border) 88%,transparent)}.z-bulk-action-bar-button{flex:none}@keyframes z-bulk-action-bar-enter{0%{opacity:0;transform:translateY(.875rem)}to{opacity:1;transform:translateY(0)}}@keyframes z-bulk-action-bar-exit{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(.875rem)}}@media(prefers-reduced-motion:reduce){.z-bulk-action-bar-inner{animation:none}}:host ::ng-deep .z-table-cell-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;min-width:0;-webkit-user-select:text;user-select:text}:host ::ng-deep .z-table-cell-text>*,:host ::ng-deep .z-table-cell-text *{display:inline-block;max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}:host ::ng-deep .z-table-cell-content-trigger{display:inline-block;max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}.z-template-content{display:block;width:100%;min-width:0;max-width:100%;overflow:hidden}.z-template-content>*{min-width:0;max-width:100%}.z-template-content>[class*=flex]{min-width:0;max-width:100%}.z-template-content>[class*=flex]>*{min-width:0;flex-shrink:1}.z-template-content>[class*=grid]{min-width:0;max-width:100%}.z-thead-wrapper{flex-shrink:0;background:var(--muted);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;position:relative;z-index:4}.z-thead-wrapper::-webkit-scrollbar{display:none}.z-thead-wrapper th{height:auto;padding:.5rem;text-align:left;vertical-align:middle;font-weight:500;color:var(--foreground);white-space:nowrap;overflow:hidden;background:var(--muted);border-left:thin solid var(--border);border-bottom:thin solid var(--border);-webkit-user-select:none;user-select:none}.z-thead-wrapper th.z-at-left-edge{border-left:none}.z-thead-wrapper th[colspan]{text-align:center;background:var(--muted);font-weight:500;color:var(--foreground)}.z-thead-wrapper.z-shadow-header{box-shadow:0 1px 3px #00000014;position:relative;z-index:15}.z-thead-wrapper.z-shadow-header:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}.z-tbody-wrapper{flex:1;width:100%;max-width:100%;min-width:0;min-height:6.25rem;display:flex;flex-direction:column;overflow:hidden}.z-tbody-scrollbar{flex:1;width:100%;max-width:100%;min-width:0;height:100%}.z-empty-state,.z-loading-state{flex:1 1 0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;min-height:6.25rem;height:100%;color:var(--muted-foreground);font-size:.875rem;animation:z-fade-in .2s ease-out}.z-tbody-scrollbar,.z-tbody-scrollbar table{animation:z-fade-in .2s ease-out}@keyframes z-fade-in{0%{opacity:0;transform:translateY(.25rem)}to{opacity:1;transform:translateY(0)}}.z-tbody-wrapper tr{transition:background-color .15s ease}.z-tbody-wrapper tr:hover,.z-tbody-wrapper tr:hover td[style*=sticky]{background-color:var(--muted)}.z-tbody-wrapper tr.z-pinned-top td.z-sticky-left,.z-tbody-wrapper tr.z-pinned-top td.z-sticky-right,.z-tbody-wrapper tr.z-pinned-bottom td.z-sticky-left,.z-tbody-wrapper tr.z-pinned-bottom td.z-sticky-right{z-index:3}.z-tbody-wrapper tr.z-shadow-bottom{box-shadow:0 1px 3px #00000014!important;position:relative;z-index:15}.z-tbody-wrapper tr.z-shadow-bottom:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d!important}.z-tbody-wrapper tr.z-shadow-top{box-shadow:0 -2px 4px #0000000d!important;position:relative;z-index:15}.z-tbody-wrapper tr.z-shadow-top:where(.dark,.dark *){box-shadow:0 -2px 4px #0003!important}.z-tbody-wrapper td{padding:.5rem 12px;height:var(--z-row-height, 2.375rem);vertical-align:middle;color:var(--foreground);white-space:nowrap;overflow:hidden;background:var(--card);border-left:thin solid var(--border);border-bottom:thin solid var(--border);box-sizing:border-box}.z-tbody-wrapper tbody.z-has-vertical-scroll td.z-at-bottom,.z-tbody-wrapper tbody.z-last-row-touches-bottom td.z-at-bottom{border-bottom-color:transparent}.z-tbody-wrapper tbody.z-has-bottom-pinned td.z-at-bottom{border-bottom-color:var(--border)}.z-tbody-wrapper td.z-at-left-edge{border-left:none}.z-tbody-wrapper td i{color:var(--muted-foreground);font-style:italic}.z-tbody-wrapper td[rowspan]{vertical-align:top;padding-top:.75rem}.z-tbody-wrapper td.z-row-hover{background-color:var(--muted)!important}.z-tbody-wrapper td.z-col-select,.z-tbody-wrapper td.z-col-expand,.z-tbody-wrapper td.z-col-actions{padding:.5rem 4px!important;text-align:center}.z-tbody-wrapper tr.z-child-row td.z-col-select:first-child,.z-tbody-wrapper tr.z-child-row td.z-col-expand:first-child,.z-tbody-wrapper tr.z-child-row td.z-col-actions:first-child{padding-left:0!important}.z-virtual-scroll-inner{position:relative;box-sizing:border-box;width:100%}.z-virtual-row{position:absolute;top:0;left:0;width:100%}.z-virtual-row-group-header{z-index:2}.z-virtual-row-sticky-group{position:sticky}.z-virtual-row-sticky-group-shadow{box-shadow:0 1px 3px #00000014}.z-virtual-row-sticky-group-shadow:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}tr.z-group-row-sticky{position:sticky;z-index:2}tr.z-group-row-sticky>td{background:var(--card)}tr.z-group-row-sticky-shadow{box-shadow:0 1px 3px #00000014}tr.z-group-row-sticky-shadow:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}tr.z-child-row td:first-child{border-left:.125rem solid var(--primary)!important;padding-left:.75rem!important}tbody tr.z-context-menu-active,tbody tr.z-context-menu-active td{background-color:var(--muted)!important}tbody tr.z-selected,tbody tr.z-selected td{background-color:color-mix(in srgb,var(--primary) 15%,var(--background))!important}tbody tr.z-selected:hover,tbody tr.z-selected:hover td{background-color:color-mix(in srgb,var(--primary) 20%,var(--background))!important}tbody tr.z-indeterminate-selected,tbody tr.z-indeterminate-selected td{background-color:color-mix(in srgb,var(--primary) 10%,var(--background))!important}tbody tr.z-indeterminate-selected:hover,tbody tr.z-indeterminate-selected:hover td{background-color:color-mix(in srgb,var(--primary) 15%,var(--background))!important}tbody tr.z-pinned-top td{background-color:var(--card)!important}tbody tr.z-pinned-top:hover{background-color:var(--muted)}tbody tr.z-pinned-top:hover td{background-color:var(--muted)!important}tbody tr.z-pinned-bottom td{background-color:var(--card)!important}tbody tr.z-pinned-bottom:hover{background-color:var(--muted)}tbody tr.z-pinned-bottom:hover td{background-color:var(--muted)!important}tbody tr.z-pinned-bottom-last>td{border-bottom-color:transparent!important}tbody tr.z-pinned-bottom-first>td{border-top:thin solid var(--border)}:host .z-tbody-wrapper tbody tr:not(.z-pinned-top):not(.z-pinned-bottom):has(+tr.z-pinned-bottom)>td{border-bottom-color:transparent}tr.z-expanded-row>td{border-left:.125rem solid var(--primary);background-color:var(--background)!important}.z-expanded-row-content{transform-origin:top center}@keyframes z-expanded-row-reveal{0%{clip-path:inset(0 0 100% 0);translate:0 -.375rem;opacity:0}to{clip-path:inset(0 0 0 0);translate:none;opacity:1}}@keyframes z-expanded-row-fade-in{0%{opacity:0}to{opacity:1}}tr.z-expanded-row-enter{animation:z-expanded-row-fade-in .18s ease-out}tr.z-expanded-row-enter .z-expanded-row-content{animation:z-expanded-row-reveal .18s ease-out}@keyframes z-child-row-slide-in{0%{translate:0 -.375rem;opacity:0}to{translate:none;opacity:1}}tr.z-child-row.z-row-enter,tr.z-group-child-row.z-row-enter{animation:z-child-row-slide-in .18s ease-out}@media(prefers-reduced-motion:reduce){tr.z-expanded-row-enter,tr.z-child-row.z-row-enter,tr.z-group-child-row.z-row-enter,tr.z-expanded-row-enter .z-expanded-row-content,tr.z-child-row.z-row-enter .z-expanded-row-content,tr.z-group-child-row.z-row-enter .z-expanded-row-content{animation-duration:1ms}}.z-sub-table-container{padding:.75rem 1rem .75rem 3rem;background-color:var(--background)}.z-table-content-trigger{display:block;width:100%;min-width:0;min-height:1.5rem;padding:0;border:0;border-radius:0;background:transparent;color:inherit;font:inherit;line-height:1.5rem;text-align:inherit;outline:0;cursor:text}.z-table-content-trigger:hover{color:var(--primary)}.z-content-edit-active{position:relative;z-index:2}td:has(>.z-table-content-trigger:focus-visible){position:relative;z-index:2}td:has(>.z-table-content-trigger:focus-visible):after{position:absolute;z-index:3;inset:0;border:1px solid var(--primary);content:\"\";pointer-events:none}td.z-cell-selectable{-webkit-user-select:none;user-select:none}td.z-cell-range-selected{position:relative;isolation:isolate}td.z-cell-range-selected:before{position:absolute;z-index:0;box-sizing:border-box;top:var(--z-cell-range-top, 0);right:var(--z-cell-range-right, 0);bottom:var(--z-cell-range-bottom, 0);left:var(--z-cell-range-left, 0);background-color:var(--z-cell-selection-background);content:\"\";pointer-events:none}td.z-cell-range-selected>*{position:relative;z-index:1}td.z-cell-range-top:before{border-top:1px solid var(--primary)}td.z-cell-range-right:before{border-right:1px solid var(--primary)}td.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}td.z-cell-range-left:before{border-left:1px solid var(--primary)}td.z-cell-active{position:relative;z-index:3;background-color:var(--z-cell-selection-background)!important}td.z-cell-active:after{position:absolute;z-index:4;inset:0;border:1px solid var(--primary);content:\"\";pointer-events:none}td.z-content-edit-active{-webkit-user-select:text;user-select:text}td.z-cell-active.z-row-hover,td.z-content-edit-active.z-row-hover{background-color:var(--card)!important}thead th{position:relative}thead th .z-resizer{position:absolute;right:0;top:0;height:100%;width:.5rem;background:transparent;cursor:col-resize;-webkit-user-select:none;user-select:none;touch-action:none;z-index:5}thead th .z-resizer:after{content:\"\";position:absolute;right:0;top:0;height:100%;width:.1875rem;background:#0000001a;opacity:0;transition:opacity .2s ease}thead th .z-resizer:after:where(.dark,.dark *){background:#ffffff1a}thead th .z-resizer:hover:after{opacity:1;background:var(--primary);width:.1875rem}thead th .z-resizer.z-is-resizing:after{opacity:1;background:var(--primary);width:.1875rem}thead th .z-resizer.z-resizer-left{right:auto;left:0}thead th .z-resizer.z-resizer-left:after{right:auto;left:0}.z-thead-wrapper th.z-sticky-left,.z-thead-wrapper th.z-sticky-right,.z-tbody-wrapper th.z-sticky-left,.z-tbody-wrapper th.z-sticky-right,.z-tfoot-wrapper th.z-sticky-left,.z-tfoot-wrapper th.z-sticky-right{background-color:var(--muted);z-index:1;transform:translateZ(0);backface-visibility:hidden}.z-thead-wrapper td.z-sticky-left,.z-thead-wrapper td.z-sticky-right,.z-tbody-wrapper td.z-sticky-left,.z-tbody-wrapper td.z-sticky-right,.z-tfoot-wrapper td.z-sticky-left,.z-tfoot-wrapper td.z-sticky-right{background-color:var(--card);z-index:1;transform:translateZ(0);backface-visibility:hidden}.z-thead-wrapper th.z-sticky-left-last,.z-thead-wrapper td.z-sticky-left-last,.z-tbody-wrapper th.z-sticky-left-last,.z-tbody-wrapper td.z-sticky-left-last,.z-tfoot-wrapper th.z-sticky-left-last,.z-tfoot-wrapper td.z-sticky-left-last{position:relative;overflow:visible;border-right:thin solid var(--z-sticky-left-border-color)}.z-thead-wrapper th.z-sticky-left-last:after,.z-thead-wrapper td.z-sticky-left-last:after,.z-tbody-wrapper th.z-sticky-left-last:after,.z-tbody-wrapper td.z-sticky-left-last:after,.z-tfoot-wrapper th.z-sticky-left-last:after,.z-tfoot-wrapper td.z-sticky-left-last:after{content:\"\";position:absolute;top:0;bottom:0;right:var(--z-shadow-left-right);width:var(--z-shadow-left-width);pointer-events:none;box-shadow:inset 10px 0 8px -8px #0000001a;z-index:10;opacity:var(--z-shadow-left-opacity)}:host-context(.dark) .z-thead-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-thead-wrapper td.z-sticky-left-last:after,:host-context(.dark) .z-tbody-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-tbody-wrapper td.z-sticky-left-last:after,:host-context(.dark) .z-tfoot-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-tfoot-wrapper td.z-sticky-left-last:after{box-shadow:inset 10px 0 10px -8px #0000004d}.z-thead-wrapper.z-scroll-left,.z-tbody-wrapper.z-scroll-left,.z-tfoot-wrapper.z-scroll-left{--z-shadow-left-opacity: 1}.z-thead-wrapper.z-scroll-left:where(.dark,.dark *),.z-tbody-wrapper.z-scroll-left:where(.dark,.dark *),.z-tfoot-wrapper.z-scroll-left:where(.dark,.dark *){--z-sticky-left-border-color: var(--border)}.z-thead-wrapper th.z-sticky-right-first,.z-thead-wrapper td.z-sticky-right-first,.z-tbody-wrapper th.z-sticky-right-first,.z-tbody-wrapper td.z-sticky-right-first,.z-tfoot-wrapper th.z-sticky-right-first,.z-tfoot-wrapper td.z-sticky-right-first{position:relative;overflow:visible;border-left:thin solid var(--z-sticky-right-border-color)}.z-thead-wrapper th.z-sticky-right-first:before,.z-thead-wrapper td.z-sticky-right-first:before,.z-tbody-wrapper th.z-sticky-right-first:before,.z-tbody-wrapper td.z-sticky-right-first:before,.z-tfoot-wrapper th.z-sticky-right-first:before,.z-tfoot-wrapper td.z-sticky-right-first:before{content:\"\";position:absolute;top:0;bottom:0;left:var(--z-shadow-right-left);width:var(--z-shadow-right-width);pointer-events:none;box-shadow:inset -10px 0 8px -8px #0000001a;z-index:10;opacity:var(--z-shadow-right-opacity)}:host-context(.dark) .z-thead-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-thead-wrapper td.z-sticky-right-first:before,:host-context(.dark) .z-tbody-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-tbody-wrapper td.z-sticky-right-first:before,:host-context(.dark) .z-tfoot-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-tfoot-wrapper td.z-sticky-right-first:before{box-shadow:inset -10px 0 10px -8px #0000004d}.z-thead-wrapper.z-scroll-right,.z-tbody-wrapper.z-scroll-right,.z-tfoot-wrapper.z-scroll-right{--z-shadow-right-opacity: 1}.z-thead-wrapper.z-scroll-right:not(:where(.dark,.dark *)),.z-tbody-wrapper.z-scroll-right:not(:where(.dark,.dark *)),.z-tfoot-wrapper.z-scroll-right:not(:where(.dark,.dark *)){--z-sticky-right-border-color: transparent}.z-pinning-overflow{--z-shadow-left-opacity: 0 !important;--z-shadow-right-opacity: 0 !important;--z-sticky-left-border-color: transparent !important;--z-sticky-right-border-color: transparent !important}.z-pinning-overflow .z-sticky-left,.z-pinning-overflow .z-sticky-right{position:relative!important;right:auto!important;left:auto!important}.z-pinning-overflow .z-sticky-left-last:after,.z-pinning-overflow .z-sticky-right-first:before,.z-pinning-overflow .z-sticky-right-last:after{display:none!important}.z-thead-wrapper th.z-sticky-right-last,.z-tfoot-wrapper th.z-sticky-right-last{position:relative}.z-thead-wrapper th.z-sticky-right-last:after,.z-tfoot-wrapper th.z-sticky-right-last:after{content:\"\";position:absolute;top:0;bottom:0;right:-1.875rem;width:1.875rem;background:var(--muted);pointer-events:none}.z-tfoot-wrapper{flex-shrink:0;width:100%;max-width:100%;min-width:0;background:var(--muted);overflow-x:hidden;overflow-y:hidden;touch-action:pan-y pinch-zoom}.z-tfoot-wrapper th{height:auto;padding:.5rem 12px;text-align:left;vertical-align:middle;font-weight:500;font-size:.75rem;color:var(--muted-foreground);text-transform:uppercase;letter-spacing:.5px;background:var(--muted);border-left:thin solid var(--border);border-top:thin solid var(--border)}.z-tfoot-wrapper th.z-at-left-edge{border-left:none}.z-tfoot-wrapper.z-shadow-footer{box-shadow:0 -2px 4px #0000000d;position:relative;z-index:15}.z-tfoot-wrapper.z-shadow-footer:where(.dark,.dark *){box-shadow:0 -2px 4px #0003}.z-pin-btn{padding:.125rem 4px;border-radius:.25rem;color:var(--muted-foreground);transition:all .15s ease}.z-pin-btn:hover{background-color:var(--muted);color:var(--foreground)}.z-pin-btn.z-pin-btn-active{color:var(--primary);background-color:var(--primary)}.z-pin-btn.z-pin-btn-active:hover{background-color:var(--primary);opacity:.8}.z-row-pin-trigger{opacity:1}.z-row-pin-trigger:focus-visible,.z-row-pin-trigger.z-popover-open{background-color:color-mix(in srgb,var(--foreground) 8%,transparent);color:var(--foreground)}.z-row-pin-trigger:active{background-color:color-mix(in srgb,var(--foreground) 12%,transparent)}.z-row-pin-trigger.text-primary{color:var(--primary)}.z-row-pin-unpin-trigger{color:var(--muted-foreground);outline:none}.z-row-pin-unpin-trigger:hover{color:var(--destructive);background-color:color-mix(in srgb,var(--destructive) 10%,transparent)}.z-row-pin-unpin-trigger:focus,.z-row-pin-unpin-trigger:focus-visible{color:var(--muted-foreground);background-color:transparent;outline:none;box-shadow:none}.z-row-pin-unpin-trigger:active{color:var(--destructive);background-color:color-mix(in srgb,var(--destructive) 14%,transparent)}.z-header-pin-trigger{opacity:1}.z-header-pin-trigger.text-primary{color:var(--primary)}th{overflow:hidden}th .z-header-content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}th .z-header-text-wrapper{transition:background-color .15s ease;border-radius:.25rem;min-width:0;overflow:hidden;flex-shrink:1}th .z-header-text-wrapper.z-has-options:hover,th .z-header-text-wrapper.z-has-options:focus-visible,th .z-header-text-wrapper.z-has-options.z-popover-open{background-color:color-mix(in srgb,var(--foreground) 8%,transparent);outline:none}th .z-header-text-wrapper.z-has-options:active{background-color:color-mix(in srgb,var(--foreground) 12%,transparent)}.z-column-menu-item{line-height:1.25rem}.z-column-menu-item:focus-visible,.z-column-menu-item.z-popover-open{background-color:var(--muted);outline:none}.cdk-drag-preview,.z-drag-preview{box-sizing:border-box;border:1px solid var(--primary);border-radius:.375rem;background-color:var(--card);box-shadow:0 5px 20px #0003;overflow:hidden;pointer-events:none;z-index:10000!important}.cdk-drag-preview:where(.dark,.dark *),.z-drag-preview:where(.dark,.dark *){box-shadow:0 5px 20px #00000080}.cdk-drag-placeholder{box-sizing:border-box;border:2px dashed var(--primary);border-radius:.375rem;background-color:color-mix(in srgb,var(--primary) 10%,var(--background))}.cdk-drag-animating,.cdk-drop-list-dragging .cdk-drag:not(.cdk-drag-placeholder){transition:transform .1s cubic-bezier(0,0,.2,1)}.z-drag-item.cdk-drag-dragging{transition:none!important}.z-table-drag-preview{box-sizing:border-box;border-radius:.375rem;background-color:var(--card);border:1px solid var(--primary);box-shadow:0 10px 24px #00000029;overflow:hidden;z-index:10000!important;pointer-events:none}.z-table-drag-preview:where(.dark,.dark *){box-shadow:0 5px 20px #00000080}.z-table-drag-preview-row{border:0;border-radius:.125rem;background-color:var(--background);box-shadow:0 8px 20px #0000001f,inset 0 0 0 1px color-mix(in srgb,var(--primary) 45%,var(--border))}.z-table-drag-preview-row table,.z-table-drag-preview-row tbody,.z-table-drag-preview-row tr{height:100%}.z-table-drag-preview-row td{vertical-align:middle!important;background-color:var(--background)}.z-table-drag-source{display:none!important}.z-virtual-row.z-table-drag-source{display:block!important;pointer-events:none;outline:1px solid var(--border);outline-offset:-1px}.z-virtual-row.z-table-drag-source td{color:color-mix(in srgb,var(--foreground) 45%,transparent);border-color:var(--border)!important;background-color:var(--card)!important}.z-virtual-row.z-table-drag-source td>*{opacity:.45}[data-z-table-drag-handle]{touch-action:none;-webkit-user-select:none;user-select:none}.z-column-drop-list{min-height:3.125rem;overscroll-behavior:contain}.z-column-drop-list.cdk-drop-list-dragging{overflow:clip}.z-table-drag-placeholder{width:100%;min-height:2.625rem;box-sizing:border-box;border:2px dashed var(--primary);border-radius:.375rem;background-color:color-mix(in srgb,var(--primary) 10%,var(--background));pointer-events:none}.z-table-drag-placeholder-row>td{padding:0!important;border:0!important;background:transparent!important}.z-table-drag-placeholder-row .z-table-drag-placeholder{border-radius:0;background-color:color-mix(in srgb,var(--primary) 10%,transparent)}.z-table-drag-placeholder-virtual{position:absolute;top:0;left:0;z-index:20;border-radius:0}.z-tbody-wrapper tr.z-group-row td{background:var(--card);border-top:none;border-bottom:1px solid var(--border)}.z-virtual-row tr.z-group-row td{background:var(--card);border-top:none;border-bottom:none}.z-group-row-sticky-wrapper{display:inline-flex;align-items:center;translate:var(--z-scroll-x, 0px) 0}.z-table-container:not(.z-hide-horizontal-border) .z-virtual-row:after{content:\"\";position:absolute;right:0;bottom:0;left:0;z-index:3;height:1px;background:var(--border);pointer-events:none}.z-tbody-wrapper tr.z-group-child-row td.z-at-left-edge,.z-virtual-row tr.z-group-child-row td.z-at-left-edge{border-left:2px solid var(--primary)!important;padding-left:var(--z-group-content-indent, .75rem)}.z-group-row-trigger{display:inline-flex;min-height:2rem;max-width:100%;align-items:center;gap:.5rem;padding:.25rem .5rem .25rem .75rem;color:var(--primary);font-size:.8125rem;font-weight:600;vertical-align:middle;cursor:pointer}.z-group-row-remove{margin-left:.125rem;color:var(--muted-foreground);vertical-align:middle}.z-group-row-remove:hover,.z-group-row-remove:focus-visible{color:var(--destructive);background:color-mix(in srgb,var(--destructive) 10%,transparent);outline:none}.z-group-row-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-column-label{color:color-mix(in srgb,var(--primary) 65%,var(--foreground));font-weight:500;margin-right:.25rem}.z-group-row-count{display:inline-flex;min-width:1.25rem;height:1.25rem;align-items:center;justify-content:center;padding:0 .375rem;border-radius:999px;background:var(--primary);color:var(--primary-foreground);font-size:.6875rem;font-weight:600}.z-group-row-loading{display:inline-flex;align-items:center;margin-left:.25rem}.z-group-row-has-totals td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-has-totals .z-group-row-label-cell{position:sticky;left:0;z-index:2;background:var(--card)}.z-group-row-has-totals .z-group-row-label-cell .z-group-row-sticky-wrapper{max-width:100%;translate:none}.z-group-row-total{display:inline-block;max-width:100%;color:var(--foreground);font-size:.8125rem;font-weight:600;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-total-cell{text-align:right}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-selected:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:before{position:absolute!important;z-index:0!important;box-sizing:border-box!important;top:var(--z-cell-range-top, 0)!important;right:var(--z-cell-range-right, 0)!important;bottom:var(--z-cell-range-bottom, 0)!important;left:var(--z-cell-range-left, 0)!important;width:auto!important;background-color:var(--z-cell-selection-background-opaque)!important;box-shadow:none!important;content:\"\"!important;pointer-events:none!important;opacity:1!important}:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:after{display:none!important}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-top:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-top:before{border-top:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-right:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-right:before{border-right:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-bottom:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-left:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-left:before{border-left:1px solid var(--primary)}:host-context(.z-table-pointer-dragging) .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-selected:before,:host-context(.z-table-pointer-dragging) .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:before{background-color:transparent!important}:host td.z-cell-range-selected:before{position:absolute;z-index:0;box-sizing:border-box;top:var(--z-cell-range-top, 0);right:var(--z-cell-range-right, 0);bottom:var(--z-cell-range-bottom, 0);left:var(--z-cell-range-left, 0);background-color:var(--z-cell-selection-background);box-shadow:none;content:\"\";pointer-events:none;opacity:1}:host td.z-cell-range-top:before{border-top:1px solid var(--primary)}:host td.z-cell-range-right:before{border-right:1px solid var(--primary)}:host td.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}:host td.z-cell-range-left:before{border-left:1px solid var(--primary)}:host-context(.z-table-pointer-dragging) td.z-row-hover{background-color:var(--background)!important}:host td.z-cell-active,:host td.z-cell-active.z-row-hover{background-color:var(--z-cell-selection-background)!important}:host td.z-content-edit-active.z-row-hover{background-color:var(--card)!important}:host tr.z-pinned-top td.z-cell-active,:host tr.z-pinned-top td.z-cell-active.z-row-hover,:host tr.z-pinned-bottom td.z-cell-active,:host tr.z-pinned-bottom td.z-cell-active.z-row-hover,:host td.z-cell-active.z-sticky-left,:host td.z-cell-active.z-sticky-left.z-row-hover,:host td.z-cell-active.z-sticky-right,:host td.z-cell-active.z-sticky-right.z-row-hover{background-color:var(--z-cell-selection-background-opaque)!important}:host tr.z-pinned-top td.z-cell-range-selected,:host tr.z-pinned-bottom td.z-cell-range-selected,:host td.z-cell-range-selected.z-sticky-left,:host td.z-cell-range-selected.z-sticky-right{background-color:var(--card)}:host tr.z-pinned-top td.z-cell-range-selected:before,:host tr.z-pinned-bottom td.z-cell-range-selected:before,:host td.z-cell-range-selected.z-sticky-left:before,:host td.z-cell-range-selected.z-sticky-right:before{background-color:var(--z-cell-selection-background-opaque)}:host-context(.z-table-pointer-dragging) td.z-cell-range-selected,:host-context(.z-table-pointer-dragging) td.z-cell-range-selected.z-row-hover,:host-context(.z-table-pointer-dragging) td.z-cell-active,:host-context(.z-table-pointer-dragging) td.z-cell-active.z-row-hover{background-color:var(--card)!important}:host-context(.z-table-pointer-dragging) td.z-cell-range-selected:before{background-color:transparent}:host .z-tbody-wrapper tbody tr.z-group-child-row:has(+tr.z-group-row)>td.z-at-bottom{border-bottom-color:var(--border)}:host .z-virtual-row:has(tr.z-group-child-row):has(+.z-virtual-row tr.z-group-row) tr.z-group-child-row>td.z-at-bottom{border-bottom-color:var(--border)}.z-thead-wrapper th.z-virtual-column-spacer,.z-tfoot-wrapper th.z-virtual-column-spacer{box-sizing:border-box;padding:0!important;background:var(--muted);border-left:thin solid var(--border)}.z-thead-wrapper th.z-virtual-header-spacer{border-bottom:thin solid var(--border)}.z-tfoot-wrapper th.z-virtual-footer-spacer{border-top:thin solid var(--border)}.z-tbody-wrapper td.z-virtual-column-spacer{box-sizing:border-box;height:auto;padding:0!important;background:var(--card);border-left:thin solid var(--border);border-bottom:thin solid var(--border)}.z-tbody-wrapper tr:hover td.z-virtual-column-spacer{background-color:var(--muted)}.z-table-settings-drawer input[type=checkbox]{appearance:none;-webkit-appearance:none;-moz-appearance:none;width:1rem;height:1rem;border:thin solid var(--input);border-radius:.25rem;background-color:var(--background);cursor:pointer;position:relative;transition:all .2s ease}.z-table-settings-drawer input[type=checkbox]:hover{border-color:var(--primary)}.z-table-settings-drawer input[type=checkbox]:checked{background-color:var(--primary);border-color:var(--primary)}.z-table-settings-drawer input[type=checkbox]:checked:after{content:\"\";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:.375rem;height:.625rem;border:solid var(--primary-foreground);border-width:0 .125rem .125rem 0;transform:translate(-50%,-60%) rotate(45deg)}.z-table-settings-drawer input[type=checkbox]:disabled{opacity:.5;cursor:not-allowed}.z-virtual-pinned-top{position:sticky;top:0;left:0;z-index:3;width:100%}.z-virtual-pinned-bottom{position:sticky;bottom:0;left:0;z-index:3;width:100%}\n"], dependencies: [{ kind: "component", type: ZTableComponent, selector: "z-table", inputs: ["zClass", "zConfig", "zLoading", "zKey", "zVariant"], outputs: ["zChange", "zControl"], exportAs: ["zTable"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "component", type: NgScrollbar, selector: "ng-scrollbar:not([externalViewport]), [ngScrollbar]", exportAs: ["ngScrollbar"] }, { kind: "directive", type: FlexRenderDirective, selector: "ng-template[flexRender]", inputs: ["flexRender", "flexRenderProps", "flexRenderInjector"] }, { 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: ZTableDraggableDirective, selector: "[z-table-draggable]", inputs: ["z-table-draggable", "z-table-drag-table-id", "z-table-drag-item-id", "z-table-drag-disabled", "z-table-drag-handle"] }, { kind: "directive", type: ZTableDropTargetDirective, selector: "[z-table-drop-target]", inputs: ["z-table-drop-target", "z-table-drop-table-id", "z-table-drop-item-id", "z-table-drop-disabled"], outputs: ["zTableDropped"] }, { kind: "component", type: ZCheckboxComponent, selector: "z-checkbox", inputs: ["class", "zType", "zSize", "zLabel", "zText", "zDisabled", "zIndeterminate", "zValue", "zOptions", "zOrientation", "zCheckAll", "zCheckAllText", "zChecked", "zGroupValue"], outputs: ["zChange", "zGroupChange", "zOnBlur", "zOnFocus", "zControl", "zEvent", "zCheckedChange", "zGroupValueChange"] }, { kind: "component", type: ZEmptyComponent, selector: "z-empty", inputs: ["class", "zType", "zIcon", "zIconSize", "zSize", "zMessage", "zDescription"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zAnimatedType", "zAnimate", "zAnimationTrigger", "zSize", "zStrokeWidth", "zSvg"] }, { kind: "component", type: ZInputComponent, selector: "z-input", inputs: ["class", "zType", "zSize", "zAlign", "zLabel", "zLabelClass", "zPlaceholder", "zRequired", "zDisabled", "zReadonly", "zLoading", "zLoadingOutline", "zPrefix", "zSuffix", "zMin", "zMax", "zStep", "zShowArrows", "zMask", "zDecimalPlaces", "zAllowNegative", "zThousandSeparator", "zDecimalMarker", "zValidators", "zAsyncValidators", "zAsyncDebounce", "zAsyncValidateOn", "zShowPasswordToggle", "zSearch", "zDebounce", "zAutofocus", "zAutoComplete", "zAllowClear", "zAutoSizeContent", "zRows", "zResize", "zMaxLength", "zAutoSuggest", "zColorConfig"], outputs: ["zOnSearch", "zOnChange", "zOnBlur", "zOnFocus", "zOnKeydown", "zOnEnter", "zOnColorCollapse", "zControl", "zEvent"], exportAs: ["zInput"] }, { kind: "component", type: ZLoadingComponent, selector: "z-loading", inputs: ["class", "zSpinner", "zSize", "zColor", "zText", "zOverlay", "zOverlayType", "zFullscreen", "zLoading"] }, { kind: "component", type: ZSkeletonComponent, selector: "z-skeleton", inputs: ["class", "zType", "zSize", "zWidth", "zHeight", "zRows", "zGap", "zAnimated", "zRadius"] }, { kind: "component", type: ZDrawerComponent, selector: "z-drawer", inputs: ["class", "zBodyClass", "zVisible", "zTitle", "zDescription", "zWidth", "zHeight", "zPlacement", "zClosable", "zMaskClosable", "zDisableShadow", "zHeaderBorder", "zFooterBorder", "zHideFooter", "zHideHeader", "zOkText", "zCancelText", "zOkDestructive", "zOkDisabled", "zLoading", "zOverlay", "zShadow", "zShape", "zContentLoading", "zSkeletonRows", "zExpand"], outputs: ["zOnOk", "zOnCancel", "zAfterClose", "zScrollbar", "zVisibleChange"], exportAs: ["zDrawer"] }, { kind: "component", type: ZPaginationComponent, selector: "z-pagination", inputs: ["zPageIndex", "zPageSize", "zTotal", "zPageSizeOptions", "zShowSizeChanger", "zShowQuickJumper", "zShowTotal", "zSimple", "zSize", "zDisabled", "zTotalLabel", "zPerPageLabel", "zGoToLabel"], outputs: ["zOnPageChange", "zPageIndexChange", "zPageSizeChange"] }, { kind: "component", type: ZTableFilterComponent, selector: "z-table-filter", inputs: ["zColumn", "zTable", "zResetVersion", "zSortingState", "zEnableMultiSort"] }, { kind: "component", type: ZTableEditCellComponent, selector: "z-table-edit-cell", inputs: ["zRow", "zRowId", "zRowIndex", "zColumnId", "zValue", "zEditConfig", "zRowUpdate"], outputs: ["zChange"] }, { kind: "directive", type: ZPopoverDirective, selector: "[z-popover]", inputs: ["zPopoverContent", "zPosition", "zTrigger", "zPopoverTrigger", "zClass", "zShowDelay", "zHideDelay", "zDisabled", "zOffset", "zPopoverWidth", "zTriggerRef", "zManualClose", "zOutsideClickClose", "zScrollClose", "zSticky", "zShowArrow", "zKeyboardSafe"], outputs: ["zShow", "zHide", "zHideStart", "zControl", "zPositionChange", "zOutsideClick"], exportAs: ["zPopover"] }, { kind: "component", type: ZButtonComponent, selector: "z-button, button[z-button], a[z-button]", inputs: ["class", "zType", "zSize", "zShape", "zLabel", "zLoading", "zDisabled", "zTypeIcon", "zAnimatedTypeIcon", "zAnimateIcon", "zAnimationTriggerIcon", "zSizeIcon", "zStrokeWidthIcon", "zWave"], exportAs: ["zButton"] }, { kind: "directive", type: ZTooltipDirective, selector: "[z-tooltip], [zTooltip]", inputs: ["zContent", "zPosition", "zTooltipPosition", "zTrigger", "zTooltipTrigger", "zTooltipType", "zTooltipSize", "zClass", "zTooltipClass", "zShowDelay", "zTooltipShowDelay", "zHideDelay", "zTooltipHideDelay", "zArrow", "zTooltipArrow", "zDisabled", "zTooltipDisabled", "zOffset", "zTooltipOffset", "zAutoDetect", "zTriggerElement", "zAlwaysShow", "zMaxWidth"], outputs: ["zShow", "zHide"], exportAs: ["zTooltip"] }, { kind: "directive", type: ZTableResizeDirective, selector: "[z-table-resize],[zTableResize]", inputs: ["zTableResize"] }, { kind: "directive", type: ZTableRowHoverDirective, selector: "[z-table-row-hover], [zTableRowHover]", inputs: ["zTableRowHover"] }, { kind: "component", type: ZTableIconTextComponent, selector: "z-table-icon-text", inputs: ["zText", "zTooltip", "zTriggerElement"] }, { kind: "component", type: ZTableActionsComponent, selector: "z-table-actions", inputs: ["zConfig", "zRow", "zRowId", "zDropdownButtonSize"], outputs: ["zActionClick"] }, { kind: "component", type: ZTableContentEditorComponent, selector: "z-table-content-editor", inputs: ["zValue", "zConfig"], outputs: ["zCommit", "zCancel"] }, { kind: "pipe", type: ZTableIsTemplateRefPipe, name: "zTableIsTemplateRef" }, { kind: "pipe", type: ZTableHasIconPipe, name: "zTableHasIcon" }, { kind: "pipe", type: ZTableCellBottomPipe, name: "zTableCellBottom" }, { kind: "pipe", type: ZTableCellClickablePipe, name: "zTableCellClickable" }, { kind: "pipe", type: ZTableCellConfigPipe, name: "zTableCellConfig" }, { kind: "pipe", type: ZTableCellEditPipe, name: "zTableCellEdit" }, { kind: "pipe", type: ZTableCellOffsetPipe, name: "zTableCellOffset" }, { kind: "pipe", type: ZTableCellPinPipe, name: "zTableCellPin" }, { kind: "pipe", type: ZTableCellVisiblePipe, name: "zTableCellVisible" }, { kind: "pipe", type: ZTableColumnConfigPipe, name: "zTableColumnConfig" }, { kind: "pipe", type: ZTableColumnHeaderPipe, name: "zTableColumnHeader" }, { kind: "pipe", type: ZTableColumnParentsPipe, name: "zTableColumnParents" }, { kind: "pipe", type: ZTableFooterContentPipe, name: "zTableFooterContent" }, { kind: "pipe", type: ZTableFooterRenderPipe, name: "zTableFooterRender" }, { kind: "pipe", type: ZTablePinningStylesPipe, name: "zTablePinningStyles" }, { kind: "pipe", type: ZTablePopoverConfigPipe, name: "zTablePopoverConfig" }, { kind: "pipe", type: ZTableRowPipe, name: "zTableRow" }, { kind: "pipe", type: ZTableRowConfigPipe, name: "zTableRowConfig" }, { kind: "pipe", type: ZTableSpanPipe, name: "zTableSpan" }, { kind: "pipe", type: ZTableSubTableConfigPipe, name: "zTableSubTableConfig" }, { kind: "pipe", type: ZTableTooltipConfigPipe, name: "zTableTooltipConfig" }, { kind: "pipe", type: ZTableCellRenderPipe, name: "zTableCellRender" }, { kind: "pipe", type: ZFormatNumPipe, name: "zFormatNum" }, { kind: "pipe", type: ZSafeHtmlPipe, name: "zSafeHtml" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
10808
11121
|
}
|
|
10809
11122
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: ZTableComponent, decorators: [{
|
|
10810
11123
|
type: Component,
|
|
@@ -10864,8 +11177,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImpor
|
|
|
10864
11177
|
TranslatePipe,
|
|
10865
11178
|
], standalone: true, providers: [TranslatePipe, ZTableDragService], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
10866
11179
|
class: 'z-table block relative py-1',
|
|
10867
|
-
}, exportAs: 'zTable', template: "<!-- Toolbar: Search & Settings -->\n@if (isSearchEnabled() || zConfig().enableSettings) {\n <div class=\"z-table-toolbar mb-2 flex items-center justify-between gap-4\">\n <!-- Search -->\n @if (isSearchEnabled()) {\n @let config = searchConfig();\n <z-input\n [class]=\"config?.width ?? 'w-64'\"\n [zSize]=\"config?.size ?? 'sm'\"\n [zPlaceholder]=\"config?.placeholder ?? 'i18n_z_ui_table_search' | translate\"\n [zSearch]=\"true\"\n [zDebounce]=\"config?.debounceTime ?? 300\"\n (zOnSearch)=\"onSearchChange($event)\" />\n } @else {\n <div></div>\n }\n\n <!-- Settings Button -->\n @if (zConfig().enableSettings) {\n <z-button zType=\"outline\" zSize=\"sm\" zTypeIcon=\"lucideSettings\" (click)=\"openSettingsDrawer()\">\n {{ 'i18n_z_ui_table_settings' | translate }}\n </z-button>\n }\n </div>\n}\n\n@if (zConfig().enableFilterHeader && appliedFilterChips().length > 0) {\n <div class=\"z-table-filter-header mb-2 flex min-w-0 items-center gap-2\">\n <div class=\"flex min-w-0 flex-1 flex-wrap items-center gap-1.5\">\n @for (chip of visibleAppliedFilterChips(); track chip.id) {\n <span\n class=\"border-border bg-muted/60 text-foreground inline-flex max-w-80 min-w-0 shrink-0 items-center gap-1 rounded-sm border px-2 py-1 text-[0.8125rem] shadow-xs\">\n <span class=\"font-medium whitespace-nowrap\">{{ chip.label }}</span>\n <span class=\"text-muted-foreground\">:</span>\n <span class=\"truncate\" z-tooltip [zContent]=\"chip.value\" zTooltipTrigger=\"hover\" zTooltipPosition=\"top\">\n {{ chip.value }}\n </span>\n <button\n type=\"button\"\n class=\"hover:bg-destructive/10 hover:text-destructive focus-visible:ring-ring -mr-1 inline-flex size-5 cursor-pointer items-center justify-center rounded-sm outline-none focus-visible:ring-2\"\n [attr.aria-label]=\"'i18n_z_ui_table_filter_remove' | translate\"\n (click)=\"clearAppliedFilterChip(chip)\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </span>\n }\n @if (hiddenAppliedFilterChipCount() > 0 && isFilterHeaderExpanded()) {\n @for (chip of overflowAppliedFilterChips(); track chip.id) {\n <span\n class=\"z-table-filter-header-overflow-chip border-border bg-muted/60 text-foreground inline-flex max-w-80 min-w-0 shrink-0 items-center gap-1 rounded-sm border px-2 py-1 text-[0.8125rem] shadow-xs\"\n [attr.aria-hidden]=\"!isFilterHeaderExpanded()\">\n <span class=\"font-medium whitespace-nowrap\">{{ chip.label }}</span>\n <span class=\"text-muted-foreground\">:</span>\n <span class=\"truncate\" z-tooltip [zContent]=\"chip.value\" zTooltipTrigger=\"hover\" zTooltipPosition=\"top\">\n {{ chip.value }}\n </span>\n <button\n type=\"button\"\n class=\"hover:bg-destructive/10 hover:text-destructive focus-visible:ring-ring -mr-1 inline-flex size-5 cursor-pointer items-center justify-center rounded-sm outline-none focus-visible:ring-2\"\n [attr.aria-label]=\"'i18n_z_ui_table_filter_remove' | translate\"\n (click)=\"clearAppliedFilterChip(chip)\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </span>\n }\n }\n @if (hiddenAppliedFilterChipCount() > 0) {\n <button\n type=\"button\"\n class=\"text-primary hover:bg-primary/10 focus-visible:ring-ring inline-flex h-7 cursor-pointer items-center rounded-sm px-2 text-xs font-medium outline-none focus-visible:ring-2\"\n (click)=\"toggleFilterHeaderExpanded()\">\n {{\n isFilterHeaderExpanded()\n ? ('i18n_z_ui_table_show_less' | translate)\n : ('i18n_z_ui_table_show_more' | translate: { count: hiddenAppliedFilterChipCount() })\n }}\n </button>\n }\n <button\n type=\"button\"\n class=\"bg-destructive/10 text-destructive hover:bg-destructive/20 dark:bg-destructive/15 dark:text-destructive-foreground dark:hover:bg-destructive/25 focus-visible:ring-destructive inline-flex h-7 cursor-pointer items-center gap-1 rounded-sm px-2 text-xs font-medium shadow-xs outline-none focus-visible:ring-2\"\n (click)=\"clearAppliedFilters()\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_clear_filter' | translate }}</span>\n </button>\n </div>\n </div>\n}\n\n<div\n #tableContainer\n [class]=\"classTable()\"\n [class.z-pinning-overflow]=\"!isPinnedLayoutWithinContainer()\"\n [class.z-hide-horizontal-border]=\"!showHorizontalBorder()\"\n [class.z-hide-vertical-border]=\"!showVerticalBorder()\"\n [class.z-hide-pinned-top-border]=\"hasScrollTop()\"\n [class.z-hide-pinned-bottom-border]=\"hasScrollBottom()\"\n [style.width]=\"zConfig().width\"\n [style.height]=\"zConfig().height\"\n [style.max-height]=\"zConfig().maxHeight\"\n [style.min-height]=\"zConfig().minHeight\"\n [attr.tabindex]=\"canUseContentRowInsert() || canUseCellSelection() ? 0 : null\"\n (keydown)=\"onContentTableKeydown($event)\">\n @let isColumnPinningActive = isPinnedLayoutWithinContainer();\n <ng-template #contentRowMenuContent>\n <div class=\"flex min-w-36 flex-col gap-0.5 p-1\">\n @if (contentRowMenu()?.columnId) {\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"copyContentCell()\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_cell' | translate }}</span>\n </button>\n <div class=\"border-border my-0 border-t\"></div>\n }\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (click)=\"copyContentRows()\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_row' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"contentRowClipboard().length === 0\"\n (click)=\"pasteContentRows('below')\">\n <z-icon zType=\"lucideClipboardPaste\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_paste_row_below' | translate }}</span>\n </button>\n <div class=\"border-border my-0 border-t\"></div>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canMoveContentRowUp()\"\n (click)=\"moveContentRow('up')\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_move_row_up' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canMoveContentRowDown()\"\n (click)=\"moveContentRow('down')\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_move_row_down' | translate }}</span>\n </button>\n <div class=\"border-border my-0 border-t\"></div>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (click)=\"insertContentRow('above')\">\n <z-icon zType=\"lucideArrowUpToLine\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_insert_row_above' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (click)=\"insertContentRow('below')\">\n <z-icon zType=\"lucideArrowDownToLine\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_insert_row_below' | translate }}</span>\n </button>\n <div class=\"border-border my-0 border-t\"></div>\n <button\n type=\"button\"\n class=\"text-destructive hover:bg-destructive/10 focus:bg-destructive/10 flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (click)=\"deleteContentRows()\">\n <z-icon zType=\"lucideTrash2\" zSize=\"12\" />\n <span>\n {{\n contentRowDeleteCount() > 1\n ? ('i18n_z_ui_table_delete_selected_rows' | translate)\n : ('i18n_z_ui_table_delete_row' | translate)\n }}\n </span>\n </button>\n </div>\n </ng-template>\n\n <ng-template #cellMenuContent>\n <div class=\"flex min-w-36 flex-col gap-0.5 p-1\">\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canCopyCellMenuSelection()\"\n (click)=\"copySelectedCells(false)\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_cell' | translate }}</span>\n </button>\n @if (cellSelectionOptions().copyWithHeaders) {\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canCopyCellMenuSelection()\"\n (click)=\"copySelectedCells(true)\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_cell_with_headers' | translate }}</span>\n </button>\n }\n </div>\n </ng-template>\n\n <div\n class=\"pointer-events-none fixed size-px opacity-0\"\n z-popover\n [zPopoverContent]=\"contentRowMenuContent\"\n zTrigger=\"manual\"\n zPosition=\"bottom-left\"\n zClass=\"z-table-content-row-menu\"\n [zOffset]=\"0\"\n [zManualClose]=\"true\"\n [zScrollClose]=\"true\"\n [style.left.px]=\"contentRowMenu()?.left ?? -9999\"\n [style.top.px]=\"contentRowMenu()?.top ?? -9999\"\n (zControl)=\"setContentRowMenuControl($event)\"\n (zHide)=\"clearContentRowMenu()\"></div>\n\n <div\n class=\"pointer-events-none fixed size-px opacity-0\"\n z-popover\n [zPopoverContent]=\"cellMenuContent\"\n zTrigger=\"manual\"\n zPosition=\"bottom-left\"\n zClass=\"z-table-cell-menu\"\n [zOffset]=\"0\"\n [zManualClose]=\"true\"\n [zScrollClose]=\"true\"\n [style.left.px]=\"cellMenu()?.left ?? -9999\"\n [style.top.px]=\"cellMenu()?.top ?? -9999\"\n (zControl)=\"setCellMenuControl($event)\"\n (zHide)=\"clearCellMenu()\"></div>\n\n <!-- Shared colgroup template -->\n <ng-template #colGroupTpl>\n <colgroup>\n @if (canUseVirtualColumns()) {\n @for (column of leftLeafColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <col [style.width.px]=\"virtualRenderedLeftSpacerWidth()\" />\n }\n @for (column of virtualCenterColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n @if (virtualRightSpacerWidth() > 0) {\n <col [style.width.px]=\"virtualRenderedRightSpacerWidth()\" />\n }\n @for (column of rightLeafColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n } @else {\n @for (column of orderedLeafColumns(); track column.id) {\n @if (column.getIsVisible()) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n }\n }\n </colgroup>\n </ng-template>\n\n <!-- Header table -->\n <div\n class=\"z-thead-wrapper shadow-card\"\n [class.z-shadow-header]=\"shouldHeaderShowShadow()\"\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\"\n (wheel)=\"onTheadWheel($event)\"\n #theadWrapper>\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <thead>\n @if (canUseVirtualColumns()) {\n <tr>\n @for (header of leftHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: leftHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (effectiveEnableOrdering) {\n <button\n type=\"button\"\n [disabled]=\"isFirstMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnLeft(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_left' | translate }}</span>\n </button>\n <button\n type=\"button\"\n [disabled]=\"isLastMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnRight(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideChevronsLeftRight\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_column' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeAllColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_all_columns' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"resetColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRotateCcw\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_reset_columns' | translate }}</span>\n </button>\n @if (hideableColumns().length > 0) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover)\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded px-1.5 py-1\"\n [class.cursor-pointer]=\"hasColumnOptions\"\n [class.z-has-options]=\"hasColumnOptions\"\n [attr.z-popover]=\"hasColumnOptions ? '' : null\"\n #colOptionsPopover=\"zPopover\"\n #headerTextWrapper\n z-popover\n [zPopoverContent]=\"hasColumnOptions ? colOptionsPopoverContent : null\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <th\n class=\"z-virtual-column-spacer z-virtual-header-spacer z-virtual-left-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></th>\n }\n @for (header of virtualCenterHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: virtualCenterHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (effectiveEnableOrdering) {\n <button\n type=\"button\"\n [disabled]=\"isFirstMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnLeft(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_left' | translate }}</span>\n </button>\n <button\n type=\"button\"\n [disabled]=\"isLastMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnRight(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideChevronsLeftRight\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_column' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeAllColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_all_columns' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"resetColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRotateCcw\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_reset_columns' | translate }}</span>\n </button>\n @if (hideableColumns().length > 0) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover)\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded px-1.5 py-1\"\n [class.cursor-pointer]=\"hasColumnOptions\"\n [class.z-has-options]=\"hasColumnOptions\"\n [attr.z-popover]=\"hasColumnOptions ? '' : null\"\n #colOptionsPopover=\"zPopover\"\n #headerTextWrapper\n z-popover\n [zPopoverContent]=\"hasColumnOptions ? colOptionsPopoverContent : null\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualRightSpacerWidth() > 0) {\n <th\n class=\"z-virtual-column-spacer z-virtual-header-spacer z-virtual-right-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></th>\n }\n @for (header of rightHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: rightHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <!-- Header Checkbox -->\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <!-- Expand All Button -->\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <!-- Header Content with Sort and Pin -->\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <!-- Column Options Popover Template -->\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (effectiveEnableOrdering) {\n <button\n type=\"button\"\n [disabled]=\"isFirstMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnLeft(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_left' | translate }}</span>\n </button>\n <button\n type=\"button\"\n [disabled]=\"isLastMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnRight(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideChevronsLeftRight\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_column' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeAllColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_all_columns' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"resetColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRotateCcw\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_reset_columns' | translate }}</span>\n </button>\n @if (hideableColumns().length > 0) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover)\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded px-1.5 py-1\"\n [class.cursor-pointer]=\"hasColumnOptions\"\n [class.z-has-options]=\"hasColumnOptions\"\n [attr.z-popover]=\"hasColumnOptions ? '' : null\"\n #colOptionsPopover=\"zPopover\"\n #headerTextWrapper\n z-popover\n [zPopoverContent]=\"hasColumnOptions ? colOptionsPopoverContent : null\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n <!-- Dropdown indicator when has options (between text and sort icon) -->\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n <!-- Sort Icon (outside wrapper, no hover background) -->\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n <!-- Column Resizer -->\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n </tr>\n } @else {\n @for (headerGroup of orderedHeaderGroups(); track headerGroup.id) {\n <tr>\n @for (header of headerGroup.headers; track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: headerGroup.headers : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (effectiveEnableOrdering) {\n <button\n type=\"button\"\n [disabled]=\"isFirstMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnLeft(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_move_left' | translate }}</span>\n </button>\n <button\n type=\"button\"\n [disabled]=\"isLastMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnRight(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"15\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"\n handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\n \"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"15\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon\n zType=\"lucideChevronsLeftRight\"\n zSize=\"14\"\n class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_column' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeAllColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_all_columns' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"resetColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRotateCcw\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_reset_columns' | translate }}</span>\n </button>\n @if (hideableColumns().length > 0) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover)\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded px-1.5 py-1\"\n [class.cursor-pointer]=\"hasColumnOptions\"\n [class.z-has-options]=\"hasColumnOptions\"\n [attr.z-popover]=\"hasColumnOptions ? '' : null\"\n #colOptionsPopover=\"zPopover\"\n #headerTextWrapper\n z-popover\n [zPopoverContent]=\"hasColumnOptions ? colOptionsPopoverContent : null\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"\n header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\n \"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n </tr>\n }\n }\n </thead>\n </table>\n </div>\n\n <!-- Body table -->\n <div\n class=\"z-tbody-wrapper relative\"\n #tbodyContainer\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\">\n @if (isLoading() || isProcessing()) {\n <!-- Loading State -->\n @if (zConfig().useSkeleton) {\n <!-- Skeleton Loading -->\n <div class=\"animate-in fade-in flex h-full flex-col duration-200\">\n @for (i of skeletonRows(); track $index; let last = $last) {\n <div\n class=\"border-border box-border flex flex-1 flex-col items-start justify-center gap-1.5 px-2\"\n [class.border-b]=\"!last\">\n <z-skeleton zType=\"bar\" zWidth=\"100%\" zHeight=\"22px\" zRadius=\"4px\" />\n <z-skeleton zType=\"bar\" zWidth=\"50%\" zHeight=\"14px\" zRadius=\"4px\" />\n </div>\n }\n </div>\n } @else {\n <!-- Spinner Loading -->\n <div class=\"z-loading-state\">\n <z-loading [zLoading]=\"true\" zSize=\"lg\" [zText]=\"'i18n_z_ui_table_loading' | translate\" />\n </div>\n }\n } @else if (isEmpty()) {\n <div class=\"z-empty-state\">\n @if (isNoSearchResults()) {\n <z-empty zIcon=\"lucideSearchX\" zSize=\"sm\" [zMessage]=\"'i18n_z_ui_table_no_results' | translate\" />\n } @else {\n <z-empty zIcon=\"lucidePackageOpen\" zSize=\"sm\" [zMessage]=\"'i18n_z_ui_table_no_data' | translate\" />\n }\n </div>\n } @else {\n <ng-scrollbar class=\"z-tbody-scrollbar\" #tbodyWrapper (scroll)=\"onTbodyScroll($event)\">\n @if (isVirtual()) {\n <!-- Virtual Scroll Mode -->\n\n <div\n class=\"z-virtual-scroll-inner\"\n [style.height.px]=\"virtualizer.getTotalSize()\"\n [style.min-width.px]=\"table.getTotalSize()\">\n <!-- Pinned rows v\u00E0 center rows d\u00F9ng chung m\u1ED9t virtual canvas. -->\n @if (virtualPinnedTopRows().length > 0) {\n <div class=\"z-virtual-pinned-top\" [style.min-width.px]=\"table.getTotalSize()\">\n @for (row of virtualPinnedTopRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"virtualPinnedRowTpl; context: { $implicit: row }\" />\n }\n </div>\n }\n\n @for (virtualItem of virtualizer.getVirtualItems(); track virtualItem.index) {\n @let groupRows = dynamicGroupRows()[virtualItem.index] || [];\n @let virtualFlatItem = virtualGroupedFlatItems()[virtualItem.index];\n <div\n #virtualRow\n class=\"z-virtual-row\"\n z-table-draggable=\"row\"\n z-table-drop-target=\"row\"\n [z-table-drag-table-id]=\"dragInstanceId\"\n [z-table-drop-table-id]=\"dragInstanceId\"\n [z-table-drag-item-id]=\"groupRows.length > 0 ? groupRows[0].id : ''\"\n [z-table-drop-item-id]=\"groupRows.length > 0 ? groupRows[0].id : ''\"\n [z-table-drag-disabled]=\"!isVirtualRowDragEnabled() || groupRows.length !== 1\"\n [z-table-drop-disabled]=\"!isVirtualRowDragEnabled() || groupRows.length !== 1\"\n (zTableDropped)=\"_handleDragDrop($event)\"\n [attr.data-index]=\"virtualItem.index\"\n [style.height.px]=\"\n effectiveDynamicRowSizing()\n ? null\n : (dynamicGroupHeights()[virtualItem.index] ?? groupSize() * virtualRowHeight())\n \"\n [style.transform]=\"'translate3d(0,' + virtualItem.start + 'px,0)'\">\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-has-bottom-pinned]=\"table.getBottomRows().length > 0\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n @let groupHeaderItem = _getVirtualGroupHeader(virtualFlatItem);\n @if (groupHeaderItem) {\n <tr\n class=\"z-group-row\"\n [class.z-group-row-has-totals]=\"groupHeaderItem.totals\"\n [class.z-group-row-expanded]=\"groupHeaderItem.expanded\"\n [attr.data-group-id]=\"groupHeaderItem.id\"\n [attr.data-group-depth]=\"groupHeaderItem.depth\">\n @if (groupHeaderItem.totals) {\n @let totalColumnMap = groupTotalColumnMap();\n @for (column of orderedLeafColumns(); track column.id; let isFirstGroupCell = $first) {\n <td\n [class.z-group-row-label-cell]=\"isFirstGroupCell\"\n [class.z-group-row-total-cell]=\"!isFirstGroupCell && totalColumnMap[column.id]\"\n [attr.data-column-id]=\"column.id\">\n @if (isFirstGroupCell) {\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + groupHeaderItem.depth * 0.75\"\n [attr.aria-expanded]=\"groupHeaderItem.expanded\"\n (click)=\"toggleGroupRow(groupHeaderItem.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"groupHeaderItem.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"\n (groupHeaderItem.columnLabel ? groupHeaderItem.columnLabel + ': ' : '') +\n groupHeaderItem.label\n \">\n @if (groupHeaderItem.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ groupHeaderItem.columnLabel }}:</span>\n }\n {{ groupHeaderItem.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ groupHeaderItem.count }}</span>\n }\n @if (groupHeaderItem.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n [zWave]=\"false\"\n z-tooltip\n zSizeIcon=\"14\"\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(groupHeaderItem.columnId)\"></button>\n }\n </div>\n }\n @if (!isFirstGroupCell && totalColumnMap[column.id]) {\n @let totalConfig = groupTotalConfigMap()[column.id];\n @let totalTooltip = totalConfig.tooltip;\n @let totalPopover = totalConfig.popover;\n @let totalPopoverContent = totalPopover | zTablePopoverConfig: 'content';\n <ng-template #groupTotalPopoverTpl>\n @if (totalPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(totalPopoverContent)\" />\n }\n @if (!(totalPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(totalPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n <span\n class=\"z-group-row-total\"\n z-tooltip\n z-popover\n [class]=\"totalConfig.class\"\n [zContent]=\"\n $any(\n (totalTooltip | zTableTooltipConfig: 'content') ||\n groupHeaderItem.totals[column.id]\n )\n \"\n [zTooltipPosition]=\"$any(totalTooltip | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(totalTooltip | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(totalTooltip | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(totalTooltip | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(totalTooltip | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'showDelay')\"\n [zTooltipHideDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'hideDelay')\"\n [zTooltipArrow]=\"$any(totalTooltip | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(totalTooltip | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(totalTooltip | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(totalTooltip | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(totalTooltip | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"totalPopoverContent ? groupTotalPopoverTpl : null\"\n [zPosition]=\"$any(totalPopover | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(totalPopover | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(totalPopover | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(totalPopover | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(totalPopover | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(totalPopover | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(totalPopover | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(totalPopover | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(totalPopover | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"$any(totalPopover | zTablePopoverConfig: 'outsideClickClose')\"\n [zScrollClose]=\"$any(totalPopover | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(totalPopover | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(totalPopover | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(totalPopover | zTablePopoverConfig: 'keyboardSafe')\">\n {{ groupHeaderItem.totals[column.id] }}\n </span>\n }\n </td>\n }\n } @else {\n <td [attr.colspan]=\"renderedColumnCount()\">\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + groupHeaderItem.depth * 0.75\"\n [attr.aria-expanded]=\"groupHeaderItem.expanded\"\n (click)=\"toggleGroupRow(groupHeaderItem.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"groupHeaderItem.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"\n (groupHeaderItem.columnLabel ? groupHeaderItem.columnLabel + ': ' : '') +\n groupHeaderItem.label\n \">\n @if (groupHeaderItem.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ groupHeaderItem.columnLabel }}:</span>\n }\n {{ groupHeaderItem.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ groupHeaderItem.count }}</span>\n }\n @if (groupHeaderItem.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n [zWave]=\"false\"\n z-tooltip\n zSizeIcon=\"14\"\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(groupHeaderItem.columnId)\"></button>\n }\n </div>\n </td>\n }\n </tr>\n }\n @for (row of groupRows; track row.id) {\n @let virtualGroupDepth = _getVirtualGroupDepth(virtualFlatItem);\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <tr\n z-table-row-hover\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"effectiveDynamicRowSizing() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"effectiveDynamicRowSizing() ? virtualRowHeight() : null\"\n [style.--z-row-height]=\"effectiveDynamicRowSizing() ? 'auto' : virtualRowHeight() + 'px'\"\n [class.z-child-row]=\"row.depth > 0\"\n [class.z-group-child-row]=\"_isVirtualGroupChild(virtualFlatItem)\"\n [style.--z-group-content-indent]=\"\n virtualGroupDepth > 0 ? 1.75 + (virtualGroupDepth - 1) * 0.75 + 'rem' : null\n \"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"\n rowPinned === 'top' && (row | zTableRow: table : 'isFirstTopPinned')\n \"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"\n rowPinned === 'bottom' && (row | zTableRow: table : 'isLastBottomPinned')\n \"\n [class.z-pinned-bottom-first]=\"\n rowPinned === 'bottom' && (row | zTableRow: table : 'isFirstBottomPinned')\n \"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n (row | zTableRow: table : 'isLastTopPinned')\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n (row | zTableRow: table : 'isFirstBottomPinned')\n \"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : bodyRowSpanRows();\n @let shouldRenderColSpan = cell | zTableCellRender: visibleCells : zConfig().columns : 'body';\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (shouldRenderRowSpan && shouldRenderColSpan && isVirtualColumnVisible) {\n @let cellSelectionId = row.id + '::' + cell.column.id;\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"isColumnPinningActive && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActive && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"cell.column.id === actionColumnInfo()?.columnId\"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [class.z-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"cell | zTableCellBottom: zConfig().columns : renderedBodyRows()\"\n [attr.rowspan]=\"cell | zTableSpan: zConfig().columns : 'cellRowSpan' : bodyRowSpanRows()\"\n [attr.colspan]=\"cell | zTableSpan: zConfig().columns : 'cellColSpan'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n [style.--z-cell-range-top]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\n \"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\n \"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <button\n data-z-table-drag-handle\n type=\"button\"\n class=\"text-muted-foreground inline-flex size-7 items-center justify-center rounded-md\"\n [class.cursor-grab]=\"isRowDragEnabled()\"\n [class.opacity-40]=\"!isRowDragEnabled()\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === 'select') {\n <!-- Row Checkbox -->\n <div class=\"flex items-center justify-center\">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && cell.row.getIsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && cell.row.getIsSomeSelected() && !cell.row.getIsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection() || !cell.row.getCanSelect()\"\n (zChange)=\"canUseRowSelection() && cell.row.toggleSelected()\" />\n </div>\n } @else if (cell.column.id === 'expand') {\n <!-- Expand Button -->\n <div class=\"flex items-center justify-center\">\n @if (cell.row.getCanExpand()) {\n <button\n type=\"button\"\n (click)=\"cell.row.toggleExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"cell.row.getIsExpanded()\" />\n </button>\n }\n </div>\n } @else if (\n (cell.column.id === 'actionRowPin' || cell.column.id === 'actions') &&\n cell.column.id !== actionColumnInfo()?.columnId\n ) {\n @if (cell.row.depth === 0 && !hasBodyRowSpan()) {\n <div class=\"flex items-center justify-center\">\n <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (cell.row.getIsPinned() !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cell.row.getIsPinned() !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cell.row.getIsPinned()) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded p-1 outline-none\"\n [class.text-primary]=\"cell.row.getIsPinned()\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n </div>\n }\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisible = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisible) {\n @let editInfoVirtual = cell.getContext() | zTableCellEdit: zConfig().columns;\n @if (editInfoVirtual.enabled) {\n <!-- Editable Cell (Virtual) -->\n <z-table-edit-cell\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n [zRowIndex]=\"cell.row.index\"\n [zColumnId]=\"cell.column.id\"\n [zValue]=\"cell.getValue()\"\n [zRowUpdate]=\"_rowUpdate()\"\n [zEditConfig]=\"$any(editInfoVirtual.config)\"\n (zChange)=\"onCellEdit($any($event))\" />\n } @else if (editInfoVirtual.contentEnabled) {\n @let contentConfigVirtual = editInfoVirtual.contentConfig!;\n @if (\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n ) {\n <z-table-content-editor\n [zValue]=\"cell.getValue()\"\n [zConfig]=\"contentConfigVirtual\"\n (zCommit)=\"onContentEditCommit($event, row, cell.column.id, cell.getValue())\"\n (zCancel)=\"onContentEditCancel()\" />\n } @else {\n <button\n type=\"button\"\n class=\"z-table-content-trigger\"\n [attr.data-z-table-edit-row]=\"row.id\"\n [attr.data-z-table-edit-column]=\"cell.column.id\"\n (keydown)=\"onContentEditKeydown($event, row.id, cell.column.id)\"\n (click)=\"onContentEditStart($event, row.id, cell.column.id)\">\n {{ contentConfigVirtual.displayValue }}\n </button>\n }\n } @else {\n <ng-container\n *flexRender=\"\n cell.column.columnDef.cell;\n props: cell.getContext();\n let cellContent\n \">\n @if (cellContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n @let isClickable = cell.column.id | zTableCellClickable: zConfig().columns;\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickable && onCellClick(row, cell.column.id, cell.getValue())\">\n <ng-container\n *ngTemplateOutlet=\"\n cellContent;\n context: { $implicit: cell.getContext() }\n \" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n @let isClickableIcon = cell.column.id | zTableCellClickable: zConfig().columns;\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"\n isClickableIcon && onCellClick(row, cell.column.id, cell.getValue())\n \" />\n } @else {\n <!-- Default/innerHTML rendering -->\n @let isClickableDefault =\n cell.column.id | zTableCellClickable: zConfig().columns;\n @let cellTooltipConfig = cell | zTableCellConfig: zConfig() : 'contentTooltip';\n @let cellPopoverConfig = cell | zTableCellConfig: zConfig() : 'contentPopover';\n @let cellPopoverContent = cellPopoverConfig | zTablePopoverConfig: 'content';\n <ng-template #cellPopoverTpl>\n @if (cellPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(cellPopoverContent)\" />\n }\n @if (!(cellPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(cellPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n @if (cellPopoverContent) {\n <div\n class=\"z-table-cell-text\"\n z-popover\n z-tooltip\n [zTriggerElement]=\"cellOverlayContent\"\n [zTriggerRef]=\"cellOverlayContent\"\n [zContent]=\"\n (cellTooltipConfig | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'position')\n \"\n [zTooltipTrigger]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"cellPopoverTpl\"\n [zPosition]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'manualClose')\n \"\n [zOutsideClickClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'outsideClickClose')\n \"\n [zScrollClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'scrollClose')\n \"\n [zSticky]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'keyboardSafe')\n \"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellOverlayContent\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n } @else {\n <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zTriggerElement]=\"cellTooltipContent\"\n [zContent]=\"\n (cellTooltipConfig | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'position')\n \"\n [zTooltipTrigger]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'maxWidth')\"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellTooltipContent\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n }\n }\n </ng-container>\n }\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n\n <!--\n Bottom pinned rows: sibling AFTER the virtual canvas (not absolute like the\n center rows). The virtualizer reserves their height inside getTotalSize() via\n `paddingEnd`, leaving an empty band at the canvas bottom. `margin-top: -bottomHeight`\n pulls this real flow element back over that band, and `position: sticky; bottom: 0`\n floats it to the viewport bottom while scrolling.\n -->\n @if (virtualPinnedBottomRows().length > 0) {\n <div\n class=\"z-virtual-pinned-bottom\"\n [style.min-width.px]=\"table.getTotalSize()\"\n [style.margin-top.px]=\"-virtualPinnedBottomHeight()\">\n @for (row of virtualPinnedBottomRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"virtualPinnedRowTpl; context: { $implicit: row }\" />\n }\n </div>\n }\n\n <!-- Template for rendering pinned rows in virtual scroll mode -->\n <ng-template #virtualPinnedRowTpl let-row>\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody [class.z-has-vertical-scroll]=\"hasVerticalScroll()\">\n <tr\n z-table-row-hover\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"effectiveDynamicRowSizing() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"effectiveDynamicRowSizing() ? virtualRowHeight() : null\"\n [style.--z-row-height]=\"effectiveDynamicRowSizing() ? 'auto' : virtualRowHeight() + 'px'\"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && (row | zTableRow: table : 'isFirstTopPinned')\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"\n rowPinned === 'bottom' && (row | zTableRow: table : 'isLastBottomPinned')\n \"\n [class.z-pinned-bottom-first]=\"\n rowPinned === 'bottom' && (row | zTableRow: table : 'isFirstBottomPinned')\n \"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n (row | zTableRow: table : 'isLastTopPinned')\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n (row | zTableRow: table : 'isFirstBottomPinned')\n \"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @let isColumnPinningActivePinned = isPinnedLayoutWithinContainer();\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @let cellSelectionId = row.id + '::' + cell.column.id;\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (isVirtualColumnVisible) {\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActivePinned\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"isColumnPinningActivePinned && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActivePinned && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"cell.column.id === actionColumnInfo()?.columnId\"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [style.--z-cell-range-top]=\"(selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"(selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'select') {\n <z-checkbox\n [zChecked]=\"rowSelected\"\n [zIndeterminate]=\"rowSomeSelected && !rowSelected\"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && row.toggleSelected()\" />\n } @else if (cell.column.id === 'expand') {\n <button\n type=\"button\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"row.toggleExpanded()\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"row.getIsExpanded()\" />\n </button>\n } @else if (cell.column.id === 'actionRowPin') {\n <div class=\"flex items-center justify-center\">\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisible = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisible) {\n <ng-container\n *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let cellContent\">\n @if (cellContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { $implicit: cell.getContext() }\" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"(cell | zTableCellConfig: zConfig() : 'contentTooltip') || cellContent\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"></span>\n }\n </ng-container>\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n </tbody>\n </table>\n </ng-template>\n } @else {\n <!-- Normal Scroll Mode -->\n\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n class=\"z-table-drag-body\"\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-has-bottom-pinned]=\"table.getBottomRows().length > 0\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n <!-- Row Template -->\n <ng-template #rowTemplate let-row let-isGroupChild=\"isGroupChild\" let-groupDepth=\"groupDepth\">\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <tr\n z-table-row-hover\n z-table-draggable=\"row\"\n z-table-drop-target=\"row\"\n [z-table-drag-table-id]=\"dragInstanceId\"\n [z-table-drop-table-id]=\"dragInstanceId\"\n [z-table-drag-item-id]=\"row.id\"\n [z-table-drop-item-id]=\"row.id\"\n [z-table-drag-disabled]=\"!isRowDragEnabled()\"\n [z-table-drop-disabled]=\"!isRowDragEnabled()\"\n (zTableDropped)=\"_handleDragDrop($event)\"\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [ngStyle]=\"row | zTableRow: table : 'pinningStyles' : pinnedRowHeights() : virtualRowHeight()\"\n [class.z-child-row]=\"row.depth > 0\"\n [class.z-group-child-row]=\"isGroupChild\"\n [style.--z-group-content-indent]=\"groupDepth > 0 ? 1.75 + (groupDepth - 1) * 0.75 + 'rem' : null\"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && (row | zTableRow: table : 'isFirstTopPinned')\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"\n rowPinned === 'bottom' && (row | zTableRow: table : 'isLastBottomPinned')\n \"\n [class.z-pinned-bottom-first]=\"\n rowPinned === 'bottom' && (row | zTableRow: table : 'isFirstBottomPinned')\n \"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n (row | zTableRow: table : 'isLastTopPinned')\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n (row | zTableRow: table : 'isFirstBottomPinned')\n \"\n [attr.data-depth]=\"row.depth\"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @let cellRowPinned = cell.row.getIsPinned();\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : bodyRowSpanRows();\n @let shouldRenderColSpan = cell | zTableCellRender: visibleCells : zConfig().columns : 'body';\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (shouldRenderRowSpan && shouldRenderColSpan && isVirtualColumnVisible) {\n @let cellSelectionId = row.id + '::' + cell.column.id;\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n [class.z-sticky-left]=\"isColumnPinningActive && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActive && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"\n cell.column.id === 'actions' || cell.column.id === actionColumnInfo()?.columnId\n \"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [class.z-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"cell | zTableCellBottom: zConfig().columns : renderedBodyRows()\"\n [attr.rowspan]=\"cell | zTableSpan: zConfig().columns : 'cellRowSpan' : bodyRowSpanRows()\"\n [attr.colspan]=\"cell | zTableSpan: zConfig().columns : 'cellColSpan'\"\n [style.--z-cell-range-top]=\"(selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"(selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <button\n data-z-table-drag-handle\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground inline-flex size-7 items-center justify-center rounded-md transition-colors\"\n [class.cursor-grab]=\"isRowDragEnabled()\"\n [class.cursor-not-allowed]=\"!isRowDragEnabled()\"\n [class.opacity-40]=\"!isRowDragEnabled()\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === 'select') {\n <!-- Row Checkbox with Pin Button -->\n <div class=\"flex items-center justify-center gap-1\">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && cell.row.getIsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && cell.row.getIsSomeSelected() && !cell.row.getIsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection() || !cell.row.getCanSelect()\"\n (zChange)=\"canUseRowSelection() && cell.row.toggleSelected()\" />\n @if (zConfig().enableRowPinning && cell.row.depth === 0 && !hasBodyRowSpan()) {\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n }\n </div>\n } @else if (cell.column.id === 'expand') {\n <!-- Expand Button with Row Pin Popover -->\n <div class=\"flex items-center justify-center gap-1\">\n @if (cell.row.getCanExpand()) {\n <button\n type=\"button\"\n (click)=\"cell.row.toggleExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"cell.row.getIsExpanded()\" />\n </button>\n }\n @if (\n zConfig().enableRowPinning &&\n cell.row.depth === 0 &&\n !(cell.row.subRows && cell.row.subRows.length > 0) &&\n !hasBodyRowSpan()\n ) {\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n }\n </div>\n } @else if (\n (cell.column.id === 'actionRowPin' || cell.column.id === 'actions') &&\n cell.column.id !== actionColumnInfo()?.columnId\n ) {\n <!-- Actions Column - Row Pin Only (for parent rows) -->\n @if (cell.row.depth === 0 && !hasBodyRowSpan()) {\n <div class=\"flex items-center justify-center\">\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n </div>\n }\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisibleNormal = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisibleNormal) {\n @let editInfo = cell.getContext() | zTableCellEdit: zConfig().columns;\n @if (editInfo.enabled) {\n <!-- Editable Cell -->\n <z-table-edit-cell\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n [zRowIndex]=\"cell.row.index\"\n [zColumnId]=\"cell.column.id\"\n [zValue]=\"cell.getValue()\"\n [zRowUpdate]=\"_rowUpdate()\"\n [zEditConfig]=\"$any(editInfo.config)\"\n (zChange)=\"onCellEdit($any($event))\" />\n } @else if (editInfo.contentEnabled) {\n @let contentConfig = editInfo.contentConfig!;\n @if (\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n ) {\n <z-table-content-editor\n [zValue]=\"cell.getValue()\"\n [zConfig]=\"contentConfig\"\n (zCommit)=\"onContentEditCommit($event, row, cell.column.id, cell.getValue())\"\n (zCancel)=\"onContentEditCancel()\" />\n } @else {\n <button\n type=\"button\"\n class=\"z-table-content-trigger\"\n [attr.data-z-table-edit-row]=\"row.id\"\n [attr.data-z-table-edit-column]=\"cell.column.id\"\n (keydown)=\"onContentEditKeydown($event, row.id, cell.column.id)\"\n (click)=\"onContentEditStart($event, row.id, cell.column.id)\">\n {{ contentConfig.displayValue }}\n </button>\n }\n } @else {\n <ng-container\n *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let cellContent\">\n @if (cellContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n @let isClickableTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickableTpl && onCellClick(row, cell.column.id, cell.getValue())\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { $implicit: cell.getContext() }\" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n @let isClickableIconTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickableIconTpl && onCellClick(row, cell.column.id, cell.getValue())\" />\n } @else {\n <!-- Default/innerHTML rendering -->\n @let isClickableDefaultTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n @let cellTooltipConfigTpl = cell | zTableCellConfig: zConfig() : 'contentTooltip';\n @let cellPopoverConfigTpl = cell | zTableCellConfig: zConfig() : 'contentPopover';\n @let cellPopoverContentTpl = cellPopoverConfigTpl | zTablePopoverConfig: 'content';\n <ng-template #cellPopoverTplNormal>\n @if (cellPopoverContentTpl | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(cellPopoverContentTpl)\" />\n }\n @if (!(cellPopoverContentTpl | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(cellPopoverContentTpl) | zSafeHtml\"></div>\n }\n </ng-template>\n @if (cellPopoverContentTpl) {\n <div\n class=\"z-table-cell-text\"\n z-popover\n z-tooltip\n [zTriggerElement]=\"cellOverlayContentTpl\"\n [zTriggerRef]=\"cellOverlayContentTpl\"\n [zContent]=\"\n (cellTooltipConfigTpl | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"cellPopoverTplNormal\"\n [zPosition]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"\n $any(cellPopoverConfigTpl | zTablePopoverConfig: 'outsideClickClose')\n \"\n [zScrollClose]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'keyboardSafe')\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellOverlayContentTpl\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n } @else {\n <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zTriggerElement]=\"cellTooltipContentTpl\"\n [zContent]=\"\n (cellTooltipConfigTpl | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'maxWidth')\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellTooltipContentTpl\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n }\n }\n </ng-container>\n }\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n\n <!-- Expanded Row Detail -->\n @if (row.getIsExpanded() && row.depth === 0 && !row.subRows?.length) {\n @let resolvedSubTableConfig = row | zTableSubTableConfig: zConfig();\n <tr class=\"z-expanded-row\">\n <td [attr.colspan]=\"renderedColumnCount()\" class=\"p-0\">\n @if (zConfig().expandedRowTemplate) {\n <ng-container *ngTemplateOutlet=\"zConfig().expandedRowTemplate!; context: { $implicit: row }\" />\n } @else if (resolvedSubTableConfig) {\n <div class=\"z-sub-table-container\">\n <z-table [zConfig]=\"$any(resolvedSubTableConfig)\" zVariant=\"borderless\" />\n </div>\n }\n </td>\n </tr>\n }\n </ng-template>\n\n <!-- Render Top Pinned Rows (hidden when filtered data is empty) -->\n @if (!isEmpty()) {\n @for (row of table.getTopRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\n }\n }\n\n <!-- Render Center Rows -->\n @for (item of groupedCenterRowItems(); track item.type === 'group' ? item.id : item.row.id) {\n @if (item.type === 'group') {\n <tr\n class=\"z-group-row\"\n [class.z-group-row-has-totals]=\"item.totals\"\n [class.z-group-row-expanded]=\"item.expanded\"\n [attr.data-group-id]=\"item.id\"\n [attr.data-group-depth]=\"item.depth\">\n @if (item.totals) {\n @let totalColumnMap = groupTotalColumnMap();\n @for (column of orderedLeafColumns(); track column.id; let isFirstGroupCell = $first) {\n <td\n [class.z-group-row-label-cell]=\"isFirstGroupCell\"\n [class.z-group-row-total-cell]=\"!isFirstGroupCell && totalColumnMap[column.id]\"\n [attr.data-column-id]=\"column.id\">\n @if (isFirstGroupCell) {\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + item.depth * 0.75\"\n [attr.aria-expanded]=\"item.expanded\"\n (click)=\"toggleGroupRow(item.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"item.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"(item.columnLabel ? item.columnLabel + ': ' : '') + item.label\">\n @if (item.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ item.columnLabel }}:</span>\n }\n {{ item.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ item.count }}</span>\n }\n @if (item.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n zSizeIcon=\"14\"\n [zWave]=\"false\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(item.columnId)\"></button>\n }\n </div>\n }\n @if (!isFirstGroupCell && totalColumnMap[column.id]) {\n @let totalConfig = groupTotalConfigMap()[column.id];\n @let totalTooltip = totalConfig.tooltip;\n @let totalPopover = totalConfig.popover;\n @let totalPopoverContent = totalPopover | zTablePopoverConfig: 'content';\n <ng-template #groupTotalPopoverTpl>\n @if (totalPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(totalPopoverContent)\" />\n }\n @if (!(totalPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(totalPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n <span\n class=\"z-group-row-total\"\n z-tooltip\n z-popover\n [class]=\"totalConfig.class\"\n [zContent]=\"\n $any((totalTooltip | zTableTooltipConfig: 'content') || item.totals[column.id])\n \"\n [zTooltipPosition]=\"$any(totalTooltip | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(totalTooltip | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(totalTooltip | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(totalTooltip | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(totalTooltip | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'showDelay')\"\n [zTooltipHideDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'hideDelay')\"\n [zTooltipArrow]=\"$any(totalTooltip | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(totalTooltip | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(totalTooltip | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(totalTooltip | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(totalTooltip | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"totalPopoverContent ? groupTotalPopoverTpl : null\"\n [zPosition]=\"$any(totalPopover | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(totalPopover | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(totalPopover | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(totalPopover | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(totalPopover | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(totalPopover | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(totalPopover | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(totalPopover | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(totalPopover | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"$any(totalPopover | zTablePopoverConfig: 'outsideClickClose')\"\n [zScrollClose]=\"$any(totalPopover | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(totalPopover | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(totalPopover | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(totalPopover | zTablePopoverConfig: 'keyboardSafe')\">\n {{ item.totals[column.id] }}\n </span>\n }\n </td>\n }\n } @else {\n <td [attr.colspan]=\"renderedColumnCount()\">\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + item.depth * 0.75\"\n [attr.aria-expanded]=\"item.expanded\"\n (click)=\"toggleGroupRow(item.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"item.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"(item.columnLabel ? item.columnLabel + ': ' : '') + item.label\">\n @if (item.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ item.columnLabel }}:</span>\n }\n {{ item.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ item.count }}</span>\n }\n @if (item.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n zSizeIcon=\"14\"\n [zWave]=\"false\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(item.columnId)\"></button>\n }\n </div>\n </td>\n }\n </tr>\n }\n @if (item.type === 'row') {\n <ng-container\n *ngTemplateOutlet=\"\n rowTemplate;\n context: {\n $implicit: item.row,\n isGroupChild: item.isGroupChild,\n groupDepth: item.groupDepth,\n }\n \" />\n }\n }\n\n <!-- Render Bottom Pinned Rows (hidden when filtered data is empty) -->\n @if (!isEmpty()) {\n @for (row of bottomRowsReversed(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\n }\n }\n </tbody>\n </table>\n }\n </ng-scrollbar>\n }\n <!-- end @else -->\n </div>\n\n <!-- Footer table -->\n @if (hasFooter()) {\n <div\n class=\"z-tfoot-wrapper\"\n [class.z-shadow-footer]=\"shouldFooterShowShadow()\"\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\"\n #tfootWrapper>\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tfoot>\n @for (footerGroup of orderedFooterGroups(); track footerGroup.id; let footerRowIndex = $index) {\n @if (footerGroup | zTableFooterContent: zConfig().columns : footerRowIndex) {\n <tr>\n @for (footer of footerGroup.headers; track footer.id) {\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n footer.column.id === firstVirtualCenterColumnId()\n ) {\n <th\n class=\"z-virtual-column-spacer z-virtual-footer-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></th>\n }\n @let rowSpan = footer | zTableSpan: zConfig().columns : 'footerRowSpan' : footerRowIndex;\n @let shouldRender =\n footer\n | zTableCellRender\n : footerGroup.headers\n : zConfig().columns\n : 'footer'\n : footerRowIndex\n : orderedFooterGroups();\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n footer.column.getIsPinned() !== false ||\n virtualCenterColumnVisibilityMap()[footer.column.id];\n @if (rowSpan && shouldRender && isVirtualColumnVisible) {\n <th\n [attr.data-column-id]=\"footer.column.id\"\n [ngStyle]=\"\n footer.column\n | zTablePinningStyles\n : footer\n : 'footer'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerClass' : footerRowIndex) +\n ' ' +\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex)\n \"\n [style]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerStyle' : footerRowIndex\n \"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (footer | zTableCellPin: 'isLeftPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-at-left-edge]=\"footer | zTableCellOffset: orderedLeafColumns()\"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"footer | zTableSpan: zConfig().columns : 'footerColSpan' : footerRowIndex\">\n @let configFooterContent =\n footer.column.id | zTableFooterRender: zConfig().columns : footerRowIndex;\n @if (configFooterContent !== undefined && configFooterContent !== '') {\n <ng-container *flexRender=\"configFooterContent; props: footer.getContext(); let footerContent\">\n <div\n class=\"flex w-full items-center\"\n [class.justify-center]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex) ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex) ===\n 'text-right'\n \">\n @if (footerContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n <div\n class=\"z-template-content\"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \">\n <ng-container\n *ngTemplateOutlet=\"footerContent; context: { $implicit: footer.getContext() }\" />\n </div>\n } @else if (footerContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n <z-table-icon-text\n [zText]=\"footerContent\"\n [zTooltip]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerTooltip' : footerRowIndex\n \"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \" />\n } @else {\n <!-- Default/string rendering -->\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerTooltip' : footerRowIndex) ||\n footerContent\n \"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \">\n {{ footerContent | translate }}\n </span>\n }\n </div>\n </ng-container>\n }\n </th>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n footer.column.id === lastVirtualCenterColumnId()\n ) {\n <th\n class=\"z-virtual-column-spacer z-virtual-footer-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></th>\n }\n }\n </tr>\n }\n }\n </tfoot>\n </table>\n </div>\n }\n</div>\n\n<!-- Pagination -->\n@if (zConfig().pagination?.enabled !== false) {\n <div class=\"mt-4 flex items-center justify-between gap-4\">\n <div class=\"truncate text-sm text-gray-500\">\n {{ 'i18n_z_ui_table_total_rows' | translate: { total: (paginationTotal() | zFormatNum) } }}\n </div>\n <z-pagination\n [zTotal]=\"paginationTotal()\"\n [(zPageIndex)]=\"pagination().pageIndex\"\n [(zPageSize)]=\"pagination().pageSize\"\n [zPageSizeOptions]=\"zConfig().pagination?.pageSizeOptions ?? [10, 20, 50, 100]\"\n [zShowSizeChanger]=\"zConfig().pagination?.showSizeChanger ?? true\"\n [zShowQuickJumper]=\"zConfig().pagination?.showQuickJumper ?? false\"\n [zShowTotal]=\"false\"\n [zDisabled]=\"zConfig().pagination?.disabled || isLoading() || isProcessing()\"\n (zOnPageChange)=\"onPageChange($event)\" />\n </div>\n}\n\n<!-- Floating Bulk Action Bar -->\n<div class=\"z-bulk-action-bar-origin\" cdkOverlayOrigin #bulkBarOrigin=\"cdkOverlayOrigin\"></div>\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"bulkBarOrigin\"\n [cdkConnectedOverlayOpen]=\"bulkBarMounted()\"\n [cdkConnectedOverlayPositions]=\"bulkBarPositions\"\n [cdkConnectedOverlayHasBackdrop]=\"false\"\n cdkConnectedOverlayPanelClass=\"z-bulk-action-bar-overlay\">\n @if (bulkBarConfig(); as config) {\n <div class=\"z-bulk-action-bar-inner\" [class.z-leaving]=\"bulkBarClosing()\">\n <div class=\"z-bulk-action-bar-count\">\n {{ bulkBarContext()?.selectedRowIds?.length ?? 0 | zFormatNum }}\n {{ config.selectedLabel ?? ('i18n_z_ui_table_selected' | translate) }}\n </div>\n\n <div class=\"z-bulk-action-bar-divider\"></div>\n\n @for (item of bulkBarItems(); track item.action.key) {\n <button\n type=\"button\"\n z-button\n zSize=\"sm\"\n [zType]=\"item.buttonType\"\n [zDisabled]=\"item.disabled\"\n class=\"z-bulk-action-bar-button\"\n [disabled]=\"item.disabled\"\n (click)=\"onBulkActionClick(item.action)\">\n @if (item.action.icon) {\n <z-icon [zType]=\"item.action.icon\" [zSize]=\"item.action.iconSize ?? '14'\" />\n }\n @if (item.action.label) {\n <span>{{ item.action.label | translate }}</span>\n }\n </button>\n }\n </div>\n }\n</ng-template>\n\n<!-- Settings Drawer -->\n<z-drawer\n [(zVisible)]=\"showSettingsDrawer\"\n [zTitle]=\"'i18n_z_ui_table_settings_title' | translate\"\n zPlacement=\"right\"\n zWidth=\"500px\"\n [zShadow]=\"true\"\n [zOkText]=\"null\"\n [zCancelText]=\"'i18n_z_ui_drawer_close' | translate\">\n <div class=\"z-table-settings-drawer px-4\">\n <!-- Display Settings -->\n <div class=\"mb-4\">\n <h4 class=\"text-foreground mb-2 text-sm font-semibold\">{{ 'i18n_z_ui_table_display_settings' | translate }}</h4>\n <p class=\"text-muted-foreground mb-3 text-xs\">{{ 'i18n_z_ui_table_display_settings_desc' | translate }}</p>\n <div class=\"grid grid-cols-2 gap-x-4 gap-y-3\">\n <z-checkbox\n [zChecked]=\"showHorizontalBorder()\"\n [zText]=\"'i18n_z_ui_table_horizontal_border' | translate\"\n (zChange)=\"showHorizontalBorder.set(!showHorizontalBorder())\" />\n <z-checkbox\n [zChecked]=\"showVerticalBorder()\"\n [zText]=\"'i18n_z_ui_table_vertical_border' | translate\"\n (zChange)=\"showVerticalBorder.set(!showVerticalBorder())\" />\n <z-checkbox\n [zChecked]=\"showHeaderFooterShadow()\"\n [zText]=\"'i18n_z_ui_table_header_footer_shadow' | translate\"\n (zChange)=\"showHeaderFooterShadow.set(!showHeaderFooterShadow())\" />\n </div>\n </div>\n\n <!-- Divider -->\n <div class=\"border-border my-4 border-t\"></div>\n\n <!-- Unified Column Settings -->\n <!-- T\u1EA1m t\u1EAFt \u0111i\u1EC1u ki\u1EC7n: @if (zConfig().enableSettings) -->\n <div class=\"mb-4\">\n <h4 class=\"text-foreground mb-2 text-sm font-semibold\">{{ 'i18n_z_ui_table_column_settings' | translate }}</h4>\n <p class=\"text-muted-foreground mb-3 text-xs\">{{ 'i18n_z_ui_table_column_settings_desc' | translate }}</p>\n\n <!-- Unpinned Columns (Draggable) -->\n <div\n cdkDropList\n #columnDropList=\"cdkDropList\"\n [cdkDropListAutoScrollDisabled]=\"true\"\n (cdkDropListDropped)=\"onPendingColumnDrop($event)\"\n class=\"z-column-drop-list space-y-1.5\">\n @for (columnId of columnOrder(); track columnId; let i = $index) {\n @if (columnId !== 'expand' && columnId !== 'select' && columnId !== 'rowDrag') {\n @let column = table.getColumn(columnId);\n @let isPinned = column?.getIsPinned();\n @let isVisible = pendingVisibleColumns().includes(columnId);\n @let isVisibilityDisabled = pendingColumnVisibilityDisabledMap()[columnId];\n @let isGroupedColumn = groupingColumnMap()[columnId];\n @let columnEnablePinningConfig = columnId | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let canPin =\n (columnEnablePinningConfig ?? zConfig().enableColumnPinning ?? true) && column?.getCanPin() !== false;\n @if (!isPinned) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"isGroupedColumn\"\n [cdkDragData]=\"columnId\"\n cdkDragLockAxis=\"y\"\n cdkDragPreviewContainer=\"global\"\n cdkDragPreviewClass=\"z-drag-preview\"\n class=\"z-drag-item border-border bg-card hover:border-primary flex cursor-default items-center gap-2 rounded border px-2 py-1.5 text-sm\"\n [class.opacity-60]=\"!isVisible\">\n <!-- Drag Handle -->\n <z-icon\n cdkDragHandle\n zType=\"lucideGripVertical\"\n zSize=\"14\"\n class=\"text-muted-foreground shrink-0\"\n [class.cursor-pointer]=\"!isGroupedColumn\"\n [class.cursor-default]=\"isGroupedColumn\"\n [class.opacity-40]=\"isGroupedColumn\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n [disabled]=\"isVisibilityDisabled\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n (mousedown)=\"$event.stopPropagation()\"\n class=\"border-input h-4 w-4 shrink-0 cursor-default rounded disabled:opacity-50\" />\n\n <!-- Column Name -->\n <span class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\" [class.text-muted-foreground]=\"!isVisible\">\n {{ columnId | zTableColumnHeader: zConfig().columns | translate }}\n </span>\n @let parents = columnId | zTableColumnParents: zConfig().columns;\n @if (parents) {\n <span class=\"text-muted-foreground truncate text-[0.625rem]\">({{ parents | translate }})</span>\n }\n </span>\n\n <!-- Pin Buttons -->\n @if (canPin) {\n <div class=\"flex shrink-0 items-center gap-0.5\" (mousedown)=\"$event.stopPropagation()\">\n <button\n type=\"button\"\n [disabled]=\"!isVisible || isGroupedColumn || !pinAvailabilityMap()[columnId]?.left\"\n (click)=\"onToggleColumnPin(columnId, 'left')\"\n class=\"text-muted-foreground hover:bg-muted cursor-pointer rounded p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Pin Left\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"12\" />\n </button>\n <button\n type=\"button\"\n [disabled]=\"!isVisible || isGroupedColumn || !pinAvailabilityMap()[columnId]?.right\"\n (click)=\"onToggleColumnPin(columnId, 'right')\"\n class=\"text-muted-foreground hover:bg-muted cursor-pointer rounded p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Pin Right\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"12\" />\n </button>\n </div>\n }\n </div>\n }\n }\n }\n </div>\n\n <!-- Pinned Columns Section -->\n @if (zConfig().enableColumnPinning ?? true) {\n @if (pinnedColumnIds().length > 0) {\n <div class=\"border-border mt-4 border-t pt-4\">\n <h5 class=\"text-muted-foreground mb-2 text-xs font-medium\">\n {{ 'i18n_z_ui_table_pinned_columns' | translate }}\n </h5>\n <div class=\"space-y-1.5\">\n @for (columnId of pinnedColumnIds(); track columnId) {\n @let column = table.getColumn(columnId);\n @let isPinned = column?.getIsPinned();\n @let isVisible = pendingVisibleColumns().includes(columnId);\n @let isVisibilityDisabled = pendingColumnVisibilityDisabledMap()[columnId];\n @let isGroupedColumn = groupingColumnMap()[columnId];\n <div\n class=\"border-border bg-muted/30 flex items-center gap-2 rounded border px-2 py-1.5 text-sm\"\n [class.opacity-60]=\"!isVisible\">\n <!-- Pin Icon -->\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"text-primary shrink-0\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n [disabled]=\"isVisibilityDisabled\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n class=\"border-input h-4 w-4 shrink-0 cursor-default rounded disabled:opacity-50\" />\n\n <!-- Column Name -->\n <span class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\" [class.text-muted-foreground]=\"!isVisible\">\n {{ columnId | zTableColumnHeader: zConfig().columns | translate }}\n </span>\n @let pinnedParents = columnId | zTableColumnParents: zConfig().columns;\n @if (pinnedParents) {\n <span class=\"text-muted-foreground truncate text-[0.625rem]\">\n ({{ pinnedParents | translate }})\n </span>\n }\n </span>\n\n <!-- Position Badge -->\n <span class=\"bg-primary/10 text-primary shrink-0 rounded px-1.5 py-0.5 text-[0.625rem] font-medium\">\n {{\n isPinned === 'start'\n ? ('i18n_z_ui_table_left' | translate)\n : ('i18n_z_ui_table_right' | translate)\n }}\n </span>\n\n <!-- Unpin Button -->\n <button\n type=\"button\"\n [disabled]=\"isGroupedColumn\"\n (click)=\"onToggleColumnPin(columnId, isPinned === 'start' ? 'left' : 'right')\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground cursor-pointer rounded p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Unpin\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </div>\n }\n </div>\n </div>\n }\n }\n </div>\n </div>\n</z-drawer>\n", styles: [":host{display:flex;flex-direction:column;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;overflow-x:visible;--scrollbar-track-thickness: 7px;--scrollbar-track-color: transparent;--scrollbar-thumb-shape: 3px;--z-shadow-left-right: -1.875rem;--z-shadow-left-width: 1.875rem;--z-shadow-left-opacity: 0;--z-shadow-right-left: -1.875rem;--z-shadow-right-width: 1.875rem;--z-shadow-right-opacity: 0;--z-sticky-left-border-color: transparent;--z-sticky-right-border-color: var(--border);--z-cell-selection-background: color-mix(in srgb, var(--primary) 12%, transparent);--z-cell-selection-background-opaque: color-mix(in srgb, var(--primary) 12%, var(--card))}.z-table-container{display:flex;flex-direction:column;position:relative;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;overflow:hidden;border-radius:.3125rem;border:thin solid var(--border);background-color:var(--card)}.z-table-container:focus{outline:none}.z-table-container.z-table-borderless{border:none;border-radius:0;box-shadow:none!important;background-color:transparent}.z-table-container.z-hide-horizontal-border th,.z-table-container.z-hide-horizontal-border td{border-bottom:none!important;border-top:none!important}.z-table-container.z-hide-vertical-border th,.z-table-container.z-hide-vertical-border td{border-left:none!important}.z-table-container.z-hide-pinned-top-border tbody tr.z-pinned-top.z-shadow-bottom>td{border-bottom-color:var(--border)!important}.z-table-container.z-hide-pinned-bottom-border tbody.z-has-bottom-pinned td.z-at-bottom{border-bottom-color:transparent}table{width:fit-content;min-width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed;font-size:.875rem}.z-table-container.z-column-resizing table,.z-table-toolbar{min-width:0}.z-table-toolbar .z-settings-btn{transition:all .15s ease}.z-table-toolbar .z-settings-btn:hover{border-color:var(--muted-foreground)}.z-table-filter-header{min-width:0}.z-table-filter-header button{flex:none}.z-table-filter-header-overflow-chip{animation:z-table-filter-chip-enter .16s ease}@media(prefers-reduced-motion:reduce){.z-table-filter-header-overflow-chip{animation:none}}@keyframes z-table-filter-chip-enter{0%{opacity:0;transform:translate(-.25rem)}to{opacity:1;transform:translate(0)}}.z-bulk-action-bar-origin{position:fixed;left:50%;bottom:1rem;width:1px;height:1px;pointer-events:none}:host ::ng-deep .z-bulk-action-bar-overlay{max-width:calc(100vw - 2rem);margin-bottom:1rem;transform-origin:center bottom}.z-bulk-action-bar-inner{border:thin solid color-mix(in srgb,var(--border) 88%,transparent);border-radius:.4rem;background:color-mix(in srgb,var(--card) 96%,var(--background));color:var(--foreground);box-shadow:0 1rem 2.5rem color-mix(in srgb,var(--foreground) 20%,transparent),0 .25rem .75rem color-mix(in srgb,var(--foreground) 12%,transparent),0 0 0 1px color-mix(in srgb,var(--background) 65%,transparent) inset;display:flex;align-items:center;gap:.5rem;width:max-content;min-height:2.25rem;max-width:calc(100vw - 2rem);padding:.5rem;transform-origin:center bottom;animation:z-bulk-action-bar-enter .18s cubic-bezier(.16,1,.3,1);will-change:opacity,transform}.z-bulk-action-bar-inner.z-leaving{pointer-events:none;animation:z-bulk-action-bar-exit .14s ease-in forwards}.z-bulk-action-bar-count{padding:0 .25rem;white-space:nowrap;font-size:.8125rem;font-weight:500;color:var(--foreground)}.z-bulk-action-bar-divider{width:1px;height:1.5rem;flex:none;background:color-mix(in srgb,var(--border) 88%,transparent)}.z-bulk-action-bar-button{flex:none}@keyframes z-bulk-action-bar-enter{0%{opacity:0;transform:translateY(.875rem)}to{opacity:1;transform:translateY(0)}}@keyframes z-bulk-action-bar-exit{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(.875rem)}}@media(prefers-reduced-motion:reduce){.z-bulk-action-bar-inner{animation:none}}:host ::ng-deep .z-table-cell-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;min-width:0;-webkit-user-select:text;user-select:text}:host ::ng-deep .z-table-cell-text>*,:host ::ng-deep .z-table-cell-text *{display:inline-block;max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}:host ::ng-deep .z-table-cell-content-trigger{display:inline-block;max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}.z-template-content{display:block;width:100%;min-width:0;max-width:100%;overflow:hidden}.z-template-content>*{min-width:0;max-width:100%}.z-template-content>[class*=flex]{min-width:0;max-width:100%}.z-template-content>[class*=flex]>*{min-width:0;flex-shrink:1}.z-template-content>[class*=grid]{min-width:0;max-width:100%}.z-thead-wrapper{flex-shrink:0;background:var(--muted);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;position:relative;z-index:4}.z-thead-wrapper::-webkit-scrollbar{display:none}.z-thead-wrapper th{height:auto;padding:.5rem;text-align:left;vertical-align:middle;font-weight:500;color:var(--foreground);white-space:nowrap;overflow:hidden;background:var(--muted);border-left:thin solid var(--border);border-bottom:thin solid var(--border);-webkit-user-select:none;user-select:none}.z-thead-wrapper th.z-at-left-edge{border-left:none}.z-thead-wrapper th[colspan]{text-align:center;background:var(--muted);font-weight:500;color:var(--foreground)}.z-thead-wrapper.z-shadow-header{box-shadow:0 1px 3px #00000014;position:relative;z-index:15}.z-thead-wrapper.z-shadow-header:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}.z-tbody-wrapper{flex:1;width:100%;max-width:100%;min-width:0;min-height:6.25rem;display:flex;flex-direction:column;overflow:hidden}.z-tbody-scrollbar{flex:1;width:100%;max-width:100%;min-width:0;height:100%}.z-empty-state,.z-loading-state{flex:1 1 0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;min-height:6.25rem;height:100%;color:var(--muted-foreground);font-size:.875rem;animation:z-fade-in .2s ease-out}.z-tbody-scrollbar,.z-tbody-scrollbar table{animation:z-fade-in .2s ease-out}@keyframes z-fade-in{0%{opacity:0;transform:translateY(.25rem)}to{opacity:1;transform:translateY(0)}}.z-tbody-wrapper tr{transition:background-color .15s ease}.z-tbody-wrapper tr:hover,.z-tbody-wrapper tr:hover td[style*=sticky]{background-color:var(--muted)}.z-tbody-wrapper tr.z-pinned-top td.z-sticky-left,.z-tbody-wrapper tr.z-pinned-top td.z-sticky-right,.z-tbody-wrapper tr.z-pinned-bottom td.z-sticky-left,.z-tbody-wrapper tr.z-pinned-bottom td.z-sticky-right{z-index:3}.z-tbody-wrapper tr.z-shadow-bottom{box-shadow:0 1px 3px #00000014!important;position:relative;z-index:15}.z-tbody-wrapper tr.z-shadow-bottom:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d!important}.z-tbody-wrapper tr.z-shadow-top{box-shadow:0 -2px 4px #0000000d!important;position:relative;z-index:15}.z-tbody-wrapper tr.z-shadow-top:where(.dark,.dark *){box-shadow:0 -2px 4px #0003!important}.z-tbody-wrapper td{padding:.5rem 12px;height:var(--z-row-height, 2.375rem);vertical-align:middle;color:var(--foreground);white-space:nowrap;overflow:hidden;background:var(--card);border-left:thin solid var(--border);border-bottom:thin solid var(--border);box-sizing:border-box}.z-tbody-wrapper tbody.z-has-vertical-scroll td.z-at-bottom,.z-tbody-wrapper tbody.z-last-row-touches-bottom td.z-at-bottom{border-bottom-color:transparent}.z-tbody-wrapper tbody.z-has-bottom-pinned td.z-at-bottom{border-bottom-color:var(--border)}.z-tbody-wrapper td.z-at-left-edge{border-left:none}.z-tbody-wrapper td i{color:var(--muted-foreground);font-style:italic}.z-tbody-wrapper td[rowspan]{vertical-align:top;padding-top:.75rem}.z-tbody-wrapper td.z-row-hover{background-color:var(--muted)!important}.z-tbody-wrapper td.z-col-select,.z-tbody-wrapper td.z-col-expand,.z-tbody-wrapper td.z-col-actions{padding:.5rem 4px!important;text-align:center}.z-tbody-wrapper tr.z-child-row td.z-col-select:first-child,.z-tbody-wrapper tr.z-child-row td.z-col-expand:first-child,.z-tbody-wrapper tr.z-child-row td.z-col-actions:first-child{padding-left:0!important}.z-virtual-scroll-inner{position:relative;box-sizing:border-box;width:100%}.z-virtual-row{position:absolute;top:0;left:0;width:100%}tr.z-child-row td:first-child{border-left:.125rem solid var(--primary)!important;padding-left:.75rem!important}tbody tr.z-context-menu-active,tbody tr.z-context-menu-active td{background-color:var(--muted)!important}tbody tr.z-selected,tbody tr.z-selected td{background-color:color-mix(in srgb,var(--primary) 15%,var(--background))!important}tbody tr.z-selected:hover,tbody tr.z-selected:hover td{background-color:color-mix(in srgb,var(--primary) 20%,var(--background))!important}tbody tr.z-indeterminate-selected,tbody tr.z-indeterminate-selected td{background-color:color-mix(in srgb,var(--primary) 10%,var(--background))!important}tbody tr.z-indeterminate-selected:hover,tbody tr.z-indeterminate-selected:hover td{background-color:color-mix(in srgb,var(--primary) 15%,var(--background))!important}tbody tr.z-pinned-top td{background-color:var(--card)!important}tbody tr.z-pinned-top:hover{background-color:var(--muted)}tbody tr.z-pinned-top:hover td{background-color:var(--muted)!important}tbody tr.z-pinned-bottom td{background-color:var(--card)!important}tbody tr.z-pinned-bottom:hover{background-color:var(--muted)}tbody tr.z-pinned-bottom:hover td{background-color:var(--muted)!important}tbody tr.z-pinned-bottom-last>td{border-bottom-color:transparent!important}tbody tr.z-pinned-bottom-first>td{border-top:thin solid var(--border)}:host .z-tbody-wrapper tbody tr:not(.z-pinned-top):not(.z-pinned-bottom):has(+tr.z-pinned-bottom)>td{border-bottom-color:transparent}tr.z-expanded-row>td{border-left:.125rem solid var(--primary);background-color:var(--background)!important}.z-sub-table-container{padding:.75rem 1rem .75rem 3rem;background-color:var(--background)}.z-table-content-trigger{display:block;width:100%;min-width:0;min-height:1.5rem;padding:0;border:0;border-radius:0;background:transparent;color:inherit;font:inherit;line-height:1.5rem;text-align:inherit;outline:0;cursor:text}.z-table-content-trigger:hover{color:var(--primary)}.z-content-edit-active{position:relative;z-index:2}td:has(>.z-table-content-trigger:focus-visible){position:relative;z-index:2}td:has(>.z-table-content-trigger:focus-visible):after{position:absolute;z-index:3;inset:0;border:1px solid var(--primary);content:\"\";pointer-events:none}td.z-cell-selectable{-webkit-user-select:none;user-select:none}td.z-cell-range-selected{position:relative;isolation:isolate}td.z-cell-range-selected:before{position:absolute;z-index:0;box-sizing:border-box;top:var(--z-cell-range-top, 0);right:var(--z-cell-range-right, 0);bottom:var(--z-cell-range-bottom, 0);left:var(--z-cell-range-left, 0);background-color:var(--z-cell-selection-background);content:\"\";pointer-events:none}td.z-cell-range-selected>*{position:relative;z-index:1}td.z-cell-range-top:before{border-top:1px solid var(--primary)}td.z-cell-range-right:before{border-right:1px solid var(--primary)}td.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}td.z-cell-range-left:before{border-left:1px solid var(--primary)}td.z-cell-active{position:relative;z-index:3;background-color:var(--z-cell-selection-background)!important}td.z-cell-active:after{position:absolute;z-index:4;inset:0;border:1px solid var(--primary);content:\"\";pointer-events:none}td.z-content-edit-active{-webkit-user-select:text;user-select:text}td.z-cell-active.z-row-hover,td.z-content-edit-active.z-row-hover{background-color:var(--card)!important}thead th{position:relative}thead th .z-resizer{position:absolute;right:0;top:0;height:100%;width:.5rem;background:transparent;cursor:col-resize;-webkit-user-select:none;user-select:none;touch-action:none;z-index:5}thead th .z-resizer:after{content:\"\";position:absolute;right:0;top:0;height:100%;width:.1875rem;background:#0000001a;opacity:0;transition:opacity .2s ease}thead th .z-resizer:after:where(.dark,.dark *){background:#ffffff1a}thead th .z-resizer:hover:after{opacity:1;background:var(--primary);width:.1875rem}thead th .z-resizer.z-is-resizing:after{opacity:1;background:var(--primary);width:.1875rem}thead th .z-resizer.z-resizer-left{right:auto;left:0}thead th .z-resizer.z-resizer-left:after{right:auto;left:0}.z-thead-wrapper th.z-sticky-left,.z-thead-wrapper th.z-sticky-right,.z-tbody-wrapper th.z-sticky-left,.z-tbody-wrapper th.z-sticky-right,.z-tfoot-wrapper th.z-sticky-left,.z-tfoot-wrapper th.z-sticky-right{background-color:var(--muted);z-index:1;transform:translateZ(0);backface-visibility:hidden}.z-thead-wrapper td.z-sticky-left,.z-thead-wrapper td.z-sticky-right,.z-tbody-wrapper td.z-sticky-left,.z-tbody-wrapper td.z-sticky-right,.z-tfoot-wrapper td.z-sticky-left,.z-tfoot-wrapper td.z-sticky-right{background-color:var(--card);z-index:1;transform:translateZ(0);backface-visibility:hidden}.z-thead-wrapper th.z-sticky-left-last,.z-thead-wrapper td.z-sticky-left-last,.z-tbody-wrapper th.z-sticky-left-last,.z-tbody-wrapper td.z-sticky-left-last,.z-tfoot-wrapper th.z-sticky-left-last,.z-tfoot-wrapper td.z-sticky-left-last{position:relative;overflow:visible;border-right:thin solid var(--z-sticky-left-border-color)}.z-thead-wrapper th.z-sticky-left-last:after,.z-thead-wrapper td.z-sticky-left-last:after,.z-tbody-wrapper th.z-sticky-left-last:after,.z-tbody-wrapper td.z-sticky-left-last:after,.z-tfoot-wrapper th.z-sticky-left-last:after,.z-tfoot-wrapper td.z-sticky-left-last:after{content:\"\";position:absolute;top:0;bottom:0;right:var(--z-shadow-left-right);width:var(--z-shadow-left-width);pointer-events:none;box-shadow:inset 10px 0 8px -8px #0000001a;z-index:10;opacity:var(--z-shadow-left-opacity)}:host-context(.dark) .z-thead-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-thead-wrapper td.z-sticky-left-last:after,:host-context(.dark) .z-tbody-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-tbody-wrapper td.z-sticky-left-last:after,:host-context(.dark) .z-tfoot-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-tfoot-wrapper td.z-sticky-left-last:after{box-shadow:inset 10px 0 10px -8px #0000004d}.z-thead-wrapper.z-scroll-left,.z-tbody-wrapper.z-scroll-left,.z-tfoot-wrapper.z-scroll-left{--z-shadow-left-opacity: 1}.z-thead-wrapper.z-scroll-left:where(.dark,.dark *),.z-tbody-wrapper.z-scroll-left:where(.dark,.dark *),.z-tfoot-wrapper.z-scroll-left:where(.dark,.dark *){--z-sticky-left-border-color: var(--border)}.z-thead-wrapper th.z-sticky-right-first,.z-thead-wrapper td.z-sticky-right-first,.z-tbody-wrapper th.z-sticky-right-first,.z-tbody-wrapper td.z-sticky-right-first,.z-tfoot-wrapper th.z-sticky-right-first,.z-tfoot-wrapper td.z-sticky-right-first{position:relative;overflow:visible;border-left:thin solid var(--z-sticky-right-border-color)}.z-thead-wrapper th.z-sticky-right-first:before,.z-thead-wrapper td.z-sticky-right-first:before,.z-tbody-wrapper th.z-sticky-right-first:before,.z-tbody-wrapper td.z-sticky-right-first:before,.z-tfoot-wrapper th.z-sticky-right-first:before,.z-tfoot-wrapper td.z-sticky-right-first:before{content:\"\";position:absolute;top:0;bottom:0;left:var(--z-shadow-right-left);width:var(--z-shadow-right-width);pointer-events:none;box-shadow:inset -10px 0 8px -8px #0000001a;z-index:10;opacity:var(--z-shadow-right-opacity)}:host-context(.dark) .z-thead-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-thead-wrapper td.z-sticky-right-first:before,:host-context(.dark) .z-tbody-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-tbody-wrapper td.z-sticky-right-first:before,:host-context(.dark) .z-tfoot-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-tfoot-wrapper td.z-sticky-right-first:before{box-shadow:inset -10px 0 10px -8px #0000004d}.z-thead-wrapper.z-scroll-right,.z-tbody-wrapper.z-scroll-right,.z-tfoot-wrapper.z-scroll-right{--z-shadow-right-opacity: 1}.z-thead-wrapper.z-scroll-right:not(:where(.dark,.dark *)),.z-tbody-wrapper.z-scroll-right:not(:where(.dark,.dark *)),.z-tfoot-wrapper.z-scroll-right:not(:where(.dark,.dark *)){--z-sticky-right-border-color: transparent}.z-pinning-overflow{--z-shadow-left-opacity: 0 !important;--z-shadow-right-opacity: 0 !important;--z-sticky-left-border-color: transparent !important;--z-sticky-right-border-color: transparent !important}.z-pinning-overflow .z-sticky-left,.z-pinning-overflow .z-sticky-right{position:relative!important;right:auto!important;left:auto!important}.z-pinning-overflow .z-sticky-left-last:after,.z-pinning-overflow .z-sticky-right-first:before,.z-pinning-overflow .z-sticky-right-last:after{display:none!important}.z-thead-wrapper th.z-sticky-right-last,.z-tfoot-wrapper th.z-sticky-right-last{position:relative}.z-thead-wrapper th.z-sticky-right-last:after,.z-tfoot-wrapper th.z-sticky-right-last:after{content:\"\";position:absolute;top:0;bottom:0;right:-1.875rem;width:1.875rem;background:var(--muted);pointer-events:none}.z-tfoot-wrapper{flex-shrink:0;width:100%;max-width:100%;min-width:0;background:var(--muted);overflow-x:hidden;overflow-y:hidden;touch-action:pan-y pinch-zoom}.z-tfoot-wrapper th{height:auto;padding:.5rem 12px;text-align:left;vertical-align:middle;font-weight:500;font-size:.75rem;color:var(--muted-foreground);text-transform:uppercase;letter-spacing:.5px;background:var(--muted);border-left:thin solid var(--border);border-top:thin solid var(--border)}.z-tfoot-wrapper th.z-at-left-edge{border-left:none}.z-tfoot-wrapper.z-shadow-footer{box-shadow:0 -2px 4px #0000000d;position:relative;z-index:15}.z-tfoot-wrapper.z-shadow-footer:where(.dark,.dark *){box-shadow:0 -2px 4px #0003}.z-pin-btn{padding:.125rem 4px;border-radius:.25rem;color:var(--muted-foreground);transition:all .15s ease}.z-pin-btn:hover{background-color:var(--muted);color:var(--foreground)}.z-pin-btn.z-pin-btn-active{color:var(--primary);background-color:var(--primary)}.z-pin-btn.z-pin-btn-active:hover{background-color:var(--primary);opacity:.8}.z-row-pin-trigger{opacity:1}.z-row-pin-trigger:focus-visible,.z-row-pin-trigger.z-popover-open{background-color:color-mix(in srgb,var(--foreground) 8%,transparent);color:var(--foreground)}.z-row-pin-trigger:active{background-color:color-mix(in srgb,var(--foreground) 12%,transparent)}.z-row-pin-trigger.text-primary{color:var(--primary)}.z-row-pin-unpin-trigger{color:var(--muted-foreground);outline:none}.z-row-pin-unpin-trigger:hover{color:var(--destructive);background-color:color-mix(in srgb,var(--destructive) 10%,transparent)}.z-row-pin-unpin-trigger:focus,.z-row-pin-unpin-trigger:focus-visible{color:var(--muted-foreground);background-color:transparent;outline:none;box-shadow:none}.z-row-pin-unpin-trigger:active{color:var(--destructive);background-color:color-mix(in srgb,var(--destructive) 14%,transparent)}.z-header-pin-trigger{opacity:1}.z-header-pin-trigger.text-primary{color:var(--primary)}th{overflow:hidden}th .z-header-content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}th .z-header-text-wrapper{transition:background-color .15s ease;border-radius:.25rem;min-width:0;overflow:hidden;flex-shrink:1}th .z-header-text-wrapper.z-has-options:hover,th .z-header-text-wrapper.z-has-options:focus-visible,th .z-header-text-wrapper.z-has-options.z-popover-open{background-color:color-mix(in srgb,var(--foreground) 8%,transparent);outline:none}th .z-header-text-wrapper.z-has-options:active{background-color:color-mix(in srgb,var(--foreground) 12%,transparent)}.z-column-menu-item{line-height:1.25rem}.z-column-menu-item:focus-visible,.z-column-menu-item.z-popover-open{background-color:var(--muted);outline:none}.cdk-drag-preview,.z-drag-preview{box-sizing:border-box;border:1px solid var(--primary);border-radius:.375rem;background-color:var(--card);box-shadow:0 5px 20px #0003;overflow:hidden;pointer-events:none;z-index:10000!important}.cdk-drag-preview:where(.dark,.dark *),.z-drag-preview:where(.dark,.dark *){box-shadow:0 5px 20px #00000080}.cdk-drag-placeholder{box-sizing:border-box;border:2px dashed var(--primary);border-radius:.375rem;background-color:color-mix(in srgb,var(--primary) 10%,var(--background))}.cdk-drag-animating,.cdk-drop-list-dragging .cdk-drag:not(.cdk-drag-placeholder){transition:transform .1s cubic-bezier(0,0,.2,1)}.z-drag-item.cdk-drag-dragging{transition:none!important}.z-table-drag-preview{box-sizing:border-box;border-radius:.375rem;background-color:var(--card);border:1px solid var(--primary);box-shadow:0 10px 24px #00000029;overflow:hidden;z-index:10000!important;pointer-events:none}.z-table-drag-preview:where(.dark,.dark *){box-shadow:0 5px 20px #00000080}.z-table-drag-preview-row{border:0;border-radius:.125rem;background-color:var(--background);box-shadow:0 8px 20px #0000001f,inset 0 0 0 1px color-mix(in srgb,var(--primary) 45%,var(--border))}.z-table-drag-preview-row table,.z-table-drag-preview-row tbody,.z-table-drag-preview-row tr{height:100%}.z-table-drag-preview-row td{vertical-align:middle!important;background-color:var(--background)}.z-table-drag-source{display:none!important}.z-virtual-row.z-table-drag-source{display:block!important;pointer-events:none;outline:1px solid var(--border);outline-offset:-1px}.z-virtual-row.z-table-drag-source td{color:color-mix(in srgb,var(--foreground) 45%,transparent);border-color:var(--border)!important;background-color:var(--card)!important}.z-virtual-row.z-table-drag-source td>*{opacity:.45}[data-z-table-drag-handle]{touch-action:none;-webkit-user-select:none;user-select:none}.z-column-drop-list{min-height:3.125rem;overscroll-behavior:contain}.z-column-drop-list.cdk-drop-list-dragging{overflow:clip}.z-table-drag-placeholder{width:100%;min-height:2.625rem;box-sizing:border-box;border:2px dashed var(--primary);border-radius:.375rem;background-color:color-mix(in srgb,var(--primary) 10%,var(--background));pointer-events:none}.z-table-drag-placeholder-row>td{padding:0!important;border:0!important;background:transparent!important}.z-table-drag-placeholder-row .z-table-drag-placeholder{border-radius:0;background-color:color-mix(in srgb,var(--primary) 10%,transparent)}.z-table-drag-placeholder-virtual{position:absolute;top:0;left:0;z-index:20;border-radius:0}.z-tbody-wrapper tr.z-group-row td{background:var(--card);border-top:none;border-bottom:1px solid var(--border)}.z-virtual-row tr.z-group-row td{background:var(--card);border-top:none;border-bottom:none}.z-group-row-sticky-wrapper{display:inline-flex;align-items:center;translate:var(--z-scroll-x, 0px) 0}.z-table-container:not(.z-hide-horizontal-border) .z-virtual-row:after{content:\"\";position:absolute;right:0;bottom:0;left:0;z-index:3;height:1px;background:var(--border);pointer-events:none}.z-tbody-wrapper tr.z-group-child-row td.z-at-left-edge,.z-virtual-row tr.z-group-child-row td.z-at-left-edge{border-left:2px solid var(--primary)!important;padding-left:var(--z-group-content-indent, .75rem)}.z-group-row-trigger{display:inline-flex;min-height:2rem;max-width:100%;align-items:center;gap:.5rem;padding:.25rem .5rem .25rem .75rem;color:var(--primary);font-size:.8125rem;font-weight:600;vertical-align:middle;cursor:pointer}.z-group-row-remove{margin-left:.125rem;color:var(--muted-foreground);vertical-align:middle}.z-group-row-remove:hover,.z-group-row-remove:focus-visible{color:var(--destructive);background:color-mix(in srgb,var(--destructive) 10%,transparent);outline:none}.z-group-row-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-column-label{color:color-mix(in srgb,var(--primary) 65%,var(--foreground));font-weight:500;margin-right:.25rem}.z-group-row-count{display:inline-flex;min-width:1.25rem;height:1.25rem;align-items:center;justify-content:center;padding:0 .375rem;border-radius:999px;background:var(--primary);color:var(--primary-foreground);font-size:.6875rem;font-weight:600}.z-group-row-loading{display:inline-flex;align-items:center;margin-left:.25rem}.z-group-row-has-totals td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-has-totals .z-group-row-label-cell{position:sticky;left:0;z-index:2;background:var(--card)}.z-group-row-has-totals .z-group-row-label-cell .z-group-row-sticky-wrapper{max-width:100%;translate:none}.z-group-row-total{display:inline-block;max-width:100%;color:var(--foreground);font-size:.8125rem;font-weight:600;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-total-cell{text-align:right}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-selected:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:before{position:absolute!important;z-index:0!important;box-sizing:border-box!important;top:var(--z-cell-range-top, 0)!important;right:var(--z-cell-range-right, 0)!important;bottom:var(--z-cell-range-bottom, 0)!important;left:var(--z-cell-range-left, 0)!important;width:auto!important;background-color:var(--z-cell-selection-background-opaque)!important;box-shadow:none!important;content:\"\"!important;pointer-events:none!important;opacity:1!important}:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:after{display:none!important}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-top:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-top:before{border-top:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-right:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-right:before{border-right:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-bottom:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-left:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-left:before{border-left:1px solid var(--primary)}:host-context(.z-table-pointer-dragging) .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-selected:before,:host-context(.z-table-pointer-dragging) .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:before{background-color:transparent!important}:host td.z-cell-range-selected:before{position:absolute;z-index:0;box-sizing:border-box;top:var(--z-cell-range-top, 0);right:var(--z-cell-range-right, 0);bottom:var(--z-cell-range-bottom, 0);left:var(--z-cell-range-left, 0);background-color:var(--z-cell-selection-background);box-shadow:none;content:\"\";pointer-events:none;opacity:1}:host td.z-cell-range-top:before{border-top:1px solid var(--primary)}:host td.z-cell-range-right:before{border-right:1px solid var(--primary)}:host td.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}:host td.z-cell-range-left:before{border-left:1px solid var(--primary)}:host-context(.z-table-pointer-dragging) td.z-row-hover{background-color:var(--background)!important}:host td.z-cell-active,:host td.z-cell-active.z-row-hover{background-color:var(--z-cell-selection-background)!important}:host td.z-content-edit-active.z-row-hover{background-color:var(--card)!important}:host tr.z-pinned-top td.z-cell-active,:host tr.z-pinned-top td.z-cell-active.z-row-hover,:host tr.z-pinned-bottom td.z-cell-active,:host tr.z-pinned-bottom td.z-cell-active.z-row-hover,:host td.z-cell-active.z-sticky-left,:host td.z-cell-active.z-sticky-left.z-row-hover,:host td.z-cell-active.z-sticky-right,:host td.z-cell-active.z-sticky-right.z-row-hover{background-color:var(--z-cell-selection-background-opaque)!important}:host tr.z-pinned-top td.z-cell-range-selected,:host tr.z-pinned-bottom td.z-cell-range-selected,:host td.z-cell-range-selected.z-sticky-left,:host td.z-cell-range-selected.z-sticky-right{background-color:var(--card)}:host tr.z-pinned-top td.z-cell-range-selected:before,:host tr.z-pinned-bottom td.z-cell-range-selected:before,:host td.z-cell-range-selected.z-sticky-left:before,:host td.z-cell-range-selected.z-sticky-right:before{background-color:var(--z-cell-selection-background-opaque)}:host-context(.z-table-pointer-dragging) td.z-cell-range-selected,:host-context(.z-table-pointer-dragging) td.z-cell-range-selected.z-row-hover,:host-context(.z-table-pointer-dragging) td.z-cell-active,:host-context(.z-table-pointer-dragging) td.z-cell-active.z-row-hover{background-color:var(--card)!important}:host-context(.z-table-pointer-dragging) td.z-cell-range-selected:before{background-color:transparent}:host .z-tbody-wrapper tbody tr.z-group-child-row:has(+tr.z-group-row)>td.z-at-bottom{border-bottom-color:var(--border)}:host .z-virtual-row:has(tr.z-group-child-row):has(+.z-virtual-row tr.z-group-row) tr.z-group-child-row>td.z-at-bottom{border-bottom-color:var(--border)}.z-thead-wrapper th.z-virtual-column-spacer,.z-tfoot-wrapper th.z-virtual-column-spacer{box-sizing:border-box;padding:0!important;background:var(--muted);border-left:thin solid var(--border)}.z-thead-wrapper th.z-virtual-header-spacer{border-bottom:thin solid var(--border)}.z-tfoot-wrapper th.z-virtual-footer-spacer{border-top:thin solid var(--border)}.z-tbody-wrapper td.z-virtual-column-spacer{box-sizing:border-box;height:auto;padding:0!important;background:var(--card);border-left:thin solid var(--border);border-bottom:thin solid var(--border)}.z-tbody-wrapper tr:hover td.z-virtual-column-spacer{background-color:var(--muted)}.z-table-settings-drawer input[type=checkbox]{appearance:none;-webkit-appearance:none;-moz-appearance:none;width:1rem;height:1rem;border:thin solid var(--input);border-radius:.25rem;background-color:var(--background);cursor:pointer;position:relative;transition:all .2s ease}.z-table-settings-drawer input[type=checkbox]:hover{border-color:var(--primary)}.z-table-settings-drawer input[type=checkbox]:checked{background-color:var(--primary);border-color:var(--primary)}.z-table-settings-drawer input[type=checkbox]:checked:after{content:\"\";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:.375rem;height:.625rem;border:solid var(--primary-foreground);border-width:0 .125rem .125rem 0;transform:translate(-50%,-60%) rotate(45deg)}.z-table-settings-drawer input[type=checkbox]:disabled{opacity:.5;cursor:not-allowed}.z-virtual-pinned-top{position:sticky;top:0;left:0;z-index:3;width:100%}.z-virtual-pinned-bottom{position:sticky;bottom:0;left:0;z-index:3;width:100%}\n"] }]
|
|
10868
|
-
}], ctorParameters: () => [], propDecorators: { zChange: [{ type: i0.Output, args: ["zChange"] }], zControl: [{ type: i0.Output, args: ["zControl"] }], zClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "zClass", required: false }] }], zConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "zConfig", required: false }] }], zLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "zLoading", required: false }] }], zKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "zKey", required: false }] }], zVariant: [{ type: i0.Input, args: [{ isSignal: true, alias: "zVariant", required: false }] }], theadWrapper: [{ type: i0.ViewChild, args: ['theadWrapper', { isSignal: true }] }], tableContainer: [{ type: i0.ViewChild, args: ['tableContainer', { isSignal: true }] }], tbodyContainer: [{ type: i0.ViewChild, args: ['tbodyContainer', { isSignal: true }] }], tbodyWrapper: [{ type: i0.ViewChild, args: ['tbodyWrapper', { isSignal: true }] }], tbodyScrollbar: [{ type: i0.ViewChild, args: ['tbodyWrapper', { isSignal: true }] }], tfootWrapper: [{ type: i0.ViewChild, args: ['tfootWrapper', { isSignal: true }] }], expandedRowTemplate: [{ type: i0.ViewChild, args: ['expandedRowTemplate', { isSignal: true }] }], virtualRowElements: [{ type: i0.ViewChildren, args: ['virtualRow', { isSignal: true }] }] } });
|
|
11180
|
+
}, exportAs: 'zTable', template: "<!-- Toolbar: Search & Settings -->\n@if (isSearchEnabled() || zConfig().enableSettings) {\n <div class=\"z-table-toolbar mb-2 flex items-center justify-between gap-4\">\n <!-- Search -->\n @if (isSearchEnabled()) {\n @let config = searchConfig();\n <z-input\n [class]=\"config?.width ?? 'w-64'\"\n [zSize]=\"config?.size ?? 'sm'\"\n [zPlaceholder]=\"config?.placeholder ?? 'i18n_z_ui_table_search' | translate\"\n [zSearch]=\"true\"\n [zDebounce]=\"config?.debounceTime ?? 300\"\n (zOnSearch)=\"onSearchChange($event)\" />\n } @else {\n <div></div>\n }\n\n <!-- Settings Button -->\n @if (zConfig().enableSettings) {\n <z-button zType=\"outline\" zSize=\"sm\" zTypeIcon=\"lucideSettings\" (click)=\"openSettingsDrawer()\">\n {{ 'i18n_z_ui_table_settings' | translate }}\n </z-button>\n }\n </div>\n}\n\n@if (zConfig().enableFilterHeader && appliedFilterChips().length > 0) {\n <div class=\"z-table-filter-header mb-2 flex min-w-0 items-center gap-2\">\n <div class=\"flex min-w-0 flex-1 flex-wrap items-center gap-1.5\">\n @for (chip of visibleAppliedFilterChips(); track chip.id) {\n <span\n class=\"border-border bg-muted/60 text-foreground inline-flex max-w-80 min-w-0 shrink-0 items-center gap-1 rounded-sm border px-2 py-1 text-[0.8125rem] shadow-xs\">\n <span class=\"font-medium whitespace-nowrap\">{{ chip.label }}</span>\n <span class=\"text-muted-foreground\">:</span>\n <span class=\"truncate\" z-tooltip [zContent]=\"chip.value\" zTooltipTrigger=\"hover\" zTooltipPosition=\"top\">\n {{ chip.value }}\n </span>\n <button\n type=\"button\"\n class=\"hover:bg-destructive/10 hover:text-destructive focus-visible:ring-ring -mr-1 inline-flex size-5 cursor-pointer items-center justify-center rounded-sm outline-none focus-visible:ring-2\"\n [attr.aria-label]=\"'i18n_z_ui_table_filter_remove' | translate\"\n (click)=\"clearAppliedFilterChip(chip)\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </span>\n }\n @if (hiddenAppliedFilterChipCount() > 0 && isFilterHeaderExpanded()) {\n @for (chip of overflowAppliedFilterChips(); track chip.id) {\n <span\n class=\"z-table-filter-header-overflow-chip border-border bg-muted/60 text-foreground inline-flex max-w-80 min-w-0 shrink-0 items-center gap-1 rounded-sm border px-2 py-1 text-[0.8125rem] shadow-xs\"\n [attr.aria-hidden]=\"!isFilterHeaderExpanded()\">\n <span class=\"font-medium whitespace-nowrap\">{{ chip.label }}</span>\n <span class=\"text-muted-foreground\">:</span>\n <span class=\"truncate\" z-tooltip [zContent]=\"chip.value\" zTooltipTrigger=\"hover\" zTooltipPosition=\"top\">\n {{ chip.value }}\n </span>\n <button\n type=\"button\"\n class=\"hover:bg-destructive/10 hover:text-destructive focus-visible:ring-ring -mr-1 inline-flex size-5 cursor-pointer items-center justify-center rounded-sm outline-none focus-visible:ring-2\"\n [attr.aria-label]=\"'i18n_z_ui_table_filter_remove' | translate\"\n (click)=\"clearAppliedFilterChip(chip)\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </span>\n }\n }\n @if (hiddenAppliedFilterChipCount() > 0) {\n <button\n type=\"button\"\n class=\"text-primary hover:bg-primary/10 focus-visible:ring-ring inline-flex h-7 cursor-pointer items-center rounded-sm px-2 text-xs font-medium outline-none focus-visible:ring-2\"\n (click)=\"toggleFilterHeaderExpanded()\">\n {{\n isFilterHeaderExpanded()\n ? ('i18n_z_ui_table_show_less' | translate)\n : ('i18n_z_ui_table_show_more' | translate: { count: hiddenAppliedFilterChipCount() })\n }}\n </button>\n }\n <button\n type=\"button\"\n class=\"bg-destructive/10 text-destructive hover:bg-destructive/20 dark:bg-destructive/15 dark:text-destructive-foreground dark:hover:bg-destructive/25 focus-visible:ring-destructive inline-flex h-7 cursor-pointer items-center gap-1 rounded-sm px-2 text-xs font-medium shadow-xs outline-none focus-visible:ring-2\"\n (click)=\"clearAppliedFilters()\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_clear_filter' | translate }}</span>\n </button>\n </div>\n </div>\n}\n\n<div\n #tableContainer\n [class]=\"classTable()\"\n [class.z-pinning-overflow]=\"!isPinnedLayoutWithinContainer()\"\n [class.z-hide-horizontal-border]=\"!showHorizontalBorder()\"\n [class.z-hide-vertical-border]=\"!showVerticalBorder()\"\n [class.z-hide-pinned-top-border]=\"hasScrollTop()\"\n [class.z-hide-pinned-bottom-border]=\"hasScrollBottom()\"\n [style.width]=\"zConfig().width\"\n [style.height]=\"zConfig().height\"\n [style.max-height]=\"zConfig().maxHeight\"\n [style.min-height]=\"zConfig().minHeight\"\n [attr.tabindex]=\"canUseContentRowInsert() || canUseCellSelection() ? 0 : null\"\n (keydown)=\"onContentTableKeydown($event)\">\n @let isColumnPinningActive = isPinnedLayoutWithinContainer();\n <ng-template #contentRowMenuContent>\n <div class=\"flex min-w-36 flex-col gap-0.5 p-1\">\n @if (contentRowMenu()?.columnId) {\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"copyContentCell()\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_cell' | translate }}</span>\n </button>\n <div class=\"border-border my-0 border-t\"></div>\n }\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (click)=\"copyContentRows()\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_row' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"contentRowClipboard().length === 0\"\n (click)=\"pasteContentRows('below')\">\n <z-icon zType=\"lucideClipboardPaste\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_paste_row_below' | translate }}</span>\n </button>\n <div class=\"border-border my-0 border-t\"></div>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canMoveContentRowUp()\"\n (click)=\"moveContentRow('up')\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_move_row_up' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canMoveContentRowDown()\"\n (click)=\"moveContentRow('down')\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_move_row_down' | translate }}</span>\n </button>\n <div class=\"border-border my-0 border-t\"></div>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (click)=\"insertContentRow('above')\">\n <z-icon zType=\"lucideArrowUpToLine\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_insert_row_above' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (click)=\"insertContentRow('below')\">\n <z-icon zType=\"lucideArrowDownToLine\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_insert_row_below' | translate }}</span>\n </button>\n <div class=\"border-border my-0 border-t\"></div>\n <button\n type=\"button\"\n class=\"text-destructive hover:bg-destructive/10 focus:bg-destructive/10 flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none\"\n (click)=\"deleteContentRows()\">\n <z-icon zType=\"lucideTrash2\" zSize=\"12\" />\n <span>\n {{\n contentRowDeleteCount() > 1\n ? ('i18n_z_ui_table_delete_selected_rows' | translate)\n : ('i18n_z_ui_table_delete_row' | translate)\n }}\n </span>\n </button>\n </div>\n </ng-template>\n\n <ng-template #cellMenuContent>\n <div class=\"flex min-w-36 flex-col gap-0.5 p-1\">\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canCopyCellMenuSelection()\"\n (click)=\"copySelectedCells(false)\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_cell' | translate }}</span>\n </button>\n @if (cellSelectionOptions().copyWithHeaders) {\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canCopyCellMenuSelection()\"\n (click)=\"copySelectedCells(true)\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_cell_with_headers' | translate }}</span>\n </button>\n }\n </div>\n </ng-template>\n\n <div\n class=\"pointer-events-none fixed size-px opacity-0\"\n z-popover\n [zPopoverContent]=\"contentRowMenuContent\"\n zTrigger=\"manual\"\n zPosition=\"bottom-left\"\n zClass=\"z-table-content-row-menu\"\n [zOffset]=\"0\"\n [zManualClose]=\"true\"\n [zScrollClose]=\"true\"\n [style.left.px]=\"contentRowMenu()?.left ?? -9999\"\n [style.top.px]=\"contentRowMenu()?.top ?? -9999\"\n (zControl)=\"setContentRowMenuControl($event)\"\n (zHide)=\"clearContentRowMenu()\"></div>\n\n <div\n class=\"pointer-events-none fixed size-px opacity-0\"\n z-popover\n [zPopoverContent]=\"cellMenuContent\"\n zTrigger=\"manual\"\n zPosition=\"bottom-left\"\n zClass=\"z-table-cell-menu\"\n [zOffset]=\"0\"\n [zManualClose]=\"true\"\n [zScrollClose]=\"true\"\n [style.left.px]=\"cellMenu()?.left ?? -9999\"\n [style.top.px]=\"cellMenu()?.top ?? -9999\"\n (zControl)=\"setCellMenuControl($event)\"\n (zHide)=\"clearCellMenu()\"></div>\n\n <!-- Shared colgroup template -->\n <ng-template #colGroupTpl>\n <colgroup>\n @if (canUseVirtualColumns()) {\n @for (column of leftLeafColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <col [style.width.px]=\"virtualRenderedLeftSpacerWidth()\" />\n }\n @for (column of virtualCenterColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n @if (virtualRightSpacerWidth() > 0) {\n <col [style.width.px]=\"virtualRenderedRightSpacerWidth()\" />\n }\n @for (column of rightLeafColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n } @else {\n @for (column of orderedLeafColumns(); track column.id) {\n @if (column.getIsVisible()) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n }\n }\n </colgroup>\n </ng-template>\n\n <!-- Header table -->\n <div\n class=\"z-thead-wrapper shadow-card\"\n [class.z-shadow-header]=\"shouldHeaderShowShadow()\"\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\"\n (wheel)=\"onTheadWheel($event)\"\n #theadWrapper>\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <thead>\n @if (canUseVirtualColumns()) {\n <tr>\n @for (header of leftHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: leftHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (effectiveEnableOrdering) {\n <button\n type=\"button\"\n [disabled]=\"isFirstMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnLeft(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_left' | translate }}</span>\n </button>\n <button\n type=\"button\"\n [disabled]=\"isLastMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnRight(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideChevronsLeftRight\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_column' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeAllColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_all_columns' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"resetColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRotateCcw\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_reset_columns' | translate }}</span>\n </button>\n @if (hideableColumns().length > 0) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover)\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded px-1.5 py-1\"\n [class.cursor-pointer]=\"hasColumnOptions\"\n [class.z-has-options]=\"hasColumnOptions\"\n [attr.z-popover]=\"hasColumnOptions ? '' : null\"\n #colOptionsPopover=\"zPopover\"\n #headerTextWrapper\n z-popover\n [zPopoverContent]=\"hasColumnOptions ? colOptionsPopoverContent : null\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <th\n class=\"z-virtual-column-spacer z-virtual-header-spacer z-virtual-left-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></th>\n }\n @for (header of virtualCenterHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: virtualCenterHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (effectiveEnableOrdering) {\n <button\n type=\"button\"\n [disabled]=\"isFirstMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnLeft(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_left' | translate }}</span>\n </button>\n <button\n type=\"button\"\n [disabled]=\"isLastMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnRight(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideChevronsLeftRight\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_column' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeAllColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_all_columns' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"resetColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRotateCcw\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_reset_columns' | translate }}</span>\n </button>\n @if (hideableColumns().length > 0) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover)\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded px-1.5 py-1\"\n [class.cursor-pointer]=\"hasColumnOptions\"\n [class.z-has-options]=\"hasColumnOptions\"\n [attr.z-popover]=\"hasColumnOptions ? '' : null\"\n #colOptionsPopover=\"zPopover\"\n #headerTextWrapper\n z-popover\n [zPopoverContent]=\"hasColumnOptions ? colOptionsPopoverContent : null\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualRightSpacerWidth() > 0) {\n <th\n class=\"z-virtual-column-spacer z-virtual-header-spacer z-virtual-right-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></th>\n }\n @for (header of rightHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: rightHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <!-- Header Checkbox -->\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <!-- Expand All Button -->\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <!-- Header Content with Sort and Pin -->\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <!-- Column Options Popover Template -->\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (effectiveEnableOrdering) {\n <button\n type=\"button\"\n [disabled]=\"isFirstMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnLeft(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_left' | translate }}</span>\n </button>\n <button\n type=\"button\"\n [disabled]=\"isLastMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnRight(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideChevronsLeftRight\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_column' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeAllColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_all_columns' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"resetColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRotateCcw\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_reset_columns' | translate }}</span>\n </button>\n @if (hideableColumns().length > 0) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover)\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded px-1.5 py-1\"\n [class.cursor-pointer]=\"hasColumnOptions\"\n [class.z-has-options]=\"hasColumnOptions\"\n [attr.z-popover]=\"hasColumnOptions ? '' : null\"\n #colOptionsPopover=\"zPopover\"\n #headerTextWrapper\n z-popover\n [zPopoverContent]=\"hasColumnOptions ? colOptionsPopoverContent : null\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n <!-- Dropdown indicator when has options (between text and sort icon) -->\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n <!-- Sort Icon (outside wrapper, no hover background) -->\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n <!-- Column Resizer -->\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n </tr>\n } @else {\n @for (headerGroup of orderedHeaderGroups(); track headerGroup.id) {\n <tr>\n @for (header of headerGroup.headers; track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: headerGroup.headers : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (effectiveEnableOrdering) {\n <button\n type=\"button\"\n [disabled]=\"isFirstMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnLeft(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_move_left' | translate }}</span>\n </button>\n <button\n type=\"button\"\n [disabled]=\"isLastMovableColumn(header.column.id) || header.column.getIsPinned()\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"moveColumnRight(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"15\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"\n handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\n \"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"15\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon\n zType=\"lucideChevronsLeftRight\"\n zSize=\"14\"\n class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_column' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeAllColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_autosize_all_columns' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"resetColumns(); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRotateCcw\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_reset_columns' | translate }}</span>\n </button>\n @if (hideableColumns().length > 0) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover)\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded px-1.5 py-1\"\n [class.cursor-pointer]=\"hasColumnOptions\"\n [class.z-has-options]=\"hasColumnOptions\"\n [attr.z-popover]=\"hasColumnOptions ? '' : null\"\n #colOptionsPopover=\"zPopover\"\n #headerTextWrapper\n z-popover\n [zPopoverContent]=\"hasColumnOptions ? colOptionsPopoverContent : null\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"\n header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\n \"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n </tr>\n }\n }\n </thead>\n </table>\n </div>\n\n <!-- Body table -->\n <div\n class=\"z-tbody-wrapper relative\"\n #tbodyContainer\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\">\n @if (isLoading() || isProcessing()) {\n <!-- Loading State -->\n @if (zConfig().useSkeleton) {\n <!-- Skeleton Loading -->\n <div class=\"animate-in fade-in flex h-full flex-col duration-200\">\n @for (i of skeletonRows(); track $index; let last = $last) {\n <div\n class=\"border-border box-border flex flex-1 flex-col items-start justify-center gap-1.5 px-2\"\n [class.border-b]=\"!last\">\n <z-skeleton zType=\"bar\" zWidth=\"100%\" zHeight=\"22px\" zRadius=\"4px\" />\n <z-skeleton zType=\"bar\" zWidth=\"50%\" zHeight=\"14px\" zRadius=\"4px\" />\n </div>\n }\n </div>\n } @else {\n <!-- Spinner Loading -->\n <div class=\"z-loading-state\">\n <z-loading [zLoading]=\"true\" zSize=\"lg\" [zText]=\"'i18n_z_ui_table_loading' | translate\" />\n </div>\n }\n } @else if (isEmpty()) {\n <div class=\"z-empty-state\">\n @if (isNoSearchResults()) {\n <z-empty zIcon=\"lucideSearchX\" zSize=\"sm\" [zMessage]=\"'i18n_z_ui_table_no_results' | translate\" />\n } @else {\n <z-empty zIcon=\"lucidePackageOpen\" zSize=\"sm\" [zMessage]=\"'i18n_z_ui_table_no_data' | translate\" />\n }\n </div>\n } @else {\n <ng-scrollbar class=\"z-tbody-scrollbar\" #tbodyWrapper (scroll)=\"onTbodyScroll($event)\">\n @if (isVirtual()) {\n <!-- Virtual Scroll Mode -->\n\n <div\n class=\"z-virtual-scroll-inner\"\n [style.height.px]=\"virtualizer.getTotalSize()\"\n [style.min-width.px]=\"table.getTotalSize()\">\n <!-- Pinned rows v\u00E0 center rows d\u00F9ng chung m\u1ED9t virtual canvas. -->\n @if (virtualPinnedTopRows().length > 0) {\n <div class=\"z-virtual-pinned-top\" [style.min-width.px]=\"table.getTotalSize()\">\n @for (row of virtualPinnedTopRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"virtualPinnedRowTpl; context: { $implicit: row }\" />\n }\n </div>\n }\n\n @for (virtualItem of virtualizer.getVirtualItems(); track virtualItem.index) {\n @let groupRows = dynamicGroupRows()[virtualItem.index] || [];\n @let virtualFlatItem = virtualGroupedFlatItems()[virtualItem.index];\n @let stickyGroupState = stickyGroupHeaderState();\n @let stickyGroupTop = stickyGroupState.tops[virtualItem.index];\n @let isStickyGroupHeader = stickyGroupTop !== undefined;\n <div\n #virtualRow\n class=\"z-virtual-row\"\n [class.z-virtual-row-group-header]=\"virtualFlatItem?.type === 'group-header'\"\n [class.z-virtual-row-sticky-group]=\"isStickyGroupHeader\"\n [class.z-virtual-row-sticky-group-shadow]=\"stickyGroupState.shadowIndex === virtualItem.index\"\n [style.top.px]=\"stickyGroupTop\"\n z-table-draggable=\"row\"\n z-table-drop-target=\"row\"\n [z-table-drag-table-id]=\"dragInstanceId\"\n [z-table-drop-table-id]=\"dragInstanceId\"\n [z-table-drag-item-id]=\"groupRows.length > 0 ? groupRows[0].id : ''\"\n [z-table-drop-item-id]=\"groupRows.length > 0 ? groupRows[0].id : ''\"\n [z-table-drag-disabled]=\"!isVirtualRowDragEnabled() || groupRows.length !== 1\"\n [z-table-drop-disabled]=\"!isVirtualRowDragEnabled() || groupRows.length !== 1\"\n (zTableDropped)=\"_handleDragDrop($event)\"\n [attr.data-index]=\"virtualItem.index\"\n [style.height.px]=\"\n effectiveDynamicRowSizing()\n ? null\n : (dynamicGroupHeights()[virtualItem.index] ?? groupSize() * virtualRowHeight())\n \"\n [style.transform]=\"isStickyGroupHeader ? null : 'translate3d(0,' + virtualItem.start + 'px,0)'\">\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-has-bottom-pinned]=\"table.getBottomRows().length > 0\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n @let groupHeaderItem = _getVirtualGroupHeader(virtualFlatItem);\n @if (groupHeaderItem) {\n <tr\n class=\"z-group-row\"\n [class.z-group-row-has-totals]=\"groupHeaderItem.totals\"\n [class.z-group-row-expanded]=\"groupHeaderItem.expanded\"\n [attr.data-group-id]=\"groupHeaderItem.id\"\n [attr.data-group-depth]=\"groupHeaderItem.depth\">\n @if (groupHeaderItem.totals) {\n @let totalColumnMap = groupTotalColumnMap();\n @for (column of orderedLeafColumns(); track column.id; let isFirstGroupCell = $first) {\n <td\n [class.z-group-row-label-cell]=\"isFirstGroupCell\"\n [class.z-group-row-total-cell]=\"!isFirstGroupCell && totalColumnMap[column.id]\"\n [attr.data-column-id]=\"column.id\">\n @if (isFirstGroupCell) {\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + groupHeaderItem.depth * 0.75\"\n [attr.aria-expanded]=\"groupHeaderItem.expanded\"\n (click)=\"toggleGroupRow(groupHeaderItem.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"groupHeaderItem.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"\n (groupHeaderItem.columnLabel ? groupHeaderItem.columnLabel + ': ' : '') +\n groupHeaderItem.label\n \">\n @if (groupHeaderItem.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ groupHeaderItem.columnLabel }}:</span>\n }\n {{ groupHeaderItem.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ groupHeaderItem.count }}</span>\n }\n @if (groupHeaderItem.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n [zWave]=\"false\"\n z-tooltip\n zSizeIcon=\"14\"\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(groupHeaderItem.columnId)\"></button>\n }\n </div>\n }\n @if (!isFirstGroupCell && totalColumnMap[column.id]) {\n @let totalConfig = groupTotalConfigMap()[column.id];\n @let totalTooltip = totalConfig.tooltip;\n @let totalPopover = totalConfig.popover;\n @let totalPopoverContent = totalPopover | zTablePopoverConfig: 'content';\n <ng-template #groupTotalPopoverTpl>\n @if (totalPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(totalPopoverContent)\" />\n }\n @if (!(totalPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(totalPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n <span\n class=\"z-group-row-total\"\n z-tooltip\n z-popover\n [class]=\"totalConfig.class\"\n [zContent]=\"\n $any(\n (totalTooltip | zTableTooltipConfig: 'content') ||\n groupHeaderItem.totals[column.id]\n )\n \"\n [zTooltipPosition]=\"$any(totalTooltip | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(totalTooltip | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(totalTooltip | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(totalTooltip | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(totalTooltip | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'showDelay')\"\n [zTooltipHideDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'hideDelay')\"\n [zTooltipArrow]=\"$any(totalTooltip | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(totalTooltip | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(totalTooltip | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(totalTooltip | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(totalTooltip | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"totalPopoverContent ? groupTotalPopoverTpl : null\"\n [zPosition]=\"$any(totalPopover | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(totalPopover | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(totalPopover | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(totalPopover | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(totalPopover | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(totalPopover | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(totalPopover | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(totalPopover | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(totalPopover | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"$any(totalPopover | zTablePopoverConfig: 'outsideClickClose')\"\n [zScrollClose]=\"$any(totalPopover | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(totalPopover | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(totalPopover | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(totalPopover | zTablePopoverConfig: 'keyboardSafe')\">\n {{ groupHeaderItem.totals[column.id] }}\n </span>\n }\n </td>\n }\n } @else {\n <td [attr.colspan]=\"renderedColumnCount()\">\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + groupHeaderItem.depth * 0.75\"\n [attr.aria-expanded]=\"groupHeaderItem.expanded\"\n (click)=\"toggleGroupRow(groupHeaderItem.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"groupHeaderItem.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"\n (groupHeaderItem.columnLabel ? groupHeaderItem.columnLabel + ': ' : '') +\n groupHeaderItem.label\n \">\n @if (groupHeaderItem.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ groupHeaderItem.columnLabel }}:</span>\n }\n {{ groupHeaderItem.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ groupHeaderItem.count }}</span>\n }\n @if (groupHeaderItem.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n [zWave]=\"false\"\n z-tooltip\n zSizeIcon=\"14\"\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(groupHeaderItem.columnId)\"></button>\n }\n </div>\n </td>\n }\n </tr>\n }\n @for (row of groupRows; track row.id) {\n @let virtualGroupDepth = _getVirtualGroupDepth(virtualFlatItem);\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <tr\n z-table-row-hover\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"effectiveDynamicRowSizing() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"effectiveDynamicRowSizing() ? virtualRowHeight() : null\"\n [style.--z-row-height]=\"effectiveDynamicRowSizing() ? 'auto' : virtualRowHeight() + 'px'\"\n [class.z-child-row]=\"row.depth > 0\"\n [class.z-group-child-row]=\"_isVirtualGroupChild(virtualFlatItem)\"\n [style.--z-group-content-indent]=\"\n virtualGroupDepth > 0 ? 1.75 + (virtualGroupDepth - 1) * 0.75 + 'rem' : null\n \"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && row.id === firstTopPinnedRowId()\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"rowPinned === 'bottom' && row.id === lastBottomPinnedRowId()\"\n [class.z-pinned-bottom-first]=\"rowPinned === 'bottom' && row.id === firstBottomPinnedRowId()\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n row.id === lastTopPinnedRowId()\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n row.id === firstBottomPinnedRowId()\n \"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : bodyRowSpanRows();\n @let shouldRenderColSpan = cell | zTableCellRender: visibleCells : zConfig().columns : 'body';\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (shouldRenderRowSpan && shouldRenderColSpan && isVirtualColumnVisible) {\n @let cellSelectionId = row.id + '::' + cell.column.id;\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"isColumnPinningActive && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActive && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"cell.column.id === actionColumnInfo()?.columnId\"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [class.z-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"cell | zTableCellBottom: zConfig().columns : renderedBodyRows()\"\n [attr.rowspan]=\"cell | zTableSpan: zConfig().columns : 'cellRowSpan' : bodyRowSpanRows()\"\n [attr.colspan]=\"cell | zTableSpan: zConfig().columns : 'cellColSpan'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n [style.--z-cell-range-top]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\n \"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\n \"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <button\n data-z-table-drag-handle\n type=\"button\"\n class=\"text-muted-foreground inline-flex size-7 items-center justify-center rounded-md\"\n [class.cursor-grab]=\"isRowDragEnabled()\"\n [class.opacity-40]=\"!isRowDragEnabled()\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === 'select') {\n <!-- Row Checkbox -->\n <div class=\"flex items-center justify-center\">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && cell.row.getIsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && cell.row.getIsSomeSelected() && !cell.row.getIsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection() || !cell.row.getCanSelect()\"\n (zChange)=\"canUseRowSelection() && cell.row.toggleSelected()\" />\n </div>\n } @else if (cell.column.id === 'expand') {\n <!-- Expand Button -->\n <div class=\"flex items-center justify-center\">\n @if (cell.row.getCanExpand()) {\n <button\n type=\"button\"\n (click)=\"cell.row.toggleExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"cell.row.getIsExpanded()\" />\n </button>\n }\n </div>\n } @else if (\n (cell.column.id === 'actionRowPin' || cell.column.id === 'actions') &&\n cell.column.id !== actionColumnInfo()?.columnId\n ) {\n @if (cell.row.depth === 0 && !hasBodyRowSpan()) {\n <div class=\"flex items-center justify-center\">\n <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n @if (cell.row.getIsPinned() !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cell.row.getIsPinned() !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cell.row.getIsPinned()) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded p-1 outline-none\"\n [class.text-primary]=\"cell.row.getIsPinned()\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n </div>\n }\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisible = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisible) {\n @let editInfoVirtual = cell.getContext() | zTableCellEdit: zConfig().columns;\n @if (editInfoVirtual.enabled) {\n <!-- Editable Cell (Virtual) -->\n <z-table-edit-cell\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n [zRowIndex]=\"cell.row.index\"\n [zColumnId]=\"cell.column.id\"\n [zValue]=\"cell.getValue()\"\n [zRowUpdate]=\"_rowUpdate()\"\n [zEditConfig]=\"$any(editInfoVirtual.config)\"\n (zChange)=\"onCellEdit($any($event))\" />\n } @else if (editInfoVirtual.contentEnabled) {\n @let contentConfigVirtual = editInfoVirtual.contentConfig!;\n @if (\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n ) {\n <z-table-content-editor\n [zValue]=\"cell.getValue()\"\n [zConfig]=\"contentConfigVirtual\"\n (zCommit)=\"onContentEditCommit($event, row, cell.column.id, cell.getValue())\"\n (zCancel)=\"onContentEditCancel()\" />\n } @else {\n <button\n type=\"button\"\n class=\"z-table-content-trigger\"\n [attr.data-z-table-edit-row]=\"row.id\"\n [attr.data-z-table-edit-column]=\"cell.column.id\"\n (keydown)=\"onContentEditKeydown($event, row.id, cell.column.id)\"\n (click)=\"onContentEditStart($event, row.id, cell.column.id)\">\n {{ contentConfigVirtual.displayValue }}\n </button>\n }\n } @else {\n <ng-container\n *flexRender=\"\n cell.column.columnDef.cell;\n props: cell.getContext();\n let cellContent\n \">\n @if (cellContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n @let isClickable = cell.column.id | zTableCellClickable: zConfig().columns;\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickable && onCellClick(row, cell.column.id, cell.getValue())\">\n <ng-container\n *ngTemplateOutlet=\"\n cellContent;\n context: { $implicit: cell.getContext() }\n \" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n @let isClickableIcon = cell.column.id | zTableCellClickable: zConfig().columns;\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"\n isClickableIcon && onCellClick(row, cell.column.id, cell.getValue())\n \" />\n } @else {\n <!-- Default/innerHTML rendering -->\n @let isClickableDefault =\n cell.column.id | zTableCellClickable: zConfig().columns;\n @let cellTooltipConfig = cell | zTableCellConfig: zConfig() : 'contentTooltip';\n @let cellPopoverConfig = cell | zTableCellConfig: zConfig() : 'contentPopover';\n @let cellPopoverContent = cellPopoverConfig | zTablePopoverConfig: 'content';\n <ng-template #cellPopoverTpl>\n @if (cellPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(cellPopoverContent)\" />\n }\n @if (!(cellPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(cellPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n @if (cellPopoverContent) {\n <div\n class=\"z-table-cell-text\"\n z-popover\n z-tooltip\n [zTriggerElement]=\"cellOverlayContent\"\n [zTriggerRef]=\"cellOverlayContent\"\n [zContent]=\"\n (cellTooltipConfig | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'position')\n \"\n [zTooltipTrigger]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"cellPopoverTpl\"\n [zPosition]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'manualClose')\n \"\n [zOutsideClickClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'outsideClickClose')\n \"\n [zScrollClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'scrollClose')\n \"\n [zSticky]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'keyboardSafe')\n \"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellOverlayContent\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n } @else {\n <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zTriggerElement]=\"cellTooltipContent\"\n [zContent]=\"\n (cellTooltipConfig | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'position')\n \"\n [zTooltipTrigger]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'maxWidth')\"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellTooltipContent\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n }\n }\n </ng-container>\n }\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n\n <!--\n Bottom pinned rows: sibling AFTER the virtual canvas (not absolute like the\n center rows). The virtualizer reserves their height inside getTotalSize() via\n `paddingEnd`, leaving an empty band at the canvas bottom. `margin-top: -bottomHeight`\n pulls this real flow element back over that band, and `position: sticky; bottom: 0`\n floats it to the viewport bottom while scrolling.\n -->\n @if (virtualPinnedBottomRows().length > 0) {\n <div\n class=\"z-virtual-pinned-bottom\"\n [style.min-width.px]=\"table.getTotalSize()\"\n [style.margin-top.px]=\"-virtualPinnedBottomHeight()\">\n @for (row of virtualPinnedBottomRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"virtualPinnedRowTpl; context: { $implicit: row }\" />\n }\n </div>\n }\n\n <!-- Template for rendering pinned rows in virtual scroll mode -->\n <ng-template #virtualPinnedRowTpl let-row>\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody [class.z-has-vertical-scroll]=\"hasVerticalScroll()\">\n <tr\n z-table-row-hover\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"effectiveDynamicRowSizing() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"effectiveDynamicRowSizing() ? virtualRowHeight() : null\"\n [style.--z-row-height]=\"effectiveDynamicRowSizing() ? 'auto' : virtualRowHeight() + 'px'\"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && row.id === firstTopPinnedRowId()\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"rowPinned === 'bottom' && row.id === lastBottomPinnedRowId()\"\n [class.z-pinned-bottom-first]=\"rowPinned === 'bottom' && row.id === firstBottomPinnedRowId()\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() && hasScrollTop() && rowPinned === 'top' && row.id === lastTopPinnedRowId()\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n row.id === firstBottomPinnedRowId()\n \"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @let isColumnPinningActivePinned = isPinnedLayoutWithinContainer();\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @let cellSelectionId = row.id + '::' + cell.column.id;\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (isVirtualColumnVisible) {\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActivePinned\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"isColumnPinningActivePinned && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActivePinned && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"cell.column.id === actionColumnInfo()?.columnId\"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [style.--z-cell-range-top]=\"(selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"(selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'select') {\n <z-checkbox\n [zChecked]=\"rowSelected\"\n [zIndeterminate]=\"rowSomeSelected && !rowSelected\"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && row.toggleSelected()\" />\n } @else if (cell.column.id === 'expand') {\n <button\n type=\"button\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"row.toggleExpanded()\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"row.getIsExpanded()\" />\n </button>\n } @else if (cell.column.id === 'actionRowPin') {\n <div class=\"flex items-center justify-center\">\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisible = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisible) {\n <ng-container\n *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let cellContent\">\n @if (cellContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { $implicit: cell.getContext() }\" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"(cell | zTableCellConfig: zConfig() : 'contentTooltip') || cellContent\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"></span>\n }\n </ng-container>\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n </tbody>\n </table>\n </ng-template>\n } @else {\n <!-- Normal Scroll Mode -->\n\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n class=\"z-table-drag-body\"\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-has-bottom-pinned]=\"table.getBottomRows().length > 0\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n <!-- Row Template -->\n <ng-template #rowTemplate let-row let-isGroupChild=\"isGroupChild\" let-groupDepth=\"groupDepth\">\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <tr\n z-table-row-hover\n z-table-draggable=\"row\"\n z-table-drop-target=\"row\"\n [animate.enter]=\"row.depth > 0 || isGroupChild ? 'z-row-enter' : ''\"\n [z-table-drag-table-id]=\"dragInstanceId\"\n [z-table-drop-table-id]=\"dragInstanceId\"\n [z-table-drag-item-id]=\"row.id\"\n [z-table-drop-item-id]=\"row.id\"\n [z-table-drag-disabled]=\"!isRowDragEnabled()\"\n [z-table-drop-disabled]=\"!isRowDragEnabled()\"\n (zTableDropped)=\"_handleDragDrop($event)\"\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [ngStyle]=\"row | zTableRow: table : 'pinningStyles' : pinnedRowHeights() : virtualRowHeight()\"\n [class.z-child-row]=\"row.depth > 0\"\n [class.z-group-child-row]=\"isGroupChild\"\n [style.--z-group-content-indent]=\"groupDepth > 0 ? 1.75 + (groupDepth - 1) * 0.75 + 'rem' : null\"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && row.id === firstTopPinnedRowId()\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"rowPinned === 'bottom' && row.id === lastBottomPinnedRowId()\"\n [class.z-pinned-bottom-first]=\"rowPinned === 'bottom' && row.id === firstBottomPinnedRowId()\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() && hasScrollTop() && rowPinned === 'top' && row.id === lastTopPinnedRowId()\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n row.id === firstBottomPinnedRowId()\n \"\n [attr.data-depth]=\"row.depth\"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @let cellRowPinned = cell.row.getIsPinned();\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : bodyRowSpanRows();\n @let shouldRenderColSpan = cell | zTableCellRender: visibleCells : zConfig().columns : 'body';\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (shouldRenderRowSpan && shouldRenderColSpan && isVirtualColumnVisible) {\n @let cellSelectionId = row.id + '::' + cell.column.id;\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n [class.z-sticky-left]=\"isColumnPinningActive && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActive && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"\n cell.column.id === 'actions' || cell.column.id === actionColumnInfo()?.columnId\n \"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [class.z-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"cell | zTableCellBottom: zConfig().columns : renderedBodyRows()\"\n [attr.rowspan]=\"cell | zTableSpan: zConfig().columns : 'cellRowSpan' : bodyRowSpanRows()\"\n [attr.colspan]=\"cell | zTableSpan: zConfig().columns : 'cellColSpan'\"\n [style.--z-cell-range-top]=\"(selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"(selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <button\n data-z-table-drag-handle\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground inline-flex size-7 items-center justify-center rounded-md transition-colors\"\n [class.cursor-grab]=\"isRowDragEnabled()\"\n [class.cursor-not-allowed]=\"!isRowDragEnabled()\"\n [class.opacity-40]=\"!isRowDragEnabled()\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === 'select') {\n <!-- Row Checkbox with Pin Button -->\n <div class=\"flex items-center justify-center gap-1\">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && cell.row.getIsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && cell.row.getIsSomeSelected() && !cell.row.getIsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection() || !cell.row.getCanSelect()\"\n (zChange)=\"canUseRowSelection() && cell.row.toggleSelected()\" />\n @if (zConfig().enableRowPinning && cell.row.depth === 0 && !hasBodyRowSpan()) {\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n }\n </div>\n } @else if (cell.column.id === 'expand') {\n <!-- Expand Button with Row Pin Popover -->\n <div class=\"flex items-center justify-center gap-1\">\n @if (cell.row.getCanExpand()) {\n <button\n type=\"button\"\n (click)=\"cell.row.toggleExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"cell.row.getIsExpanded()\" />\n </button>\n }\n @if (\n zConfig().enableRowPinning &&\n cell.row.depth === 0 &&\n !(cell.row.subRows && cell.row.subRows.length > 0) &&\n !hasBodyRowSpan()\n ) {\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n }\n </div>\n } @else if (\n (cell.column.id === 'actionRowPin' || cell.column.id === 'actions') &&\n cell.column.id !== actionColumnInfo()?.columnId\n ) {\n <!-- Actions Column - Row Pin Only (for parent rows) -->\n @if (cell.row.depth === 0 && !hasBodyRowSpan()) {\n <div class=\"flex items-center justify-center\">\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n </div>\n }\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisibleNormal = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisibleNormal) {\n @let editInfo = cell.getContext() | zTableCellEdit: zConfig().columns;\n @if (editInfo.enabled) {\n <!-- Editable Cell -->\n <z-table-edit-cell\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n [zRowIndex]=\"cell.row.index\"\n [zColumnId]=\"cell.column.id\"\n [zValue]=\"cell.getValue()\"\n [zRowUpdate]=\"_rowUpdate()\"\n [zEditConfig]=\"$any(editInfo.config)\"\n (zChange)=\"onCellEdit($any($event))\" />\n } @else if (editInfo.contentEnabled) {\n @let contentConfig = editInfo.contentConfig!;\n @if (\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n ) {\n <z-table-content-editor\n [zValue]=\"cell.getValue()\"\n [zConfig]=\"contentConfig\"\n (zCommit)=\"onContentEditCommit($event, row, cell.column.id, cell.getValue())\"\n (zCancel)=\"onContentEditCancel()\" />\n } @else {\n <button\n type=\"button\"\n class=\"z-table-content-trigger\"\n [attr.data-z-table-edit-row]=\"row.id\"\n [attr.data-z-table-edit-column]=\"cell.column.id\"\n (keydown)=\"onContentEditKeydown($event, row.id, cell.column.id)\"\n (click)=\"onContentEditStart($event, row.id, cell.column.id)\">\n {{ contentConfig.displayValue }}\n </button>\n }\n } @else {\n <ng-container\n *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let cellContent\">\n @if (cellContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n @let isClickableTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickableTpl && onCellClick(row, cell.column.id, cell.getValue())\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { $implicit: cell.getContext() }\" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n @let isClickableIconTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickableIconTpl && onCellClick(row, cell.column.id, cell.getValue())\" />\n } @else {\n <!-- Default/innerHTML rendering -->\n @let isClickableDefaultTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n @let cellTooltipConfigTpl = cell | zTableCellConfig: zConfig() : 'contentTooltip';\n @let cellPopoverConfigTpl = cell | zTableCellConfig: zConfig() : 'contentPopover';\n @let cellPopoverContentTpl = cellPopoverConfigTpl | zTablePopoverConfig: 'content';\n <ng-template #cellPopoverTplNormal>\n @if (cellPopoverContentTpl | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(cellPopoverContentTpl)\" />\n }\n @if (!(cellPopoverContentTpl | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(cellPopoverContentTpl) | zSafeHtml\"></div>\n }\n </ng-template>\n @if (cellPopoverContentTpl) {\n <div\n class=\"z-table-cell-text\"\n z-popover\n z-tooltip\n [zTriggerElement]=\"cellOverlayContentTpl\"\n [zTriggerRef]=\"cellOverlayContentTpl\"\n [zContent]=\"\n (cellTooltipConfigTpl | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"cellPopoverTplNormal\"\n [zPosition]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"\n $any(cellPopoverConfigTpl | zTablePopoverConfig: 'outsideClickClose')\n \"\n [zScrollClose]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'keyboardSafe')\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellOverlayContentTpl\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n } @else {\n <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zTriggerElement]=\"cellTooltipContentTpl\"\n [zContent]=\"\n (cellTooltipConfigTpl | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'maxWidth')\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellTooltipContentTpl\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n }\n }\n </ng-container>\n }\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n\n <!-- Expanded Row Detail -->\n @if (row.getIsExpanded() && row.depth === 0 && !row.subRows?.length) {\n @let resolvedSubTableConfig = row | zTableSubTableConfig: zConfig();\n <tr class=\"z-expanded-row\" animate.enter=\"z-expanded-row-enter\">\n <td [attr.colspan]=\"renderedColumnCount()\" class=\"p-0\">\n <!-- Animate \u1EDF wrapper n\u00E0y b\u1EB1ng clip-path/translate/opacity \u2014 xem z-expanded-row-reveal. -->\n <div class=\"z-expanded-row-content\">\n @if (zConfig().expandedRowTemplate) {\n <ng-container\n *ngTemplateOutlet=\"zConfig().expandedRowTemplate!; context: { $implicit: row }\" />\n } @else if (resolvedSubTableConfig) {\n <div class=\"z-sub-table-container\">\n <z-table [zConfig]=\"$any(resolvedSubTableConfig)\" zVariant=\"borderless\" />\n </div>\n }\n </div>\n </td>\n </tr>\n }\n </ng-template>\n\n <!-- Render Top Pinned Rows (hidden when filtered data is empty) -->\n @if (!isEmpty()) {\n @for (row of table.getTopRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\n }\n }\n\n <!-- Render Center Rows -->\n @for (item of groupedCenterRowItems(); track item.type === 'group' ? item.id : item.row.id) {\n @if (item.type === 'group') {\n <tr\n #groupRow\n class=\"z-group-row\"\n [class.z-group-row-has-totals]=\"item.totals\"\n [class.z-group-row-expanded]=\"item.expanded\"\n [class.z-group-row-sticky]=\"isStickyGroupHeaderEnabled()\"\n [class.z-group-row-sticky-shadow]=\"shadowGroupRowId() === item.id\"\n [style.top.px]=\"stickyGroupTopByDepth()[item.depth]\"\n [attr.data-group-id]=\"item.id\"\n [attr.data-group-depth]=\"item.depth\">\n @if (item.totals) {\n @let totalColumnMap = groupTotalColumnMap();\n @for (column of orderedLeafColumns(); track column.id; let isFirstGroupCell = $first) {\n <td\n [class.z-group-row-label-cell]=\"isFirstGroupCell\"\n [class.z-group-row-total-cell]=\"!isFirstGroupCell && totalColumnMap[column.id]\"\n [attr.data-column-id]=\"column.id\">\n @if (isFirstGroupCell) {\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + item.depth * 0.75\"\n [attr.aria-expanded]=\"item.expanded\"\n (click)=\"toggleGroupRow(item.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"item.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"(item.columnLabel ? item.columnLabel + ': ' : '') + item.label\">\n @if (item.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ item.columnLabel }}:</span>\n }\n {{ item.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ item.count }}</span>\n }\n @if (item.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n zSizeIcon=\"14\"\n [zWave]=\"false\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(item.columnId)\"></button>\n }\n </div>\n }\n @if (!isFirstGroupCell && totalColumnMap[column.id]) {\n @let totalConfig = groupTotalConfigMap()[column.id];\n @let totalTooltip = totalConfig.tooltip;\n @let totalPopover = totalConfig.popover;\n @let totalPopoverContent = totalPopover | zTablePopoverConfig: 'content';\n <ng-template #groupTotalPopoverTpl>\n @if (totalPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(totalPopoverContent)\" />\n }\n @if (!(totalPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(totalPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n <span\n class=\"z-group-row-total\"\n z-tooltip\n z-popover\n [class]=\"totalConfig.class\"\n [zContent]=\"\n $any((totalTooltip | zTableTooltipConfig: 'content') || item.totals[column.id])\n \"\n [zTooltipPosition]=\"$any(totalTooltip | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(totalTooltip | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(totalTooltip | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(totalTooltip | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(totalTooltip | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'showDelay')\"\n [zTooltipHideDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'hideDelay')\"\n [zTooltipArrow]=\"$any(totalTooltip | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(totalTooltip | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(totalTooltip | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(totalTooltip | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(totalTooltip | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"totalPopoverContent ? groupTotalPopoverTpl : null\"\n [zPosition]=\"$any(totalPopover | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(totalPopover | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(totalPopover | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(totalPopover | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(totalPopover | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(totalPopover | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(totalPopover | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(totalPopover | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(totalPopover | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"$any(totalPopover | zTablePopoverConfig: 'outsideClickClose')\"\n [zScrollClose]=\"$any(totalPopover | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(totalPopover | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(totalPopover | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(totalPopover | zTablePopoverConfig: 'keyboardSafe')\">\n {{ item.totals[column.id] }}\n </span>\n }\n </td>\n }\n } @else {\n <td [attr.colspan]=\"renderedColumnCount()\">\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + item.depth * 0.75\"\n [attr.aria-expanded]=\"item.expanded\"\n (click)=\"toggleGroupRow(item.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"item.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"(item.columnLabel ? item.columnLabel + ': ' : '') + item.label\">\n @if (item.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ item.columnLabel }}:</span>\n }\n {{ item.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ item.count }}</span>\n }\n @if (item.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n zSizeIcon=\"14\"\n [zWave]=\"false\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(item.columnId)\"></button>\n }\n </div>\n </td>\n }\n </tr>\n }\n @if (item.type === 'row') {\n <ng-container\n *ngTemplateOutlet=\"\n rowTemplate;\n context: {\n $implicit: item.row,\n isGroupChild: item.isGroupChild,\n groupDepth: item.groupDepth,\n }\n \" />\n }\n }\n\n <!-- Render Bottom Pinned Rows (hidden when filtered data is empty) -->\n @if (!isEmpty()) {\n @for (row of bottomRowsReversed(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\n }\n }\n </tbody>\n </table>\n }\n </ng-scrollbar>\n }\n <!-- end @else -->\n </div>\n\n <!-- Footer table -->\n @if (hasFooter()) {\n <div\n class=\"z-tfoot-wrapper\"\n [class.z-shadow-footer]=\"shouldFooterShowShadow()\"\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\"\n #tfootWrapper>\n <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tfoot>\n @for (footerGroup of orderedFooterGroups(); track footerGroup.id; let footerRowIndex = $index) {\n @if (footerGroup | zTableFooterContent: zConfig().columns : footerRowIndex) {\n <tr>\n @for (footer of footerGroup.headers; track footer.id) {\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n footer.column.id === firstVirtualCenterColumnId()\n ) {\n <th\n class=\"z-virtual-column-spacer z-virtual-footer-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></th>\n }\n @let rowSpan = footer | zTableSpan: zConfig().columns : 'footerRowSpan' : footerRowIndex;\n @let shouldRender =\n footer\n | zTableCellRender\n : footerGroup.headers\n : zConfig().columns\n : 'footer'\n : footerRowIndex\n : orderedFooterGroups();\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n footer.column.getIsPinned() !== false ||\n virtualCenterColumnVisibilityMap()[footer.column.id];\n @if (rowSpan && shouldRender && isVirtualColumnVisible) {\n <th\n [attr.data-column-id]=\"footer.column.id\"\n [ngStyle]=\"\n footer.column\n | zTablePinningStyles\n : footer\n : 'footer'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerClass' : footerRowIndex) +\n ' ' +\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex)\n \"\n [style]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerStyle' : footerRowIndex\n \"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (footer | zTableCellPin: 'isLeftPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-at-left-edge]=\"footer | zTableCellOffset: orderedLeafColumns()\"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"footer | zTableSpan: zConfig().columns : 'footerColSpan' : footerRowIndex\">\n @let configFooterContent =\n footer.column.id | zTableFooterRender: zConfig().columns : footerRowIndex;\n @if (configFooterContent !== undefined && configFooterContent !== '') {\n <ng-container *flexRender=\"configFooterContent; props: footer.getContext(); let footerContent\">\n <div\n class=\"flex w-full items-center\"\n [class.justify-center]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex) ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex) ===\n 'text-right'\n \">\n @if (footerContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n <div\n class=\"z-template-content\"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \">\n <ng-container\n *ngTemplateOutlet=\"footerContent; context: { $implicit: footer.getContext() }\" />\n </div>\n } @else if (footerContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n <z-table-icon-text\n [zText]=\"footerContent\"\n [zTooltip]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerTooltip' : footerRowIndex\n \"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \" />\n } @else {\n <!-- Default/string rendering -->\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerTooltip' : footerRowIndex) ||\n footerContent\n \"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \">\n {{ footerContent | translate }}\n </span>\n }\n </div>\n </ng-container>\n }\n </th>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n footer.column.id === lastVirtualCenterColumnId()\n ) {\n <th\n class=\"z-virtual-column-spacer z-virtual-footer-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></th>\n }\n }\n </tr>\n }\n }\n </tfoot>\n </table>\n </div>\n }\n</div>\n\n<!-- Pagination -->\n@if (zConfig().pagination?.enabled !== false) {\n <div class=\"mt-4 flex items-center justify-between gap-4\">\n <div class=\"truncate text-sm text-gray-500\">\n {{ 'i18n_z_ui_table_total_rows' | translate: { total: (paginationTotal() | zFormatNum) } }}\n </div>\n <z-pagination\n [zTotal]=\"paginationTotal()\"\n [(zPageIndex)]=\"pagination().pageIndex\"\n [(zPageSize)]=\"pagination().pageSize\"\n [zPageSizeOptions]=\"zConfig().pagination?.pageSizeOptions ?? [10, 20, 50, 100]\"\n [zShowSizeChanger]=\"zConfig().pagination?.showSizeChanger ?? true\"\n [zShowQuickJumper]=\"zConfig().pagination?.showQuickJumper ?? false\"\n [zShowTotal]=\"false\"\n [zDisabled]=\"zConfig().pagination?.disabled || isLoading() || isProcessing()\"\n (zOnPageChange)=\"onPageChange($event)\" />\n </div>\n}\n\n<!-- Floating Bulk Action Bar -->\n<div class=\"z-bulk-action-bar-origin\" cdkOverlayOrigin #bulkBarOrigin=\"cdkOverlayOrigin\"></div>\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"bulkBarOrigin\"\n [cdkConnectedOverlayOpen]=\"bulkBarMounted()\"\n [cdkConnectedOverlayPositions]=\"bulkBarPositions\"\n [cdkConnectedOverlayHasBackdrop]=\"false\"\n cdkConnectedOverlayPanelClass=\"z-bulk-action-bar-overlay\">\n @if (bulkBarConfig(); as config) {\n <div class=\"z-bulk-action-bar-inner\" [class.z-leaving]=\"bulkBarClosing()\">\n <div class=\"z-bulk-action-bar-count\">\n {{ bulkBarContext()?.selectedRowIds?.length ?? 0 | zFormatNum }}\n {{ config.selectedLabel ?? ('i18n_z_ui_table_selected' | translate) }}\n </div>\n\n <div class=\"z-bulk-action-bar-divider\"></div>\n\n @for (item of bulkBarItems(); track item.action.key) {\n <button\n type=\"button\"\n z-button\n zSize=\"sm\"\n [zType]=\"item.buttonType\"\n [zDisabled]=\"item.disabled\"\n class=\"z-bulk-action-bar-button\"\n [disabled]=\"item.disabled\"\n (click)=\"onBulkActionClick(item.action)\">\n @if (item.action.icon) {\n <z-icon [zType]=\"item.action.icon\" [zSize]=\"item.action.iconSize ?? '14'\" />\n }\n @if (item.action.label) {\n <span>{{ item.action.label | translate }}</span>\n }\n </button>\n }\n </div>\n }\n</ng-template>\n\n<!-- Settings Drawer -->\n<z-drawer\n [(zVisible)]=\"showSettingsDrawer\"\n [zTitle]=\"'i18n_z_ui_table_settings_title' | translate\"\n zPlacement=\"right\"\n zWidth=\"500px\"\n [zShadow]=\"true\"\n [zOkText]=\"null\"\n [zCancelText]=\"'i18n_z_ui_drawer_close' | translate\">\n <div class=\"z-table-settings-drawer px-4\">\n <!-- Display Settings -->\n <div class=\"mb-4\">\n <h4 class=\"text-foreground mb-2 text-sm font-semibold\">{{ 'i18n_z_ui_table_display_settings' | translate }}</h4>\n <p class=\"text-muted-foreground mb-3 text-xs\">{{ 'i18n_z_ui_table_display_settings_desc' | translate }}</p>\n <div class=\"grid grid-cols-2 gap-x-4 gap-y-3\">\n <z-checkbox\n [zChecked]=\"showHorizontalBorder()\"\n [zText]=\"'i18n_z_ui_table_horizontal_border' | translate\"\n (zChange)=\"showHorizontalBorder.set(!showHorizontalBorder())\" />\n <z-checkbox\n [zChecked]=\"showVerticalBorder()\"\n [zText]=\"'i18n_z_ui_table_vertical_border' | translate\"\n (zChange)=\"showVerticalBorder.set(!showVerticalBorder())\" />\n <z-checkbox\n [zChecked]=\"showHeaderFooterShadow()\"\n [zText]=\"'i18n_z_ui_table_header_footer_shadow' | translate\"\n (zChange)=\"showHeaderFooterShadow.set(!showHeaderFooterShadow())\" />\n </div>\n </div>\n\n <!-- Divider -->\n <div class=\"border-border my-4 border-t\"></div>\n\n <!-- Unified Column Settings -->\n <!-- T\u1EA1m t\u1EAFt \u0111i\u1EC1u ki\u1EC7n: @if (zConfig().enableSettings) -->\n <div class=\"mb-4\">\n <h4 class=\"text-foreground mb-2 text-sm font-semibold\">{{ 'i18n_z_ui_table_column_settings' | translate }}</h4>\n <p class=\"text-muted-foreground mb-3 text-xs\">{{ 'i18n_z_ui_table_column_settings_desc' | translate }}</p>\n\n <!-- Unpinned Columns (Draggable) -->\n <div\n cdkDropList\n #columnDropList=\"cdkDropList\"\n [cdkDropListAutoScrollDisabled]=\"true\"\n (cdkDropListDropped)=\"onPendingColumnDrop($event)\"\n class=\"z-column-drop-list space-y-1.5\">\n @for (columnId of columnOrder(); track columnId; let i = $index) {\n @if (columnId !== 'expand' && columnId !== 'select' && columnId !== 'rowDrag') {\n @let column = table.getColumn(columnId);\n @let isPinned = column?.getIsPinned();\n @let isVisible = pendingVisibleColumns().includes(columnId);\n @let isVisibilityDisabled = pendingColumnVisibilityDisabledMap()[columnId];\n @let isGroupedColumn = groupingColumnMap()[columnId];\n @let columnEnablePinningConfig = columnId | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let canPin =\n (columnEnablePinningConfig ?? zConfig().enableColumnPinning ?? true) && column?.getCanPin() !== false;\n @if (!isPinned) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"isGroupedColumn\"\n [cdkDragData]=\"columnId\"\n cdkDragLockAxis=\"y\"\n cdkDragPreviewContainer=\"global\"\n cdkDragPreviewClass=\"z-drag-preview\"\n class=\"z-drag-item border-border bg-card hover:border-primary flex cursor-default items-center gap-2 rounded border px-2 py-1.5 text-sm\"\n [class.opacity-60]=\"!isVisible\">\n <!-- Drag Handle -->\n <z-icon\n cdkDragHandle\n zType=\"lucideGripVertical\"\n zSize=\"14\"\n class=\"text-muted-foreground shrink-0\"\n [class.cursor-pointer]=\"!isGroupedColumn\"\n [class.cursor-default]=\"isGroupedColumn\"\n [class.opacity-40]=\"isGroupedColumn\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n [disabled]=\"isVisibilityDisabled\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n (mousedown)=\"$event.stopPropagation()\"\n class=\"border-input h-4 w-4 shrink-0 cursor-default rounded disabled:opacity-50\" />\n\n <!-- Column Name -->\n <span class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\" [class.text-muted-foreground]=\"!isVisible\">\n {{ columnId | zTableColumnHeader: zConfig().columns | translate }}\n </span>\n @let parents = columnId | zTableColumnParents: zConfig().columns;\n @if (parents) {\n <span class=\"text-muted-foreground truncate text-[0.625rem]\">({{ parents | translate }})</span>\n }\n </span>\n\n <!-- Pin Buttons -->\n @if (canPin) {\n <div class=\"flex shrink-0 items-center gap-0.5\" (mousedown)=\"$event.stopPropagation()\">\n <button\n type=\"button\"\n [disabled]=\"!isVisible || isGroupedColumn || !pinAvailabilityMap()[columnId]?.left\"\n (click)=\"onToggleColumnPin(columnId, 'left')\"\n class=\"text-muted-foreground hover:bg-muted cursor-pointer rounded p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Pin Left\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"12\" />\n </button>\n <button\n type=\"button\"\n [disabled]=\"!isVisible || isGroupedColumn || !pinAvailabilityMap()[columnId]?.right\"\n (click)=\"onToggleColumnPin(columnId, 'right')\"\n class=\"text-muted-foreground hover:bg-muted cursor-pointer rounded p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Pin Right\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"12\" />\n </button>\n </div>\n }\n </div>\n }\n }\n }\n </div>\n\n <!-- Pinned Columns Section -->\n @if (zConfig().enableColumnPinning ?? true) {\n @if (pinnedColumnIds().length > 0) {\n <div class=\"border-border mt-4 border-t pt-4\">\n <h5 class=\"text-muted-foreground mb-2 text-xs font-medium\">\n {{ 'i18n_z_ui_table_pinned_columns' | translate }}\n </h5>\n <div class=\"space-y-1.5\">\n @for (columnId of pinnedColumnIds(); track columnId) {\n @let column = table.getColumn(columnId);\n @let isPinned = column?.getIsPinned();\n @let isVisible = pendingVisibleColumns().includes(columnId);\n @let isVisibilityDisabled = pendingColumnVisibilityDisabledMap()[columnId];\n @let isGroupedColumn = groupingColumnMap()[columnId];\n <div\n class=\"border-border bg-muted/30 flex items-center gap-2 rounded border px-2 py-1.5 text-sm\"\n [class.opacity-60]=\"!isVisible\">\n <!-- Pin Icon -->\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"text-primary shrink-0\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n [disabled]=\"isVisibilityDisabled\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n class=\"border-input h-4 w-4 shrink-0 cursor-default rounded disabled:opacity-50\" />\n\n <!-- Column Name -->\n <span class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\" [class.text-muted-foreground]=\"!isVisible\">\n {{ columnId | zTableColumnHeader: zConfig().columns | translate }}\n </span>\n @let pinnedParents = columnId | zTableColumnParents: zConfig().columns;\n @if (pinnedParents) {\n <span class=\"text-muted-foreground truncate text-[0.625rem]\">\n ({{ pinnedParents | translate }})\n </span>\n }\n </span>\n\n <!-- Position Badge -->\n <span class=\"bg-primary/10 text-primary shrink-0 rounded px-1.5 py-0.5 text-[0.625rem] font-medium\">\n {{\n isPinned === 'start'\n ? ('i18n_z_ui_table_left' | translate)\n : ('i18n_z_ui_table_right' | translate)\n }}\n </span>\n\n <!-- Unpin Button -->\n <button\n type=\"button\"\n [disabled]=\"isGroupedColumn\"\n (click)=\"onToggleColumnPin(columnId, isPinned === 'start' ? 'left' : 'right')\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground cursor-pointer rounded p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Unpin\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </div>\n }\n </div>\n </div>\n }\n }\n </div>\n </div>\n</z-drawer>\n", styles: [":host{display:flex;flex-direction:column;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;overflow-x:visible;--scrollbar-track-thickness: 7px;--scrollbar-track-color: transparent;--scrollbar-thumb-shape: 3px;--z-shadow-left-right: -1.875rem;--z-shadow-left-width: 1.875rem;--z-shadow-left-opacity: 0;--z-shadow-right-left: -1.875rem;--z-shadow-right-width: 1.875rem;--z-shadow-right-opacity: 0;--z-sticky-left-border-color: transparent;--z-sticky-right-border-color: var(--border);--z-cell-selection-background: color-mix(in srgb, var(--primary) 12%, transparent);--z-cell-selection-background-opaque: color-mix(in srgb, var(--primary) 12%, var(--card))}.z-table-container{display:flex;flex-direction:column;position:relative;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;overflow:hidden;border-radius:.3125rem;border:thin solid var(--border);background-color:var(--card)}.z-table-container:focus{outline:none}.z-table-container.z-table-borderless{border:none;border-radius:0;box-shadow:none!important;background-color:transparent}.z-table-container.z-hide-horizontal-border th,.z-table-container.z-hide-horizontal-border td{border-bottom:none!important;border-top:none!important}.z-table-container.z-hide-vertical-border th,.z-table-container.z-hide-vertical-border td{border-left:none!important}.z-table-container.z-hide-pinned-top-border tbody tr.z-pinned-top.z-shadow-bottom>td{border-bottom-color:var(--border)!important}.z-table-container.z-hide-pinned-bottom-border tbody.z-has-bottom-pinned td.z-at-bottom{border-bottom-color:transparent}table{width:fit-content;min-width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed;font-size:.875rem}.z-table-container.z-column-resizing table,.z-table-toolbar{min-width:0}.z-table-toolbar .z-settings-btn{transition:all .15s ease}.z-table-toolbar .z-settings-btn:hover{border-color:var(--muted-foreground)}.z-table-filter-header{min-width:0}.z-table-filter-header button{flex:none}.z-table-filter-header-overflow-chip{animation:z-table-filter-chip-enter .16s ease}@media(prefers-reduced-motion:reduce){.z-table-filter-header-overflow-chip{animation:none}}@keyframes z-table-filter-chip-enter{0%{opacity:0;transform:translate(-.25rem)}to{opacity:1;transform:translate(0)}}.z-bulk-action-bar-origin{position:fixed;left:50%;bottom:1rem;width:1px;height:1px;pointer-events:none}:host ::ng-deep .z-bulk-action-bar-overlay{max-width:calc(100vw - 2rem);margin-bottom:1rem;transform-origin:center bottom}.z-bulk-action-bar-inner{border:thin solid color-mix(in srgb,var(--border) 88%,transparent);border-radius:.4rem;background:color-mix(in srgb,var(--card) 96%,var(--background));color:var(--foreground);box-shadow:0 1rem 2.5rem color-mix(in srgb,var(--foreground) 20%,transparent),0 .25rem .75rem color-mix(in srgb,var(--foreground) 12%,transparent),0 0 0 1px color-mix(in srgb,var(--background) 65%,transparent) inset;display:flex;align-items:center;gap:.5rem;width:max-content;min-height:2.25rem;max-width:calc(100vw - 2rem);padding:.5rem;transform-origin:center bottom;animation:z-bulk-action-bar-enter .18s cubic-bezier(.16,1,.3,1);will-change:opacity,transform}.z-bulk-action-bar-inner.z-leaving{pointer-events:none;animation:z-bulk-action-bar-exit .14s ease-in forwards}.z-bulk-action-bar-count{padding:0 .25rem;white-space:nowrap;font-size:.8125rem;font-weight:500;color:var(--foreground)}.z-bulk-action-bar-divider{width:1px;height:1.5rem;flex:none;background:color-mix(in srgb,var(--border) 88%,transparent)}.z-bulk-action-bar-button{flex:none}@keyframes z-bulk-action-bar-enter{0%{opacity:0;transform:translateY(.875rem)}to{opacity:1;transform:translateY(0)}}@keyframes z-bulk-action-bar-exit{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(.875rem)}}@media(prefers-reduced-motion:reduce){.z-bulk-action-bar-inner{animation:none}}:host ::ng-deep .z-table-cell-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;min-width:0;-webkit-user-select:text;user-select:text}:host ::ng-deep .z-table-cell-text>*,:host ::ng-deep .z-table-cell-text *{display:inline-block;max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}:host ::ng-deep .z-table-cell-content-trigger{display:inline-block;max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}.z-template-content{display:block;width:100%;min-width:0;max-width:100%;overflow:hidden}.z-template-content>*{min-width:0;max-width:100%}.z-template-content>[class*=flex]{min-width:0;max-width:100%}.z-template-content>[class*=flex]>*{min-width:0;flex-shrink:1}.z-template-content>[class*=grid]{min-width:0;max-width:100%}.z-thead-wrapper{flex-shrink:0;background:var(--muted);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;position:relative;z-index:4}.z-thead-wrapper::-webkit-scrollbar{display:none}.z-thead-wrapper th{height:auto;padding:.5rem;text-align:left;vertical-align:middle;font-weight:500;color:var(--foreground);white-space:nowrap;overflow:hidden;background:var(--muted);border-left:thin solid var(--border);border-bottom:thin solid var(--border);-webkit-user-select:none;user-select:none}.z-thead-wrapper th.z-at-left-edge{border-left:none}.z-thead-wrapper th[colspan]{text-align:center;background:var(--muted);font-weight:500;color:var(--foreground)}.z-thead-wrapper.z-shadow-header{box-shadow:0 1px 3px #00000014;position:relative;z-index:15}.z-thead-wrapper.z-shadow-header:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}.z-tbody-wrapper{flex:1;width:100%;max-width:100%;min-width:0;min-height:6.25rem;display:flex;flex-direction:column;overflow:hidden}.z-tbody-scrollbar{flex:1;width:100%;max-width:100%;min-width:0;height:100%}.z-empty-state,.z-loading-state{flex:1 1 0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;min-height:6.25rem;height:100%;color:var(--muted-foreground);font-size:.875rem;animation:z-fade-in .2s ease-out}.z-tbody-scrollbar,.z-tbody-scrollbar table{animation:z-fade-in .2s ease-out}@keyframes z-fade-in{0%{opacity:0;transform:translateY(.25rem)}to{opacity:1;transform:translateY(0)}}.z-tbody-wrapper tr{transition:background-color .15s ease}.z-tbody-wrapper tr:hover,.z-tbody-wrapper tr:hover td[style*=sticky]{background-color:var(--muted)}.z-tbody-wrapper tr.z-pinned-top td.z-sticky-left,.z-tbody-wrapper tr.z-pinned-top td.z-sticky-right,.z-tbody-wrapper tr.z-pinned-bottom td.z-sticky-left,.z-tbody-wrapper tr.z-pinned-bottom td.z-sticky-right{z-index:3}.z-tbody-wrapper tr.z-shadow-bottom{box-shadow:0 1px 3px #00000014!important;position:relative;z-index:15}.z-tbody-wrapper tr.z-shadow-bottom:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d!important}.z-tbody-wrapper tr.z-shadow-top{box-shadow:0 -2px 4px #0000000d!important;position:relative;z-index:15}.z-tbody-wrapper tr.z-shadow-top:where(.dark,.dark *){box-shadow:0 -2px 4px #0003!important}.z-tbody-wrapper td{padding:.5rem 12px;height:var(--z-row-height, 2.375rem);vertical-align:middle;color:var(--foreground);white-space:nowrap;overflow:hidden;background:var(--card);border-left:thin solid var(--border);border-bottom:thin solid var(--border);box-sizing:border-box}.z-tbody-wrapper tbody.z-has-vertical-scroll td.z-at-bottom,.z-tbody-wrapper tbody.z-last-row-touches-bottom td.z-at-bottom{border-bottom-color:transparent}.z-tbody-wrapper tbody.z-has-bottom-pinned td.z-at-bottom{border-bottom-color:var(--border)}.z-tbody-wrapper td.z-at-left-edge{border-left:none}.z-tbody-wrapper td i{color:var(--muted-foreground);font-style:italic}.z-tbody-wrapper td[rowspan]{vertical-align:top;padding-top:.75rem}.z-tbody-wrapper td.z-row-hover{background-color:var(--muted)!important}.z-tbody-wrapper td.z-col-select,.z-tbody-wrapper td.z-col-expand,.z-tbody-wrapper td.z-col-actions{padding:.5rem 4px!important;text-align:center}.z-tbody-wrapper tr.z-child-row td.z-col-select:first-child,.z-tbody-wrapper tr.z-child-row td.z-col-expand:first-child,.z-tbody-wrapper tr.z-child-row td.z-col-actions:first-child{padding-left:0!important}.z-virtual-scroll-inner{position:relative;box-sizing:border-box;width:100%}.z-virtual-row{position:absolute;top:0;left:0;width:100%}.z-virtual-row-group-header{z-index:2}.z-virtual-row-sticky-group{position:sticky}.z-virtual-row-sticky-group-shadow{box-shadow:0 1px 3px #00000014}.z-virtual-row-sticky-group-shadow:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}tr.z-group-row-sticky{position:sticky;z-index:2}tr.z-group-row-sticky>td{background:var(--card)}tr.z-group-row-sticky-shadow{box-shadow:0 1px 3px #00000014}tr.z-group-row-sticky-shadow:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}tr.z-child-row td:first-child{border-left:.125rem solid var(--primary)!important;padding-left:.75rem!important}tbody tr.z-context-menu-active,tbody tr.z-context-menu-active td{background-color:var(--muted)!important}tbody tr.z-selected,tbody tr.z-selected td{background-color:color-mix(in srgb,var(--primary) 15%,var(--background))!important}tbody tr.z-selected:hover,tbody tr.z-selected:hover td{background-color:color-mix(in srgb,var(--primary) 20%,var(--background))!important}tbody tr.z-indeterminate-selected,tbody tr.z-indeterminate-selected td{background-color:color-mix(in srgb,var(--primary) 10%,var(--background))!important}tbody tr.z-indeterminate-selected:hover,tbody tr.z-indeterminate-selected:hover td{background-color:color-mix(in srgb,var(--primary) 15%,var(--background))!important}tbody tr.z-pinned-top td{background-color:var(--card)!important}tbody tr.z-pinned-top:hover{background-color:var(--muted)}tbody tr.z-pinned-top:hover td{background-color:var(--muted)!important}tbody tr.z-pinned-bottom td{background-color:var(--card)!important}tbody tr.z-pinned-bottom:hover{background-color:var(--muted)}tbody tr.z-pinned-bottom:hover td{background-color:var(--muted)!important}tbody tr.z-pinned-bottom-last>td{border-bottom-color:transparent!important}tbody tr.z-pinned-bottom-first>td{border-top:thin solid var(--border)}:host .z-tbody-wrapper tbody tr:not(.z-pinned-top):not(.z-pinned-bottom):has(+tr.z-pinned-bottom)>td{border-bottom-color:transparent}tr.z-expanded-row>td{border-left:.125rem solid var(--primary);background-color:var(--background)!important}.z-expanded-row-content{transform-origin:top center}@keyframes z-expanded-row-reveal{0%{clip-path:inset(0 0 100% 0);translate:0 -.375rem;opacity:0}to{clip-path:inset(0 0 0 0);translate:none;opacity:1}}@keyframes z-expanded-row-fade-in{0%{opacity:0}to{opacity:1}}tr.z-expanded-row-enter{animation:z-expanded-row-fade-in .18s ease-out}tr.z-expanded-row-enter .z-expanded-row-content{animation:z-expanded-row-reveal .18s ease-out}@keyframes z-child-row-slide-in{0%{translate:0 -.375rem;opacity:0}to{translate:none;opacity:1}}tr.z-child-row.z-row-enter,tr.z-group-child-row.z-row-enter{animation:z-child-row-slide-in .18s ease-out}@media(prefers-reduced-motion:reduce){tr.z-expanded-row-enter,tr.z-child-row.z-row-enter,tr.z-group-child-row.z-row-enter,tr.z-expanded-row-enter .z-expanded-row-content,tr.z-child-row.z-row-enter .z-expanded-row-content,tr.z-group-child-row.z-row-enter .z-expanded-row-content{animation-duration:1ms}}.z-sub-table-container{padding:.75rem 1rem .75rem 3rem;background-color:var(--background)}.z-table-content-trigger{display:block;width:100%;min-width:0;min-height:1.5rem;padding:0;border:0;border-radius:0;background:transparent;color:inherit;font:inherit;line-height:1.5rem;text-align:inherit;outline:0;cursor:text}.z-table-content-trigger:hover{color:var(--primary)}.z-content-edit-active{position:relative;z-index:2}td:has(>.z-table-content-trigger:focus-visible){position:relative;z-index:2}td:has(>.z-table-content-trigger:focus-visible):after{position:absolute;z-index:3;inset:0;border:1px solid var(--primary);content:\"\";pointer-events:none}td.z-cell-selectable{-webkit-user-select:none;user-select:none}td.z-cell-range-selected{position:relative;isolation:isolate}td.z-cell-range-selected:before{position:absolute;z-index:0;box-sizing:border-box;top:var(--z-cell-range-top, 0);right:var(--z-cell-range-right, 0);bottom:var(--z-cell-range-bottom, 0);left:var(--z-cell-range-left, 0);background-color:var(--z-cell-selection-background);content:\"\";pointer-events:none}td.z-cell-range-selected>*{position:relative;z-index:1}td.z-cell-range-top:before{border-top:1px solid var(--primary)}td.z-cell-range-right:before{border-right:1px solid var(--primary)}td.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}td.z-cell-range-left:before{border-left:1px solid var(--primary)}td.z-cell-active{position:relative;z-index:3;background-color:var(--z-cell-selection-background)!important}td.z-cell-active:after{position:absolute;z-index:4;inset:0;border:1px solid var(--primary);content:\"\";pointer-events:none}td.z-content-edit-active{-webkit-user-select:text;user-select:text}td.z-cell-active.z-row-hover,td.z-content-edit-active.z-row-hover{background-color:var(--card)!important}thead th{position:relative}thead th .z-resizer{position:absolute;right:0;top:0;height:100%;width:.5rem;background:transparent;cursor:col-resize;-webkit-user-select:none;user-select:none;touch-action:none;z-index:5}thead th .z-resizer:after{content:\"\";position:absolute;right:0;top:0;height:100%;width:.1875rem;background:#0000001a;opacity:0;transition:opacity .2s ease}thead th .z-resizer:after:where(.dark,.dark *){background:#ffffff1a}thead th .z-resizer:hover:after{opacity:1;background:var(--primary);width:.1875rem}thead th .z-resizer.z-is-resizing:after{opacity:1;background:var(--primary);width:.1875rem}thead th .z-resizer.z-resizer-left{right:auto;left:0}thead th .z-resizer.z-resizer-left:after{right:auto;left:0}.z-thead-wrapper th.z-sticky-left,.z-thead-wrapper th.z-sticky-right,.z-tbody-wrapper th.z-sticky-left,.z-tbody-wrapper th.z-sticky-right,.z-tfoot-wrapper th.z-sticky-left,.z-tfoot-wrapper th.z-sticky-right{background-color:var(--muted);z-index:1;transform:translateZ(0);backface-visibility:hidden}.z-thead-wrapper td.z-sticky-left,.z-thead-wrapper td.z-sticky-right,.z-tbody-wrapper td.z-sticky-left,.z-tbody-wrapper td.z-sticky-right,.z-tfoot-wrapper td.z-sticky-left,.z-tfoot-wrapper td.z-sticky-right{background-color:var(--card);z-index:1;transform:translateZ(0);backface-visibility:hidden}.z-thead-wrapper th.z-sticky-left-last,.z-thead-wrapper td.z-sticky-left-last,.z-tbody-wrapper th.z-sticky-left-last,.z-tbody-wrapper td.z-sticky-left-last,.z-tfoot-wrapper th.z-sticky-left-last,.z-tfoot-wrapper td.z-sticky-left-last{position:relative;overflow:visible;border-right:thin solid var(--z-sticky-left-border-color)}.z-thead-wrapper th.z-sticky-left-last:after,.z-thead-wrapper td.z-sticky-left-last:after,.z-tbody-wrapper th.z-sticky-left-last:after,.z-tbody-wrapper td.z-sticky-left-last:after,.z-tfoot-wrapper th.z-sticky-left-last:after,.z-tfoot-wrapper td.z-sticky-left-last:after{content:\"\";position:absolute;top:0;bottom:0;right:var(--z-shadow-left-right);width:var(--z-shadow-left-width);pointer-events:none;box-shadow:inset 10px 0 8px -8px #0000001a;z-index:10;opacity:var(--z-shadow-left-opacity)}:host-context(.dark) .z-thead-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-thead-wrapper td.z-sticky-left-last:after,:host-context(.dark) .z-tbody-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-tbody-wrapper td.z-sticky-left-last:after,:host-context(.dark) .z-tfoot-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-tfoot-wrapper td.z-sticky-left-last:after{box-shadow:inset 10px 0 10px -8px #0000004d}.z-thead-wrapper.z-scroll-left,.z-tbody-wrapper.z-scroll-left,.z-tfoot-wrapper.z-scroll-left{--z-shadow-left-opacity: 1}.z-thead-wrapper.z-scroll-left:where(.dark,.dark *),.z-tbody-wrapper.z-scroll-left:where(.dark,.dark *),.z-tfoot-wrapper.z-scroll-left:where(.dark,.dark *){--z-sticky-left-border-color: var(--border)}.z-thead-wrapper th.z-sticky-right-first,.z-thead-wrapper td.z-sticky-right-first,.z-tbody-wrapper th.z-sticky-right-first,.z-tbody-wrapper td.z-sticky-right-first,.z-tfoot-wrapper th.z-sticky-right-first,.z-tfoot-wrapper td.z-sticky-right-first{position:relative;overflow:visible;border-left:thin solid var(--z-sticky-right-border-color)}.z-thead-wrapper th.z-sticky-right-first:before,.z-thead-wrapper td.z-sticky-right-first:before,.z-tbody-wrapper th.z-sticky-right-first:before,.z-tbody-wrapper td.z-sticky-right-first:before,.z-tfoot-wrapper th.z-sticky-right-first:before,.z-tfoot-wrapper td.z-sticky-right-first:before{content:\"\";position:absolute;top:0;bottom:0;left:var(--z-shadow-right-left);width:var(--z-shadow-right-width);pointer-events:none;box-shadow:inset -10px 0 8px -8px #0000001a;z-index:10;opacity:var(--z-shadow-right-opacity)}:host-context(.dark) .z-thead-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-thead-wrapper td.z-sticky-right-first:before,:host-context(.dark) .z-tbody-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-tbody-wrapper td.z-sticky-right-first:before,:host-context(.dark) .z-tfoot-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-tfoot-wrapper td.z-sticky-right-first:before{box-shadow:inset -10px 0 10px -8px #0000004d}.z-thead-wrapper.z-scroll-right,.z-tbody-wrapper.z-scroll-right,.z-tfoot-wrapper.z-scroll-right{--z-shadow-right-opacity: 1}.z-thead-wrapper.z-scroll-right:not(:where(.dark,.dark *)),.z-tbody-wrapper.z-scroll-right:not(:where(.dark,.dark *)),.z-tfoot-wrapper.z-scroll-right:not(:where(.dark,.dark *)){--z-sticky-right-border-color: transparent}.z-pinning-overflow{--z-shadow-left-opacity: 0 !important;--z-shadow-right-opacity: 0 !important;--z-sticky-left-border-color: transparent !important;--z-sticky-right-border-color: transparent !important}.z-pinning-overflow .z-sticky-left,.z-pinning-overflow .z-sticky-right{position:relative!important;right:auto!important;left:auto!important}.z-pinning-overflow .z-sticky-left-last:after,.z-pinning-overflow .z-sticky-right-first:before,.z-pinning-overflow .z-sticky-right-last:after{display:none!important}.z-thead-wrapper th.z-sticky-right-last,.z-tfoot-wrapper th.z-sticky-right-last{position:relative}.z-thead-wrapper th.z-sticky-right-last:after,.z-tfoot-wrapper th.z-sticky-right-last:after{content:\"\";position:absolute;top:0;bottom:0;right:-1.875rem;width:1.875rem;background:var(--muted);pointer-events:none}.z-tfoot-wrapper{flex-shrink:0;width:100%;max-width:100%;min-width:0;background:var(--muted);overflow-x:hidden;overflow-y:hidden;touch-action:pan-y pinch-zoom}.z-tfoot-wrapper th{height:auto;padding:.5rem 12px;text-align:left;vertical-align:middle;font-weight:500;font-size:.75rem;color:var(--muted-foreground);text-transform:uppercase;letter-spacing:.5px;background:var(--muted);border-left:thin solid var(--border);border-top:thin solid var(--border)}.z-tfoot-wrapper th.z-at-left-edge{border-left:none}.z-tfoot-wrapper.z-shadow-footer{box-shadow:0 -2px 4px #0000000d;position:relative;z-index:15}.z-tfoot-wrapper.z-shadow-footer:where(.dark,.dark *){box-shadow:0 -2px 4px #0003}.z-pin-btn{padding:.125rem 4px;border-radius:.25rem;color:var(--muted-foreground);transition:all .15s ease}.z-pin-btn:hover{background-color:var(--muted);color:var(--foreground)}.z-pin-btn.z-pin-btn-active{color:var(--primary);background-color:var(--primary)}.z-pin-btn.z-pin-btn-active:hover{background-color:var(--primary);opacity:.8}.z-row-pin-trigger{opacity:1}.z-row-pin-trigger:focus-visible,.z-row-pin-trigger.z-popover-open{background-color:color-mix(in srgb,var(--foreground) 8%,transparent);color:var(--foreground)}.z-row-pin-trigger:active{background-color:color-mix(in srgb,var(--foreground) 12%,transparent)}.z-row-pin-trigger.text-primary{color:var(--primary)}.z-row-pin-unpin-trigger{color:var(--muted-foreground);outline:none}.z-row-pin-unpin-trigger:hover{color:var(--destructive);background-color:color-mix(in srgb,var(--destructive) 10%,transparent)}.z-row-pin-unpin-trigger:focus,.z-row-pin-unpin-trigger:focus-visible{color:var(--muted-foreground);background-color:transparent;outline:none;box-shadow:none}.z-row-pin-unpin-trigger:active{color:var(--destructive);background-color:color-mix(in srgb,var(--destructive) 14%,transparent)}.z-header-pin-trigger{opacity:1}.z-header-pin-trigger.text-primary{color:var(--primary)}th{overflow:hidden}th .z-header-content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}th .z-header-text-wrapper{transition:background-color .15s ease;border-radius:.25rem;min-width:0;overflow:hidden;flex-shrink:1}th .z-header-text-wrapper.z-has-options:hover,th .z-header-text-wrapper.z-has-options:focus-visible,th .z-header-text-wrapper.z-has-options.z-popover-open{background-color:color-mix(in srgb,var(--foreground) 8%,transparent);outline:none}th .z-header-text-wrapper.z-has-options:active{background-color:color-mix(in srgb,var(--foreground) 12%,transparent)}.z-column-menu-item{line-height:1.25rem}.z-column-menu-item:focus-visible,.z-column-menu-item.z-popover-open{background-color:var(--muted);outline:none}.cdk-drag-preview,.z-drag-preview{box-sizing:border-box;border:1px solid var(--primary);border-radius:.375rem;background-color:var(--card);box-shadow:0 5px 20px #0003;overflow:hidden;pointer-events:none;z-index:10000!important}.cdk-drag-preview:where(.dark,.dark *),.z-drag-preview:where(.dark,.dark *){box-shadow:0 5px 20px #00000080}.cdk-drag-placeholder{box-sizing:border-box;border:2px dashed var(--primary);border-radius:.375rem;background-color:color-mix(in srgb,var(--primary) 10%,var(--background))}.cdk-drag-animating,.cdk-drop-list-dragging .cdk-drag:not(.cdk-drag-placeholder){transition:transform .1s cubic-bezier(0,0,.2,1)}.z-drag-item.cdk-drag-dragging{transition:none!important}.z-table-drag-preview{box-sizing:border-box;border-radius:.375rem;background-color:var(--card);border:1px solid var(--primary);box-shadow:0 10px 24px #00000029;overflow:hidden;z-index:10000!important;pointer-events:none}.z-table-drag-preview:where(.dark,.dark *){box-shadow:0 5px 20px #00000080}.z-table-drag-preview-row{border:0;border-radius:.125rem;background-color:var(--background);box-shadow:0 8px 20px #0000001f,inset 0 0 0 1px color-mix(in srgb,var(--primary) 45%,var(--border))}.z-table-drag-preview-row table,.z-table-drag-preview-row tbody,.z-table-drag-preview-row tr{height:100%}.z-table-drag-preview-row td{vertical-align:middle!important;background-color:var(--background)}.z-table-drag-source{display:none!important}.z-virtual-row.z-table-drag-source{display:block!important;pointer-events:none;outline:1px solid var(--border);outline-offset:-1px}.z-virtual-row.z-table-drag-source td{color:color-mix(in srgb,var(--foreground) 45%,transparent);border-color:var(--border)!important;background-color:var(--card)!important}.z-virtual-row.z-table-drag-source td>*{opacity:.45}[data-z-table-drag-handle]{touch-action:none;-webkit-user-select:none;user-select:none}.z-column-drop-list{min-height:3.125rem;overscroll-behavior:contain}.z-column-drop-list.cdk-drop-list-dragging{overflow:clip}.z-table-drag-placeholder{width:100%;min-height:2.625rem;box-sizing:border-box;border:2px dashed var(--primary);border-radius:.375rem;background-color:color-mix(in srgb,var(--primary) 10%,var(--background));pointer-events:none}.z-table-drag-placeholder-row>td{padding:0!important;border:0!important;background:transparent!important}.z-table-drag-placeholder-row .z-table-drag-placeholder{border-radius:0;background-color:color-mix(in srgb,var(--primary) 10%,transparent)}.z-table-drag-placeholder-virtual{position:absolute;top:0;left:0;z-index:20;border-radius:0}.z-tbody-wrapper tr.z-group-row td{background:var(--card);border-top:none;border-bottom:1px solid var(--border)}.z-virtual-row tr.z-group-row td{background:var(--card);border-top:none;border-bottom:none}.z-group-row-sticky-wrapper{display:inline-flex;align-items:center;translate:var(--z-scroll-x, 0px) 0}.z-table-container:not(.z-hide-horizontal-border) .z-virtual-row:after{content:\"\";position:absolute;right:0;bottom:0;left:0;z-index:3;height:1px;background:var(--border);pointer-events:none}.z-tbody-wrapper tr.z-group-child-row td.z-at-left-edge,.z-virtual-row tr.z-group-child-row td.z-at-left-edge{border-left:2px solid var(--primary)!important;padding-left:var(--z-group-content-indent, .75rem)}.z-group-row-trigger{display:inline-flex;min-height:2rem;max-width:100%;align-items:center;gap:.5rem;padding:.25rem .5rem .25rem .75rem;color:var(--primary);font-size:.8125rem;font-weight:600;vertical-align:middle;cursor:pointer}.z-group-row-remove{margin-left:.125rem;color:var(--muted-foreground);vertical-align:middle}.z-group-row-remove:hover,.z-group-row-remove:focus-visible{color:var(--destructive);background:color-mix(in srgb,var(--destructive) 10%,transparent);outline:none}.z-group-row-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-column-label{color:color-mix(in srgb,var(--primary) 65%,var(--foreground));font-weight:500;margin-right:.25rem}.z-group-row-count{display:inline-flex;min-width:1.25rem;height:1.25rem;align-items:center;justify-content:center;padding:0 .375rem;border-radius:999px;background:var(--primary);color:var(--primary-foreground);font-size:.6875rem;font-weight:600}.z-group-row-loading{display:inline-flex;align-items:center;margin-left:.25rem}.z-group-row-has-totals td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-has-totals .z-group-row-label-cell{position:sticky;left:0;z-index:2;background:var(--card)}.z-group-row-has-totals .z-group-row-label-cell .z-group-row-sticky-wrapper{max-width:100%;translate:none}.z-group-row-total{display:inline-block;max-width:100%;color:var(--foreground);font-size:.8125rem;font-weight:600;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-total-cell{text-align:right}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-selected:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:before{position:absolute!important;z-index:0!important;box-sizing:border-box!important;top:var(--z-cell-range-top, 0)!important;right:var(--z-cell-range-right, 0)!important;bottom:var(--z-cell-range-bottom, 0)!important;left:var(--z-cell-range-left, 0)!important;width:auto!important;background-color:var(--z-cell-selection-background-opaque)!important;box-shadow:none!important;content:\"\"!important;pointer-events:none!important;opacity:1!important}:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:after{display:none!important}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-top:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-top:before{border-top:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-right:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-right:before{border-right:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-bottom:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-left:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-left:before{border-left:1px solid var(--primary)}:host-context(.z-table-pointer-dragging) .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-selected:before,:host-context(.z-table-pointer-dragging) .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:before{background-color:transparent!important}:host td.z-cell-range-selected:before{position:absolute;z-index:0;box-sizing:border-box;top:var(--z-cell-range-top, 0);right:var(--z-cell-range-right, 0);bottom:var(--z-cell-range-bottom, 0);left:var(--z-cell-range-left, 0);background-color:var(--z-cell-selection-background);box-shadow:none;content:\"\";pointer-events:none;opacity:1}:host td.z-cell-range-top:before{border-top:1px solid var(--primary)}:host td.z-cell-range-right:before{border-right:1px solid var(--primary)}:host td.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}:host td.z-cell-range-left:before{border-left:1px solid var(--primary)}:host-context(.z-table-pointer-dragging) td.z-row-hover{background-color:var(--background)!important}:host td.z-cell-active,:host td.z-cell-active.z-row-hover{background-color:var(--z-cell-selection-background)!important}:host td.z-content-edit-active.z-row-hover{background-color:var(--card)!important}:host tr.z-pinned-top td.z-cell-active,:host tr.z-pinned-top td.z-cell-active.z-row-hover,:host tr.z-pinned-bottom td.z-cell-active,:host tr.z-pinned-bottom td.z-cell-active.z-row-hover,:host td.z-cell-active.z-sticky-left,:host td.z-cell-active.z-sticky-left.z-row-hover,:host td.z-cell-active.z-sticky-right,:host td.z-cell-active.z-sticky-right.z-row-hover{background-color:var(--z-cell-selection-background-opaque)!important}:host tr.z-pinned-top td.z-cell-range-selected,:host tr.z-pinned-bottom td.z-cell-range-selected,:host td.z-cell-range-selected.z-sticky-left,:host td.z-cell-range-selected.z-sticky-right{background-color:var(--card)}:host tr.z-pinned-top td.z-cell-range-selected:before,:host tr.z-pinned-bottom td.z-cell-range-selected:before,:host td.z-cell-range-selected.z-sticky-left:before,:host td.z-cell-range-selected.z-sticky-right:before{background-color:var(--z-cell-selection-background-opaque)}:host-context(.z-table-pointer-dragging) td.z-cell-range-selected,:host-context(.z-table-pointer-dragging) td.z-cell-range-selected.z-row-hover,:host-context(.z-table-pointer-dragging) td.z-cell-active,:host-context(.z-table-pointer-dragging) td.z-cell-active.z-row-hover{background-color:var(--card)!important}:host-context(.z-table-pointer-dragging) td.z-cell-range-selected:before{background-color:transparent}:host .z-tbody-wrapper tbody tr.z-group-child-row:has(+tr.z-group-row)>td.z-at-bottom{border-bottom-color:var(--border)}:host .z-virtual-row:has(tr.z-group-child-row):has(+.z-virtual-row tr.z-group-row) tr.z-group-child-row>td.z-at-bottom{border-bottom-color:var(--border)}.z-thead-wrapper th.z-virtual-column-spacer,.z-tfoot-wrapper th.z-virtual-column-spacer{box-sizing:border-box;padding:0!important;background:var(--muted);border-left:thin solid var(--border)}.z-thead-wrapper th.z-virtual-header-spacer{border-bottom:thin solid var(--border)}.z-tfoot-wrapper th.z-virtual-footer-spacer{border-top:thin solid var(--border)}.z-tbody-wrapper td.z-virtual-column-spacer{box-sizing:border-box;height:auto;padding:0!important;background:var(--card);border-left:thin solid var(--border);border-bottom:thin solid var(--border)}.z-tbody-wrapper tr:hover td.z-virtual-column-spacer{background-color:var(--muted)}.z-table-settings-drawer input[type=checkbox]{appearance:none;-webkit-appearance:none;-moz-appearance:none;width:1rem;height:1rem;border:thin solid var(--input);border-radius:.25rem;background-color:var(--background);cursor:pointer;position:relative;transition:all .2s ease}.z-table-settings-drawer input[type=checkbox]:hover{border-color:var(--primary)}.z-table-settings-drawer input[type=checkbox]:checked{background-color:var(--primary);border-color:var(--primary)}.z-table-settings-drawer input[type=checkbox]:checked:after{content:\"\";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:.375rem;height:.625rem;border:solid var(--primary-foreground);border-width:0 .125rem .125rem 0;transform:translate(-50%,-60%) rotate(45deg)}.z-table-settings-drawer input[type=checkbox]:disabled{opacity:.5;cursor:not-allowed}.z-virtual-pinned-top{position:sticky;top:0;left:0;z-index:3;width:100%}.z-virtual-pinned-bottom{position:sticky;bottom:0;left:0;z-index:3;width:100%}\n"] }]
|
|
11181
|
+
}], ctorParameters: () => [], propDecorators: { zChange: [{ type: i0.Output, args: ["zChange"] }], zControl: [{ type: i0.Output, args: ["zControl"] }], zClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "zClass", required: false }] }], zConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "zConfig", required: false }] }], zLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "zLoading", required: false }] }], zKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "zKey", required: false }] }], zVariant: [{ type: i0.Input, args: [{ isSignal: true, alias: "zVariant", required: false }] }], theadWrapper: [{ type: i0.ViewChild, args: ['theadWrapper', { isSignal: true }] }], tableContainer: [{ type: i0.ViewChild, args: ['tableContainer', { isSignal: true }] }], tbodyContainer: [{ type: i0.ViewChild, args: ['tbodyContainer', { isSignal: true }] }], tbodyWrapper: [{ type: i0.ViewChild, args: ['tbodyWrapper', { isSignal: true }] }], tbodyScrollbar: [{ type: i0.ViewChild, args: ['tbodyWrapper', { isSignal: true }] }], tfootWrapper: [{ type: i0.ViewChild, args: ['tfootWrapper', { isSignal: true }] }], expandedRowTemplate: [{ type: i0.ViewChild, args: ['expandedRowTemplate', { isSignal: true }] }], virtualRowElements: [{ type: i0.ViewChildren, args: ['virtualRow', { isSignal: true }] }], groupRowElements: [{ type: i0.ViewChildren, args: ['groupRow', { isSignal: true }] }] } });
|
|
10869
11182
|
|
|
10870
11183
|
/**
|
|
10871
11184
|
* Generated bundle index. Do not edit.
|