@shival99/z-ui 2.0.52 → 2.0.54

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.
Files changed (31) hide show
  1. package/fesm2022/shival99-z-ui-components-z-autocomplete.mjs +1 -1
  2. package/fesm2022/shival99-z-ui-components-z-autocomplete.mjs.map +1 -1
  3. package/fesm2022/shival99-z-ui-components-z-calendar.mjs +1 -1
  4. package/fesm2022/shival99-z-ui-components-z-calendar.mjs.map +1 -1
  5. package/fesm2022/shival99-z-ui-components-z-dropdown-menu.mjs +1 -1
  6. package/fesm2022/shival99-z-ui-components-z-dropdown-menu.mjs.map +1 -1
  7. package/fesm2022/shival99-z-ui-components-z-editor.mjs +1 -1
  8. package/fesm2022/shival99-z-ui-components-z-editor.mjs.map +1 -1
  9. package/fesm2022/shival99-z-ui-components-z-filter.mjs +1 -1
  10. package/fesm2022/shival99-z-ui-components-z-filter.mjs.map +1 -1
  11. package/fesm2022/shival99-z-ui-components-z-input.mjs +1 -1
  12. package/fesm2022/shival99-z-ui-components-z-input.mjs.map +1 -1
  13. package/fesm2022/shival99-z-ui-components-z-media-player.mjs +1 -1
  14. package/fesm2022/shival99-z-ui-components-z-media-player.mjs.map +1 -1
  15. package/fesm2022/shival99-z-ui-components-z-menu.mjs +2 -2
  16. package/fesm2022/shival99-z-ui-components-z-menu.mjs.map +1 -1
  17. package/fesm2022/shival99-z-ui-components-z-popover.mjs +171 -41
  18. package/fesm2022/shival99-z-ui-components-z-popover.mjs.map +1 -1
  19. package/fesm2022/shival99-z-ui-components-z-select.mjs +22 -13
  20. package/fesm2022/shival99-z-ui-components-z-select.mjs.map +1 -1
  21. package/fesm2022/shival99-z-ui-components-z-table.mjs +722 -19
  22. package/fesm2022/shival99-z-ui-components-z-table.mjs.map +1 -1
  23. package/fesm2022/shival99-z-ui-components-z-tabs.mjs +1 -1
  24. package/fesm2022/shival99-z-ui-components-z-tabs.mjs.map +1 -1
  25. package/fesm2022/shival99-z-ui-i18n.mjs +12 -0
  26. package/fesm2022/shival99-z-ui-i18n.mjs.map +1 -1
  27. package/package.json +1 -1
  28. package/types/shival99-z-ui-components-z-modal.d.ts +1 -1
  29. package/types/shival99-z-ui-components-z-popover.d.ts +21 -3
  30. package/types/shival99-z-ui-components-z-select.d.ts +1 -0
  31. package/types/shival99-z-ui-components-z-table.d.ts +91 -4
@@ -2,7 +2,7 @@ import { moveItemInArray, CdkDropList, CdkDrag } from '@angular/cdk/drag-drop';
2
2
  import * as i1$1 from '@angular/cdk/overlay';
3
3
  import { OverlayModule } from '@angular/cdk/overlay';
4
4
  import { ScrollingModule } from '@angular/cdk/scrolling';
5
- import { NgStyle, NgClass, DOCUMENT, formatDate, NgTemplateOutlet } from '@angular/common';
5
+ import { NgStyle, DOCUMENT, formatDate, NgTemplateOutlet } from '@angular/common';
6
6
  import * as i0 from '@angular/core';
7
7
  import { input, output, computed, ChangeDetectionStrategy, Component, signal, inject, ElementRef, effect, afterNextRender, DestroyRef, NgZone, Injectable, Directive, Renderer2, Pipe, TemplateRef, viewChild, viewChildren, linkedSignal, untracked } from '@angular/core';
8
8
  import { TranslatePipe } from '@ngx-translate/core';
@@ -2073,7 +2073,7 @@ class ZTableFilterComponent {
2073
2073
  }
2074
2074
  const table = this.zTable();
2075
2075
  const column = this.zColumn();
2076
- const { rows } = table.getRowModel();
2076
+ const { rows } = table.getPreFilteredRowModel();
2077
2077
  const uniqueValues = new Map();
2078
2078
  for (const row of rows) {
2079
2079
  const value = row.getValue(column.id);
@@ -2715,7 +2715,7 @@ class ZTableFilterComponent {
2715
2715
  }
2716
2716
  </button>
2717
2717
  }
2718
- `, isInline: true, styles: [":host{display:inline-flex;color:var(--foreground);font-weight:450;font-style:normal;text-decoration:none;text-transform:none;letter-spacing:normal}.z-table-filter-trigger.z-popover-open{background-color:var(--muted);color:var(--foreground);box-shadow:0 0 0 2px color-mix(in srgb,var(--ring) 30%,transparent)}.z-table-filter-group{position:relative}.z-table-filter-condition-row{display:grid;grid-template-columns:minmax(0,1fr)}.z-table-filter-condition-divider{display:flex;align-items:center;gap:.375rem;padding-right:.25rem}.z-table-filter-condition-divider:after{content:\"\";height:1px;flex:1;border-top:1px dashed color-mix(in srgb,var(--border) 90%,var(--primary) 10%)}.z-table-filter-condition-divider--and:after{border-top-color:color-mix(in srgb,#2563eb 70%,var(--border))}.z-table-filter-condition-divider--or:after{border-top-color:color-mix(in srgb,#dc2626 70%,var(--border))}.z-table-filter-condition-divider-label{display:inline-flex;align-items:center;border-radius:.125rem;border:1px dashed currentColor;padding:.0625rem .375rem;font-size:.6875rem;font-weight:600;line-height:1rem;text-transform:uppercase}.z-table-filter-condition-divider-label--and{background:color-mix(in srgb,#2563eb 8%,transparent);color:#2563eb}.z-table-filter-condition-divider-label--or{background:color-mix(in srgb,#dc2626 8%,transparent);color:#dc2626}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "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: "component", type: ZCalendarComponent, selector: "z-calendar", inputs: ["class", "zMode", "zSize", "zLabel", "zLabelClass", "zPlaceholder", "zRequired", "zDisabled", "zReadonly", "zShowTime", "zTimeFormat", "zShowHour", "zShowMinute", "zShowSecond", "zQuickSelect", "zAllowEdit", "zShortTime", "zAllowClear", "zFormat", "zMinDate", "zMaxDate", "zValueType", "zValidators", "zShowOk", "zOkText", "zShowCancel", "zCancelText", "zDisabledDate", "zScrollClose", "zDefaultTime", "zRangeDefaultTime"], outputs: ["zControl", "zChange", "zOnBlur", "zOnFocus", "zEvent"], exportAs: ["zCalendar"] }, { 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: "directive", type: ZPopoverDirective, selector: "[z-popover]", inputs: ["zPopoverContent", "zPosition", "zTrigger", "zPopoverTrigger", "zClass", "zShowDelay", "zHideDelay", "zDisabled", "zOffset", "zPopoverWidth", "zTriggerRef", "zManualClose", "zOutsideClickClose", "zScrollClose", "zSticky", "zShowArrow"], outputs: ["zShow", "zHide", "zHideStart", "zControl", "zPositionChange", "zOutsideClick"], exportAs: ["zPopover"] }, { kind: "component", type: ZSelectComponent, selector: "z-select", inputs: ["class", "zMode", "zSize", "zLabel", "zLabelClass", "zPlaceholder", "zRequired", "zDisabled", "zReadonly", "zLoading", "zPrefix", "zAllowClear", "zWrap", "zShowSearch", "zPlaceholderSearch", "zDebounce", "zNotFoundText", "zEmptyText", "zEmptyIcon", "zMaxTagCount", "zDropdownMaxHeight", "zOptionHeight", "zVirtualScroll", "zShowAction", "zOptions", "zConfig", "zTranslateLabels", "zKey", "zSearchServer", "zLoadingMore", "zEnableLoadMore", "zScrollDistance", "zMaxVisible", "zScrollClose", "zSticky", "zPosition", "zSelectedTemplate", "zOptionTemplate", "zActionTemplate", "zAsyncValidators", "zAsyncDebounce", "zAsyncValidateOn", "zValidators"], outputs: ["zOnSearch", "zOnLoadMore", "zOnBlur", "zOnFocus", "zControl", "zEvent"], exportAs: ["zSelect"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2718
+ `, isInline: true, styles: [":host{display:inline-flex;color:var(--foreground);font-weight:450;font-style:normal;text-decoration:none;text-transform:none;letter-spacing:normal}.z-table-filter-trigger.z-popover-open{background-color:var(--muted);color:var(--foreground);box-shadow:0 0 0 2px color-mix(in srgb,var(--ring) 30%,transparent)}.z-table-filter-group{position:relative}.z-table-filter-condition-row{display:grid;grid-template-columns:minmax(0,1fr)}.z-table-filter-condition-divider{display:flex;align-items:center;gap:.375rem;padding-right:.25rem}.z-table-filter-condition-divider:after{content:\"\";height:1px;flex:1;border-top:1px dashed color-mix(in srgb,var(--border) 90%,var(--primary) 10%)}.z-table-filter-condition-divider--and:after{border-top-color:color-mix(in srgb,#2563eb 70%,var(--border))}.z-table-filter-condition-divider--or:after{border-top-color:color-mix(in srgb,#dc2626 70%,var(--border))}.z-table-filter-condition-divider-label{display:inline-flex;align-items:center;border-radius:.125rem;border:1px dashed currentColor;padding:.0625rem .375rem;font-size:.6875rem;font-weight:600;line-height:1rem;text-transform:uppercase}.z-table-filter-condition-divider-label--and{background:color-mix(in srgb,#2563eb 8%,transparent);color:#2563eb}.z-table-filter-condition-divider-label--or{background:color-mix(in srgb,#dc2626 8%,transparent);color:#dc2626}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "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: "component", type: ZCalendarComponent, selector: "z-calendar", inputs: ["class", "zMode", "zSize", "zLabel", "zLabelClass", "zPlaceholder", "zRequired", "zDisabled", "zReadonly", "zShowTime", "zTimeFormat", "zShowHour", "zShowMinute", "zShowSecond", "zQuickSelect", "zAllowEdit", "zShortTime", "zAllowClear", "zFormat", "zMinDate", "zMaxDate", "zValueType", "zValidators", "zShowOk", "zOkText", "zShowCancel", "zCancelText", "zDisabledDate", "zScrollClose", "zDefaultTime", "zRangeDefaultTime"], outputs: ["zControl", "zChange", "zOnBlur", "zOnFocus", "zEvent"], exportAs: ["zCalendar"] }, { 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: "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: ZSelectComponent, selector: "z-select", inputs: ["class", "zMode", "zSize", "zLabel", "zLabelClass", "zPlaceholder", "zRequired", "zDisabled", "zReadonly", "zLoading", "zPrefix", "zAllowClear", "zWrap", "zShowSearch", "zPlaceholderSearch", "zDebounce", "zNotFoundText", "zEmptyText", "zEmptyIcon", "zMaxTagCount", "zDropdownMaxHeight", "zOptionHeight", "zVirtualScroll", "zShowAction", "zOptions", "zConfig", "zTranslateLabels", "zKey", "zSearchServer", "zLoadingMore", "zEnableLoadMore", "zScrollDistance", "zMaxVisible", "zScrollClose", "zSticky", "zPosition", "zSelectedTemplate", "zOptionTemplate", "zActionTemplate", "zAsyncValidators", "zAsyncDebounce", "zAsyncValidateOn", "zValidators"], outputs: ["zOnSearch", "zOnLoadMore", "zOnBlur", "zOnFocus", "zControl", "zEvent"], exportAs: ["zSelect"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2719
2719
  }
