@shival99/z-ui 2.0.71 → 2.0.72

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.
@@ -5105,6 +5105,7 @@ class ZTableComponent {
5105
5105
  _cellInteractionOutsideCleanup = null;
5106
5106
  _activeColumnVisibilityPopover = signal(null, ...(ngDevMode ? [{ debugName: "_activeColumnVisibilityPopover" }] : []));
5107
5107
  _hasInitializedColumnPinning = false;
5108
+ _initializedGroupingSchemaKey = '';
5108
5109
  _isFitColumnScheduled = false;
5109
5110
  _skipNextConfigSave = false;
5110
5111
  // ─── Template-bound State ─────────────────────────────────────────────────
@@ -5128,7 +5129,7 @@ class ZTableComponent {
5128
5129
  columnVisibility = signal({}, ...(ngDevMode ? [{ debugName: "columnVisibility" }] : []));
5129
5130
  columnOrder = signal([], ...(ngDevMode ? [{ debugName: "columnOrder" }] : []));
5130
5131
  expanded = signal({}, ...(ngDevMode ? [{ debugName: "expanded" }] : []));
5131
- groupingColumnId = signal(null, ...(ngDevMode ? [{ debugName: "groupingColumnId" }] : []));
5132
+ groupingColumnIds = signal([], ...(ngDevMode ? [{ debugName: "groupingColumnIds" }] : []));
5132
5133
  collapsedGroupIds = signal(new Set(), ...(ngDevMode ? [{ debugName: "collapsedGroupIds" }] : []));
5133
5134
  rowSelection = signal({}, ...(ngDevMode ? [{ debugName: "rowSelection" }] : []));
5134
5135
  rowPinning = signal({ top: [], bottom: [] }, ...(ngDevMode ? [{ debugName: "rowPinning" }] : []));
@@ -5603,6 +5604,7 @@ class ZTableComponent {
5603
5604
  enabled: grouping.enabled !== false,
5604
5605
  mode: grouping.mode ?? 'local',
5605
5606
  columns: grouping.columns,
5607
+ initialColumns: grouping.initialColumns,
5606
5608
  allowHeaderMenu: grouping.allowHeaderMenu !== false,
5607
5609
  defaultExpanded: grouping.defaultExpanded !== false,
5608
5610
  showCount: grouping.showCount !== false,
@@ -5636,16 +5638,25 @@ class ZTableComponent {
5636
5638
  const config = this.groupingConfig();
5637
5639
  return config.serverGroupColumnId ?? config.columns?.[0] ?? null;
5638
5640
  }, ...(ngDevMode ? [{ debugName: "serverGroupColumnId" }] : []));
5639
- activeGroupingColumnId = computed(() => {
5641
+ activeGroupingColumnIds = computed(() => {
5640
5642
  if (!this.canUseGrouping()) {
5641
- return null;
5643
+ return [];
5642
5644
  }
5643
5645
  if (this.isServerGrouping()) {
5644
- // Ưu tiên cột user chọn qua menu, fallback về cột cấu hình server.
5645
- return this.groupingColumnId() ?? this.serverGroupColumnId();
5646
+ const selectedColumnId = this.groupingColumnIds()[0];
5647
+ const fallbackColumnId = this.serverGroupColumnId();
5648
+ return selectedColumnId ? [selectedColumnId] : fallbackColumnId ? [fallbackColumnId] : [];
5649
+ }
5650
+ return this.groupingColumnIds();
5651
+ }, ...(ngDevMode ? [{ debugName: "activeGroupingColumnIds" }] : []));
5652
+ activeGroupingColumnId = computed(() => this.activeGroupingColumnIds()[0] ?? null, ...(ngDevMode ? [{ debugName: "activeGroupingColumnId" }] : []));
5653
+ groupingColumnMap = computed(() => {
5654
+ const result = {};
5655
+ for (const columnId of this.activeGroupingColumnIds()) {
5656
+ result[columnId] = true;
5646
5657
  }
5647
- return this.groupingColumnId();
5648
- }, ...(ngDevMode ? [{ debugName: "activeGroupingColumnId" }] : []));
5658
+ return result;
5659
+ }, ...(ngDevMode ? [{ debugName: "groupingColumnMap" }] : []));
5649
5660
  groupableColumnMap = computed(() => {
5650
5661
  const result = {};
5651
5662
  const config = this.groupingConfig();
@@ -5665,31 +5676,46 @@ class ZTableComponent {
5665
5676
  groupingHeaderMenuMap = computed(() => {
5666
5677
  const result = {};
5667
5678
  const groupableColumns = this.groupableColumnMap();
5668
- const activeColumnId = this.activeGroupingColumnId();
5679
+ const activeColumnMap = this.groupingColumnMap();
5669
5680
  for (const headerGroup of this.orderedHeaderGroups()) {
5670
5681
  for (const header of headerGroup.headers) {
5671
- const isLeafHeader = header.subHeaders.length === 0;
5672
- result[header.id] = isLeafHeader && (groupableColumns[header.column.id] || activeColumnId === header.column.id);
5682
+ const isLeafColumn = header.column.columns.length === 0;
5683
+ result[header.id] =
5684
+ isLeafColumn && Boolean(groupableColumns[header.column.id] || activeColumnMap[header.column.id]);
5673
5685
  }
5674
5686
  }
5675
5687
  return result;
5676
5688
  }, ...(ngDevMode ? [{ debugName: "groupingHeaderMenuMap" }] : []));
5677
5689
  groupedCenterRowItems = computed(() => {
5678
- const columnId = this.activeGroupingColumnId();
5679
- if (!columnId) {
5690
+ const columnIds = this.activeGroupingColumnIds();
5691
+ if (columnIds.length === 0) {
5680
5692
  return this.table.getCenterRows().map(row => ({ type: 'row', row }));
5681
5693
  }
5682
- return this.isServerGrouping() ? this._buildServerGroupedItems(columnId) : this._buildLocalGroupedItems(columnId);
5694
+ return this.isServerGrouping()
5695
+ ? this._buildServerGroupedItems(columnIds[0])
5696
+ : this._buildLocalGroupedItems(columnIds);
5683
5697
  }, ...(ngDevMode ? [{ debugName: "groupedCenterRowItems" }] : []));
5684
5698
  /** Local grouping: group được tính tại client từ rows của trang hiện tại. */
5685
- _buildLocalGroupedItems(columnId) {
5699
+ _buildLocalGroupedItems(columnIds) {
5700
+ const items = [];
5701
+ this._appendLocalGroupedItems(items, this.table.getCenterRows(), columnIds, 0, '');
5702
+ return items;
5703
+ }
5704
+ _appendLocalGroupedItems(items, rows, columnIds, depth, parentGroupId) {
5705
+ const columnId = columnIds[depth];
5706
+ if (!columnId) {
5707
+ for (const row of rows) {
5708
+ items.push({ type: 'row', row, isGroupChild: true, groupDepth: depth });
5709
+ }
5710
+ return;
5711
+ }
5686
5712
  const toggledGroupIds = this.collapsedGroupIds();
5687
5713
  const defaultExpanded = this.groupingConfig().defaultExpanded !== false;
5688
5714
  const columnLabel = this._getColumnCopyHeader(columnId);
5689
5715
  const groups = new Map();
5690
- for (const row of this.table.getCenterRows()) {
5691
- const value = row.getValue(columnId);
5692
- const groupId = this._getGroupId(columnId, value);
5716
+ for (const row of rows) {
5717
+ const value = this._getRowGroupValue(columnId, row);
5718
+ const groupId = this._getGroupId(columnId, value, parentGroupId);
5693
5719
  const current = groups.get(groupId);
5694
5720
  if (current) {
5695
5721
  current.rows.push(row);
@@ -5700,12 +5726,13 @@ class ZTableComponent {
5700
5726
  rows: [row],
5701
5727
  });
5702
5728
  }
5703
- const items = [];
5704
5729
  for (const [id, group] of groups) {
5705
5730
  const expanded = defaultExpanded ? !toggledGroupIds.has(id) : toggledGroupIds.has(id);
5706
5731
  items.push({
5707
5732
  type: 'group',
5708
5733
  id,
5734
+ columnId,
5735
+ depth,
5709
5736
  value: group.value,
5710
5737
  label: this._getColumnGroupLabel(columnId, group.value, group.rows),
5711
5738
  columnLabel,
@@ -5715,11 +5742,8 @@ class ZTableComponent {
5715
5742
  if (!expanded) {
5716
5743
  continue;
5717
5744
  }
5718
- for (const row of group.rows) {
5719
- items.push({ type: 'row', row, isGroupChild: true });
5720
- }
5745
+ this._appendLocalGroupedItems(items, group.rows, columnIds, depth + 1, id);
5721
5746
  }
5722
- return items;
5723
5747
  }
5724
5748
  /**
5725
5749
  * Server grouping: thứ tự & meta group do `config.enableGrouping.serverGroups` quyết định.
@@ -5733,7 +5757,7 @@ class ZTableComponent {
5733
5757
  // Gom rows đã fetch theo groupId để gán vào đúng group meta.
5734
5758
  const rowsByGroupId = new Map();
5735
5759
  for (const row of this.table.getCenterRows()) {
5736
- const groupId = this._getGroupId(columnId, row.getValue(columnId));
5760
+ const groupId = this._getGroupId(columnId, this._getRowGroupValue(columnId, row));
5737
5761
  const bucket = rowsByGroupId.get(groupId);
5738
5762
  if (bucket) {
5739
5763
  bucket.push(row);
@@ -5749,6 +5773,8 @@ class ZTableComponent {
5749
5773
  items.push({
5750
5774
  type: 'group',
5751
5775
  id: groupId,
5776
+ columnId,
5777
+ depth: 0,
5752
5778
  value: group.value,
5753
5779
  label: group.label ?? this._getColumnGroupLabel(columnId, group.value, rows),
5754
5780
  columnLabel,
@@ -5760,7 +5786,7 @@ class ZTableComponent {
5760
5786
  continue;
5761
5787
  }
5762
5788
  for (const row of rows) {
5763
- items.push({ type: 'row', row, isGroupChild: true });
5789
+ items.push({ type: 'row', row, isGroupChild: true, groupDepth: 1 });
5764
5790
  }
5765
5791
  }
5766
5792
  return items;
@@ -5777,7 +5803,7 @@ class ZTableComponent {
5777
5803
  * nhầm cho row đang nằm ở giữa bảng.
5778
5804
  */
5779
5805
  renderedBodyRows = computed(() => {
5780
- if (!this.activeGroupingColumnId()) {
5806
+ if (this.activeGroupingColumnIds().length === 0) {
5781
5807
  return this.table.getRowModel().rows;
5782
5808
  }
5783
5809
  const centerRows = this.groupedCenterRowItems()
@@ -5786,7 +5812,7 @@ class ZTableComponent {
5786
5812
  return [...this.table.getTopRows(), ...centerRows, ...this.table.getBottomRows()];
5787
5813
  }, ...(ngDevMode ? [{ debugName: "renderedBodyRows" }] : []));
5788
5814
  virtualGroupedFlatItems = computed(() => {
5789
- if (!this.isVirtual() || !this.activeGroupingColumnId()) {
5815
+ if (!this.isVirtual() || this.activeGroupingColumnIds().length === 0) {
5790
5816
  return [];
5791
5817
  }
5792
5818
  const items = [];
@@ -5795,7 +5821,12 @@ class ZTableComponent {
5795
5821
  items.push({ type: 'group-header', groupItem: item });
5796
5822
  }
5797
5823
  else {
5798
- items.push({ type: 'data', rows: [item.row], isGroupChild: item.isGroupChild ?? false });
5824
+ items.push({
5825
+ type: 'data',
5826
+ rows: [item.row],
5827
+ isGroupChild: item.isGroupChild ?? false,
5828
+ groupDepth: item.groupDepth ?? 0,
5829
+ });
5799
5830
  }
5800
5831
  }
5801
5832
  return items;
@@ -5806,6 +5837,9 @@ class ZTableComponent {
5806
5837
  _isVirtualGroupChild(item) {
5807
5838
  return item?.type === 'data' ? item.isGroupChild : false;
5808
5839
  }
5840
+ _getVirtualGroupDepth(item) {
5841
+ return item?.type === 'data' ? item.groupDepth : 0;
5842
+ }
5809
5843
  searchConfig = computed(() => {
5810
5844
  const { search } = this.zConfig();
5811
5845
  if (!search) {
@@ -6267,9 +6301,9 @@ class ZTableComponent {
6267
6301
  .filter(columnId => !this._isFixedLeadingColumnId(columnId))
6268
6302
  .filter(columnId => pendingVisibleColumns.has(columnId)).length;
6269
6303
  const result = {};
6270
- const groupingColumnId = this.activeGroupingColumnId();
6304
+ const groupingColumnMap = this.groupingColumnMap();
6271
6305
  for (const columnId of this.columnOrder()) {
6272
- result[columnId] = columnId === groupingColumnId || (pendingVisibleColumns.has(columnId) && visibleCount <= 2);
6306
+ result[columnId] = groupingColumnMap[columnId] || (pendingVisibleColumns.has(columnId) && visibleCount <= 2);
6273
6307
  }
6274
6308
  return result;
6275
6309
  }, ...(ngDevMode ? [{ debugName: "pendingColumnVisibilityDisabledMap" }] : []));
@@ -6346,7 +6380,7 @@ class ZTableComponent {
6346
6380
  return Array.from({ length: count }, (_, i) => i);
6347
6381
  }, ...(ngDevMode ? [{ debugName: "skeletonRows" }] : []));
6348
6382
  dynamicGroupRows = computed(() => {
6349
- if (this.activeGroupingColumnId() && this.isVirtual()) {
6383
+ if (this.activeGroupingColumnIds().length > 0 && this.isVirtual()) {
6350
6384
  return this.virtualGroupedFlatItems().map(item => (item.type === 'data' ? item.rows : []));
6351
6385
  }
6352
6386
  const rows = this.table.getRowModel().rows;
@@ -6368,7 +6402,7 @@ class ZTableComponent {
6368
6402
  return result;
6369
6403
  }, ...(ngDevMode ? [{ debugName: "dynamicGroupRows" }] : []));
6370
6404
  dynamicGroupHeights = computed(() => {
6371
- if (this.activeGroupingColumnId() && this.isVirtual()) {
6405
+ if (this.activeGroupingColumnIds().length > 0 && this.isVirtual()) {
6372
6406
  const rowHeight = this.virtualRowHeight();
6373
6407
  const isDynamic = this.dynamicSize();
6374
6408
  return this.virtualGroupedFlatItems().map(() => (isDynamic ? null : rowHeight));
@@ -6807,7 +6841,15 @@ class ZTableComponent {
6807
6841
  if (!cfg.columns || cfg.columns.length === 0) {
6808
6842
  return;
6809
6843
  }
6844
+ const groupingSchemaKey = this._getConfigCacheKey(key || 'initial-grouping');
6845
+ const shouldInitializeGrouping = this._initializedGroupingSchemaKey !== groupingSchemaKey;
6846
+ this._initializedGroupingSchemaKey = groupingSchemaKey;
6810
6847
  const cacheLoaded = key ? this._loadConfigCache(key) : false;
6848
+ if (!cacheLoaded && shouldInitializeGrouping) {
6849
+ const initialGroupingColumnIds = this._getInitialGroupingColumnIds();
6850
+ this.groupingColumnIds.set(initialGroupingColumnIds);
6851
+ this._moveGroupingColumnsToLeadingDataPosition(initialGroupingColumnIds);
6852
+ }
6811
6853
  const initial = cfg.initialState;
6812
6854
  if (initial) {
6813
6855
  if (!cacheLoaded) {
@@ -7024,6 +7066,7 @@ class ZTableComponent {
7024
7066
  this._columnBaseSizing,
7025
7067
  this.columnPinning,
7026
7068
  this.columnVisibility,
7069
+ this.groupingColumnIds,
7027
7070
  this.sorting,
7028
7071
  this.columnFilters,
7029
7072
  this.globalFilter,
@@ -8649,16 +8692,17 @@ class ZTableComponent {
8649
8692
  }
8650
8693
  return !this.table.getColumn(columnId)?.getIsPinned();
8651
8694
  });
8652
- const groupingColumnId = this.activeGroupingColumnId();
8653
- const groupingColumnIndex = groupingColumnId ? unpinnedColumns.indexOf(groupingColumnId) : -1;
8695
+ const groupingColumnIds = this.activeGroupingColumnIds();
8696
+ const groupingColumnIndexes = new Map(groupingColumnIds.map(columnId => [columnId, unpinnedColumns.indexOf(columnId)]));
8654
8697
  const draggedColumnId = unpinnedColumns[event.previousIndex];
8655
- if (draggedColumnId && draggedColumnId === groupingColumnId) {
8698
+ if (draggedColumnId && groupingColumnIds.includes(draggedColumnId)) {
8656
8699
  return;
8657
8700
  }
8658
8701
  moveItemInArray(unpinnedColumns, event.previousIndex, event.currentIndex);
8659
- if (groupingColumnId && groupingColumnIndex >= 0) {
8702
+ for (const groupingColumnId of groupingColumnIds) {
8703
+ const groupingColumnIndex = groupingColumnIndexes.get(groupingColumnId) ?? -1;
8660
8704
  const currentGroupingIndex = unpinnedColumns.indexOf(groupingColumnId);
8661
- if (currentGroupingIndex >= 0 && currentGroupingIndex !== groupingColumnIndex) {
8705
+ if (groupingColumnIndex >= 0 && currentGroupingIndex >= 0 && currentGroupingIndex !== groupingColumnIndex) {
8662
8706
  unpinnedColumns.splice(currentGroupingIndex, 1);
8663
8707
  unpinnedColumns.splice(groupingColumnIndex, 0, groupingColumnId);
8664
8708
  }
@@ -8677,7 +8721,7 @@ class ZTableComponent {
8677
8721
  }
8678
8722
  }
8679
8723
  onToggleColumnVisibility(columnId) {
8680
- if (this.activeGroupingColumnId() === columnId) {
8724
+ if (this.isGroupingColumn(columnId)) {
8681
8725
  return;
8682
8726
  }
8683
8727
  const pendingVisibleColumns = new Set(this.pendingVisibleColumns());
@@ -8706,7 +8750,7 @@ class ZTableComponent {
8706
8750
  }, 100);
8707
8751
  }
8708
8752
  onToggleColumnPin(columnId, position) {
8709
- if (this.activeGroupingColumnId() === columnId) {
8753
+ if (this.isGroupingColumn(columnId)) {
8710
8754
  return;
8711
8755
  }
8712
8756
  const column = this.table.getColumn(columnId);
@@ -8741,7 +8785,7 @@ class ZTableComponent {
8741
8785
  }, 100);
8742
8786
  }
8743
8787
  handleColumnPin(columnId, position) {
8744
- if (this.activeGroupingColumnId() === columnId) {
8788
+ if (this.isGroupingColumn(columnId)) {
8745
8789
  return;
8746
8790
  }
8747
8791
  const column = this.table.getColumn(columnId);
@@ -8773,7 +8817,7 @@ class ZTableComponent {
8773
8817
  if (!column ||
8774
8818
  !column.getCanHide() ||
8775
8819
  this._isColumnHiddenFromVisibilityMenu(columnId) ||
8776
- this.activeGroupingColumnId() === columnId) {
8820
+ this.isGroupingColumn(columnId)) {
8777
8821
  return;
8778
8822
  }
8779
8823
  const currentVisibility = this.columnVisibility();
@@ -8827,7 +8871,8 @@ class ZTableComponent {
8827
8871
  if (this._isSpecialColumnId(columnId)) {
8828
8872
  return false;
8829
8873
  }
8830
- if (this._findColumnConfig(columnId)?.enableGrouping === false) {
8874
+ const columnConfig = this._findColumnConfig(columnId);
8875
+ if (columnConfig?.columns?.length || columnConfig?.enableGrouping === false) {
8831
8876
  return false;
8832
8877
  }
8833
8878
  if (config.columns?.length) {
@@ -8836,25 +8881,37 @@ class ZTableComponent {
8836
8881
  return !!this.table.getColumn(columnId);
8837
8882
  }
8838
8883
  isGroupingColumn(columnId) {
8839
- return this.activeGroupingColumnId() === columnId;
8884
+ return this.groupingColumnMap()[columnId] === true;
8840
8885
  }
8841
8886
  groupByColumn(columnId) {
8842
- if (!this.canGroupColumn(columnId)) {
8887
+ if (!this.canGroupColumn(columnId) || this.isGroupingColumn(columnId)) {
8843
8888
  return;
8844
8889
  }
8845
- this._moveGroupingColumnToLeadingDataPosition(columnId);
8846
- this.groupingColumnId.set(columnId);
8890
+ const nextGroupingColumnIds = this.isServerGrouping() ? [columnId] : [...this.groupingColumnIds(), columnId];
8891
+ this._moveGroupingColumnsToLeadingDataPosition(nextGroupingColumnIds);
8892
+ this.groupingColumnIds.set(nextGroupingColumnIds);
8847
8893
  this.collapsedGroupIds.set(new Set());
8848
- this.zChange.emit({ type: 'grouping', data: { grouping: [columnId] } });
8894
+ this.zChange.emit({ type: 'grouping', data: { grouping: nextGroupingColumnIds } });
8849
8895
  }
8850
8896
  clearGrouping() {
8851
- if (!this.groupingColumnId()) {
8897
+ if (this.groupingColumnIds().length === 0) {
8852
8898
  return;
8853
8899
  }
8854
- this.groupingColumnId.set(null);
8900
+ this.groupingColumnIds.set([]);
8855
8901
  this.collapsedGroupIds.set(new Set());
8856
8902
  this.zChange.emit({ type: 'grouping', data: { grouping: [] } });
8857
8903
  }
8904
+ removeGroupingColumn(columnId) {
8905
+ const currentGroupingColumnIds = this.groupingColumnIds();
8906
+ const nextGroupingColumnIds = currentGroupingColumnIds.filter(id => id !== columnId);
8907
+ if (nextGroupingColumnIds.length === currentGroupingColumnIds.length) {
8908
+ return;
8909
+ }
8910
+ this._moveGroupingColumnsToLeadingDataPosition(nextGroupingColumnIds);
8911
+ this.groupingColumnIds.set(nextGroupingColumnIds);
8912
+ this.collapsedGroupIds.set(new Set());
8913
+ this.zChange.emit({ type: 'grouping', data: { grouping: nextGroupingColumnIds } });
8914
+ }
8858
8915
  toggleGroupRow(groupId) {
8859
8916
  const next = new Set(this.collapsedGroupIds());
8860
8917
  const wasToggled = next.has(groupId);
@@ -8922,12 +8979,16 @@ class ZTableComponent {
8922
8979
  const nextOrder = this.table.getAllLeafColumns().map(column => column.id);
8923
8980
  const nextVisibility = config.initialState?.columnVisibility ?? {};
8924
8981
  const nextPinning = this._defaultColumnPinning();
8982
+ const initialGroupingColumnIds = this._getInitialGroupingColumnIds(true);
8925
8983
  this.columnOrder.set(nextOrder);
8926
8984
  this.columnVisibility.set(nextVisibility);
8927
8985
  this._setColumnPinning(nextPinning);
8928
8986
  this._columnBaseSizing.set({});
8929
8987
  this.columnSizingState.set({});
8930
- this.groupingColumnId.set(null);
8988
+ this.groupingColumnIds.set(initialGroupingColumnIds);
8989
+ if (initialGroupingColumnIds.length > 0) {
8990
+ this._moveGroupingColumnsToLeadingDataPosition(initialGroupingColumnIds);
8991
+ }
8931
8992
  this.collapsedGroupIds.set(new Set());
8932
8993
  this.showHeaderFooterShadow.set(config.showHeaderShadow ?? config.showFooterShadow ?? true);
8933
8994
  this.showHorizontalBorder.set(config.showHorizontalBorder ?? true);
@@ -8939,6 +9000,18 @@ class ZTableComponent {
8939
9000
  this.pendingColumnOrder.set(nextOrder);
8940
9001
  this._scheduleFitColumnWidths();
8941
9002
  }
9003
+ _getInitialGroupingColumnIds(includeLegacyColumnsFallback = false) {
9004
+ if (!this.canUseGrouping()) {
9005
+ return [];
9006
+ }
9007
+ if (this.isServerGrouping()) {
9008
+ const columnId = this.serverGroupColumnId();
9009
+ return columnId ? [columnId] : [];
9010
+ }
9011
+ const config = this.groupingConfig();
9012
+ const configuredColumnIds = config.initialColumns ?? (includeLegacyColumnsFallback ? config.columns?.slice(0, 1) : []);
9013
+ return (configuredColumnIds ?? []).filter(columnId => this.canGroupColumn(columnId));
9014
+ }
8942
9015
  _isColumnHiddenFromVisibilityMenu(columnId) {
8943
9016
  const actionColumnId = this.actionColumnInfo()?.columnId;
8944
9017
  return this._isSpecialColumnId(columnId) || columnId === actionColumnId;
@@ -9017,25 +9090,27 @@ class ZTableComponent {
9017
9090
  }
9018
9091
  this.columnPinning.set(normalizedPinning);
9019
9092
  }
9020
- _moveGroupingColumnToLeadingDataPosition(columnId) {
9093
+ _moveGroupingColumnsToLeadingDataPosition(columnIds) {
9094
+ if (columnIds.length === 0) {
9095
+ return;
9096
+ }
9097
+ const groupingColumnIdSet = new Set(columnIds);
9021
9098
  const currentPinning = this.columnPinning();
9022
- if (currentPinning.left?.includes(columnId) || currentPinning.right?.includes(columnId)) {
9099
+ if (currentPinning.left?.some(columnId => groupingColumnIdSet.has(columnId)) ||
9100
+ currentPinning.right?.some(columnId => groupingColumnIdSet.has(columnId))) {
9023
9101
  this._setColumnPinning({
9024
- left: currentPinning.left?.filter(id => id !== columnId),
9025
- right: currentPinning.right?.filter(id => id !== columnId),
9102
+ left: currentPinning.left?.filter(columnId => !groupingColumnIdSet.has(columnId)),
9103
+ right: currentPinning.right?.filter(columnId => !groupingColumnIdSet.has(columnId)),
9026
9104
  });
9027
9105
  }
9028
9106
  const currentOrder = this.columnOrder().length
9029
9107
  ? this.columnOrder()
9030
9108
  : this.table.getAllLeafColumns().map(column => column.id);
9031
- const currentIndex = currentOrder.indexOf(columnId);
9032
- if (currentIndex < 0 || this._isFixedLeadingColumnId(columnId) || this._isSpecialColumnId(columnId)) {
9033
- return;
9034
- }
9035
- const nextOrder = currentOrder.filter(id => id !== columnId);
9109
+ const movableGroupingColumnIds = columnIds.filter(columnId => currentOrder.includes(columnId) && !this._isFixedLeadingColumnId(columnId) && !this._isSpecialColumnId(columnId));
9110
+ const nextOrder = currentOrder.filter(columnId => !groupingColumnIdSet.has(columnId));
9036
9111
  const insertIndex = nextOrder.findIndex(id => !this._isFixedLeadingColumnId(id));
9037
9112
  const targetIndex = insertIndex >= 0 ? insertIndex : nextOrder.length;
9038
- nextOrder.splice(targetIndex, 0, columnId);
9113
+ nextOrder.splice(targetIndex, 0, ...movableGroupingColumnIds);
9039
9114
  if (this._areColumnIdListsEqual(currentOrder, nextOrder)) {
9040
9115
  return;
9041
9116
  }
@@ -9124,6 +9199,8 @@ class ZTableComponent {
9124
9199
  right: this.columnPinning().right,
9125
9200
  },
9126
9201
  columnVisibility: this.columnVisibility(),
9202
+ groupingColumnId: this.groupingColumnIds()[0] ?? null,
9203
+ groupingColumnIds: this.groupingColumnIds(),
9127
9204
  columnInfo,
9128
9205
  showHeaderFooterShadow: this.showHeaderFooterShadow(),
9129
9206
  showHorizontalBorder: this.showHorizontalBorder(),
@@ -9186,6 +9263,17 @@ class ZTableComponent {
9186
9263
  if (config.columnVisibility) {
9187
9264
  this.columnVisibility.set(config.columnVisibility);
9188
9265
  }
9266
+ if (config.groupingColumnIds) {
9267
+ this.groupingColumnIds.set(config.groupingColumnIds.filter(columnId => this.canGroupColumn(columnId)));
9268
+ }
9269
+ if (!config.groupingColumnIds && config.groupingColumnId === null) {
9270
+ this.groupingColumnIds.set([]);
9271
+ }
9272
+ if (!config.groupingColumnIds &&
9273
+ typeof config.groupingColumnId === 'string' &&
9274
+ this.canGroupColumn(config.groupingColumnId)) {
9275
+ this.groupingColumnIds.set([config.groupingColumnId]);
9276
+ }
9189
9277
  if (typeof config.showHeaderFooterShadow === 'boolean') {
9190
9278
  this.showHeaderFooterShadow.set(config.showHeaderFooterShadow);
9191
9279
  }
@@ -9311,8 +9399,19 @@ class ZTableComponent {
9311
9399
  _filterServerModeSorting(sorting) {
9312
9400
  return sorting.filter(sort => !this._isColumnSortModeLocal(sort.id));
9313
9401
  }
9314
- _getGroupId(columnId, value) {
9315
- return `${columnId}:${this._getGroupLabel(value)}`;
9402
+ _getGroupId(columnId, value, parentGroupId = '') {
9403
+ const groupId = `${columnId}:${this._getGroupLabel(value)}`;
9404
+ return parentGroupId ? `${parentGroupId}>${groupId}` : groupId;
9405
+ }
9406
+ _getRowGroupValue(columnId, row) {
9407
+ const groupKey = this._findColumnConfig(columnId)?.groupKey;
9408
+ if (typeof groupKey === 'function') {
9409
+ return groupKey(row.original);
9410
+ }
9411
+ if (groupKey !== undefined) {
9412
+ return row.original[groupKey];
9413
+ }
9414
+ return row.getValue(columnId);
9316
9415
  }
9317
9416
  _getColumnGroupLabel(columnId, value, rows) {
9318
9417
  const formatter = this._findColumnConfig(columnId)?.groupLabel;
@@ -9388,7 +9487,7 @@ class ZTableComponent {
9388
9487
  return result;
9389
9488
  }
9390
9489
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9391
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.9", 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<div\n #tableContainer\n [class]=\"classTable()\"\n [class.z-hide-horizontal-border]=\"!showHorizontalBorder()\"\n [class.z-hide-vertical-border]=\"!showVerticalBorder()\"\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 <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]=\"virtualLeftSpacerWidth()\" />\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]=\"virtualRightSpacerWidth()\" />\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 #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: header : 'header' : table : zConfig().columns : columnSizingInfo()\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]=\"header.column.getIsPinned() === 'left'\"\n [class.z-sticky-right]=\"header.column.getIsPinned() === 'right'\"\n [class.z-sticky-left-last]=\"header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns\"\n [class.z-sticky-right-first]=\"header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns\"\n [class.z-sticky-right-last]=\"header | zTableCellPin: 'isLastRightPinned' : zConfig().columns\"\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;\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() !== 'left') {\n <button\n type=\"button\"\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\">\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() !== 'right') {\n <button\n type=\"button\"\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\">\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 = activeGroupingColumnId() === 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)=\"clearGrouping(); 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 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 [zColumn]=\"$any(header.column)\" [zTable]=\"$any(table)\" />\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() === 'right' || header.column.getIsLastColumn()\n \"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <th class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualLeftSpacerWidth()\"></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;\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() !== 'left') {\n <button\n type=\"button\"\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\">\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() !== 'right') {\n <button\n type=\"button\"\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\">\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 = activeGroupingColumnId() === 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)=\"clearGrouping(); 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 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 [zColumn]=\"$any(header.column)\" [zTable]=\"$any(table)\" />\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() === 'right' || header.column.getIsLastColumn()\n \"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualRightSpacerWidth() > 0) {\n <th class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualRightSpacerWidth()\"></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: header : 'header' : table : zConfig().columns : columnSizingInfo()\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]=\"header.column.getIsPinned() === 'left'\"\n [class.z-sticky-right]=\"header.column.getIsPinned() === 'right'\"\n [class.z-sticky-left-last]=\"header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns\"\n [class.z-sticky-right-first]=\"header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns\"\n [class.z-sticky-right-last]=\"header | zTableCellPin: 'isLastRightPinned' : zConfig().columns\"\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;\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() !== 'left') {\n <button\n type=\"button\"\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\">\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() !== 'right') {\n <button\n type=\"button\"\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\">\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 = activeGroupingColumnId() === 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)=\"clearGrouping(); 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 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 [zColumn]=\"$any(header.column)\" [zTable]=\"$any(table)\" />\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]=\"\n header.column.getIsPinned() === 'right' || header.column.getIsLastColumn()\n \"\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: header : 'header' : table : zConfig().columns : columnSizingInfo()\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]=\"header.column.getIsPinned() === 'left'\"\n [class.z-sticky-right]=\"header.column.getIsPinned() === 'right'\"\n [class.z-sticky-left-last]=\"header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns\"\n [class.z-sticky-right-first]=\"header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns\"\n [class.z-sticky-right-last]=\"header | zTableCellPin: 'isLastRightPinned' : zConfig().columns\"\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;\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() !== 'left') {\n <button\n type=\"button\"\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\">\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() !== 'right') {\n <button\n type=\"button\"\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\">\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 = activeGroupingColumnId() === 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)=\"clearGrouping(); 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 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 [zColumn]=\"$any(header.column)\" [zTable]=\"$any(table)\" />\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() === 'right' || 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 <div\n class=\"z-virtual-scroll-inner\"\n [style.height.px]=\"virtualizer.getTotalSize()\"\n [style.min-width.px]=\"table.getTotalSize()\">\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[0]?.id ?? ''\"\n [z-table-drop-item-id]=\"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 dynamicSize() ? null : (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-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-expanded]=\"groupHeaderItem.expanded\"\n [attr.data-group-id]=\"groupHeaderItem.id\">\n <td [attr.colspan]=\"renderedColumnCount()\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\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 class=\"z-group-row-label\">\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 </td>\n </tr>\n }\n @for (row of groupRows; track row.id) {\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n <tr\n z-table-row-hover\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"dynamicSize() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"dynamicSize() ? virtualRowHeight() : null\"\n [class.z-child-row]=\"row.depth > 0\"\n [class.z-group-child-row]=\"_isVirtualGroupChild(virtualFlatItem)\"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\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=\"pointer-events-none border-0 p-0\"\n [style.width.px]=\"virtualLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : table.getRowModel().rows;\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 : columnSizingInfo()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"cellPinned === 'left'\"\n [class.z-sticky-right]=\"cellPinned === 'right'\"\n [class.z-sticky-left-last]=\"cellPinned === 'left' && cell.column.getIsLastColumn('left')\"\n [class.z-sticky-right-first]=\"\n cellPinned === 'right' && cell.column.getIsFirstColumn('right')\n \"\n [class.z-sticky-right-last]=\"\n cellPinned === 'right' && cell.column.getIsLastColumn('right')\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]=\"\n cell | zTableSpan: zConfig().columns : 'cellRowSpan' : table.getRowModel().rows\n \"\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 (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 <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (cell | zTableCellConfig: zConfig() : 'contentTooltip') || cellContent\n \"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \"></div>\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=\"pointer-events-none border-0 p-0\"\n [style.width.px]=\"virtualRightSpacerWidth()\"></td>\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\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-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n <!-- Row Template -->\n <ng-template #rowTemplate let-row let-isGroupChild=\"isGroupChild\">\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 [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-bottom]=\"rowPinned === 'bottom'\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() && rowPinned === 'top' && (row | zTableRow: table : 'isLastTopPinned')\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\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 class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : table.getRowModel().rows;\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: cell : 'body' : visibleCells : zConfig().columns : columnSizingInfo()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n [class.z-sticky-left]=\"cellPinned === 'left'\"\n [class.z-sticky-right]=\"cellPinned === 'right'\"\n [class.z-sticky-left-last]=\"cellPinned === 'left' && cell.column.getIsLastColumn('left')\"\n [class.z-sticky-right-first]=\"cellPinned === 'right' && cell.column.getIsFirstColumn('right')\"\n [class.z-sticky-right-last]=\"cellPinned === 'right' && cell.column.getIsLastColumn('right')\"\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' : table.getRowModel().rows\"\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 <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 p-1\">\n @if (cellRowPinned !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cellRowPinned !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cellRowPinned) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\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\"\n [class.text-primary]=\"cellRowPinned\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\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 <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 p-1\">\n @if (cellRowPinned !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cellRowPinned !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cellRowPinned) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\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\"\n [class.text-primary]=\"cellRowPinned\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\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 <!-- Actions Column - Row Pin Only (for parent rows) -->\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 p-1\">\n @if (cellRowPinned !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cellRowPinned !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cellRowPinned) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\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\"\n [class.text-primary]=\"cellRowPinned\">\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 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 <div\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'\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \"></div>\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 class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualRightSpacerWidth()\"></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 class=\"z-group-row\" [class.z-group-row-expanded]=\"item.expanded\" [attr.data-group-id]=\"item.id\">\n <td [attr.colspan]=\"renderedColumnCount()\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\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 class=\"z-group-row-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 </td>\n </tr>\n }\n @if (item.type === 'row') {\n <ng-container\n *ngTemplateOutlet=\"\n rowTemplate;\n context: { $implicit: item.row, isGroupChild: item.isGroupChild }\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) {\n @if (footerGroup | zTableFooterContent: zConfig().columns) {\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 class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualLeftSpacerWidth()\"></th>\n }\n @let rowSpan = footer | zTableSpan: zConfig().columns : 'footerRowSpan';\n @let shouldRender = footer | zTableCellRender: footerGroup.headers : zConfig().columns : 'footer';\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: footer : 'footer' : table : zConfig().columns : columnSizingInfo()\n \"\n [class]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerClass') +\n ' ' +\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass')\n \"\n [style]=\"footer.column.id | zTableColumnConfig: zConfig().columns : 'footerStyle'\"\n [class.z-sticky-left]=\"footer.column.getIsPinned() === 'left'\"\n [class.z-sticky-right]=\"footer.column.getIsPinned() === 'right'\"\n [class.z-sticky-left-last]=\"\n footer | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'footer'\n \"\n [class.z-sticky-right-first]=\"\n footer | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'footer'\n \"\n [class.z-sticky-right-last]=\"\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'\">\n @let configFooterContent =\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContent';\n @if (footer.column.columnDef.footer) {\n <ng-container\n *flexRender=\"footer.column.columnDef.footer; props: footer.getContext(); let footerContent\">\n <div\n class=\"flex w-full items-center\"\n [class.justify-center]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass') ===\n 'text-right'\n \">\n @if (footerContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n <div\n class=\"z-template-content\"\n [class]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentClass'\n \"\n [ngStyle]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentStyle'\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]=\"footer.column.id | zTableColumnConfig: zConfig().columns : 'footerTooltip'\"\n [class]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentClass'\n \"\n [ngStyle]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentStyle'\n \" />\n } @else {\n <!-- Default/string rendering -->\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerTooltip') ||\n footerContent\n \"\n [class]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentClass'\n \"\n [ngStyle]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentStyle'\n \">\n {{ footerContent | translate }}\n </span>\n }\n </div>\n </ng-container>\n } @else if (configFooterContent) {\n <!-- Fallback for group columns without TanStack footer -->\n <div\n class=\"flex w-full items-center\"\n [class.justify-center]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass') ===\n 'text-right'\n \">\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerTooltip') ||\n $any(configFooterContent)\n \"\n [class]=\"footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentClass'\"\n [ngStyle]=\"footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentStyle'\">\n {{ $any(configFooterContent) | translate }}\n </span>\n </div>\n }\n </th>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n footer.column.id === lastVirtualCenterColumnId()\n ) {\n <th class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualRightSpacerWidth()\"></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 = activeGroupingColumnId() === columnId;\n @let canPin = column?.getCanPin() !== false && zConfig().enableColumnPinning;\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\"\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\"\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) {\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 = activeGroupingColumnId() === 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 === 'left' ? ('i18n_z_ui_table_left' | translate) : ('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 === 'left' ? '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-table-container.z-column-resizing table,.z-table-toolbar{min-width: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}.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}.z-thead-wrapper::-webkit-scrollbar{display:none}.z-tbody-scrollbar{flex:1;width:100%;max-width:100%;min-width:0;height:100%}.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,td:has(>.z-table-content-trigger:focus-visible){position:relative;z-index:2}.z-content-edit-active:after,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:-1px;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}.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-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}.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)}[data-z-table-drag-handle]{touch-action:none;-webkit-user-select:none;user-select:none}.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-virtual-row:has(tr.z-group-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}.z-group-row-trigger{display:inline-flex;min-height:2rem;max-width:100%;align-items:center;gap:.5rem;padding:.25rem .75rem;color:var(--primary);font-size:.8125rem;font-weight:600;cursor:pointer}.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}: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)!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{display:flex;flex-direction:column;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;--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-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}table{width:fit-content;min-width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed;font-size:.875rem}.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-thead-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-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-wrapper{flex:1;display:flex;flex-direction:column;min-height:0;width:100%}.z-tbody-scrollbar{flex:1;width:100%;max-width:100%;min-width:0;height:100%;transition:opacity .2s ease-in-out}.z-empty-state,.z-loading-state{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:2.5rem;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 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;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}tr.z-expanded-row>td{border-left:.125rem solid var(--primary);background-color:var(--background)!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-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;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.text-primary{color:var(--primary)}.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)}.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-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}.z-column-drop-list{min-height:3.125rem;overscroll-behavior:contain}.z-column-drop-list.cdk-drop-list-dragging{overflow:clip}: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-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-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}\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: "[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", "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"], 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"] }, { 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: ZTablePinningStylesPipe, name: "zTablePinningStyles" }, { 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: 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 });
9490
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.9", 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<div\n #tableContainer\n [class]=\"classTable()\"\n [class.z-hide-horizontal-border]=\"!showHorizontalBorder()\"\n [class.z-hide-vertical-border]=\"!showVerticalBorder()\"\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 <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]=\"virtualLeftSpacerWidth()\" />\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]=\"virtualRightSpacerWidth()\" />\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 #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: header : 'header' : table : zConfig().columns : columnSizingInfo()\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]=\"header.column.getIsPinned() === 'left'\"\n [class.z-sticky-right]=\"header.column.getIsPinned() === 'right'\"\n [class.z-sticky-left-last]=\"header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns\"\n [class.z-sticky-right-first]=\"header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns\"\n [class.z-sticky-right-last]=\"header | zTableCellPin: 'isLastRightPinned' : zConfig().columns\"\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;\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() !== 'left') {\n <button\n type=\"button\"\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\">\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() !== 'right') {\n <button\n type=\"button\"\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\">\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 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 [zColumn]=\"$any(header.column)\" [zTable]=\"$any(table)\" />\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() === 'right' || header.column.getIsLastColumn()\n \"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <th class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualLeftSpacerWidth()\"></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;\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() !== 'left') {\n <button\n type=\"button\"\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\">\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() !== 'right') {\n <button\n type=\"button\"\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\">\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 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 [zColumn]=\"$any(header.column)\" [zTable]=\"$any(table)\" />\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() === 'right' || header.column.getIsLastColumn()\n \"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualRightSpacerWidth() > 0) {\n <th class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualRightSpacerWidth()\"></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: header : 'header' : table : zConfig().columns : columnSizingInfo()\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]=\"header.column.getIsPinned() === 'left'\"\n [class.z-sticky-right]=\"header.column.getIsPinned() === 'right'\"\n [class.z-sticky-left-last]=\"header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns\"\n [class.z-sticky-right-first]=\"header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns\"\n [class.z-sticky-right-last]=\"header | zTableCellPin: 'isLastRightPinned' : zConfig().columns\"\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;\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() !== 'left') {\n <button\n type=\"button\"\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\">\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() !== 'right') {\n <button\n type=\"button\"\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\">\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 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 [zColumn]=\"$any(header.column)\" [zTable]=\"$any(table)\" />\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]=\"\n header.column.getIsPinned() === 'right' || header.column.getIsLastColumn()\n \"\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: header : 'header' : table : zConfig().columns : columnSizingInfo()\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]=\"header.column.getIsPinned() === 'left'\"\n [class.z-sticky-right]=\"header.column.getIsPinned() === 'right'\"\n [class.z-sticky-left-last]=\"header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns\"\n [class.z-sticky-right-first]=\"header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns\"\n [class.z-sticky-right-last]=\"header | zTableCellPin: 'isLastRightPinned' : zConfig().columns\"\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;\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() !== 'left') {\n <button\n type=\"button\"\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\">\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() !== 'right') {\n <button\n type=\"button\"\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\">\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 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 [zColumn]=\"$any(header.column)\" [zTable]=\"$any(table)\" />\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() === 'right' || 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 <div\n class=\"z-virtual-scroll-inner\"\n [style.height.px]=\"virtualizer.getTotalSize()\"\n [style.min-width.px]=\"table.getTotalSize()\">\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[0]?.id ?? ''\"\n [z-table-drop-item-id]=\"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 dynamicSize() ? null : (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-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-expanded]=\"groupHeaderItem.expanded\"\n [attr.data-group-id]=\"groupHeaderItem.id\"\n [attr.data-group-depth]=\"groupHeaderItem.depth\">\n <td [attr.colspan]=\"renderedColumnCount()\">\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 class=\"z-group-row-label\">\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 [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(groupHeaderItem.columnId)\"></button>\n }\n </td>\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 <tr\n z-table-row-hover\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"dynamicSize() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"dynamicSize() ? virtualRowHeight() : null\"\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 (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=\"pointer-events-none border-0 p-0\"\n [style.width.px]=\"virtualLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : table.getRowModel().rows;\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 : columnSizingInfo()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"cellPinned === 'left'\"\n [class.z-sticky-right]=\"cellPinned === 'right'\"\n [class.z-sticky-left-last]=\"cellPinned === 'left' && cell.column.getIsLastColumn('left')\"\n [class.z-sticky-right-first]=\"\n cellPinned === 'right' && cell.column.getIsFirstColumn('right')\n \"\n [class.z-sticky-right-last]=\"\n cellPinned === 'right' && cell.column.getIsLastColumn('right')\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]=\"\n cell | zTableSpan: zConfig().columns : 'cellRowSpan' : table.getRowModel().rows\n \"\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 (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 <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (cell | zTableCellConfig: zConfig() : 'contentTooltip') || cellContent\n \"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \"></div>\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=\"pointer-events-none border-0 p-0\"\n [style.width.px]=\"virtualRightSpacerWidth()\"></td>\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\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-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-bottom]=\"rowPinned === 'bottom'\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() && rowPinned === 'top' && (row | zTableRow: table : 'isLastTopPinned')\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\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 class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : table.getRowModel().rows;\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: cell : 'body' : visibleCells : zConfig().columns : columnSizingInfo()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n [class.z-sticky-left]=\"cellPinned === 'left'\"\n [class.z-sticky-right]=\"cellPinned === 'right'\"\n [class.z-sticky-left-last]=\"cellPinned === 'left' && cell.column.getIsLastColumn('left')\"\n [class.z-sticky-right-first]=\"cellPinned === 'right' && cell.column.getIsFirstColumn('right')\"\n [class.z-sticky-right-last]=\"cellPinned === 'right' && cell.column.getIsLastColumn('right')\"\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' : table.getRowModel().rows\"\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 <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 p-1\">\n @if (cellRowPinned !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cellRowPinned !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cellRowPinned) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\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\"\n [class.text-primary]=\"cellRowPinned\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\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 <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 p-1\">\n @if (cellRowPinned !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cellRowPinned !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cellRowPinned) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\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\"\n [class.text-primary]=\"cellRowPinned\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\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 <!-- Actions Column - Row Pin Only (for parent rows) -->\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 p-1\">\n @if (cellRowPinned !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cellRowPinned !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cellRowPinned) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\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\"\n [class.text-primary]=\"cellRowPinned\">\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 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 <div\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'\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \"></div>\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 class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualRightSpacerWidth()\"></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-expanded]=\"item.expanded\"\n [attr.data-group-id]=\"item.id\"\n [attr.data-group-depth]=\"item.depth\">\n <td [attr.colspan]=\"renderedColumnCount()\">\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 class=\"z-group-row-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 [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(item.columnId)\"></button>\n }\n </td>\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) {\n @if (footerGroup | zTableFooterContent: zConfig().columns) {\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 class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualLeftSpacerWidth()\"></th>\n }\n @let rowSpan = footer | zTableSpan: zConfig().columns : 'footerRowSpan';\n @let shouldRender = footer | zTableCellRender: footerGroup.headers : zConfig().columns : 'footer';\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: footer : 'footer' : table : zConfig().columns : columnSizingInfo()\n \"\n [class]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerClass') +\n ' ' +\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass')\n \"\n [style]=\"footer.column.id | zTableColumnConfig: zConfig().columns : 'footerStyle'\"\n [class.z-sticky-left]=\"footer.column.getIsPinned() === 'left'\"\n [class.z-sticky-right]=\"footer.column.getIsPinned() === 'right'\"\n [class.z-sticky-left-last]=\"\n footer | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'footer'\n \"\n [class.z-sticky-right-first]=\"\n footer | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'footer'\n \"\n [class.z-sticky-right-last]=\"\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'\">\n @let configFooterContent =\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContent';\n @if (footer.column.columnDef.footer) {\n <ng-container\n *flexRender=\"footer.column.columnDef.footer; props: footer.getContext(); let footerContent\">\n <div\n class=\"flex w-full items-center\"\n [class.justify-center]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass') ===\n 'text-right'\n \">\n @if (footerContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n <div\n class=\"z-template-content\"\n [class]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentClass'\n \"\n [ngStyle]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentStyle'\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]=\"footer.column.id | zTableColumnConfig: zConfig().columns : 'footerTooltip'\"\n [class]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentClass'\n \"\n [ngStyle]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentStyle'\n \" />\n } @else {\n <!-- Default/string rendering -->\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerTooltip') ||\n footerContent\n \"\n [class]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentClass'\n \"\n [ngStyle]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentStyle'\n \">\n {{ footerContent | translate }}\n </span>\n }\n </div>\n </ng-container>\n } @else if (configFooterContent) {\n <!-- Fallback for group columns without TanStack footer -->\n <div\n class=\"flex w-full items-center\"\n [class.justify-center]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass') ===\n 'text-right'\n \">\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerTooltip') ||\n $any(configFooterContent)\n \"\n [class]=\"footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentClass'\"\n [ngStyle]=\"footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentStyle'\">\n {{ $any(configFooterContent) | translate }}\n </span>\n </div>\n }\n </th>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n footer.column.id === lastVirtualCenterColumnId()\n ) {\n <th class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualRightSpacerWidth()\"></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 canPin = column?.getCanPin() !== false && zConfig().enableColumnPinning;\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\"\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\"\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) {\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 === 'left' ? ('i18n_z_ui_table_left' | translate) : ('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 === 'left' ? '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-table-container.z-column-resizing table,.z-table-toolbar{min-width: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}.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}.z-thead-wrapper::-webkit-scrollbar{display:none}.z-tbody-scrollbar{flex:1;width:100%;max-width:100%;min-width:0;height:100%}.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,td:has(>.z-table-content-trigger:focus-visible){position:relative;z-index:2}.z-content-edit-active:after,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:-1px;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}.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-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}.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)}[data-z-table-drag-handle]{touch-action:none;-webkit-user-select:none;user-select:none}.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-virtual-row:has(tr.z-group-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}: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)!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{display:flex;flex-direction:column;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;--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-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}table{width:fit-content;min-width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed;font-size:.875rem}.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-thead-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-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-wrapper{flex:1;display:flex;flex-direction:column;min-height:0;width:100%}.z-tbody-scrollbar{flex:1;width:100%;max-width:100%;min-width:0;height:100%;transition:opacity .2s ease-in-out}.z-empty-state,.z-loading-state{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:2.5rem;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 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;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}tr.z-expanded-row>td{border-left:.125rem solid var(--primary);background-color:var(--background)!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-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;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.text-primary{color:var(--primary)}.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)}.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-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}.z-column-drop-list{min-height:3.125rem;overscroll-behavior:contain}.z-column-drop-list.cdk-drop-list-dragging{overflow:clip}: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-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-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}\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: "[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", "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"], 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"] }, { 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: ZTablePinningStylesPipe, name: "zTablePinningStyles" }, { 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: 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 });
9392
9491
  }
9393
9492
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZTableComponent, decorators: [{
9394
9493
  type: Component,
@@ -9445,7 +9544,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImpor
9445
9544
  TranslatePipe,
9446
9545
  ], standalone: true, providers: [TranslatePipe, ZTableDragService], changeDetection: ChangeDetectionStrategy.OnPush, host: {
9447
9546
  class: 'z-table block relative py-1',
9448
- }, 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<div\n #tableContainer\n [class]=\"classTable()\"\n [class.z-hide-horizontal-border]=\"!showHorizontalBorder()\"\n [class.z-hide-vertical-border]=\"!showVerticalBorder()\"\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 <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]=\"virtualLeftSpacerWidth()\" />\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]=\"virtualRightSpacerWidth()\" />\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 #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: header : 'header' : table : zConfig().columns : columnSizingInfo()\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]=\"header.column.getIsPinned() === 'left'\"\n [class.z-sticky-right]=\"header.column.getIsPinned() === 'right'\"\n [class.z-sticky-left-last]=\"header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns\"\n [class.z-sticky-right-first]=\"header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns\"\n [class.z-sticky-right-last]=\"header | zTableCellPin: 'isLastRightPinned' : zConfig().columns\"\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;\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() !== 'left') {\n <button\n type=\"button\"\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\">\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() !== 'right') {\n <button\n type=\"button\"\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\">\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 = activeGroupingColumnId() === 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)=\"clearGrouping(); 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 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 [zColumn]=\"$any(header.column)\" [zTable]=\"$any(table)\" />\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() === 'right' || header.column.getIsLastColumn()\n \"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <th class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualLeftSpacerWidth()\"></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;\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() !== 'left') {\n <button\n type=\"button\"\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\">\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() !== 'right') {\n <button\n type=\"button\"\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\">\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 = activeGroupingColumnId() === 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)=\"clearGrouping(); 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 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 [zColumn]=\"$any(header.column)\" [zTable]=\"$any(table)\" />\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() === 'right' || header.column.getIsLastColumn()\n \"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualRightSpacerWidth() > 0) {\n <th class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualRightSpacerWidth()\"></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: header : 'header' : table : zConfig().columns : columnSizingInfo()\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]=\"header.column.getIsPinned() === 'left'\"\n [class.z-sticky-right]=\"header.column.getIsPinned() === 'right'\"\n [class.z-sticky-left-last]=\"header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns\"\n [class.z-sticky-right-first]=\"header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns\"\n [class.z-sticky-right-last]=\"header | zTableCellPin: 'isLastRightPinned' : zConfig().columns\"\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;\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() !== 'left') {\n <button\n type=\"button\"\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\">\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() !== 'right') {\n <button\n type=\"button\"\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\">\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 = activeGroupingColumnId() === 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)=\"clearGrouping(); 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 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 [zColumn]=\"$any(header.column)\" [zTable]=\"$any(table)\" />\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]=\"\n header.column.getIsPinned() === 'right' || header.column.getIsLastColumn()\n \"\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: header : 'header' : table : zConfig().columns : columnSizingInfo()\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]=\"header.column.getIsPinned() === 'left'\"\n [class.z-sticky-right]=\"header.column.getIsPinned() === 'right'\"\n [class.z-sticky-left-last]=\"header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns\"\n [class.z-sticky-right-first]=\"header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns\"\n [class.z-sticky-right-last]=\"header | zTableCellPin: 'isLastRightPinned' : zConfig().columns\"\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;\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() !== 'left') {\n <button\n type=\"button\"\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\">\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() !== 'right') {\n <button\n type=\"button\"\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\">\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 = activeGroupingColumnId() === 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)=\"clearGrouping(); 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 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 [zColumn]=\"$any(header.column)\" [zTable]=\"$any(table)\" />\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() === 'right' || 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 <div\n class=\"z-virtual-scroll-inner\"\n [style.height.px]=\"virtualizer.getTotalSize()\"\n [style.min-width.px]=\"table.getTotalSize()\">\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[0]?.id ?? ''\"\n [z-table-drop-item-id]=\"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 dynamicSize() ? null : (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-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-expanded]=\"groupHeaderItem.expanded\"\n [attr.data-group-id]=\"groupHeaderItem.id\">\n <td [attr.colspan]=\"renderedColumnCount()\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\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 class=\"z-group-row-label\">\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 </td>\n </tr>\n }\n @for (row of groupRows; track row.id) {\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n <tr\n z-table-row-hover\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"dynamicSize() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"dynamicSize() ? virtualRowHeight() : null\"\n [class.z-child-row]=\"row.depth > 0\"\n [class.z-group-child-row]=\"_isVirtualGroupChild(virtualFlatItem)\"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\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=\"pointer-events-none border-0 p-0\"\n [style.width.px]=\"virtualLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : table.getRowModel().rows;\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 : columnSizingInfo()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"cellPinned === 'left'\"\n [class.z-sticky-right]=\"cellPinned === 'right'\"\n [class.z-sticky-left-last]=\"cellPinned === 'left' && cell.column.getIsLastColumn('left')\"\n [class.z-sticky-right-first]=\"\n cellPinned === 'right' && cell.column.getIsFirstColumn('right')\n \"\n [class.z-sticky-right-last]=\"\n cellPinned === 'right' && cell.column.getIsLastColumn('right')\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]=\"\n cell | zTableSpan: zConfig().columns : 'cellRowSpan' : table.getRowModel().rows\n \"\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 (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 <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (cell | zTableCellConfig: zConfig() : 'contentTooltip') || cellContent\n \"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \"></div>\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=\"pointer-events-none border-0 p-0\"\n [style.width.px]=\"virtualRightSpacerWidth()\"></td>\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\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-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n <!-- Row Template -->\n <ng-template #rowTemplate let-row let-isGroupChild=\"isGroupChild\">\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 [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-bottom]=\"rowPinned === 'bottom'\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() && rowPinned === 'top' && (row | zTableRow: table : 'isLastTopPinned')\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\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 class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : table.getRowModel().rows;\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: cell : 'body' : visibleCells : zConfig().columns : columnSizingInfo()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n [class.z-sticky-left]=\"cellPinned === 'left'\"\n [class.z-sticky-right]=\"cellPinned === 'right'\"\n [class.z-sticky-left-last]=\"cellPinned === 'left' && cell.column.getIsLastColumn('left')\"\n [class.z-sticky-right-first]=\"cellPinned === 'right' && cell.column.getIsFirstColumn('right')\"\n [class.z-sticky-right-last]=\"cellPinned === 'right' && cell.column.getIsLastColumn('right')\"\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' : table.getRowModel().rows\"\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 <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 p-1\">\n @if (cellRowPinned !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cellRowPinned !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cellRowPinned) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\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\"\n [class.text-primary]=\"cellRowPinned\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\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 <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 p-1\">\n @if (cellRowPinned !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cellRowPinned !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cellRowPinned) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\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\"\n [class.text-primary]=\"cellRowPinned\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\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 <!-- Actions Column - Row Pin Only (for parent rows) -->\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 p-1\">\n @if (cellRowPinned !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cellRowPinned !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cellRowPinned) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\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\"\n [class.text-primary]=\"cellRowPinned\">\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 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 <div\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'\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \"></div>\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 class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualRightSpacerWidth()\"></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 class=\"z-group-row\" [class.z-group-row-expanded]=\"item.expanded\" [attr.data-group-id]=\"item.id\">\n <td [attr.colspan]=\"renderedColumnCount()\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\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 class=\"z-group-row-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 </td>\n </tr>\n }\n @if (item.type === 'row') {\n <ng-container\n *ngTemplateOutlet=\"\n rowTemplate;\n context: { $implicit: item.row, isGroupChild: item.isGroupChild }\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) {\n @if (footerGroup | zTableFooterContent: zConfig().columns) {\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 class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualLeftSpacerWidth()\"></th>\n }\n @let rowSpan = footer | zTableSpan: zConfig().columns : 'footerRowSpan';\n @let shouldRender = footer | zTableCellRender: footerGroup.headers : zConfig().columns : 'footer';\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: footer : 'footer' : table : zConfig().columns : columnSizingInfo()\n \"\n [class]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerClass') +\n ' ' +\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass')\n \"\n [style]=\"footer.column.id | zTableColumnConfig: zConfig().columns : 'footerStyle'\"\n [class.z-sticky-left]=\"footer.column.getIsPinned() === 'left'\"\n [class.z-sticky-right]=\"footer.column.getIsPinned() === 'right'\"\n [class.z-sticky-left-last]=\"\n footer | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'footer'\n \"\n [class.z-sticky-right-first]=\"\n footer | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'footer'\n \"\n [class.z-sticky-right-last]=\"\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'\">\n @let configFooterContent =\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContent';\n @if (footer.column.columnDef.footer) {\n <ng-container\n *flexRender=\"footer.column.columnDef.footer; props: footer.getContext(); let footerContent\">\n <div\n class=\"flex w-full items-center\"\n [class.justify-center]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass') ===\n 'text-right'\n \">\n @if (footerContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n <div\n class=\"z-template-content\"\n [class]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentClass'\n \"\n [ngStyle]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentStyle'\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]=\"footer.column.id | zTableColumnConfig: zConfig().columns : 'footerTooltip'\"\n [class]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentClass'\n \"\n [ngStyle]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentStyle'\n \" />\n } @else {\n <!-- Default/string rendering -->\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerTooltip') ||\n footerContent\n \"\n [class]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentClass'\n \"\n [ngStyle]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentStyle'\n \">\n {{ footerContent | translate }}\n </span>\n }\n </div>\n </ng-container>\n } @else if (configFooterContent) {\n <!-- Fallback for group columns without TanStack footer -->\n <div\n class=\"flex w-full items-center\"\n [class.justify-center]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass') ===\n 'text-right'\n \">\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerTooltip') ||\n $any(configFooterContent)\n \"\n [class]=\"footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentClass'\"\n [ngStyle]=\"footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentStyle'\">\n {{ $any(configFooterContent) | translate }}\n </span>\n </div>\n }\n </th>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n footer.column.id === lastVirtualCenterColumnId()\n ) {\n <th class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualRightSpacerWidth()\"></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 = activeGroupingColumnId() === columnId;\n @let canPin = column?.getCanPin() !== false && zConfig().enableColumnPinning;\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\"\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\"\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) {\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 = activeGroupingColumnId() === 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 === 'left' ? ('i18n_z_ui_table_left' | translate) : ('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 === 'left' ? '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-table-container.z-column-resizing table,.z-table-toolbar{min-width: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}.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}.z-thead-wrapper::-webkit-scrollbar{display:none}.z-tbody-scrollbar{flex:1;width:100%;max-width:100%;min-width:0;height:100%}.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,td:has(>.z-table-content-trigger:focus-visible){position:relative;z-index:2}.z-content-edit-active:after,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:-1px;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}.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-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}.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)}[data-z-table-drag-handle]{touch-action:none;-webkit-user-select:none;user-select:none}.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-virtual-row:has(tr.z-group-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}.z-group-row-trigger{display:inline-flex;min-height:2rem;max-width:100%;align-items:center;gap:.5rem;padding:.25rem .75rem;color:var(--primary);font-size:.8125rem;font-weight:600;cursor:pointer}.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}: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)!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{display:flex;flex-direction:column;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;--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-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}table{width:fit-content;min-width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed;font-size:.875rem}.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-thead-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-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-wrapper{flex:1;display:flex;flex-direction:column;min-height:0;width:100%}.z-tbody-scrollbar{flex:1;width:100%;max-width:100%;min-width:0;height:100%;transition:opacity .2s ease-in-out}.z-empty-state,.z-loading-state{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:2.5rem;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 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;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}tr.z-expanded-row>td{border-left:.125rem solid var(--primary);background-color:var(--background)!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-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;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.text-primary{color:var(--primary)}.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)}.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-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}.z-column-drop-list{min-height:3.125rem;overscroll-behavior:contain}.z-column-drop-list.cdk-drop-list-dragging{overflow:clip}: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-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-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}\n"] }]
9547
+ }, 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<div\n #tableContainer\n [class]=\"classTable()\"\n [class.z-hide-horizontal-border]=\"!showHorizontalBorder()\"\n [class.z-hide-vertical-border]=\"!showVerticalBorder()\"\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 <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]=\"virtualLeftSpacerWidth()\" />\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]=\"virtualRightSpacerWidth()\" />\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 #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: header : 'header' : table : zConfig().columns : columnSizingInfo()\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]=\"header.column.getIsPinned() === 'left'\"\n [class.z-sticky-right]=\"header.column.getIsPinned() === 'right'\"\n [class.z-sticky-left-last]=\"header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns\"\n [class.z-sticky-right-first]=\"header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns\"\n [class.z-sticky-right-last]=\"header | zTableCellPin: 'isLastRightPinned' : zConfig().columns\"\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;\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() !== 'left') {\n <button\n type=\"button\"\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\">\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() !== 'right') {\n <button\n type=\"button\"\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\">\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 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 [zColumn]=\"$any(header.column)\" [zTable]=\"$any(table)\" />\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() === 'right' || header.column.getIsLastColumn()\n \"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <th class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualLeftSpacerWidth()\"></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;\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() !== 'left') {\n <button\n type=\"button\"\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\">\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() !== 'right') {\n <button\n type=\"button\"\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\">\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 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 [zColumn]=\"$any(header.column)\" [zTable]=\"$any(table)\" />\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() === 'right' || header.column.getIsLastColumn()\n \"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualRightSpacerWidth() > 0) {\n <th class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualRightSpacerWidth()\"></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: header : 'header' : table : zConfig().columns : columnSizingInfo()\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]=\"header.column.getIsPinned() === 'left'\"\n [class.z-sticky-right]=\"header.column.getIsPinned() === 'right'\"\n [class.z-sticky-left-last]=\"header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns\"\n [class.z-sticky-right-first]=\"header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns\"\n [class.z-sticky-right-last]=\"header | zTableCellPin: 'isLastRightPinned' : zConfig().columns\"\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;\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() !== 'left') {\n <button\n type=\"button\"\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\">\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() !== 'right') {\n <button\n type=\"button\"\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\">\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 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 [zColumn]=\"$any(header.column)\" [zTable]=\"$any(table)\" />\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]=\"\n header.column.getIsPinned() === 'right' || header.column.getIsLastColumn()\n \"\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: header : 'header' : table : zConfig().columns : columnSizingInfo()\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]=\"header.column.getIsPinned() === 'left'\"\n [class.z-sticky-right]=\"header.column.getIsPinned() === 'right'\"\n [class.z-sticky-left-last]=\"header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns\"\n [class.z-sticky-right-first]=\"header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns\"\n [class.z-sticky-right-last]=\"header | zTableCellPin: 'isLastRightPinned' : zConfig().columns\"\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;\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() !== 'left') {\n <button\n type=\"button\"\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\">\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() !== 'right') {\n <button\n type=\"button\"\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\">\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 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 [zColumn]=\"$any(header.column)\" [zTable]=\"$any(table)\" />\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() === 'right' || 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 <div\n class=\"z-virtual-scroll-inner\"\n [style.height.px]=\"virtualizer.getTotalSize()\"\n [style.min-width.px]=\"table.getTotalSize()\">\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[0]?.id ?? ''\"\n [z-table-drop-item-id]=\"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 dynamicSize() ? null : (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-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-expanded]=\"groupHeaderItem.expanded\"\n [attr.data-group-id]=\"groupHeaderItem.id\"\n [attr.data-group-depth]=\"groupHeaderItem.depth\">\n <td [attr.colspan]=\"renderedColumnCount()\">\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 class=\"z-group-row-label\">\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 [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(groupHeaderItem.columnId)\"></button>\n }\n </td>\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 <tr\n z-table-row-hover\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"dynamicSize() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"dynamicSize() ? virtualRowHeight() : null\"\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 (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=\"pointer-events-none border-0 p-0\"\n [style.width.px]=\"virtualLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : table.getRowModel().rows;\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 : columnSizingInfo()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"cellPinned === 'left'\"\n [class.z-sticky-right]=\"cellPinned === 'right'\"\n [class.z-sticky-left-last]=\"cellPinned === 'left' && cell.column.getIsLastColumn('left')\"\n [class.z-sticky-right-first]=\"\n cellPinned === 'right' && cell.column.getIsFirstColumn('right')\n \"\n [class.z-sticky-right-last]=\"\n cellPinned === 'right' && cell.column.getIsLastColumn('right')\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]=\"\n cell | zTableSpan: zConfig().columns : 'cellRowSpan' : table.getRowModel().rows\n \"\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 (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 <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (cell | zTableCellConfig: zConfig() : 'contentTooltip') || cellContent\n \"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \"></div>\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=\"pointer-events-none border-0 p-0\"\n [style.width.px]=\"virtualRightSpacerWidth()\"></td>\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\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-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-bottom]=\"rowPinned === 'bottom'\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() && rowPinned === 'top' && (row | zTableRow: table : 'isLastTopPinned')\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\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 class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : table.getRowModel().rows;\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: cell : 'body' : visibleCells : zConfig().columns : columnSizingInfo()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n [class.z-sticky-left]=\"cellPinned === 'left'\"\n [class.z-sticky-right]=\"cellPinned === 'right'\"\n [class.z-sticky-left-last]=\"cellPinned === 'left' && cell.column.getIsLastColumn('left')\"\n [class.z-sticky-right-first]=\"cellPinned === 'right' && cell.column.getIsFirstColumn('right')\"\n [class.z-sticky-right-last]=\"cellPinned === 'right' && cell.column.getIsLastColumn('right')\"\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' : table.getRowModel().rows\"\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 <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 p-1\">\n @if (cellRowPinned !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cellRowPinned !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cellRowPinned) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\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\"\n [class.text-primary]=\"cellRowPinned\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\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 <ng-template #rowPinPopoverContent>\n <div class=\"flex flex-col gap-1 p-1\">\n @if (cellRowPinned !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cellRowPinned !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cellRowPinned) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\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\"\n [class.text-primary]=\"cellRowPinned\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\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 <!-- Actions Column - Row Pin Only (for parent rows) -->\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 p-1\">\n @if (cellRowPinned !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cellRowPinned !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cellRowPinned) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-1.5 rounded px-2 py-1 text-xs\">\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\"\n [class.text-primary]=\"cellRowPinned\">\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 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 <div\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'\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \"></div>\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 class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualRightSpacerWidth()\"></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-expanded]=\"item.expanded\"\n [attr.data-group-id]=\"item.id\"\n [attr.data-group-depth]=\"item.depth\">\n <td [attr.colspan]=\"renderedColumnCount()\">\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 class=\"z-group-row-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 [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(item.columnId)\"></button>\n }\n </td>\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) {\n @if (footerGroup | zTableFooterContent: zConfig().columns) {\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 class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualLeftSpacerWidth()\"></th>\n }\n @let rowSpan = footer | zTableSpan: zConfig().columns : 'footerRowSpan';\n @let shouldRender = footer | zTableCellRender: footerGroup.headers : zConfig().columns : 'footer';\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: footer : 'footer' : table : zConfig().columns : columnSizingInfo()\n \"\n [class]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerClass') +\n ' ' +\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass')\n \"\n [style]=\"footer.column.id | zTableColumnConfig: zConfig().columns : 'footerStyle'\"\n [class.z-sticky-left]=\"footer.column.getIsPinned() === 'left'\"\n [class.z-sticky-right]=\"footer.column.getIsPinned() === 'right'\"\n [class.z-sticky-left-last]=\"\n footer | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'footer'\n \"\n [class.z-sticky-right-first]=\"\n footer | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'footer'\n \"\n [class.z-sticky-right-last]=\"\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'\">\n @let configFooterContent =\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContent';\n @if (footer.column.columnDef.footer) {\n <ng-container\n *flexRender=\"footer.column.columnDef.footer; props: footer.getContext(); let footerContent\">\n <div\n class=\"flex w-full items-center\"\n [class.justify-center]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass') ===\n 'text-right'\n \">\n @if (footerContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n <div\n class=\"z-template-content\"\n [class]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentClass'\n \"\n [ngStyle]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentStyle'\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]=\"footer.column.id | zTableColumnConfig: zConfig().columns : 'footerTooltip'\"\n [class]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentClass'\n \"\n [ngStyle]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentStyle'\n \" />\n } @else {\n <!-- Default/string rendering -->\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerTooltip') ||\n footerContent\n \"\n [class]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentClass'\n \"\n [ngStyle]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentStyle'\n \">\n {{ footerContent | translate }}\n </span>\n }\n </div>\n </ng-container>\n } @else if (configFooterContent) {\n <!-- Fallback for group columns without TanStack footer -->\n <div\n class=\"flex w-full items-center\"\n [class.justify-center]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass') ===\n 'text-right'\n \">\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerTooltip') ||\n $any(configFooterContent)\n \"\n [class]=\"footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentClass'\"\n [ngStyle]=\"footer.column.id | zTableColumnConfig: zConfig().columns : 'footerContentStyle'\">\n {{ $any(configFooterContent) | translate }}\n </span>\n </div>\n }\n </th>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n footer.column.id === lastVirtualCenterColumnId()\n ) {\n <th class=\"pointer-events-none border-0 p-0\" [style.width.px]=\"virtualRightSpacerWidth()\"></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 canPin = column?.getCanPin() !== false && zConfig().enableColumnPinning;\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\"\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\"\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) {\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 === 'left' ? ('i18n_z_ui_table_left' | translate) : ('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 === 'left' ? '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-table-container.z-column-resizing table,.z-table-toolbar{min-width: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}.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}.z-thead-wrapper::-webkit-scrollbar{display:none}.z-tbody-scrollbar{flex:1;width:100%;max-width:100%;min-width:0;height:100%}.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,td:has(>.z-table-content-trigger:focus-visible){position:relative;z-index:2}.z-content-edit-active:after,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:-1px;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}.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-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}.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)}[data-z-table-drag-handle]{touch-action:none;-webkit-user-select:none;user-select:none}.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-virtual-row:has(tr.z-group-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}: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)!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{display:flex;flex-direction:column;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;--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-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}table{width:fit-content;min-width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed;font-size:.875rem}.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-thead-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-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-wrapper{flex:1;display:flex;flex-direction:column;min-height:0;width:100%}.z-tbody-scrollbar{flex:1;width:100%;max-width:100%;min-width:0;height:100%;transition:opacity .2s ease-in-out}.z-empty-state,.z-loading-state{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:2.5rem;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 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;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}tr.z-expanded-row>td{border-left:.125rem solid var(--primary);background-color:var(--background)!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-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;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.text-primary{color:var(--primary)}.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)}.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-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}.z-column-drop-list{min-height:3.125rem;overscroll-behavior:contain}.z-column-drop-list.cdk-drop-list-dragging{overflow:clip}: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-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-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}\n"] }]
9449
9548
  }], 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 }] }] } });
9450
9549
 
9451
9550
  /**