2720
2720
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZTableFilterComponent, decorators: [{
2721
2721
  type: Component,
@@ -3076,11 +3076,10 @@ class ZTableIconTextComponent {
3076
3076
  @for (part of translatedParts(); track $index) {
3077
3077
  @if (part.type === 'icon') {
3078
3078
  <z-icon
3079
- class="shrink-0"
3079
+ [class]="'shrink-0 ' + (part.class ?? '')"
3080
3080
  [zType]="$any(part.value)"
3081
3081
  [zSize]="$any(part.size ?? 14)"
3082
3082
  [zStrokeWidth]="part.strokeWidth ?? 1.5"
3083
- [ngClass]="part.class ?? ''"
3084
3083
  />
3085
3084
  } @else {
3086
3085
  <span
@@ -3093,20 +3092,19 @@ class ZTableIconTextComponent {
3093
3092
  }
3094
3093
  }
3095
3094
  </span>
3096
- `, isInline: true, styles: [":host{display:inline-flex;align-items:center;min-width:0;max-width:100%}.z-table-icon-text-inner{display:inline-flex;align-items:center;gap:.25rem;line-height:1.2;min-width:0;max-width:100%}span.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zAnimatedType", "zAnimate", "zAnimationTrigger", "zSize", "zStrokeWidth", "zSvg"] }, { 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: "pipe", type: ZSafeHtmlPipe, name: "zSafeHtml" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3095
+ `, isInline: true, styles: [":host{display:inline-flex;align-items:center;min-width:0;max-width:100%}.z-table-icon-text-inner{display:inline-flex;align-items:center;gap:.25rem;line-height:1.2;min-width:0;max-width:100%}span.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"], dependencies: [{ kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zAnimatedType", "zAnimate", "zAnimationTrigger", "zSize", "zStrokeWidth", "zSvg"] }, { 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: "pipe", type: ZSafeHtmlPipe, name: "zSafeHtml" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3097
3096
  }
3098
3097
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZTableIconTextComponent, decorators: [{
3099
3098
  type: Component,
3100
- args: [{ selector: 'z-table-icon-text', imports: [NgClass, ZIconComponent, ZTooltipDirective, ZSafeHtmlPipe], standalone: true, template: `
3099
+ args: [{ selector: 'z-table-icon-text', imports: [ZIconComponent, ZTooltipDirective, ZSafeHtmlPipe], standalone: true, template: `
3101
3100
  <span class="z-table-icon-text-inner">
3102
3101
  @for (part of translatedParts(); track $index) {
3103
3102
  @if (part.type === 'icon') {
3104
3103
  <z-icon
3105
- class="shrink-0"
3104
+ [class]="'shrink-0 ' + (part.class ?? '')"
3106
3105
  [zType]="$any(part.value)"
3107
3106
  [zSize]="$any(part.size ?? 14)"
3108
3107
  [zStrokeWidth]="part.strokeWidth ?? 1.5"
3109
- [ngClass]="part.class ?? ''"
3110
3108
  />
3111
3109
  } @else {
3112
3110
  <span
@@ -5104,9 +5102,11 @@ class ZTableComponent {
5104
5102
  _bulkBarTimer = null;
5105
5103
  _contentRowMenuOutsideTimer = null;
5106
5104
  _contentRowMenuOutsideCleanup = null;
5105
+ _cellInteractionOutsideCleanup = null;
5107
5106
  _activeColumnVisibilityPopover = signal(null, ...(ngDevMode ? [{ debugName: "_activeColumnVisibilityPopover" }] : []));
5108
5107
  _hasInitializedColumnPinning = false;
5109
5108
  _isFitColumnScheduled = false;
5109
+ _skipNextConfigSave = false;
5110
5110
  // ─── Template-bound State ─────────────────────────────────────────────────
5111
5111
  /** Merged loading state from both zLoading input and config.loading */
5112
5112
  isLoading = computed(() => this.zConfig().loading ?? this.zLoading(), ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
@@ -5133,7 +5133,12 @@ class ZTableComponent {
5133
5133
  globalFilter = signal('', ...(ngDevMode ? [{ debugName: "globalFilter" }] : []));
5134
5134
  activeContentEditCell = signal(null, ...(ngDevMode ? [{ debugName: "activeContentEditCell" }] : []));
5135
5135
  contentRowMenu = signal(null, ...(ngDevMode ? [{ debugName: "contentRowMenu" }] : []));
5136
+ activeCell = signal(null, ...(ngDevMode ? [{ debugName: "activeCell" }] : []));
5137
+ cellSelectionAnchor = signal(null, ...(ngDevMode ? [{ debugName: "cellSelectionAnchor" }] : []));
5138
+ cellSelectionFocus = signal(null, ...(ngDevMode ? [{ debugName: "cellSelectionFocus" }] : []));
5139
+ cellMenu = signal(null, ...(ngDevMode ? [{ debugName: "cellMenu" }] : []));
5136
5140
  contentRowMenuControl = signal(null, ...(ngDevMode ? [{ debugName: "contentRowMenuControl" }] : []));
5141
+ cellMenuControl = signal(null, ...(ngDevMode ? [{ debugName: "cellMenuControl" }] : []));
5137
5142
  contentRowClipboard = signal([], ...(ngDevMode ? [{ debugName: "contentRowClipboard" }] : []));
5138
5143
  // Giữ kích thước cột đã ổn định khi config được tạo lại trong lúc tải dữ liệu.
5139
5144
  columnSizingState = linkedSignal({ ...(ngDevMode ? { debugName: "columnSizingState" } : {}), source: () => this._columns(),
@@ -5277,6 +5282,105 @@ class ZTableComponent {
5277
5282
  return (this.zConfig().columns ?? []).some(column => checkColumn(column));
5278
5283
  }, ...(ngDevMode ? [{ debugName: "hasContentEditableColumns" }] : []));
5279
5284
  canUseContentRowInsert = computed(() => this.zConfig().enableContentRowInsert !== false && this.hasContentEditableColumns(), ...(ngDevMode ? [{ debugName: "canUseContentRowInsert" }] : []));
5285
+ canUseRowSelection = computed(() => this.hasSelectColumn() && !this.hasContentEditableColumns(), ...(ngDevMode ? [{ debugName: "canUseRowSelection" }] : []));
5286
+ cellSelectionOptions = computed(() => {
5287
+ const config = this.zConfig().cellSelection;
5288
+ if (config === false) {
5289
+ return { enabled: false, range: false, contextMenu: false, copyWithHeaders: false };
5290
+ }
5291
+ if (config === true || config === undefined) {
5292
+ return { enabled: true, range: true, contextMenu: true, copyWithHeaders: true };
5293
+ }
5294
+ return {
5295
+ enabled: config.enabled !== false,
5296
+ range: config.range !== false,
5297
+ contextMenu: config.contextMenu !== false,
5298
+ copyWithHeaders: config.copyWithHeaders !== false,
5299
+ };
5300
+ }, ...(ngDevMode ? [{ debugName: "cellSelectionOptions" }] : []));
5301
+ canUseCellSelection = computed(() => this.cellSelectionOptions().enabled, ...(ngDevMode ? [{ debugName: "canUseCellSelection" }] : []));
5302
+ selectedCellIds = computed(() => {
5303
+ const range = this._getSelectedCellRange();
5304
+ if (!range) {
5305
+ return new Set();
5306
+ }
5307
+ const ids = new Set();
5308
+ for (const rowId of range.rowIds) {
5309
+ for (const columnId of range.columnIds) {
5310
+ ids.add(this._getCellSelectionId(rowId, columnId));
5311
+ }
5312
+ }
5313
+ return ids;
5314
+ }, ...(ngDevMode ? [{ debugName: "selectedCellIds" }] : []));
5315
+ visualSelectedCellIds = computed(() => {
5316
+ const range = this._getSelectedCellRange();
5317
+ if (!range) {
5318
+ return new Set();
5319
+ }
5320
+ return new Set(this._getSelectedCellVisualRects(range).map(rect => rect.id));
5321
+ }, ...(ngDevMode ? [{ debugName: "visualSelectedCellIds" }] : []));
5322
+ hasMultipleSelectedCells = computed(() => this.selectedCellIds().size > 1, ...(ngDevMode ? [{ debugName: "hasMultipleSelectedCells" }] : []));
5323
+ canCopyCellMenuSelection = computed(() => {
5324
+ const menu = this.cellMenu();
5325
+ if (!menu) {
5326
+ return false;
5327
+ }
5328
+ return this.selectedCellIds().has(this._getCellSelectionId(menu.rowId, menu.columnId));
5329
+ }, ...(ngDevMode ? [{ debugName: "canCopyCellMenuSelection" }] : []));
5330
+ selectedCellRangeInsets = computed(() => {
5331
+ const range = this._getSelectedCellRange();
5332
+ const insets = new Map();
5333
+ if (!range) {
5334
+ return insets;
5335
+ }
5336
+ for (const rect of this._getSelectedCellVisualRects(range)) {
5337
+ const rowSpan = rect.rowEnd - rect.rowStart + 1;
5338
+ const colSpan = rect.columnEnd - rect.columnStart + 1;
5339
+ insets.set(rect.id, {
5340
+ top: ((rect.selectedRowStart - rect.rowStart) / rowSpan) * 100,
5341
+ right: ((rect.columnEnd - rect.selectedColumnEnd) / colSpan) * 100,
5342
+ bottom: ((rect.rowEnd - rect.selectedRowEnd) / rowSpan) * 100,
5343
+ left: ((rect.selectedColumnStart - rect.columnStart) / colSpan) * 100,
5344
+ });
5345
+ }
5346
+ return insets;
5347
+ }, ...(ngDevMode ? [{ debugName: "selectedCellRangeInsets" }] : []));
5348
+ selectedCellEdgeIds = computed(() => {
5349
+ const range = this._getSelectedCellRange();
5350
+ const edges = {
5351
+ top: new Set(),
5352
+ right: new Set(),
5353
+ bottom: new Set(),
5354
+ left: new Set(),
5355
+ };
5356
+ if (!range) {
5357
+ return edges;
5358
+ }
5359
+ const rects = this._getSelectedCellVisualRects(range);
5360
+ const selectedSlots = new Set();
5361
+ for (const rect of rects) {
5362
+ for (let rowIndex = rect.selectedRowStart; rowIndex <= rect.selectedRowEnd; rowIndex++) {
5363
+ for (let columnIndex = rect.selectedColumnStart; columnIndex <= rect.selectedColumnEnd; columnIndex++) {
5364
+ selectedSlots.add(this._getCellVisualSlotId(rowIndex, columnIndex));
5365
+ }
5366
+ }
5367
+ }
5368
+ for (const rect of rects) {
5369
+ if (this._hasOutsideVisualNeighbor(rect, selectedSlots, 'top')) {
5370
+ edges.top.add(rect.id);
5371
+ }
5372
+ if (this._hasOutsideVisualNeighbor(rect, selectedSlots, 'right')) {
5373
+ edges.right.add(rect.id);
5374
+ }
5375
+ if (this._hasOutsideVisualNeighbor(rect, selectedSlots, 'bottom')) {
5376
+ edges.bottom.add(rect.id);
5377
+ }
5378
+ if (this._hasOutsideVisualNeighbor(rect, selectedSlots, 'left')) {
5379
+ edges.left.add(rect.id);
5380
+ }
5381
+ }
5382
+ return edges;
5383
+ }, ...(ngDevMode ? [{ debugName: "selectedCellEdgeIds" }] : []));
5280
5384
  contentRowDeleteCount = computed(() => {
5281
5385
  const selectedCount = this.selectedRowIds().length;
5282
5386
  if (selectedCount > 0) {
@@ -6008,7 +6112,7 @@ class ZTableComponent {
6008
6112
  manualPagination: isServerMode,
6009
6113
  pageCount: pageCount,
6010
6114
  columnResizeMode: 'onChange',
6011
- enableRowSelection: this.hasSelectColumn(),
6115
+ enableRowSelection: this.canUseRowSelection(),
6012
6116
  enableSubRowSelection: this.hasSelectColumn() && !!config.getSubRows,
6013
6117
  enableRowPinning: config.enableRowPinning ?? false,
6014
6118
  enableMultiSort: config.enableMultiSort ?? false,
@@ -6066,6 +6170,10 @@ class ZTableComponent {
6066
6170
  });
6067
6171
  },
6068
6172
  onRowSelectionChange: updater => {
6173
+ if (!this.canUseRowSelection()) {
6174
+ this.rowSelection.set({});
6175
+ return;
6176
+ }
6069
6177
  const currentState = this.rowSelection();
6070
6178
  const newState = typeof updater === 'function' ? updater(currentState) : updater;
6071
6179
  this._handleRowSelectionWithParents(newState);
@@ -6163,17 +6271,25 @@ class ZTableComponent {
6163
6271
  const totalRows = untracked(() => this.table.getRowModel().rows.length);
6164
6272
  return Math.ceil(totalRows / this.groupSize());
6165
6273
  }, ...(ngDevMode ? [{ debugName: "_virtualGroupCount" }] : []));
6166
- selectedRowIds = computed(() => Object.entries(this.rowSelection())
6167
- .filter(([, selected]) => selected)
6168
- .map(([rowId]) => rowId), ...(ngDevMode ? [{ debugName: "selectedRowIds" }] : []));
6274
+ selectedRowIds = computed(() => {
6275
+ if (!this.canUseRowSelection()) {
6276
+ return [];
6277
+ }
6278
+ return Object.entries(this.rowSelection())
6279
+ .filter(([, selected]) => selected)
6280
+ .map(([rowId]) => rowId);
6281
+ }, ...(ngDevMode ? [{ debugName: "selectedRowIds" }] : []));
6169
6282
  selectedRows = computed(() => {
6283
+ if (!this.canUseRowSelection()) {
6284
+ return [];
6285
+ }
6170
6286
  this.rowSelection();
6171
6287
  return this.table.getSelectedRowModel().rows.map(row => row.original);
6172
6288
  }, ...(ngDevMode ? [{ debugName: "selectedRows" }] : []));
6173
6289
  bulkActionContext = computed(() => ({
6174
6290
  selectedRows: this.selectedRows(),
6175
6291
  selectedRowIds: this.selectedRowIds(),
6176
- selection: this.rowSelection(),
6292
+ selection: this.canUseRowSelection() ? this.rowSelection() : {},
6177
6293
  }), ...(ngDevMode ? [{ debugName: "bulkActionContext" }] : []));
6178
6294
  bulkActionConfig = computed(() => {
6179
6295
  const config = this.zConfig().bulkAction;
@@ -6283,6 +6399,26 @@ class ZTableComponent {
6283
6399
  });
6284
6400
  onCleanup(cleanup);
6285
6401
  }, ...(ngDevMode ? [{ debugName: "_rowDragAutoScroll" }] : []));
6402
+ _rowDragCellSelectionCleanup = effect(onCleanup => {
6403
+ const cleanup = this._dragService.registerMonitor({
6404
+ onDragStart: source => {
6405
+ if (source.tableId === this.dragInstanceId && source.entity === 'row') {
6406
+ this._clearCellInteractionState();
6407
+ }
6408
+ },
6409
+ onDrop: event => {
6410
+ if (event.source.tableId === this.dragInstanceId && event.source.entity === 'row') {
6411
+ this._clearCellInteractionState();
6412
+ }
6413
+ },
6414
+ onDragEnd: source => {
6415
+ if (source.tableId === this.dragInstanceId && source.entity === 'row') {
6416
+ this._clearCellInteractionState();
6417
+ }
6418
+ },
6419
+ });
6420
+ onCleanup(cleanup);
6421
+ }, ...(ngDevMode ? [{ debugName: "_rowDragCellSelectionCleanup" }] : []));
6286
6422
  // ─── Constructor Effects ──────────────────────────────────────────────────
6287
6423
  //
6288
6424
  // Effects run in the constructor because Angular signals + effects don't
@@ -6320,6 +6456,8 @@ class ZTableComponent {
6320
6456
  this._destroy$.subscribe(() => {
6321
6457
  this._clearBulkBarTimer();
6322
6458
  this._clearContentRowMenuOutsideListener();
6459
+ this._cellInteractionOutsideCleanup?.();
6460
+ this._cellInteractionOutsideCleanup = null;
6323
6461
  });
6324
6462
  explicitEffect([this.zConfig], ([cfg]) => {
6325
6463
  if (this._lastExternalDataRef !== cfg.data) {
@@ -6565,6 +6703,7 @@ class ZTableComponent {
6565
6703
  ngAfterViewInit() {
6566
6704
  queueMicrotask(() => this._checkScrollState());
6567
6705
  queueMicrotask(() => this._scheduleFitColumnWidths());
6706
+ this._listenCellInteractionOutside();
6568
6707
  this.zControl.emit({
6569
6708
  updateConfig: (config) => {
6570
6709
  const current = this.zConfig();
@@ -6955,14 +7094,48 @@ class ZTableComponent {
6955
7094
  return this.tbodyWrapper()?.nativeElement;
6956
7095
  }
6957
7096
  _handleColumnSizingChange(updater) {
6958
- const next = typeof updater === 'function' ? updater(this.columnSizingState()) : updater;
7097
+ const nextRaw = typeof updater === 'function' ? updater(this.columnSizingState()) : updater;
7098
+ const resizingColumnId = this.columnSizingInfo().isResizingColumn;
7099
+ const next = this._clampColumnSizing(nextRaw, resizingColumnId || undefined);
6959
7100
  if (this._isSameColumnSizing(this.columnSizingState(), next)) {
6960
7101
  return;
6961
7102
  }
6962
7103
  this.columnSizingState.set(next);
6963
7104
  this._columnBaseSizing.set(next);
7105
+ if (this.columnSizingInfo().isResizingColumn) {
7106
+ this._checkHorizontalScroll();
7107
+ return;
7108
+ }
6964
7109
  this._scheduleFitColumnWidths();
6965
7110
  }
7111
+ _clampColumnSizing(sizing, activeColumnId) {
7112
+ const activeColumn = activeColumnId ? this.table.getColumn(activeColumnId) : undefined;
7113
+ const activeWidth = activeColumnId ? sizing[activeColumnId] : undefined;
7114
+ if (activeColumnId && activeColumn && typeof activeWidth === 'number') {
7115
+ const activeMinSize = activeColumn.columnDef.minSize ?? Z_DEFAULT_COLUMN_MIN_SIZE;
7116
+ const activeMaxSize = activeColumn.columnDef.maxSize;
7117
+ if (activeWidth < activeMinSize) {
7118
+ return { ...this.columnSizingState(), [activeColumnId]: activeMinSize };
7119
+ }
7120
+ if (typeof activeMaxSize === 'number' && activeWidth > activeMaxSize) {
7121
+ return { ...this.columnSizingState(), [activeColumnId]: activeMaxSize };
7122
+ }
7123
+ }
7124
+ let changed = false;
7125
+ const nextSizing = {};
7126
+ for (const [columnId, width] of Object.entries(sizing)) {
7127
+ const column = this.table.getColumn(columnId);
7128
+ const minSize = column?.columnDef.minSize ?? Z_DEFAULT_COLUMN_MIN_SIZE;
7129
+ const maxSize = column?.columnDef.maxSize;
7130
+ let nextWidth = Math.max(width, minSize);
7131
+ if (typeof maxSize === 'number') {
7132
+ nextWidth = Math.min(nextWidth, maxSize);
7133
+ }
7134
+ nextSizing[columnId] = nextWidth;
7135
+ changed = changed || nextWidth !== width;
7136
+ }
7137
+ return changed ? nextSizing : sizing;
7138
+ }
6966
7139
  _syncColumnBaseSizing() {
6967
7140
  const currentBaseSizing = this._columnBaseSizing();
6968
7141
  const currentSizing = this.columnSizingState();
@@ -7232,11 +7405,94 @@ class ZTableComponent {
7232
7405
  setContentRowMenuControl(control) {
7233
7406
  this.contentRowMenuControl.set(control);
7234
7407
  }
7408
+ setCellMenuControl(control) {
7409
+ this.cellMenuControl.set(control);
7410
+ }
7411
+ clearCellMenu() {
7412
+ this.cellMenu.set(null);
7413
+ }
7235
7414
  clearContentRowMenu() {
7236
7415
  this._clearContentRowMenuOutsideListener();
7237
7416
  this.contentRowMenu.set(null);
7238
7417
  }
7239
- openContentRowMenu(event, row) {
7418
+ onCellPointerDown(event, row, columnId) {
7419
+ if (!this.canUseCellSelection()) {
7420
+ return;
7421
+ }
7422
+ if (event.button !== 0) {
7423
+ return;
7424
+ }
7425
+ if (this._isCellSelectionDragTarget(event.target)) {
7426
+ return;
7427
+ }
7428
+ if (this._isIgnoredCellSelectionTarget(event.target)) {
7429
+ return;
7430
+ }
7431
+ const cell = { rowId: row.id, columnId };
7432
+ event.preventDefault();
7433
+ this.cellMenuControl()?.closeImmediate();
7434
+ this.cellMenu.set(null);
7435
+ this.activeCell.set(cell);
7436
+ if (event.shiftKey && this.cellSelectionAnchor() && this.cellSelectionOptions().range) {
7437
+ this.cellSelectionFocus.set(cell);
7438
+ return;
7439
+ }
7440
+ this.cellSelectionAnchor.set(cell);
7441
+ this.cellSelectionFocus.set(cell);
7442
+ }
7443
+ onCellPointerEnter(event, row, columnId) {
7444
+ if (!this.canUseCellSelection() || !this.cellSelectionOptions().range) {
7445
+ return;
7446
+ }
7447
+ if ((event.buttons & 1) !== 1) {
7448
+ return;
7449
+ }
7450
+ if (!this.cellSelectionAnchor()) {
7451
+ return;
7452
+ }
7453
+ if (this._isIgnoredCellSelectionTarget(event.target)) {
7454
+ return;
7455
+ }
7456
+ event.preventDefault();
7457
+ this.activeCell.set({ rowId: row.id, columnId });
7458
+ this.cellSelectionFocus.set({ rowId: row.id, columnId });
7459
+ }
7460
+ openCellMenu(event, row, columnId) {
7461
+ const activeContentCell = this.activeContentEditCell();
7462
+ if (activeContentCell?.rowId === row.id && activeContentCell.columnId === columnId) {
7463
+ this.openContentRowMenu(event, row, columnId);
7464
+ return;
7465
+ }
7466
+ const contentCellTarget = this._getContentEditTriggerTarget(event.target);
7467
+ if (contentCellTarget?.rowId === row.id && contentCellTarget.columnId === columnId) {
7468
+ this.openContentRowMenu(event, row, columnId);
7469
+ return;
7470
+ }
7471
+ const options = this.cellSelectionOptions();
7472
+ if (!options.enabled || !options.contextMenu) {
7473
+ this.openContentRowMenu(event, row);
7474
+ return;
7475
+ }
7476
+ if (!this._isSelectableCellColumn(columnId)) {
7477
+ this.openContentRowMenu(event, row);
7478
+ return;
7479
+ }
7480
+ if (this._isIgnoredCellSelectionTarget(event.target)) {
7481
+ return;
7482
+ }
7483
+ event.preventDefault();
7484
+ event.stopPropagation();
7485
+ const currentCell = { rowId: row.id, columnId };
7486
+ this.contentRowMenuControl()?.closeImmediate();
7487
+ this.clearContentRowMenu();
7488
+ this.cellMenu.set({
7489
+ ...currentCell,
7490
+ left: event.clientX,
7491
+ top: event.clientY,
7492
+ });
7493
+ queueMicrotask(() => this.cellMenuControl()?.show());
7494
+ }
7495
+ openContentRowMenu(event, row, columnId) {
7240
7496
  if (!this.canUseContentRowInsert()) {
7241
7497
  return;
7242
7498
  }
@@ -7248,6 +7504,7 @@ class ZTableComponent {
7248
7504
  this._clearContentRowMenuOutsideListener();
7249
7505
  this.contentRowMenu.set({
7250
7506
  row,
7507
+ columnId,
7251
7508
  left: event.clientX,
7252
7509
  top: event.clientY,
7253
7510
  });
@@ -7312,6 +7569,29 @@ class ZTableComponent {
7312
7569
  });
7313
7570
  }
7314
7571
  onContentTableKeydown(event) {
7572
+ if ((event.ctrlKey || event.metaKey) &&
7573
+ event.key.toLowerCase() === 'c' &&
7574
+ this._isContentEditorTarget(event.target)) {
7575
+ const activeCell = this.activeContentEditCell();
7576
+ if (!activeCell) {
7577
+ return;
7578
+ }
7579
+ const text = this._getContentEditClipboardText(activeCell.rowId, activeCell.columnId);
7580
+ if (!text) {
7581
+ return;
7582
+ }
7583
+ event.preventDefault();
7584
+ void this._writeClipboardText(text);
7585
+ return;
7586
+ }
7587
+ if (this.canUseCellSelection() &&
7588
+ !this._isEditableKeyboardTarget(event.target) &&
7589
+ (event.ctrlKey || event.metaKey) &&
7590
+ event.key.toLowerCase() === 'c') {
7591
+ event.preventDefault();
7592
+ this.copySelectedCells(false);
7593
+ return;
7594
+ }
7315
7595
  if (!this.canUseContentRowInsert()) {
7316
7596
  return;
7317
7597
  }
@@ -7343,6 +7623,26 @@ class ZTableComponent {
7343
7623
  event.preventDefault();
7344
7624
  this.deleteContentRows();
7345
7625
  }
7626
+ copySelectedCells(includeHeaders) {
7627
+ const text = this._buildSelectedCellsText(includeHeaders);
7628
+ if (!text) {
7629
+ return;
7630
+ }
7631
+ void this._writeClipboardText(text);
7632
+ this.cellMenuControl()?.closeImmediate();
7633
+ this.clearCellMenu();
7634
+ }
7635
+ copyContentCell() {
7636
+ const menu = this.contentRowMenu();
7637
+ if (!menu?.columnId) {
7638
+ return;
7639
+ }
7640
+ const text = this._getContentEditClipboardText(menu.row.id, menu.columnId) ??
7641
+ this._formatCellClipboardValue(menu.row.getValue(menu.columnId));
7642
+ void this._writeClipboardText(text);
7643
+ this.contentRowMenuControl()?.closeImmediate();
7644
+ this.clearContentRowMenu();
7645
+ }
7346
7646
  copyContentRows(rowId) {
7347
7647
  const rows = this._getContentRowsForRowAction(rowId);
7348
7648
  if (rows.length === 0) {
@@ -7453,6 +7753,306 @@ class ZTableComponent {
7453
7753
  }
7454
7754
  return !!target.closest('input, textarea, select, [contenteditable="true"], z-input, z-select, z-calendar');
7455
7755
  }
7756
+ _isContentEditorTarget(target) {
7757
+ if (!(target instanceof HTMLElement)) {
7758
+ return false;
7759
+ }
7760
+ return !!target.closest('z-table-content-editor');
7761
+ }
7762
+ _getContentEditClipboardText(rowId, columnId) {
7763
+ const activeCell = this.activeContentEditCell();
7764
+ if (activeCell?.rowId !== rowId || activeCell.columnId !== columnId) {
7765
+ return null;
7766
+ }
7767
+ const editor = this._host.nativeElement.querySelector('z-table-content-editor');
7768
+ if (!editor) {
7769
+ return null;
7770
+ }
7771
+ const selectedText = this._getSelectedTextFromEditor(editor);
7772
+ if (selectedText !== null) {
7773
+ return selectedText;
7774
+ }
7775
+ const valueElement = editor.querySelector('input, textarea');
7776
+ if (valueElement) {
7777
+ return this._formatCellClipboardValue(valueElement.value);
7778
+ }
7779
+ const trigger = editor.querySelector('.z-select-trigger');
7780
+ if (trigger) {
7781
+ return this._formatCellClipboardValue(trigger.textContent?.trim() ?? '');
7782
+ }
7783
+ return null;
7784
+ }
7785
+ _getSelectedTextFromEditor(editor) {
7786
+ const { activeElement } = this._document;
7787
+ if (activeElement instanceof HTMLInputElement || activeElement instanceof HTMLTextAreaElement) {
7788
+ if (!editor.contains(activeElement)) {
7789
+ return null;
7790
+ }
7791
+ const { selectionStart } = activeElement;
7792
+ const { selectionEnd } = activeElement;
7793
+ if (selectionStart === null || selectionEnd === null || selectionStart === selectionEnd) {
7794
+ return null;
7795
+ }
7796
+ return activeElement.value.slice(selectionStart, selectionEnd);
7797
+ }
7798
+ const selection = this._document.getSelection();
7799
+ if (!selection || selection.isCollapsed || !editor.contains(selection.anchorNode)) {
7800
+ return null;
7801
+ }
7802
+ return selection.toString();
7803
+ }
7804
+ isCellInSelectedRange(rowId, columnId) {
7805
+ return this.selectedCellIds().has(this._getCellSelectionId(rowId, columnId));
7806
+ }
7807
+ _listenCellInteractionOutside() {
7808
+ const onPointerDown = (event) => {
7809
+ if (!this._hasCellInteractionState()) {
7810
+ return;
7811
+ }
7812
+ if (this._isInsideCellInteractionBoundary(event.target)) {
7813
+ return;
7814
+ }
7815
+ this._clearCellInteractionState();
7816
+ };
7817
+ this._document.addEventListener('pointerdown', onPointerDown, true);
7818
+ this._cellInteractionOutsideCleanup = () => {
7819
+ this._document.removeEventListener('pointerdown', onPointerDown, true);
7820
+ };
7821
+ }
7822
+ _hasCellInteractionState() {
7823
+ return (!!this.activeCell() ||
7824
+ !!this.cellSelectionAnchor() ||
7825
+ !!this.cellSelectionFocus() ||
7826
+ !!this.activeContentEditCell());
7827
+ }
7828
+ _isInsideCellInteractionBoundary(target) {
7829
+ if (!(target instanceof Element)) {
7830
+ return false;
7831
+ }
7832
+ if (target.closest('.cdk-overlay-container, .cdk-overlay-pane, .z-table-cell-menu, .z-table-content-row-menu')) {
7833
+ return true;
7834
+ }
7835
+ const tbodyContainer = this.tbodyContainer()?.nativeElement;
7836
+ if (tbodyContainer?.contains(target)) {
7837
+ return true;
7838
+ }
7839
+ const tbodyWrapper = this.tbodyWrapper()?.nativeElement;
7840
+ if (tbodyWrapper?.contains(target)) {
7841
+ return true;
7842
+ }
7843
+ return false;
7844
+ }
7845
+ _clearCellInteractionState() {
7846
+ this.activeCell.set(null);
7847
+ this.cellSelectionAnchor.set(null);
7848
+ this.cellSelectionFocus.set(null);
7849
+ this.activeContentEditCell.set(null);
7850
+ this.cellMenuControl()?.closeImmediate();
7851
+ this.clearCellMenu();
7852
+ this.contentRowMenuControl()?.closeImmediate();
7853
+ this.clearContentRowMenu();
7854
+ }
7855
+ _getCellSelectionId(rowId, columnId) {
7856
+ return `${rowId}::${columnId}`;
7857
+ }
7858
+ _getSelectedCellRange() {
7859
+ const anchor = this.cellSelectionAnchor();
7860
+ const focus = this.cellSelectionFocus();
7861
+ if (!anchor || !focus) {
7862
+ return null;
7863
+ }
7864
+ const rows = this.table.getRowModel().rows;
7865
+ const rowIds = rows.map(row => row.id);
7866
+ const columnIds = this._getSelectableColumnIds();
7867
+ const anchorRowIndex = rowIds.indexOf(anchor.rowId);
7868
+ const focusRowIndex = rowIds.indexOf(focus.rowId);
7869
+ const anchorColumnIndex = columnIds.indexOf(anchor.columnId);
7870
+ const focusColumnIndex = columnIds.indexOf(focus.columnId);
7871
+ if (anchorRowIndex < 0 || focusRowIndex < 0 || anchorColumnIndex < 0 || focusColumnIndex < 0) {
7872
+ return null;
7873
+ }
7874
+ const rowStart = Math.min(anchorRowIndex, focusRowIndex);
7875
+ const rowEnd = Math.max(anchorRowIndex, focusRowIndex);
7876
+ const columnStart = Math.min(anchorColumnIndex, focusColumnIndex);
7877
+ const columnEnd = Math.max(anchorColumnIndex, focusColumnIndex);
7878
+ return {
7879
+ rowIds: rowIds.slice(rowStart, rowEnd + 1),
7880
+ columnIds: columnIds.slice(columnStart, columnEnd + 1),
7881
+ };
7882
+ }
7883
+ _getSelectedCellVisualRects(range) {
7884
+ const rows = this.table.getRowModel().rows;
7885
+ const selectableColumnIds = this._getSelectableColumnIds();
7886
+ const rangeRowStart = rows.findIndex(row => row.id === range.rowIds[0]);
7887
+ const rangeRowEnd = rows.findIndex(row => row.id === range.rowIds[range.rowIds.length - 1]);
7888
+ const rangeColumnStart = selectableColumnIds.indexOf(range.columnIds[0]);
7889
+ const rangeColumnEnd = selectableColumnIds.indexOf(range.columnIds[range.columnIds.length - 1]);
7890
+ if (rangeRowStart < 0 || rangeRowEnd < 0 || rangeColumnStart < 0 || rangeColumnEnd < 0) {
7891
+ return [];
7892
+ }
7893
+ const rects = [];
7894
+ for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
7895
+ const row = rows[rowIndex];
7896
+ const visibleCells = row.getVisibleCells();
7897
+ for (const cell of visibleCells) {
7898
+ const rect = this._getRenderedCellVisualRect(cell, rowIndex, rows, visibleCells, selectableColumnIds);
7899
+ if (!rect) {
7900
+ continue;
7901
+ }
7902
+ const selectedRowStart = Math.max(rect.rowStart, rangeRowStart);
7903
+ const selectedRowEnd = Math.min(rect.rowEnd, rangeRowEnd);
7904
+ const selectedColumnStart = Math.max(rect.columnStart, rangeColumnStart);
7905
+ const selectedColumnEnd = Math.min(rect.columnEnd, rangeColumnEnd);
7906
+ if (selectedRowStart > selectedRowEnd || selectedColumnStart > selectedColumnEnd) {
7907
+ continue;
7908
+ }
7909
+ rects.push({
7910
+ ...rect,
7911
+ selectedRowStart,
7912
+ selectedRowEnd,
7913
+ selectedColumnStart,
7914
+ selectedColumnEnd,
7915
+ });
7916
+ }
7917
+ }
7918
+ return rects;
7919
+ }
7920
+ _getRenderedCellVisualRect(cell, rowIndex, rows, visibleCells, selectableColumnIds) {
7921
+ const columnConfig = this._findColumnConfig(cell.column.id);
7922
+ if (!shouldCellRenderUtil(cell, columnConfig, rows, rowIndex)) {
7923
+ return null;
7924
+ }
7925
+ if (!shouldBodyCellRenderColSpan(cell, visibleCells, this.zConfig().columns)) {
7926
+ return null;
7927
+ }
7928
+ const columnIndex = selectableColumnIds.indexOf(cell.column.id);
7929
+ if (columnIndex < 0) {
7930
+ return null;
7931
+ }
7932
+ const rowSpan = calculateCellRowSpan(cell, columnConfig, rows, rowIndex) ?? 1;
7933
+ const colSpan = calculateCellColSpan(cell, columnConfig) ?? 1;
7934
+ return {
7935
+ id: this._getCellSelectionId(cell.row.id, cell.column.id),
7936
+ rowStart: rowIndex,
7937
+ rowEnd: Math.min(rows.length - 1, rowIndex + rowSpan - 1),
7938
+ columnStart: columnIndex,
7939
+ columnEnd: Math.min(selectableColumnIds.length - 1, columnIndex + colSpan - 1),
7940
+ selectedRowStart: rowIndex,
7941
+ selectedRowEnd: Math.min(rows.length - 1, rowIndex + rowSpan - 1),
7942
+ selectedColumnStart: columnIndex,
7943
+ selectedColumnEnd: Math.min(selectableColumnIds.length - 1, columnIndex + colSpan - 1),
7944
+ };
7945
+ }
7946
+ _hasOutsideVisualNeighbor(rect, selectedSlots, side) {
7947
+ if (side === 'top' || side === 'bottom') {
7948
+ const rowIndex = side === 'top' ? rect.selectedRowStart - 1 : rect.selectedRowEnd + 1;
7949
+ for (let columnIndex = rect.selectedColumnStart; columnIndex <= rect.selectedColumnEnd; columnIndex++) {
7950
+ if (!selectedSlots.has(this._getCellVisualSlotId(rowIndex, columnIndex))) {
7951
+ return true;
7952
+ }
7953
+ }
7954
+ return false;
7955
+ }
7956
+ const columnIndex = side === 'left' ? rect.selectedColumnStart - 1 : rect.selectedColumnEnd + 1;
7957
+ for (let rowIndex = rect.selectedRowStart; rowIndex <= rect.selectedRowEnd; rowIndex++) {
7958
+ if (!selectedSlots.has(this._getCellVisualSlotId(rowIndex, columnIndex))) {
7959
+ return true;
7960
+ }
7961
+ }
7962
+ return false;
7963
+ }
7964
+ _getCellVisualSlotId(rowIndex, columnIndex) {
7965
+ return `${rowIndex}::${columnIndex}`;
7966
+ }
7967
+ _buildSelectedCellsText(includeHeaders) {
7968
+ const range = this._getSelectedCellRange();
7969
+ if (!range) {
7970
+ return '';
7971
+ }
7972
+ const rowById = new Map(this.table.getRowModel().rows.map(row => [row.id, row]));
7973
+ const lines = [];
7974
+ if (includeHeaders && this.cellSelectionOptions().copyWithHeaders) {
7975
+ lines.push(range.columnIds.map(columnId => this._getColumnCopyHeader(columnId)).join('\t'));
7976
+ }
7977
+ for (const rowId of range.rowIds) {
7978
+ const row = rowById.get(rowId);
7979
+ if (!row) {
7980
+ continue;
7981
+ }
7982
+ lines.push(range.columnIds.map(columnId => this._formatCellClipboardValue(row.getValue(columnId))).join('\t'));
7983
+ }
7984
+ return lines.join('\n');
7985
+ }
7986
+ _getSelectableColumnIds() {
7987
+ return this.orderedLeafColumns()
7988
+ .filter(column => column.getIsVisible() && this._isSelectableCellColumn(column.id))
7989
+ .map(column => column.id);
7990
+ }
7991
+ _isSelectableCellColumn(columnId) {
7992
+ if (isZTableColumnTypeById(columnId, this.zConfig().columns, 'select')) {
7993
+ return false;
7994
+ }
7995
+ if (isZTableColumnTypeById(columnId, this.zConfig().columns, 'expand')) {
7996
+ return false;
7997
+ }
7998
+ if (isZTableColumnTypeById(columnId, this.zConfig().columns, 'rowDrag')) {
7999
+ return false;
8000
+ }
8001
+ if (columnId === 'actionRowPin' || columnId === 'actions' || columnId === this.actionColumnInfo()?.columnId) {
8002
+ return false;
8003
+ }
8004
+ return true;
8005
+ }
8006
+ _isIgnoredCellSelectionTarget(target) {
8007
+ if (!(target instanceof HTMLElement)) {
8008
+ return false;
8009
+ }
8010
+ return !!target.closest('button, input, textarea, select, [contenteditable="true"], z-input, z-select, z-calendar, z-checkbox, z-switch');
8011
+ }
8012
+ _isCellSelectionDragTarget(target) {
8013
+ if (this._document.body.classList.contains('z-table-pointer-dragging')) {
8014
+ return true;
8015
+ }
8016
+ if (!(target instanceof HTMLElement)) {
8017
+ return false;
8018
+ }
8019
+ return !!target.closest('[data-z-table-drag-handle]');
8020
+ }
8021
+ _formatCellClipboardValue(value) {
8022
+ if (value === null || value === undefined) {
8023
+ return '';
8024
+ }
8025
+ return String(value).replace(/\r?\n/g, ' ');
8026
+ }
8027
+ _getColumnCopyHeader(columnId) {
8028
+ const columnConfig = this._findColumnConfig(columnId);
8029
+ const header = columnConfig?.header;
8030
+ if (typeof header === 'string') {
8031
+ return this._zTranslate.instant(header);
8032
+ }
8033
+ if (header && typeof header === 'object' && 'content' in header && typeof header.content === 'string') {
8034
+ return this._zTranslate.instant(header.content);
8035
+ }
8036
+ return columnId;
8037
+ }
8038
+ async _writeClipboardText(text) {
8039
+ if (navigator.clipboard?.writeText) {
8040
+ await navigator.clipboard.writeText(text);
8041
+ return;
8042
+ }
8043
+ const { activeElement } = this._document;
8044
+ const textarea = this._document.createElement('textarea');
8045
+ textarea.value = text;
8046
+ textarea.style.position = 'fixed';
8047
+ textarea.style.left = '-9999px';
8048
+ this._document.body.append(textarea);
8049
+ textarea.select();
8050
+ this._document.execCommand('copy');
8051
+ textarea.remove();
8052
+ if (activeElement instanceof HTMLElement) {
8053
+ activeElement.focus();
8054
+ }
8055
+ }
7456
8056
  _getContentEditTriggerTarget(target) {
7457
8057
  if (!(target instanceof HTMLElement)) {
7458
8058
  return null;
@@ -7798,10 +8398,110 @@ class ZTableComponent {
7798
8398
  }
7799
8399
  this.openSettingsDrawer();
7800
8400
  }
8401
+ autosizeColumn(columnId) {
8402
+ const width = this._measureColumnContentWidth(columnId);
8403
+ if (!width) {
8404
+ return;
8405
+ }
8406
+ this._setMeasuredColumnWidth(columnId, width);
8407
+ }
8408
+ autosizeAllColumns() {
8409
+ const nextSizing = { ...this._columnBaseSizing() };
8410
+ let changed = false;
8411
+ for (const column of this.table.getAllLeafColumns()) {
8412
+ if (!column.getIsVisible()) {
8413
+ continue;
8414
+ }
8415
+ const width = this._measureColumnContentWidth(column.id);
8416
+ if (!width) {
8417
+ continue;
8418
+ }
8419
+ nextSizing[column.id] = width;
8420
+ changed = true;
8421
+ }
8422
+ if (!changed) {
8423
+ return;
8424
+ }
8425
+ const clampedSizing = this._clampColumnSizing(nextSizing);
8426
+ this._columnBaseSizing.set(clampedSizing);
8427
+ this.columnSizingState.set(clampedSizing);
8428
+ this._checkHorizontalScroll();
8429
+ }
8430
+ resetColumns() {
8431
+ const key = this.zKey();
8432
+ if (key) {
8433
+ ZCacheService.delete(this._getConfigCacheKey(key));
8434
+ this._skipNextConfigSave = true;
8435
+ }
8436
+ const config = this.zConfig();
8437
+ const nextOrder = this.table.getAllLeafColumns().map(column => column.id);
8438
+ const nextVisibility = config.initialState?.columnVisibility ?? {};
8439
+ const nextPinning = this._defaultColumnPinning();
8440
+ this.columnOrder.set(nextOrder);
8441
+ this.columnVisibility.set(nextVisibility);
8442
+ this._setColumnPinning(nextPinning);
8443
+ this._columnBaseSizing.set({});
8444
+ this.columnSizingState.set({});
8445
+ this.showHeaderFooterShadow.set(config.showHeaderShadow ?? config.showFooterShadow ?? true);
8446
+ this.showHorizontalBorder.set(config.showHorizontalBorder ?? true);
8447
+ this.showVerticalBorder.set(config.showVerticalBorder ?? true);
8448
+ this.pendingVisibleColumns.set(this.table
8449
+ .getAllLeafColumns()
8450
+ .filter(column => nextVisibility[column.id] !== false)
8451
+ .map(column => column.id));
8452
+ this.pendingColumnOrder.set(nextOrder);
8453
+ this._scheduleFitColumnWidths();
8454
+ }
7801
8455
  _isColumnHiddenFromVisibilityMenu(columnId) {
7802
8456
  const actionColumnId = this.actionColumnInfo()?.columnId;
7803
8457
  return this._isSpecialColumnId(columnId) || columnId === actionColumnId;
7804
8458
  }
8459
+ _setMeasuredColumnWidth(columnId, measuredWidth) {
8460
+ const nextSizing = this._clampColumnSizing({
8461
+ ...this._columnBaseSizing(),
8462
+ [columnId]: measuredWidth,
8463
+ });
8464
+ this._columnBaseSizing.set(nextSizing);
8465
+ this.columnSizingState.set(nextSizing);
8466
+ this._checkHorizontalScroll();
8467
+ }
8468
+ _measureColumnContentWidth(columnId) {
8469
+ const host = this._host.nativeElement;
8470
+ const cells = host.querySelectorAll(`[id="${CSS.escape(columnId)}"], [data-column-id="${CSS.escape(columnId)}"]`);
8471
+ if (cells.length === 0) {
8472
+ return null;
8473
+ }
8474
+ let width = 0;
8475
+ for (let index = 0; index < cells.length; index++) {
8476
+ const cell = cells.item(index);
8477
+ width = Math.max(width, Math.ceil(cell.scrollWidth));
8478
+ }
8479
+ if (width <= 0) {
8480
+ return null;
8481
+ }
8482
+ return width + 24;
8483
+ }
8484
+ _defaultColumnPinning() {
8485
+ const initialPinning = this.zConfig().initialState?.columnPinning;
8486
+ const left = [...(initialPinning?.left ?? [])];
8487
+ const right = [...(initialPinning?.right ?? [])];
8488
+ const collectPinnedColumns = (columns) => {
8489
+ for (const column of columns) {
8490
+ const isPinned = left.includes(column.id) || right.includes(column.id);
8491
+ if (column.pinned === 'left' && !isPinned) {
8492
+ left.push(column.id);
8493
+ }
8494
+ if (column.pinned === 'right' && !isPinned) {
8495
+ right.push(column.id);
8496
+ }
8497
+ if (column.columns) {
8498
+ collectPinnedColumns(column.columns);
8499
+ }
8500
+ }
8501
+ };
8502
+ collectPinnedColumns(this.zConfig().columns ?? []);
8503
+ return { left, right };
8504
+ }
7805
8505
  _setColumnPinning(pinning) {
7806
8506
  const fixedColumnPinning = this._fixedColumnPinning();
7807
8507
  const currentPinning = this.columnPinning();
@@ -7900,6 +8600,10 @@ class ZTableComponent {
7900
8600
  if (!key) {
7901
8601
  return;
7902
8602
  }
8603
+ if (this._skipNextConfigSave) {
8604
+ this._skipNextConfigSave = false;
8605
+ return;
8606
+ }
7903
8607
  const columnInfo = this._collectColumnInfo();
7904
8608
  const config = {
7905
8609
  columnOrder: this.columnOrder(),
@@ -8154,12 +8858,11 @@ class ZTableComponent {
8154
8858
  return result;
8155
8859
  }
8156
8860
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8157
- 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: "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 [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() ? 0 : null\"\n (keydown)=\"onContentTableKeydown($event)\">\n <ng-template #contentRowMenuContent>\n <div class=\"flex min-w-44 flex-col gap-1 p-1\">\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\"\n (click)=\"copyContentRows()\">\n <z-icon zType=\"lucideCopy\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_copy_row' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"contentRowClipboard().length === 0\"\n (click)=\"pasteContentRows('below')\">\n <z-icon zType=\"lucideClipboardPaste\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_paste_row_below' | translate }}</span>\n </button>\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canMoveContentRowUp()\"\n (click)=\"moveContentRow('up')\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"14\" />\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 flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canMoveContentRowDown()\"\n (click)=\"moveContentRow('down')\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_row_down' | translate }}</span>\n </button>\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\"\n (click)=\"insertContentRow('above')\">\n <z-icon zType=\"lucideArrowUpToLine\" zSize=\"14\" />\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 flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\"\n (click)=\"insertContentRow('below')\">\n <z-icon zType=\"lucideArrowDownToLine\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_insert_row_below' | translate }}</span>\n </button>\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n class=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\"\n (click)=\"deleteContentRows()\">\n <z-icon zType=\"lucideTrash2\" zSize=\"14\" />\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 <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 <!-- 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]=\"table.getTotalSize()\">\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]=\"table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\"\n (zChange)=\"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 p-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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm 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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm 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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\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=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (hideableColumns().length > 0) {\n @if (effectiveEnableOrdering || (header.column.getCanPin() && effectiveEnablePinning)) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (zConfig().enableSettings) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover, colVisPopover)\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\n <z-icon zType=\"lucideSettings\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_configure_table' | translate }}\n </span>\n </button>\n }\n <button\n type=\"button\"\n #colVisPopover=\"zPopover\"\n z-popover\n [zPopoverContent]=\"colVisPopoverContent\"\n zTrigger=\"hover\"\n [zShowDelay]=\"150\"\n [zHideDelay]=\"150\"\n [zManualClose]=\"true\"\n [zOutsideClickClose]=\"true\"\n zPosition=\"right\"\n [zOffset]=\"6\"\n (zShow)=\"setActiveColumnVisibilityPopover(colVisPopover)\"\n (zHide)=\"clearActiveColumnVisibilityPopover(colVisPopover)\"\n class=\"text-foreground hover:bg-muted data-[state=open]:bg-muted flex w-full cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm outline-none\">\n <z-icon zType=\"lucideEye\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"flex-1 text-left\">\n {{ 'i18n_z_ui_table_show_hide_columns' | translate }}\n </span>\n <z-icon zType=\"lucideChevronRight\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n </button>\n <ng-template #colVisPopoverContent>\n <div class=\"flex max-h-72 flex-col gap-0.5 overflow-y-auto p-1\" style=\"min-width: 180px\">\n @for (col of hideableColumns(); track col.id) {\n <button\n type=\"button\"\n (click)=\"\n toggleColumnVisibility(col.id);\n refreshColumnPopoverPositions(colOptionsPopover, colVisPopover)\n \"\n class=\"hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\"\n [class.text-foreground]=\"col.getIsVisible()\"\n [class.text-muted-foreground]=\"!col.getIsVisible()\">\n @if (col.getIsVisible()) {\n <z-icon zType=\"lucideCheck\" zSize=\"14\" class=\"text-primary shrink-0\" />\n } @else {\n <span class=\"inline-flex w-3.5 shrink-0\"></span>\n }\n <span class=\"truncate\">{{ col.id | zTableColumnHeader: zConfig().columns }}</span>\n </button>\n }\n </div>\n </ng-template>\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 ((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 [ngClass]=\"\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 [ngClass]=\"\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 [ngClass]=\"\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 @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]=\"table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\"\n (zChange)=\"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 p-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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm 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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm 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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\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=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (hideableColumns().length > 0) {\n @if (effectiveEnableOrdering || (header.column.getCanPin() && effectiveEnablePinning)) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (zConfig().enableSettings) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover, colVisPopover)\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\n <z-icon zType=\"lucideSettings\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_configure_table' | translate }}\n </span>\n </button>\n }\n <button\n type=\"button\"\n #colVisPopover=\"zPopover\"\n z-popover\n [zPopoverContent]=\"colVisPopoverContent\"\n zTrigger=\"hover\"\n [zShowDelay]=\"150\"\n [zHideDelay]=\"150\"\n [zManualClose]=\"true\"\n [zOutsideClickClose]=\"true\"\n zPosition=\"right\"\n [zOffset]=\"6\"\n (zShow)=\"setActiveColumnVisibilityPopover(colVisPopover)\"\n (zHide)=\"clearActiveColumnVisibilityPopover(colVisPopover)\"\n class=\"text-foreground hover:bg-muted data-[state=open]:bg-muted flex w-full cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm outline-none\">\n <z-icon zType=\"lucideEye\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"flex-1 text-left\">\n {{ 'i18n_z_ui_table_show_hide_columns' | translate }}\n </span>\n <z-icon zType=\"lucideChevronRight\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n </button>\n <ng-template #colVisPopoverContent>\n <div class=\"flex max-h-72 flex-col gap-0.5 overflow-y-auto p-1\" style=\"min-width: 180px\">\n @for (col of hideableColumns(); track col.id) {\n <button\n type=\"button\"\n (click)=\"\n toggleColumnVisibility(col.id);\n refreshColumnPopoverPositions(colOptionsPopover, colVisPopover)\n \"\n class=\"hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\"\n [class.text-foreground]=\"col.getIsVisible()\"\n [class.text-muted-foreground]=\"!col.getIsVisible()\">\n @if (col.getIsVisible()) {\n <z-icon zType=\"lucideCheck\" zSize=\"14\" class=\"text-primary shrink-0\" />\n } @else {\n <span class=\"inline-flex w-3.5 shrink-0\"></span>\n }\n <span class=\"truncate\">{{ col.id | zTableColumnHeader: zConfig().columns }}</span>\n </button>\n }\n </div>\n </ng-template>\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 ((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 [ngClass]=\"\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 [ngClass]=\"\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 [ngClass]=\"\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 @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]=\"table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\"\n (zChange)=\"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 p-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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm 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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm 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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\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=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (hideableColumns().length > 0) {\n @if (effectiveEnableOrdering || (header.column.getCanPin() && effectiveEnablePinning)) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (zConfig().enableSettings) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover, colVisPopover)\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\n <z-icon zType=\"lucideSettings\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_configure_table' | translate }}\n </span>\n </button>\n }\n <button\n type=\"button\"\n #colVisPopover=\"zPopover\"\n z-popover\n [zPopoverContent]=\"colVisPopoverContent\"\n zTrigger=\"hover\"\n [zShowDelay]=\"150\"\n [zHideDelay]=\"150\"\n [zManualClose]=\"true\"\n [zOutsideClickClose]=\"true\"\n zPosition=\"right\"\n [zOffset]=\"6\"\n (zShow)=\"setActiveColumnVisibilityPopover(colVisPopover)\"\n (zHide)=\"clearActiveColumnVisibilityPopover(colVisPopover)\"\n class=\"text-foreground hover:bg-muted data-[state=open]:bg-muted flex w-full cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm outline-none\">\n <z-icon zType=\"lucideEye\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"flex-1 text-left\">\n {{ 'i18n_z_ui_table_show_hide_columns' | translate }}\n </span>\n <z-icon zType=\"lucideChevronRight\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n </button>\n <ng-template #colVisPopoverContent>\n <div class=\"flex max-h-72 flex-col gap-0.5 overflow-y-auto p-1\" style=\"min-width: 180px\">\n @for (col of hideableColumns(); track col.id) {\n <button\n type=\"button\"\n (click)=\"\n toggleColumnVisibility(col.id);\n refreshColumnPopoverPositions(colOptionsPopover, colVisPopover)\n \"\n class=\"hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\"\n [class.text-foreground]=\"col.getIsVisible()\"\n [class.text-muted-foreground]=\"!col.getIsVisible()\">\n @if (col.getIsVisible()) {\n <z-icon zType=\"lucideCheck\" zSize=\"14\" class=\"text-primary shrink-0\" />\n } @else {\n <span class=\"inline-flex w-3.5 shrink-0\"></span>\n }\n <span class=\"truncate\">{{ col.id | zTableColumnHeader: zConfig().columns }}</span>\n </button>\n }\n </div>\n </ng-template>\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 ((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 [ngClass]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\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 [ngClass]=\"\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 [ngClass]=\"\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 <!-- 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]=\"table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\"\n (zChange)=\"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 p-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 flex min-h-8 cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-[0.9375rem] 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 flex min-h-8 cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-[0.9375rem] 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 flex min-h-8 cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-[0.9375rem] 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 flex min-h-8 cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-[0.9375rem] 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 flex min-h-8 cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-[0.9375rem] outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (hideableColumns().length > 0) {\n @if (effectiveEnableOrdering || (header.column.getCanPin() && effectiveEnablePinning)) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (zConfig().enableSettings) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover, colVisPopover)\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\n <z-icon zType=\"lucideSettings\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_configure_table' | translate }}\n </span>\n </button>\n }\n <button\n type=\"button\"\n #colVisPopover=\"zPopover\"\n z-popover\n [zPopoverContent]=\"colVisPopoverContent\"\n zTrigger=\"hover\"\n [zShowDelay]=\"150\"\n [zHideDelay]=\"150\"\n [zManualClose]=\"true\"\n [zOutsideClickClose]=\"true\"\n zPosition=\"right\"\n [zOffset]=\"6\"\n (zShow)=\"setActiveColumnVisibilityPopover(colVisPopover)\"\n (zHide)=\"clearActiveColumnVisibilityPopover(colVisPopover)\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted data-[state=open]:bg-muted flex min-h-8 w-full cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-[0.9375rem] outline-none\">\n <z-icon zType=\"lucideEye\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"flex-1 text-left\">\n {{ 'i18n_z_ui_table_show_hide_columns' | translate }}\n </span>\n <z-icon zType=\"lucideChevronRight\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n </button>\n <ng-template #colVisPopoverContent>\n <div\n class=\"flex max-h-72 flex-col gap-0.5 overflow-y-auto p-1\"\n style=\"min-width: 180px\">\n @for (col of hideableColumns(); track col.id) {\n <button\n type=\"button\"\n (click)=\"\n toggleColumnVisibility(col.id);\n refreshColumnPopoverPositions(colOptionsPopover, colVisPopover)\n \"\n class=\"z-column-menu-item hover:bg-muted focus:bg-muted flex min-h-8 cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-[0.9375rem] outline-none\"\n [class.text-foreground]=\"col.getIsVisible()\"\n [class.text-muted-foreground]=\"!col.getIsVisible()\">\n @if (col.getIsVisible()) {\n <z-icon zType=\"lucideCheck\" zSize=\"15\" class=\"text-primary shrink-0\" />\n } @else {\n <span class=\"inline-flex w-[15px] shrink-0\"></span>\n }\n <span class=\"truncate\">{{ col.id | zTableColumnHeader: zConfig().columns }}</span>\n </button>\n }\n </div>\n </ng-template>\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 ((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 [ngClass]=\"\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 [ngClass]=\"\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 [ngClass]=\"\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 <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]=\"table.getTotalSize()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n @for (row of groupRows; track row.id) {\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = row.getIsSelected();\n @let rowSomeSelected = 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-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 <td\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnSizingInfo()\n \"\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-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"\n cell | zTableCellBottom: zConfig().columns : table.getRowModel().rows\n \"\n [attr.rowspan]=\"\n cell | zTableSpan: zConfig().columns : 'cellRowSpan' : table.getRowModel().rows\n \"\n [attr.colspan]=\"cell | zTableSpan: zConfig().columns : 'cellColSpan'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\">\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]=\"cell.row.getIsSelected()\"\n [zIndeterminate]=\"cell.row.getIsSomeSelected() && !cell.row.getIsSelected()\"\n [zDisabled]=\"!cell.row.getCanSelect()\"\n (zChange)=\"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 [ngClass]=\"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 [ngClass]=\"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 [ngClass]=\"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 <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"table.getTotalSize()\">\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>\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = row.getIsSelected();\n @let rowSomeSelected = 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-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 <td\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-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"cell | zTableCellBottom: zConfig().columns : table.getRowModel().rows\"\n [attr.rowspan]=\"cell | zTableSpan: zConfig().columns : 'cellRowSpan' : table.getRowModel().rows\"\n [attr.colspan]=\"cell | zTableSpan: zConfig().columns : 'cellColSpan'\">\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]=\"cell.row.getIsSelected()\"\n [zIndeterminate]=\"cell.row.getIsSomeSelected() && !cell.row.getIsSelected()\"\n [zDisabled]=\"!cell.row.getCanSelect()\"\n (zChange)=\"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 [ngClass]=\"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 [ngClass]=\"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 [ngClass]=\"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 (row of table.getCenterRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\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]=\"table.getTotalSize()\">\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 [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 [ngClass]=\"\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 [ngClass]=\"\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 [ngClass]=\"\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 [ngClass]=\"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 canPin = column?.getCanPin() !== false && zConfig().enableColumnPinning;\n @if (!isPinned) {\n <div\n cdkDrag\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-grab items-center gap-2 rounded border px-2 py-1.5 text-sm active:cursor-grabbing\"\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 cursor-grab active:cursor-grabbing\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n (mousedown)=\"$event.stopPropagation()\"\n class=\"border-input h-4 w-4 shrink-0 cursor-pointer rounded\" />\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\"\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\"\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 <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 (change)=\"onToggleColumnVisibility(columnId)\"\n class=\"border-input h-4 w-4 shrink-0 cursor-pointer rounded\" />\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 (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\"\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:hidden;--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.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:2px solid var(--primary);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--primary) 15%,transparent);content:\"\";pointer-events:none}.z-tfoot-wrapper{flex-shrink:0;width:100%;max-width:100%;min-width:0;background:var(--muted);overflow-x:hidden;overflow-y:hidden;touch-action:pan-y pinch-zoom}.z-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}: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.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:none}.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}.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: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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"], 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 });
8861
+ 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: "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 [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() ? 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]=\"table.getTotalSize()\">\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 <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 ((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 <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 ((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 <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 ((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 <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 ((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 <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]=\"table.getTotalSize()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\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-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]=\"\n cell | zTableCellBottom: zConfig().columns : table.getRowModel().rows\n \"\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 <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"table.getTotalSize()\">\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>\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-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 : table.getRowModel().rows\"\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 (row of table.getCenterRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\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]=\"table.getTotalSize()\">\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 canPin = column?.getCanPin() !== false && zConfig().enableColumnPinning;\n @if (!isPinned) {\n <div\n cdkDrag\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-grab items-center gap-2 rounded border px-2 py-1.5 text-sm active:cursor-grabbing\"\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 cursor-grab active:cursor-grabbing\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n (mousedown)=\"$event.stopPropagation()\"\n class=\"border-input h-4 w-4 shrink-0 cursor-pointer rounded\" />\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\"\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\"\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 <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 (change)=\"onToggleColumnVisibility(columnId)\"\n class=\"border-input h-4 w-4 shrink-0 cursor-pointer rounded\" />\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 (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\"\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-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}td.z-cell-range-selected:before{position:absolute;z-index:2;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:color-mix(in srgb,var(--primary) 11%,var(--card));content:\"\";pointer-events:none}td.z-cell-range-selected>*{position:relative;z-index:3}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:color-mix(in srgb,var(--primary) 11%,var(--card))!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}: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.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:none}.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:color-mix(in srgb,var(--primary) 11%,var(--card))!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}.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 });
8158
8862
  }
8159
8863
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImport: i0, type: ZTableComponent, decorators: [{
8160
8864
  type: Component,
8161
8865
  args: [{ selector: 'z-table', imports: [
8162
- NgClass,
8163
8866
  NgStyle,
8164
8867
  NgTemplateOutlet,
8165
8868
  OverlayModule,
@@ -8212,7 +8915,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.9", ngImpor
8212
8915
  TranslatePipe,
8213
8916
  ], standalone: true, providers: [TranslatePipe, ZTableDragService], changeDetection: ChangeDetectionStrategy.OnPush, host: {
8214
8917
  class: 'z-table block relative py-1',
8215
- }, 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 [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() ? 0 : null\"\n (keydown)=\"onContentTableKeydown($event)\">\n <ng-template #contentRowMenuContent>\n <div class=\"flex min-w-44 flex-col gap-1 p-1\">\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\"\n (click)=\"copyContentRows()\">\n <z-icon zType=\"lucideCopy\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_copy_row' | translate }}</span>\n </button>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"contentRowClipboard().length === 0\"\n (click)=\"pasteContentRows('below')\">\n <z-icon zType=\"lucideClipboardPaste\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_paste_row_below' | translate }}</span>\n </button>\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canMoveContentRowUp()\"\n (click)=\"moveContentRow('up')\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"14\" />\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 flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canMoveContentRowDown()\"\n (click)=\"moveContentRow('down')\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_row_down' | translate }}</span>\n </button>\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\"\n (click)=\"insertContentRow('above')\">\n <z-icon zType=\"lucideArrowUpToLine\" zSize=\"14\" />\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 flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\"\n (click)=\"insertContentRow('below')\">\n <z-icon zType=\"lucideArrowDownToLine\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_insert_row_below' | translate }}</span>\n </button>\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n class=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\"\n (click)=\"deleteContentRows()\">\n <z-icon zType=\"lucideTrash2\" zSize=\"14\" />\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 <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 <!-- 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]=\"table.getTotalSize()\">\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]=\"table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\"\n (zChange)=\"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 p-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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm 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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm 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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\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=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (hideableColumns().length > 0) {\n @if (effectiveEnableOrdering || (header.column.getCanPin() && effectiveEnablePinning)) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (zConfig().enableSettings) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover, colVisPopover)\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\n <z-icon zType=\"lucideSettings\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_configure_table' | translate }}\n </span>\n </button>\n }\n <button\n type=\"button\"\n #colVisPopover=\"zPopover\"\n z-popover\n [zPopoverContent]=\"colVisPopoverContent\"\n zTrigger=\"hover\"\n [zShowDelay]=\"150\"\n [zHideDelay]=\"150\"\n [zManualClose]=\"true\"\n [zOutsideClickClose]=\"true\"\n zPosition=\"right\"\n [zOffset]=\"6\"\n (zShow)=\"setActiveColumnVisibilityPopover(colVisPopover)\"\n (zHide)=\"clearActiveColumnVisibilityPopover(colVisPopover)\"\n class=\"text-foreground hover:bg-muted data-[state=open]:bg-muted flex w-full cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm outline-none\">\n <z-icon zType=\"lucideEye\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"flex-1 text-left\">\n {{ 'i18n_z_ui_table_show_hide_columns' | translate }}\n </span>\n <z-icon zType=\"lucideChevronRight\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n </button>\n <ng-template #colVisPopoverContent>\n <div class=\"flex max-h-72 flex-col gap-0.5 overflow-y-auto p-1\" style=\"min-width: 180px\">\n @for (col of hideableColumns(); track col.id) {\n <button\n type=\"button\"\n (click)=\"\n toggleColumnVisibility(col.id);\n refreshColumnPopoverPositions(colOptionsPopover, colVisPopover)\n \"\n class=\"hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\"\n [class.text-foreground]=\"col.getIsVisible()\"\n [class.text-muted-foreground]=\"!col.getIsVisible()\">\n @if (col.getIsVisible()) {\n <z-icon zType=\"lucideCheck\" zSize=\"14\" class=\"text-primary shrink-0\" />\n } @else {\n <span class=\"inline-flex w-3.5 shrink-0\"></span>\n }\n <span class=\"truncate\">{{ col.id | zTableColumnHeader: zConfig().columns }}</span>\n </button>\n }\n </div>\n </ng-template>\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 ((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 [ngClass]=\"\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 [ngClass]=\"\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 [ngClass]=\"\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 @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]=\"table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\"\n (zChange)=\"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 p-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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm 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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm 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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\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=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (hideableColumns().length > 0) {\n @if (effectiveEnableOrdering || (header.column.getCanPin() && effectiveEnablePinning)) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (zConfig().enableSettings) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover, colVisPopover)\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\n <z-icon zType=\"lucideSettings\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_configure_table' | translate }}\n </span>\n </button>\n }\n <button\n type=\"button\"\n #colVisPopover=\"zPopover\"\n z-popover\n [zPopoverContent]=\"colVisPopoverContent\"\n zTrigger=\"hover\"\n [zShowDelay]=\"150\"\n [zHideDelay]=\"150\"\n [zManualClose]=\"true\"\n [zOutsideClickClose]=\"true\"\n zPosition=\"right\"\n [zOffset]=\"6\"\n (zShow)=\"setActiveColumnVisibilityPopover(colVisPopover)\"\n (zHide)=\"clearActiveColumnVisibilityPopover(colVisPopover)\"\n class=\"text-foreground hover:bg-muted data-[state=open]:bg-muted flex w-full cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm outline-none\">\n <z-icon zType=\"lucideEye\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"flex-1 text-left\">\n {{ 'i18n_z_ui_table_show_hide_columns' | translate }}\n </span>\n <z-icon zType=\"lucideChevronRight\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n </button>\n <ng-template #colVisPopoverContent>\n <div class=\"flex max-h-72 flex-col gap-0.5 overflow-y-auto p-1\" style=\"min-width: 180px\">\n @for (col of hideableColumns(); track col.id) {\n <button\n type=\"button\"\n (click)=\"\n toggleColumnVisibility(col.id);\n refreshColumnPopoverPositions(colOptionsPopover, colVisPopover)\n \"\n class=\"hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\"\n [class.text-foreground]=\"col.getIsVisible()\"\n [class.text-muted-foreground]=\"!col.getIsVisible()\">\n @if (col.getIsVisible()) {\n <z-icon zType=\"lucideCheck\" zSize=\"14\" class=\"text-primary shrink-0\" />\n } @else {\n <span class=\"inline-flex w-3.5 shrink-0\"></span>\n }\n <span class=\"truncate\">{{ col.id | zTableColumnHeader: zConfig().columns }}</span>\n </button>\n }\n </div>\n </ng-template>\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 ((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 [ngClass]=\"\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 [ngClass]=\"\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 [ngClass]=\"\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 @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]=\"table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\"\n (zChange)=\"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 p-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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm 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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm 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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\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=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\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=\"text-destructive hover:bg-destructive/10 flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (hideableColumns().length > 0) {\n @if (effectiveEnableOrdering || (header.column.getCanPin() && effectiveEnablePinning)) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (zConfig().enableSettings) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover, colVisPopover)\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\n <z-icon zType=\"lucideSettings\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_configure_table' | translate }}\n </span>\n </button>\n }\n <button\n type=\"button\"\n #colVisPopover=\"zPopover\"\n z-popover\n [zPopoverContent]=\"colVisPopoverContent\"\n zTrigger=\"hover\"\n [zShowDelay]=\"150\"\n [zHideDelay]=\"150\"\n [zManualClose]=\"true\"\n [zOutsideClickClose]=\"true\"\n zPosition=\"right\"\n [zOffset]=\"6\"\n (zShow)=\"setActiveColumnVisibilityPopover(colVisPopover)\"\n (zHide)=\"clearActiveColumnVisibilityPopover(colVisPopover)\"\n class=\"text-foreground hover:bg-muted data-[state=open]:bg-muted flex w-full cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm outline-none\">\n <z-icon zType=\"lucideEye\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"flex-1 text-left\">\n {{ 'i18n_z_ui_table_show_hide_columns' | translate }}\n </span>\n <z-icon zType=\"lucideChevronRight\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n </button>\n <ng-template #colVisPopoverContent>\n <div class=\"flex max-h-72 flex-col gap-0.5 overflow-y-auto p-1\" style=\"min-width: 180px\">\n @for (col of hideableColumns(); track col.id) {\n <button\n type=\"button\"\n (click)=\"\n toggleColumnVisibility(col.id);\n refreshColumnPopoverPositions(colOptionsPopover, colVisPopover)\n \"\n class=\"hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\"\n [class.text-foreground]=\"col.getIsVisible()\"\n [class.text-muted-foreground]=\"!col.getIsVisible()\">\n @if (col.getIsVisible()) {\n <z-icon zType=\"lucideCheck\" zSize=\"14\" class=\"text-primary shrink-0\" />\n } @else {\n <span class=\"inline-flex w-3.5 shrink-0\"></span>\n }\n <span class=\"truncate\">{{ col.id | zTableColumnHeader: zConfig().columns }}</span>\n </button>\n }\n </div>\n </ng-template>\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 ((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 [ngClass]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\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 [ngClass]=\"\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 [ngClass]=\"\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 <!-- 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]=\"table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\"\n (zChange)=\"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 p-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 flex min-h-8 cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-[0.9375rem] 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 flex min-h-8 cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-[0.9375rem] 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 flex min-h-8 cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-[0.9375rem] 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 flex min-h-8 cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-[0.9375rem] 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 flex min-h-8 cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-[0.9375rem] outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (hideableColumns().length > 0) {\n @if (effectiveEnableOrdering || (header.column.getCanPin() && effectiveEnablePinning)) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (zConfig().enableSettings) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"openSettingsDrawerFromColumnMenu(colOptionsPopover, colVisPopover)\"\n class=\"text-foreground hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm\">\n <z-icon zType=\"lucideSettings\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_configure_table' | translate }}\n </span>\n </button>\n }\n <button\n type=\"button\"\n #colVisPopover=\"zPopover\"\n z-popover\n [zPopoverContent]=\"colVisPopoverContent\"\n zTrigger=\"hover\"\n [zShowDelay]=\"150\"\n [zHideDelay]=\"150\"\n [zManualClose]=\"true\"\n [zOutsideClickClose]=\"true\"\n zPosition=\"right\"\n [zOffset]=\"6\"\n (zShow)=\"setActiveColumnVisibilityPopover(colVisPopover)\"\n (zHide)=\"clearActiveColumnVisibilityPopover(colVisPopover)\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted data-[state=open]:bg-muted flex min-h-8 w-full cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-[0.9375rem] outline-none\">\n <z-icon zType=\"lucideEye\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"flex-1 text-left\">\n {{ 'i18n_z_ui_table_show_hide_columns' | translate }}\n </span>\n <z-icon zType=\"lucideChevronRight\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n </button>\n <ng-template #colVisPopoverContent>\n <div\n class=\"flex max-h-72 flex-col gap-0.5 overflow-y-auto p-1\"\n style=\"min-width: 180px\">\n @for (col of hideableColumns(); track col.id) {\n <button\n type=\"button\"\n (click)=\"\n toggleColumnVisibility(col.id);\n refreshColumnPopoverPositions(colOptionsPopover, colVisPopover)\n \"\n class=\"z-column-menu-item hover:bg-muted focus:bg-muted flex min-h-8 cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-[0.9375rem] outline-none\"\n [class.text-foreground]=\"col.getIsVisible()\"\n [class.text-muted-foreground]=\"!col.getIsVisible()\">\n @if (col.getIsVisible()) {\n <z-icon zType=\"lucideCheck\" zSize=\"15\" class=\"text-primary shrink-0\" />\n } @else {\n <span class=\"inline-flex w-[15px] shrink-0\"></span>\n }\n <span class=\"truncate\">{{ col.id | zTableColumnHeader: zConfig().columns }}</span>\n </button>\n }\n </div>\n </ng-template>\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 ((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 [ngClass]=\"\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 [ngClass]=\"\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 [ngClass]=\"\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 <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]=\"table.getTotalSize()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n @for (row of groupRows; track row.id) {\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = row.getIsSelected();\n @let rowSomeSelected = 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-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 <td\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnSizingInfo()\n \"\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-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"\n cell | zTableCellBottom: zConfig().columns : table.getRowModel().rows\n \"\n [attr.rowspan]=\"\n cell | zTableSpan: zConfig().columns : 'cellRowSpan' : table.getRowModel().rows\n \"\n [attr.colspan]=\"cell | zTableSpan: zConfig().columns : 'cellColSpan'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\">\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]=\"cell.row.getIsSelected()\"\n [zIndeterminate]=\"cell.row.getIsSomeSelected() && !cell.row.getIsSelected()\"\n [zDisabled]=\"!cell.row.getCanSelect()\"\n (zChange)=\"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 [ngClass]=\"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 [ngClass]=\"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 [ngClass]=\"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 <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"table.getTotalSize()\">\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>\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = row.getIsSelected();\n @let rowSomeSelected = 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-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 <td\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-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"cell | zTableCellBottom: zConfig().columns : table.getRowModel().rows\"\n [attr.rowspan]=\"cell | zTableSpan: zConfig().columns : 'cellRowSpan' : table.getRowModel().rows\"\n [attr.colspan]=\"cell | zTableSpan: zConfig().columns : 'cellColSpan'\">\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]=\"cell.row.getIsSelected()\"\n [zIndeterminate]=\"cell.row.getIsSomeSelected() && !cell.row.getIsSelected()\"\n [zDisabled]=\"!cell.row.getCanSelect()\"\n (zChange)=\"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 [ngClass]=\"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 [ngClass]=\"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 [ngClass]=\"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 (row of table.getCenterRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\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]=\"table.getTotalSize()\">\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 [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 [ngClass]=\"\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 [ngClass]=\"\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 [ngClass]=\"\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 [ngClass]=\"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 canPin = column?.getCanPin() !== false && zConfig().enableColumnPinning;\n @if (!isPinned) {\n <div\n cdkDrag\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-grab items-center gap-2 rounded border px-2 py-1.5 text-sm active:cursor-grabbing\"\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 cursor-grab active:cursor-grabbing\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n (mousedown)=\"$event.stopPropagation()\"\n class=\"border-input h-4 w-4 shrink-0 cursor-pointer rounded\" />\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\"\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\"\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 <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 (change)=\"onToggleColumnVisibility(columnId)\"\n class=\"border-input h-4 w-4 shrink-0 cursor-pointer rounded\" />\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 (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\"\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:hidden;--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.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:2px solid var(--primary);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--primary) 15%,transparent);content:\"\";pointer-events:none}.z-tfoot-wrapper{flex-shrink:0;width:100%;max-width:100%;min-width:0;background:var(--muted);overflow-x:hidden;overflow-y:hidden;touch-action:pan-y pinch-zoom}.z-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}: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.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:none}.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}.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"] }]
8918
+ }, 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 [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() ? 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]=\"table.getTotalSize()\">\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 <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 ((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 <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 ((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 <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 ((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 <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 ((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 <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]=\"table.getTotalSize()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\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-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]=\"\n cell | zTableCellBottom: zConfig().columns : table.getRowModel().rows\n \"\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 <table [ngStyle]=\"columnSizeVars()\" [style.width.px]=\"table.getTotalSize()\">\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>\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-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 : table.getRowModel().rows\"\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 (row of table.getCenterRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\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]=\"table.getTotalSize()\">\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 canPin = column?.getCanPin() !== false && zConfig().enableColumnPinning;\n @if (!isPinned) {\n <div\n cdkDrag\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-grab items-center gap-2 rounded border px-2 py-1.5 text-sm active:cursor-grabbing\"\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 cursor-grab active:cursor-grabbing\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n (mousedown)=\"$event.stopPropagation()\"\n class=\"border-input h-4 w-4 shrink-0 cursor-pointer rounded\" />\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\"\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\"\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 <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 (change)=\"onToggleColumnVisibility(columnId)\"\n class=\"border-input h-4 w-4 shrink-0 cursor-pointer rounded\" />\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 (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\"\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-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}td.z-cell-range-selected:before{position:absolute;z-index:2;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:color-mix(in srgb,var(--primary) 11%,var(--card));content:\"\";pointer-events:none}td.z-cell-range-selected>*{position:relative;z-index:3}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:color-mix(in srgb,var(--primary) 11%,var(--card))!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}: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.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:none}.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:color-mix(in srgb,var(--primary) 11%,var(--card))!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}.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"] }]
8216
8919
  }], 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 }] }], 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 }] }] } });
8217
8920
 
8218
8921
  /**