@shival99/z-ui 2.4.9 → 2.4.11

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.
@@ -3306,6 +3306,7 @@ class ZTableDragService {
3306
3306
  _document = inject(DOCUMENT);
3307
3307
  _zone = inject(NgZone);
3308
3308
  _dropTargets = new Set();
3309
+ _dropTargetsByElement = new Map();
3309
3310
  _monitors = new Set();
3310
3311
  _scrollContainers = new Set();
3311
3312
  _session = null;
@@ -3333,16 +3334,22 @@ class ZTableDragService {
3333
3334
  target: null,
3334
3335
  edge: null,
3335
3336
  };
3336
- this._document.addEventListener('pointermove', this._handlePointerMove, true);
3337
- this._document.addEventListener('pointerup', this._handlePointerUp, true);
3338
- this._document.addEventListener('pointercancel', this._handlePointerCancel, true);
3339
- this._document.addEventListener('keydown', this._handleKeydown, true);
3340
- this._document.addEventListener('scroll', this._handleScroll, true);
3337
+ this._zone.runOutsideAngular(() => {
3338
+ this._document.addEventListener('pointermove', this._handlePointerMove, true);
3339
+ this._document.addEventListener('pointerup', this._handlePointerUp, true);
3340
+ this._document.addEventListener('pointercancel', this._handlePointerCancel, true);
3341
+ this._document.addEventListener('keydown', this._handleKeydown, true);
3342
+ this._document.addEventListener('scroll', this._handleScroll, true);
3343
+ });
3341
3344
  }
3342
3345
  registerDropTarget(target) {
3343
3346
  this._dropTargets.add(target);
3347
+ this._dropTargetsByElement.set(target.element, target);
3344
3348
  return () => {
3345
3349
  this._dropTargets.delete(target);
3350
+ if (this._dropTargetsByElement.get(target.element) === target) {
3351
+ this._dropTargetsByElement.delete(target.element);
3352
+ }
3346
3353
  if (this._session?.target === target) {
3347
3354
  this._clearTarget();
3348
3355
  }
@@ -3359,6 +3366,7 @@ class ZTableDragService {
3359
3366
  ngOnDestroy() {
3360
3367
  this._finish();
3361
3368
  this._dropTargets.clear();
3369
+ this._dropTargetsByElement.clear();
3362
3370
  this._monitors.clear();
3363
3371
  this._scrollContainers.clear();
3364
3372
  }
@@ -3377,14 +3385,21 @@ class ZTableDragService {
3377
3385
  if (!session.active) {
3378
3386
  this._activate(session);
3379
3387
  }
3380
- this._movePreview(session);
3381
- this._updateTarget();
3388
+ this._scheduleTargetRefresh();
3389
+ this._startAutoScroll();
3382
3390
  };
3383
3391
  _handlePointerUp = (event) => {
3384
3392
  const session = this._session;
3385
3393
  if (!session || event.pointerId !== session.pointerId) {
3386
3394
  return;
3387
3395
  }
3396
+ session.directionY = Math.sign(event.clientY - session.clientY);
3397
+ session.clientX = event.clientX;
3398
+ session.clientY = event.clientY;
3399
+ this._cancelTargetRefresh();
3400
+ if (session.active) {
3401
+ this._updateTarget();
3402
+ }
3388
3403
  if (session.active && session.target && session.edge) {
3389
3404
  const dropEvent = {
3390
3405
  source: session.source,
@@ -3410,14 +3425,23 @@ class ZTableDragService {
3410
3425
  }
3411
3426
  };
3412
3427
  _handleScroll = () => {
3413
- if (!this._session?.active || this._targetRefreshFrame !== null) {
3428
+ if (!this._session?.active) {
3429
+ return;
3430
+ }
3431
+ this._scheduleTargetRefresh();
3432
+ };
3433
+ _scheduleTargetRefresh() {
3434
+ if (this._targetRefreshFrame !== null) {
3414
3435
  return;
3415
3436
  }
3416
3437
  this._targetRefreshFrame = requestAnimationFrame(() => {
3417
3438
  this._targetRefreshFrame = null;
3439
+ if (this._session?.active) {
3440
+ this._movePreview(this._session);
3441
+ }
3418
3442
  this._updateTarget();
3419
3443
  });
3420
- };
3444
+ }
3421
3445
  _hasPassedThreshold(session) {
3422
3446
  return (Math.abs(session.clientX - session.startX) >= Z_TABLE_DRAG_THRESHOLD ||
3423
3447
  Math.abs(session.clientY - session.startY) >= Z_TABLE_DRAG_THRESHOLD);
@@ -3536,10 +3560,8 @@ class ZTableDragService {
3536
3560
  _findTarget(element, source) {
3537
3561
  let current = element;
3538
3562
  while (current instanceof HTMLElement) {
3539
- for (const target of this._dropTargets) {
3540
- if (target.element !== current || target.isDisabled()) {
3541
- continue;
3542
- }
3563
+ const target = this._dropTargetsByElement.get(current);
3564
+ if (target && !target.isDisabled()) {
3543
3565
  const data = target.getData();
3544
3566
  if (data.tableId === source.tableId && data.entity === source.entity && data.itemId !== source.itemId) {
3545
3567
  return target;
@@ -3673,23 +3695,34 @@ class ZTableDragService {
3673
3695
  }
3674
3696
  }
3675
3697
  _startAutoScroll() {
3676
- const tick = () => {
3698
+ if (this._autoScrollFrame !== null) {
3699
+ return;
3700
+ }
3701
+ this._autoScrollFrame = requestAnimationFrame(() => {
3702
+ this._autoScrollFrame = null;
3677
3703
  const session = this._session;
3678
3704
  if (!session?.active) {
3679
- this._autoScrollFrame = null;
3680
3705
  return;
3681
3706
  }
3682
3707
  const container = this._getScrollContainer(session.source);
3683
- if (container) {
3684
- const speed = this._getAutoScrollSpeed(container.element, session.clientY);
3685
- if (speed !== 0) {
3686
- container.element.scrollTop += speed;
3687
- this._updateTarget();
3688
- }
3708
+ if (!container) {
3709
+ return;
3689
3710
  }
3690
- this._autoScrollFrame = requestAnimationFrame(tick);
3691
- };
3692
- this._autoScrollFrame = requestAnimationFrame(tick);
3711
+ const speed = this._getAutoScrollSpeed(container.element, session.clientY);
3712
+ if (speed === 0) {
3713
+ return;
3714
+ }
3715
+ container.element.scrollTop += speed;
3716
+ this._scheduleTargetRefresh();
3717
+ this._startAutoScroll();
3718
+ });
3719
+ }
3720
+ _cancelTargetRefresh() {
3721
+ if (this._targetRefreshFrame === null) {
3722
+ return;
3723
+ }
3724
+ cancelAnimationFrame(this._targetRefreshFrame);
3725
+ this._targetRefreshFrame = null;
3693
3726
  }
3694
3727
  _getScrollContainer(source) {
3695
3728
  for (const container of this._scrollContainers) {
@@ -3727,6 +3760,11 @@ class ZTableDragService {
3727
3760
  }
3728
3761
  this._clearTarget();
3729
3762
  session.preview?.remove();
3763
+ if (session.active) {
3764
+ for (const cell of session.sourceElement.querySelectorAll('.z-row-hover')) {
3765
+ cell.classList.remove('z-row-hover');
3766
+ }
3767
+ }
3730
3768
  session.sourceElement.classList.remove('z-table-drag-source');
3731
3769
  this._document.body.classList.remove('z-table-pointer-dragging');
3732
3770
  this._removeDocumentListeners();
@@ -3734,10 +3772,7 @@ class ZTableDragService {
3734
3772
  cancelAnimationFrame(this._autoScrollFrame);
3735
3773
  this._autoScrollFrame = null;
3736
3774
  }
3737
- if (this._targetRefreshFrame !== null) {
3738
- cancelAnimationFrame(this._targetRefreshFrame);
3739
- this._targetRefreshFrame = null;
3740
- }
3775
+ this._cancelTargetRefresh();
3741
3776
  this._session = null;
3742
3777
  if (session.active) {
3743
3778
  this._zone.run(() => {
@@ -3856,8 +3891,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
3856
3891
  class ZTableRowHoverDirective {
3857
3892
  zTableRowHover = input(null, /* @ts-ignore */
3858
3893
  ...(ngDevMode ? [{ debugName: "zTableRowHover" }] : /* istanbul ignore next */ []));
3894
+ _document = inject(DOCUMENT);
3859
3895
  _elementRef = inject((ElementRef));
3896
+ _zone = inject(NgZone);
3860
3897
  _renderer = inject(Renderer2);
3898
+ _removeHoverListeners = null;
3899
+ _handleMouseEnter = () => {
3900
+ this.onMouseEnter();
3901
+ };
3902
+ _handleMouseLeave = () => {
3903
+ this.onMouseLeave();
3904
+ };
3905
+ ngOnInit() {
3906
+ const row = this._elementRef.nativeElement;
3907
+ this._zone.runOutsideAngular(() => {
3908
+ row.addEventListener('mouseenter', this._handleMouseEnter);
3909
+ row.addEventListener('mouseleave', this._handleMouseLeave);
3910
+ });
3911
+ this._removeHoverListeners = () => {
3912
+ row.removeEventListener('mouseenter', this._handleMouseEnter);
3913
+ row.removeEventListener('mouseleave', this._handleMouseLeave);
3914
+ this._removeHoverListeners = null;
3915
+ };
3916
+ }
3917
+ ngOnDestroy() {
3918
+ this._removeHoverListeners?.();
3919
+ }
3861
3920
  onMouseEnter() {
3862
3921
  this._handleHover(true);
3863
3922
  }
@@ -3865,6 +3924,9 @@ class ZTableRowHoverDirective {
3865
3924
  this._handleHover(false);
3866
3925
  }
3867
3926
  _handleHover(isHover) {
3927
+ if (this._document.body.classList.contains('z-table-pointer-dragging')) {
3928
+ return;
3929
+ }
3868
3930
  const row = this._elementRef.nativeElement;
3869
3931
  const table = this.zTableRowHover() || this._findParentTable(row);
3870
3932
  if (!table) {
@@ -3923,17 +3985,13 @@ class ZTableRowHoverDirective {
3923
3985
  return null;
3924
3986
  }
3925
3987
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ZTableRowHoverDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
3926
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.6", type: ZTableRowHoverDirective, isStandalone: true, selector: "[z-table-row-hover], [zTableRowHover]", inputs: { zTableRowHover: { classPropertyName: "zTableRowHover", publicName: "zTableRowHover", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()" } }, ngImport: i0 });
3988
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.6", type: ZTableRowHoverDirective, isStandalone: true, selector: "[z-table-row-hover], [zTableRowHover]", inputs: { zTableRowHover: { classPropertyName: "zTableRowHover", publicName: "zTableRowHover", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
3927
3989
  }
3928
3990
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ZTableRowHoverDirective, decorators: [{
3929
3991
  type: Directive,
3930
3992
  args: [{
3931
3993
  selector: '[z-table-row-hover], [zTableRowHover]',
3932
3994
  standalone: true,
3933
- host: {
3934
- '(mouseenter)': 'onMouseEnter()',
3935
- '(mouseleave)': 'onMouseLeave()',
3936
- },
3937
3995
  }]
3938
3996
  }], propDecorators: { zTableRowHover: [{ type: i0.Input, args: [{ isSignal: true, alias: "zTableRowHover", required: false }] }] } });
3939
3997
 
@@ -3952,13 +4010,13 @@ class ZTableResizeDirective {
3952
4010
  const element = this._elementRef.nativeElement;
3953
4011
  const header = this.zTableResize();
3954
4012
  this._mousedownHandler = (event) => {
3955
- this._ngZone.run(() => {
4013
+ this._ngZone.runOutsideAngular(() => {
3956
4014
  const resizeHandler = header.getResizeHandler();
3957
4015
  resizeHandler(event);
3958
4016
  });
3959
4017
  };
3960
4018
  this._touchstartHandler = (event) => {
3961
- this._ngZone.run(() => {
4019
+ this._ngZone.runOutsideAngular(() => {
3962
4020
  const resizeHandler = header.getResizeHandler();
3963
4021
  resizeHandler(event);
3964
4022
  });
@@ -11200,7 +11258,7 @@ class ZTableComponent {
11200
11258
  return result;
11201
11259
  }
11202
11260
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ZTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
11203
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ZTableComponent, isStandalone: true, selector: "z-table", inputs: { zClass: { classPropertyName: "zClass", publicName: "zClass", isSignal: true, isRequired: false, transformFunction: null }, zConfig: { classPropertyName: "zConfig", publicName: "zConfig", isSignal: true, isRequired: false, transformFunction: null }, zLoading: { classPropertyName: "zLoading", publicName: "zLoading", isSignal: true, isRequired: false, transformFunction: null }, zKey: { classPropertyName: "zKey", publicName: "zKey", isSignal: true, isRequired: false, transformFunction: null }, zVariant: { classPropertyName: "zVariant", publicName: "zVariant", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { zChange: "zChange", zControl: "zControl" }, host: { classAttribute: "z-table block relative py-1" }, providers: [TranslatePipe, ZTableDragService], viewQueries: [{ propertyName: "theadWrapper", first: true, predicate: ["theadWrapper"], descendants: true, isSignal: true }, { propertyName: "tableContainer", first: true, predicate: ["tableContainer"], descendants: true, isSignal: true }, { propertyName: "tbodyContainer", first: true, predicate: ["tbodyContainer"], descendants: true, isSignal: true }, { propertyName: "tbodyWrapper", first: true, predicate: ["tbodyWrapper"], descendants: true, isSignal: true }, { propertyName: "tbodyScrollbar", first: true, predicate: ["tbodyWrapper"], descendants: true, isSignal: true }, { propertyName: "tfootWrapper", first: true, predicate: ["tfootWrapper"], descendants: true, isSignal: true }, { propertyName: "expandedRowTemplate", first: true, predicate: ["expandedRowTemplate"], descendants: true, isSignal: true }, { propertyName: "virtualRowElements", predicate: ["virtualRow"], descendants: true, isSignal: true }, { propertyName: "groupRowElements", predicate: ["groupRow"], descendants: true, isSignal: true }, { propertyName: "bulkBarTemplateRef", first: true, predicate: ["bulkBarTemplate"], descendants: true, isSignal: true }], exportAs: ["zTable"], ngImport: i0, template: "<!-- Toolbar: Search & Settings -->\n@if (isSearchEnabled() || zConfig().enableSettings) {\n <div class=\"z-table-toolbar mb-2 flex items-center justify-between gap-4\">\n <!-- Search -->\n @if (isSearchEnabled()) {\n @let config = searchConfig();\n <z-input\n [class]=\"config?.width ?? 'w-64'\"\n [zSize]=\"config?.size ?? 'sm'\"\n [zPlaceholder]=\"config?.placeholder ?? 'i18n_z_ui_table_search' | translate\"\n [zSearch]=\"true\"\n [zDebounce]=\"config?.debounceTime ?? 300\"\n (zOnSearch)=\"onSearchChange($event)\" />\n } @else {\n <div></div>\n }\n\n <!-- Settings Button -->\n @if (zConfig().enableSettings) {\n <z-button zType=\"outline\" zSize=\"sm\" zTypeIcon=\"lucideSettings\" (click)=\"openSettingsDrawer()\">\n {{ 'i18n_z_ui_table_settings' | translate }}\n </z-button>\n }\n </div>\n}\n\n@if (zConfig().enableFilterHeader && appliedFilterChips().length > 0) {\n <div class=\"z-table-filter-header mb-2 flex min-w-0 items-center gap-2\">\n <div class=\"flex min-w-0 flex-1 flex-wrap items-center gap-1.5\">\n @for (chip of visibleAppliedFilterChips(); track chip.id) {\n <span\n class=\"border-border bg-muted/60 text-foreground inline-flex max-w-80 min-w-0 shrink-0 items-center gap-1 rounded-sm border px-2 py-1 text-[0.8125rem] shadow-xs\">\n <span class=\"font-medium whitespace-nowrap\">{{ chip.label }}</span>\n <span class=\"text-muted-foreground\">:</span>\n <span class=\"truncate\" z-tooltip [zContent]=\"chip.value\" zTooltipTrigger=\"hover\" zTooltipPosition=\"top\">\n {{ chip.value }}\n </span>\n <button\n type=\"button\"\n class=\"hover:bg-destructive/10 hover:text-destructive focus-visible:ring-ring -mr-1 inline-flex size-5 cursor-pointer items-center justify-center rounded-sm outline-none focus-visible:ring-2\"\n [attr.aria-label]=\"'i18n_z_ui_table_filter_remove' | translate\"\n (click)=\"clearAppliedFilterChip(chip)\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </span>\n }\n @if (hiddenAppliedFilterChipCount() > 0 && isFilterHeaderExpanded()) {\n @for (chip of overflowAppliedFilterChips(); track chip.id) {\n <span\n class=\"z-table-filter-header-overflow-chip border-border bg-muted/60 text-foreground inline-flex max-w-80 min-w-0 shrink-0 items-center gap-1 rounded-sm border px-2 py-1 text-[0.8125rem] shadow-xs\"\n [attr.aria-hidden]=\"!isFilterHeaderExpanded()\">\n <span class=\"font-medium whitespace-nowrap\">{{ chip.label }}</span>\n <span class=\"text-muted-foreground\">:</span>\n <span class=\"truncate\" z-tooltip [zContent]=\"chip.value\" zTooltipTrigger=\"hover\" zTooltipPosition=\"top\">\n {{ chip.value }}\n </span>\n <button\n type=\"button\"\n class=\"hover:bg-destructive/10 hover:text-destructive focus-visible:ring-ring -mr-1 inline-flex size-5 cursor-pointer items-center justify-center rounded-sm outline-none focus-visible:ring-2\"\n [attr.aria-label]=\"'i18n_z_ui_table_filter_remove' | translate\"\n (click)=\"clearAppliedFilterChip(chip)\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </span>\n }\n }\n @if (hiddenAppliedFilterChipCount() > 0) {\n <button\n type=\"button\"\n class=\"text-primary hover:bg-primary/10 focus-visible:ring-ring inline-flex h-7 cursor-pointer items-center rounded-sm px-2 text-xs font-medium outline-none focus-visible:ring-2\"\n (click)=\"toggleFilterHeaderExpanded()\">\n {{\n isFilterHeaderExpanded()\n ? ('i18n_z_ui_table_show_less' | translate)\n : ('i18n_z_ui_table_show_more' | translate: { count: hiddenAppliedFilterChipCount() })\n }}\n </button>\n }\n <button\n type=\"button\"\n class=\"bg-destructive/10 text-destructive hover:bg-destructive/20 dark:bg-destructive/15 dark:text-destructive-foreground dark:hover:bg-destructive/25 focus-visible:ring-destructive inline-flex h-7 cursor-pointer items-center gap-1 rounded-sm px-2 text-xs font-medium shadow-xs outline-none focus-visible:ring-2\"\n (click)=\"clearAppliedFilters()\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_clear_filter' | translate }}</span>\n </button>\n </div>\n </div>\n}\n\n<div\n #tableContainer\n [class]=\"classTable()\"\n [ngStyle]=\"columnSizeVars()\"\n [class.z-pinning-overflow]=\"!isPinnedLayoutWithinContainer()\"\n [class.z-hide-horizontal-border]=\"!showHorizontalBorder()\"\n [class.z-hide-vertical-border]=\"!showVerticalBorder()\"\n [class.z-hide-pinned-top-border]=\"hasScrollTop()\"\n [class.z-hide-pinned-bottom-border]=\"hasScrollBottom()\"\n [style.width]=\"zConfig().width\"\n [style.height]=\"zConfig().height\"\n [style.max-height]=\"zConfig().maxHeight\"\n [style.min-height]=\"zConfig().minHeight\"\n [attr.tabindex]=\"canUseContentRowInsert() || canUseCellSelection() ? 0 : null\"\n (keydown)=\"onContentTableKeydown($event)\">\n @let isColumnPinningActive = isPinnedLayoutWithinContainer();\n <ng-template #contentRowMenuContent>\n <div class=\"flex min-w-36 flex-col gap-0.5 p-1\">\n @if (contentRowMenu()?.columnId) {\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded-sm 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-sm 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-sm 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-sm 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-sm 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-sm 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-sm 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-sm 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-sm 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-sm px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canCopyCellMenuSelection()\"\n (click)=\"copySelectedCells(true)\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_cell_with_headers' | translate }}</span>\n </button>\n }\n </div>\n </ng-template>\n\n <div\n class=\"pointer-events-none fixed size-px opacity-0\"\n z-popover\n [zPopoverContent]=\"contentRowMenuContent\"\n zTrigger=\"manual\"\n zPosition=\"bottom-left\"\n zClass=\"z-table-content-row-menu\"\n [zOffset]=\"0\"\n [zManualClose]=\"true\"\n [zScrollClose]=\"true\"\n [style.left.px]=\"contentRowMenu()?.left ?? -9999\"\n [style.top.px]=\"contentRowMenu()?.top ?? -9999\"\n (zControl)=\"setContentRowMenuControl($event)\"\n (zHide)=\"clearContentRowMenu()\"></div>\n\n <div\n class=\"pointer-events-none fixed size-px opacity-0\"\n z-popover\n [zPopoverContent]=\"cellMenuContent\"\n zTrigger=\"manual\"\n zPosition=\"bottom-left\"\n zClass=\"z-table-cell-menu\"\n [zOffset]=\"0\"\n [zManualClose]=\"true\"\n [zScrollClose]=\"true\"\n [style.left.px]=\"cellMenu()?.left ?? -9999\"\n [style.top.px]=\"cellMenu()?.top ?? -9999\"\n (zControl)=\"setCellMenuControl($event)\"\n (zHide)=\"clearCellMenu()\"></div>\n\n <!-- Shared colgroup template -->\n <ng-template #colGroupTpl>\n <colgroup>\n @if (canUseVirtualColumns()) {\n @for (column of leftLeafColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <col [style.width.px]=\"virtualRenderedLeftSpacerWidth()\" />\n }\n @for (column of virtualCenterColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n @if (virtualRightSpacerWidth() > 0) {\n <col [style.width.px]=\"virtualRenderedRightSpacerWidth()\" />\n }\n @for (column of rightLeafColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n } @else {\n @for (column of orderedLeafColumns(); track column.id) {\n @if (column.getIsVisible()) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n }\n }\n </colgroup>\n </ng-template>\n\n <!-- Header table -->\n <div\n class=\"z-thead-wrapper shadow-card\"\n [class.z-shadow-header]=\"shouldHeaderShowShadow()\"\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\"\n (wheel)=\"onTheadWheel($event)\"\n #theadWrapper>\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <thead>\n @if (canUseVirtualColumns()) {\n <tr>\n @for (header of leftHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: leftHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div zHoverGlide zHoverGlideSelector=\".z-column-menu-item\" 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-sm 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-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm 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-sm 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-sm 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-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded-sm 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 zClass=\"rounded-lg overflow-hidden\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <th\n class=\"z-virtual-column-spacer z-virtual-header-spacer z-virtual-left-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></th>\n }\n @for (header of virtualCenterHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: virtualCenterHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div zHoverGlide zHoverGlideSelector=\".z-column-menu-item\" 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-sm 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-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm 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-sm 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-sm 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-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded-sm 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 zClass=\"rounded-lg overflow-hidden\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualRightSpacerWidth() > 0) {\n <th\n class=\"z-virtual-column-spacer z-virtual-header-spacer z-virtual-right-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></th>\n }\n @for (header of rightHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: rightHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <!-- Header Checkbox -->\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <!-- Expand All Button -->\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <!-- Header Content with Sort and Pin -->\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <!-- Column Options Popover Template -->\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div zHoverGlide zHoverGlideSelector=\".z-column-menu-item\" 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-sm 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-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm 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-sm 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-sm 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-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded-sm 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 zClass=\"rounded-lg overflow-hidden\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n <!-- Dropdown indicator when has options (between text and sort icon) -->\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n <!-- Sort Icon (outside wrapper, no hover background) -->\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n <!-- Column Resizer -->\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n </tr>\n } @else {\n @for (headerGroup of orderedHeaderGroups(); track headerGroup.id) {\n <tr>\n @for (header of headerGroup.headers; track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: headerGroup.headers : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div zHoverGlide zHoverGlideSelector=\".z-column-menu-item\" 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-sm 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-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"15\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"\n handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\n \"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"15\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm 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-sm 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-sm 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-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded-sm 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 zClass=\"rounded-lg overflow-hidden\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"\n header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\n \"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n </tr>\n }\n }\n </thead>\n </table>\n </div>\n\n <!-- Body table -->\n <div\n class=\"z-tbody-wrapper relative\"\n #tbodyContainer\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\">\n @if (isLoading() || isProcessing()) {\n <!-- Loading State -->\n @if (zConfig().useSkeleton) {\n <!-- Skeleton Loading -->\n <div class=\"animate-in fade-in flex h-full flex-col duration-200\">\n @for (i of skeletonRows(); track $index; let last = $last) {\n <div\n class=\"border-border box-border flex flex-1 flex-col items-start justify-center gap-1.5 px-2\"\n [class.border-b]=\"!last\">\n <z-skeleton zType=\"bar\" zWidth=\"100%\" zHeight=\"22px\" />\n <z-skeleton zType=\"bar\" zWidth=\"50%\" zHeight=\"14px\" />\n </div>\n }\n </div>\n } @else {\n <!-- Spinner Loading -->\n <div class=\"z-loading-state\">\n <z-loading [zLoading]=\"true\" zSize=\"lg\" [zText]=\"'i18n_z_ui_table_loading' | translate\" />\n </div>\n }\n } @else if (isEmpty()) {\n <div class=\"z-empty-state\">\n @if (isNoSearchResults()) {\n <z-empty zIcon=\"lucideSearchX\" zSize=\"sm\" [zMessage]=\"'i18n_z_ui_table_no_results' | translate\" />\n } @else {\n <z-empty zIcon=\"lucidePackageOpen\" zSize=\"sm\" [zMessage]=\"'i18n_z_ui_table_no_data' | translate\" />\n }\n </div>\n } @else {\n <ng-scrollbar class=\"z-tbody-scrollbar\" #tbodyWrapper (scroll)=\"onTbodyScroll($event)\">\n @if (isVirtual()) {\n <!-- Virtual Scroll Mode -->\n\n <div\n class=\"z-virtual-scroll-inner\"\n [style.height.px]=\"virtualizer.getTotalSize()\"\n [style.min-width.px]=\"table.getTotalSize()\">\n <!-- Pinned rows v\u00E0 center rows d\u00F9ng chung m\u1ED9t virtual canvas. -->\n @if (virtualPinnedTopRows().length > 0) {\n <div class=\"z-virtual-pinned-top\" [style.min-width.px]=\"table.getTotalSize()\">\n @for (row of virtualPinnedTopRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"virtualPinnedRowTpl; context: { $implicit: row }\" />\n }\n </div>\n }\n\n @if (usesFlowVirtualRows()) {\n <div\n class=\"z-virtual-flow\"\n [style.transform]=\"'translate3d(0,' + virtualFlowOffset() + 'px,0)'\"\n [style.min-width.px]=\"table.getTotalSize()\">\n <ng-container *ngTemplateOutlet=\"virtualRowsTpl\" />\n </div>\n } @else {\n <ng-container *ngTemplateOutlet=\"virtualRowsTpl\" />\n }\n\n <ng-template #virtualRowsTpl>\n @for (virtualItem of virtualizer.getVirtualItems(); track virtualItem.index) {\n @let groupRows = dynamicGroupRows()[virtualItem.index] || [];\n @let virtualFlatItem = virtualGroupedFlatItems()[virtualItem.index];\n @let stickyGroupState = stickyGroupHeaderState();\n @let stickyGroupTop = stickyGroupState.tops[virtualItem.index];\n @let isStickyGroupHeader = stickyGroupTop !== undefined;\n <div\n #virtualRow\n class=\"z-virtual-row\"\n [class.z-virtual-row-flow]=\"usesFlowVirtualRows()\"\n [class.z-virtual-row-fixed]=\"!effectiveDynamicRowSizing()\"\n [class.z-virtual-row-group-header]=\"virtualFlatItem?.type === 'group-header'\"\n [class.z-virtual-row-sticky-group]=\"isStickyGroupHeader\"\n [class.z-virtual-row-sticky-group-shadow]=\"stickyGroupState.shadowIndex === virtualItem.index\"\n [style.top.px]=\"stickyGroupTop\"\n z-table-draggable=\"row\"\n z-table-drop-target=\"row\"\n [z-table-drag-table-id]=\"dragInstanceId\"\n [z-table-drop-table-id]=\"dragInstanceId\"\n [z-table-drag-item-id]=\"groupRows.length > 0 ? groupRows[0].id : ''\"\n [z-table-drop-item-id]=\"groupRows.length > 0 ? groupRows[0].id : ''\"\n [z-table-drag-disabled]=\"!isVirtualRowDragEnabled() || groupRows.length !== 1\"\n [z-table-drop-disabled]=\"!isVirtualRowDragEnabled() || groupRows.length !== 1\"\n (zTableDropped)=\"_handleDragDrop($event)\"\n [attr.data-index]=\"virtualItem.index\"\n [style.height.px]=\"\n effectiveDynamicRowSizing()\n ? null\n : (dynamicGroupHeights()[virtualItem.index] ?? groupSize() * virtualRowHeight())\n \"\n [style.transform]=\"\n usesFlowVirtualRows() || isStickyGroupHeader ? null : 'translate3d(0,' + virtualItem.start + 'px,0)'\n \">\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-has-bottom-pinned]=\"table.getBottomRows().length > 0\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n @let groupHeaderItem = _getVirtualGroupHeader(virtualFlatItem);\n @if (groupHeaderItem) {\n <tr\n class=\"z-group-row\"\n [class.z-group-row-has-totals]=\"groupHeaderItem.totals\"\n [class.z-group-row-expanded]=\"groupHeaderItem.expanded\"\n [attr.data-group-id]=\"groupHeaderItem.id\"\n [attr.data-group-depth]=\"groupHeaderItem.depth\">\n @if (groupHeaderItem.totals) {\n @let totalColumnMap = groupTotalColumnMap();\n @for (column of orderedLeafColumns(); track column.id; let isFirstGroupCell = $first) {\n <td\n [class.z-group-row-label-cell]=\"isFirstGroupCell\"\n [class.z-group-row-total-cell]=\"!isFirstGroupCell && totalColumnMap[column.id]\"\n [attr.data-column-id]=\"column.id\">\n @if (isFirstGroupCell) {\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + groupHeaderItem.depth * 0.75\"\n [attr.aria-expanded]=\"groupHeaderItem.expanded\"\n (click)=\"toggleGroupRow(groupHeaderItem.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"groupHeaderItem.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"\n (groupHeaderItem.columnLabel ? groupHeaderItem.columnLabel + ': ' : '') +\n groupHeaderItem.label\n \">\n @if (groupHeaderItem.columnLabel) {\n <span class=\"z-group-row-column-label\">\n {{ groupHeaderItem.columnLabel }}:\n </span>\n }\n {{ groupHeaderItem.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ groupHeaderItem.count }}</span>\n }\n @if (groupHeaderItem.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n [zWave]=\"false\"\n z-tooltip\n zSizeIcon=\"14\"\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(groupHeaderItem.columnId)\"></button>\n }\n </div>\n }\n @if (!isFirstGroupCell && totalColumnMap[column.id]) {\n @let totalConfig = groupTotalConfigMap()[column.id];\n @let totalTooltip = totalConfig.tooltip;\n @let totalPopover = totalConfig.popover;\n @let totalPopoverContent = totalPopover | zTablePopoverConfig: 'content';\n <ng-template #groupTotalPopoverTpl>\n @if (totalPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(totalPopoverContent)\" />\n }\n @if (!(totalPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(totalPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n <span\n class=\"z-group-row-total\"\n z-tooltip\n z-popover\n [class]=\"totalConfig.class\"\n [zContent]=\"\n $any(\n (totalTooltip | zTableTooltipConfig: 'content') ||\n groupHeaderItem.totals[column.id]\n )\n \"\n [zTooltipPosition]=\"$any(totalTooltip | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(totalTooltip | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(totalTooltip | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(totalTooltip | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(totalTooltip | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'showDelay')\"\n [zTooltipHideDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'hideDelay')\"\n [zTooltipArrow]=\"$any(totalTooltip | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(totalTooltip | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(totalTooltip | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(totalTooltip | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(totalTooltip | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"totalPopoverContent ? groupTotalPopoverTpl : null\"\n [zPosition]=\"$any(totalPopover | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(totalPopover | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(totalPopover | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(totalPopover | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(totalPopover | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(totalPopover | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(totalPopover | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(totalPopover | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(totalPopover | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"$any(totalPopover | zTablePopoverConfig: 'outsideClickClose')\"\n [zScrollClose]=\"$any(totalPopover | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(totalPopover | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(totalPopover | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(totalPopover | zTablePopoverConfig: 'keyboardSafe')\">\n {{ groupHeaderItem.totals[column.id] }}\n </span>\n }\n </td>\n }\n } @else {\n <td [attr.colspan]=\"renderedColumnCount()\">\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + groupHeaderItem.depth * 0.75\"\n [attr.aria-expanded]=\"groupHeaderItem.expanded\"\n (click)=\"toggleGroupRow(groupHeaderItem.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"groupHeaderItem.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"\n (groupHeaderItem.columnLabel ? groupHeaderItem.columnLabel + ': ' : '') +\n groupHeaderItem.label\n \">\n @if (groupHeaderItem.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ groupHeaderItem.columnLabel }}:</span>\n }\n {{ groupHeaderItem.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ groupHeaderItem.count }}</span>\n }\n @if (groupHeaderItem.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n [zWave]=\"false\"\n z-tooltip\n zSizeIcon=\"14\"\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(groupHeaderItem.columnId)\"></button>\n }\n </div>\n </td>\n }\n </tr>\n }\n @for (row of groupRows; track row.id) {\n @let virtualGroupDepth = _getVirtualGroupDepth(virtualFlatItem);\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <tr\n z-table-row-hover\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"effectiveDynamicRowSizing() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"effectiveDynamicRowSizing() ? virtualRowHeight() : null\"\n [style.--z-row-height]=\"effectiveDynamicRowSizing() ? 'auto' : virtualRowHeight() + 'px'\"\n [class.z-child-row]=\"row.depth > 0\"\n [class.z-group-child-row]=\"_isVirtualGroupChild(virtualFlatItem)\"\n [style.--z-group-content-indent]=\"\n virtualGroupDepth > 0 ? 1.75 + (virtualGroupDepth - 1) * 0.75 + 'rem' : null\n \"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && row.id === firstTopPinnedRowId()\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"rowPinned === 'bottom' && row.id === lastBottomPinnedRowId()\"\n [class.z-pinned-bottom-first]=\"rowPinned === 'bottom' && row.id === firstBottomPinnedRowId()\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n row.id === lastTopPinnedRowId() &&\n !isStickyGroupHeaderEnabled()\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n row.id === firstBottomPinnedRowId()\n \"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : bodyRowSpanRows();\n @let shouldRenderColSpan =\n cell | zTableCellRender: visibleCells : zConfig().columns : 'body';\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (shouldRenderRowSpan && shouldRenderColSpan && isVirtualColumnVisible) {\n @let cellSelectionId = row.id + '::' + cell.column.id;\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"isColumnPinningActive && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActive && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell\n | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell\n | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"cell.column.id === actionColumnInfo()?.columnId\"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [class.z-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"cell | zTableCellBottom: zConfig().columns : renderedBodyRows()\"\n [attr.rowspan]=\"\n cell | zTableSpan: zConfig().columns : 'cellRowSpan' : bodyRowSpanRows()\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() &&\n cell.row.getIsSomeSelected() &&\n !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-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"cell.row.getIsExpanded()\" />\n </button>\n }\n </div>\n } @else if (\n (cell.column.id === 'actionRowPin' || cell.column.id === 'actions') &&\n cell.column.id !== actionColumnInfo()?.columnId\n ) {\n @if (cell.row.depth === 0 && !hasBodyRowSpan()) {\n <div class=\"flex items-center justify-center\">\n <ng-template #rowPinPopoverContent>\n <div\n zHoverGlide\n zHoverGlideSelector=\".z-column-menu-item\"\n class=\"flex flex-col gap-1 py-1\">\n @if (cell.row.getIsPinned() !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cell.row.getIsPinned() !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cell.row.getIsPinned()) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded-sm p-1 outline-none\"\n [class.text-primary]=\"cell.row.getIsPinned()\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n </div>\n }\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisible = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisible) {\n @let editInfoVirtual = cell.getContext() | zTableCellEdit: zConfig().columns;\n @if (editInfoVirtual.enabled) {\n <!-- Editable Cell (Virtual) -->\n <z-table-edit-cell\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n [zRowIndex]=\"cell.row.index\"\n [zColumnId]=\"cell.column.id\"\n [zValue]=\"cell.getValue()\"\n [zRowUpdate]=\"_rowUpdate()\"\n [zEditConfig]=\"$any(editInfoVirtual.config)\"\n (zChange)=\"onCellEdit($any($event))\" />\n } @else if (editInfoVirtual.contentEnabled) {\n @let contentConfigVirtual = editInfoVirtual.contentConfig!;\n @if (\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n ) {\n <z-table-content-editor\n [zValue]=\"cell.getValue()\"\n [zConfig]=\"contentConfigVirtual\"\n (zCommit)=\"onContentEditCommit($event, row, cell.column.id, cell.getValue())\"\n (zCancel)=\"onContentEditCancel()\" />\n } @else {\n <button\n type=\"button\"\n class=\"z-table-content-trigger\"\n [attr.data-z-table-edit-row]=\"row.id\"\n [attr.data-z-table-edit-column]=\"cell.column.id\"\n (keydown)=\"onContentEditKeydown($event, row.id, cell.column.id)\"\n (click)=\"onContentEditStart($event, row.id, cell.column.id)\">\n {{ contentConfigVirtual.displayValue }}\n </button>\n }\n } @else {\n <ng-container\n *flexRender=\"\n cell.column.columnDef.cell;\n props: cell.getContext();\n let cellContent\n \">\n @if (cellContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n @let isClickable = cell.column.id | zTableCellClickable: zConfig().columns;\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickable && onCellClick(row, cell.column.id, cell.getValue())\">\n <ng-container\n *ngTemplateOutlet=\"\n cellContent;\n context: { $implicit: cell.getContext() }\n \" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n @let isClickableIcon =\n cell.column.id | zTableCellClickable: zConfig().columns;\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"\n isClickableIcon && onCellClick(row, cell.column.id, cell.getValue())\n \" />\n } @else {\n <!-- Default/innerHTML rendering -->\n @let isClickableDefault =\n cell.column.id | zTableCellClickable: zConfig().columns;\n @let cellTooltipConfig =\n cell | zTableCellConfig: zConfig() : 'contentTooltip';\n @let cellPopoverConfig =\n cell | zTableCellConfig: zConfig() : 'contentPopover';\n @let cellPopoverContent = cellPopoverConfig | zTablePopoverConfig: 'content';\n <ng-template #cellPopoverTpl>\n @if (cellPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(cellPopoverContent)\" />\n }\n @if (!(cellPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(cellPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n @if (cellPopoverContent) {\n <div\n class=\"z-table-cell-text\"\n z-popover\n z-tooltip\n [zTriggerElement]=\"cellOverlayContent\"\n [zTriggerRef]=\"cellOverlayContent\"\n [zContent]=\"\n (cellTooltipConfig | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'position')\n \"\n [zTooltipTrigger]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'trigger')\n \"\n [zTooltipType]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'autoDetect')\n \"\n [zAlwaysShow]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'alwaysShow')\n \"\n [zMaxWidth]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"cellPopoverTpl\"\n [zPosition]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'trigger')\n \"\n [zClass]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'manualClose')\n \"\n [zOutsideClickClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'outsideClickClose')\n \"\n [zScrollClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'scrollClose')\n \"\n [zSticky]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'keyboardSafe')\n \"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellOverlayContent\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n } @else {\n <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zTriggerElement]=\"cellTooltipContent\"\n [zContent]=\"\n (cellTooltipConfig | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'position')\n \"\n [zTooltipTrigger]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'trigger')\n \"\n [zTooltipType]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'autoDetect')\n \"\n [zAlwaysShow]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'alwaysShow')\n \"\n [zMaxWidth]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'maxWidth')\"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellTooltipContent\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n }\n }\n </ng-container>\n }\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </ng-template>\n </div>\n\n <!--\n Bottom pinned rows: sibling AFTER the virtual canvas (not absolute like the\n center rows). The virtualizer reserves their height inside getTotalSize() via\n `paddingEnd`, leaving an empty band at the canvas bottom. `margin-top: -bottomHeight`\n pulls this real flow element back over that band, and `position: sticky; bottom: 0`\n floats it to the viewport bottom while scrolling.\n -->\n @if (virtualPinnedBottomRows().length > 0) {\n <div\n class=\"z-virtual-pinned-bottom\"\n [style.min-width.px]=\"table.getTotalSize()\"\n [style.margin-top.px]=\"-virtualPinnedBottomHeight()\">\n @for (row of virtualPinnedBottomRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"virtualPinnedRowTpl; context: { $implicit: row }\" />\n }\n </div>\n }\n\n <!-- Template for rendering pinned rows in virtual scroll mode -->\n <ng-template #virtualPinnedRowTpl let-row>\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody [class.z-has-vertical-scroll]=\"hasVerticalScroll()\">\n <tr\n z-table-row-hover\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"effectiveDynamicRowSizing() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"effectiveDynamicRowSizing() ? virtualRowHeight() : null\"\n [style.--z-row-height]=\"effectiveDynamicRowSizing() ? 'auto' : virtualRowHeight() + 'px'\"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && row.id === firstTopPinnedRowId()\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"rowPinned === 'bottom' && row.id === lastBottomPinnedRowId()\"\n [class.z-pinned-bottom-first]=\"rowPinned === 'bottom' && row.id === firstBottomPinnedRowId()\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n row.id === lastTopPinnedRowId() &&\n !isStickyGroupHeaderEnabled()\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n row.id === firstBottomPinnedRowId()\n \"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @let isColumnPinningActivePinned = isPinnedLayoutWithinContainer();\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @let cellSelectionId = row.id + '::' + cell.column.id;\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (isVirtualColumnVisible) {\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActivePinned\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"isColumnPinningActivePinned && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActivePinned && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"cell.column.id === actionColumnInfo()?.columnId\"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [style.--z-cell-range-top]=\"(selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"(selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'select') {\n <z-checkbox\n [zChecked]=\"rowSelected\"\n [zIndeterminate]=\"rowSomeSelected && !rowSelected\"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && row.toggleSelected()\" />\n } @else if (cell.column.id === 'expand') {\n <button\n type=\"button\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"row.toggleExpanded()\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"row.getIsExpanded()\" />\n </button>\n } @else if (cell.column.id === 'actionRowPin') {\n <div class=\"flex items-center justify-center\">\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisible = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisible) {\n <ng-container\n *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let cellContent\">\n @if (cellContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { $implicit: cell.getContext() }\" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"(cell | zTableCellConfig: zConfig() : 'contentTooltip') || cellContent\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"></span>\n }\n </ng-container>\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n </tbody>\n </table>\n </ng-template>\n } @else {\n <!-- Normal Scroll Mode -->\n\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n class=\"z-table-drag-body\"\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-has-bottom-pinned]=\"table.getBottomRows().length > 0\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n <!-- Row Template -->\n <ng-template #rowTemplate let-row let-isGroupChild=\"isGroupChild\" let-groupDepth=\"groupDepth\">\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <tr\n z-table-row-hover\n z-table-draggable=\"row\"\n z-table-drop-target=\"row\"\n [animate.enter]=\"row.depth > 0 || isGroupChild ? 'z-row-enter' : ''\"\n [z-table-drag-table-id]=\"dragInstanceId\"\n [z-table-drop-table-id]=\"dragInstanceId\"\n [z-table-drag-item-id]=\"row.id\"\n [z-table-drop-item-id]=\"row.id\"\n [z-table-drag-disabled]=\"!isRowDragEnabled()\"\n [z-table-drop-disabled]=\"!isRowDragEnabled()\"\n (zTableDropped)=\"_handleDragDrop($event)\"\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [ngStyle]=\"row | zTableRow: table : 'pinningStyles' : pinnedRowHeights() : virtualRowHeight()\"\n [class.z-child-row]=\"row.depth > 0\"\n [class.z-group-child-row]=\"isGroupChild\"\n [style.--z-group-content-indent]=\"groupDepth > 0 ? 1.75 + (groupDepth - 1) * 0.75 + 'rem' : null\"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && row.id === firstTopPinnedRowId()\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"rowPinned === 'bottom' && row.id === lastBottomPinnedRowId()\"\n [class.z-pinned-bottom-first]=\"rowPinned === 'bottom' && row.id === firstBottomPinnedRowId()\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n row.id === lastTopPinnedRowId() &&\n !isStickyGroupHeaderEnabled()\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n row.id === firstBottomPinnedRowId()\n \"\n [attr.data-depth]=\"row.depth\"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @let cellRowPinned = cell.row.getIsPinned();\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : bodyRowSpanRows();\n @let shouldRenderColSpan = cell | zTableCellRender: visibleCells : zConfig().columns : 'body';\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (shouldRenderRowSpan && shouldRenderColSpan && isVirtualColumnVisible) {\n @let cellSelectionId = row.id + '::' + cell.column.id;\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n [class.z-sticky-left]=\"isColumnPinningActive && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActive && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"\n cell.column.id === 'actions' || cell.column.id === actionColumnInfo()?.columnId\n \"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [class.z-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"cell | zTableCellBottom: zConfig().columns : renderedBodyRows()\"\n [attr.rowspan]=\"cell | zTableSpan: zConfig().columns : 'cellRowSpan' : bodyRowSpanRows()\"\n [attr.colspan]=\"cell | zTableSpan: zConfig().columns : 'cellColSpan'\"\n [style.--z-cell-range-top]=\"(selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"(selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <button\n data-z-table-drag-handle\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground inline-flex size-7 items-center justify-center rounded-md transition-colors\"\n [class.cursor-grab]=\"isRowDragEnabled()\"\n [class.cursor-not-allowed]=\"!isRowDragEnabled()\"\n [class.opacity-40]=\"!isRowDragEnabled()\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === 'select') {\n <!-- Row Checkbox with Pin Button -->\n <div class=\"flex items-center justify-center gap-1\">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && cell.row.getIsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && cell.row.getIsSomeSelected() && !cell.row.getIsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection() || !cell.row.getCanSelect()\"\n (zChange)=\"canUseRowSelection() && cell.row.toggleSelected()\" />\n @if (zConfig().enableRowPinning && cell.row.depth === 0 && !hasBodyRowSpan()) {\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div\n zHoverGlide\n zHoverGlideSelector=\".z-column-menu-item\"\n class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded-sm p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n }\n </div>\n } @else if (cell.column.id === 'expand') {\n <!-- Expand Button with Row Pin Popover -->\n <div class=\"flex items-center justify-center gap-1\">\n @if (cell.row.getCanExpand()) {\n <button\n type=\"button\"\n (click)=\"cell.row.toggleExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"cell.row.getIsExpanded()\" />\n </button>\n }\n @if (\n zConfig().enableRowPinning &&\n cell.row.depth === 0 &&\n !(cell.row.subRows && cell.row.subRows.length > 0) &&\n !hasBodyRowSpan()\n ) {\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div\n zHoverGlide\n zHoverGlideSelector=\".z-column-menu-item\"\n class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded-sm p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n }\n </div>\n } @else if (\n (cell.column.id === 'actionRowPin' || cell.column.id === 'actions') &&\n cell.column.id !== actionColumnInfo()?.columnId\n ) {\n <!-- Actions Column - Row Pin Only (for parent rows) -->\n @if (cell.row.depth === 0 && !hasBodyRowSpan()) {\n <div class=\"flex items-center justify-center\">\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div\n zHoverGlide\n zHoverGlideSelector=\".z-column-menu-item\"\n class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded-sm p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n </div>\n }\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisibleNormal = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisibleNormal) {\n @let editInfo = cell.getContext() | zTableCellEdit: zConfig().columns;\n @if (editInfo.enabled) {\n <!-- Editable Cell -->\n <z-table-edit-cell\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n [zRowIndex]=\"cell.row.index\"\n [zColumnId]=\"cell.column.id\"\n [zValue]=\"cell.getValue()\"\n [zRowUpdate]=\"_rowUpdate()\"\n [zEditConfig]=\"$any(editInfo.config)\"\n (zChange)=\"onCellEdit($any($event))\" />\n } @else if (editInfo.contentEnabled) {\n @let contentConfig = editInfo.contentConfig!;\n @if (\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n ) {\n <z-table-content-editor\n [zValue]=\"cell.getValue()\"\n [zConfig]=\"contentConfig\"\n (zCommit)=\"onContentEditCommit($event, row, cell.column.id, cell.getValue())\"\n (zCancel)=\"onContentEditCancel()\" />\n } @else {\n <button\n type=\"button\"\n class=\"z-table-content-trigger\"\n [attr.data-z-table-edit-row]=\"row.id\"\n [attr.data-z-table-edit-column]=\"cell.column.id\"\n (keydown)=\"onContentEditKeydown($event, row.id, cell.column.id)\"\n (click)=\"onContentEditStart($event, row.id, cell.column.id)\">\n {{ contentConfig.displayValue }}\n </button>\n }\n } @else {\n <ng-container\n *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let cellContent\">\n @if (cellContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n @let isClickableTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickableTpl && onCellClick(row, cell.column.id, cell.getValue())\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { $implicit: cell.getContext() }\" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n @let isClickableIconTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickableIconTpl && onCellClick(row, cell.column.id, cell.getValue())\" />\n } @else {\n <!-- Default/innerHTML rendering -->\n @let isClickableDefaultTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n @let cellTooltipConfigTpl = cell | zTableCellConfig: zConfig() : 'contentTooltip';\n @let cellPopoverConfigTpl = cell | zTableCellConfig: zConfig() : 'contentPopover';\n @let cellPopoverContentTpl = cellPopoverConfigTpl | zTablePopoverConfig: 'content';\n <ng-template #cellPopoverTplNormal>\n @if (cellPopoverContentTpl | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(cellPopoverContentTpl)\" />\n }\n @if (!(cellPopoverContentTpl | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(cellPopoverContentTpl) | zSafeHtml\"></div>\n }\n </ng-template>\n @if (cellPopoverContentTpl) {\n <div\n class=\"z-table-cell-text\"\n z-popover\n z-tooltip\n [zTriggerElement]=\"cellOverlayContentTpl\"\n [zTriggerRef]=\"cellOverlayContentTpl\"\n [zContent]=\"\n (cellTooltipConfigTpl | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"cellPopoverTplNormal\"\n [zPosition]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"\n $any(cellPopoverConfigTpl | zTablePopoverConfig: 'outsideClickClose')\n \"\n [zScrollClose]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'keyboardSafe')\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellOverlayContentTpl\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n } @else {\n <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zTriggerElement]=\"cellTooltipContentTpl\"\n [zContent]=\"\n (cellTooltipConfigTpl | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'maxWidth')\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellTooltipContentTpl\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n }\n }\n </ng-container>\n }\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n\n <!-- Expanded Row Detail -->\n @if (row.getIsExpanded() && row.depth === 0 && !row.subRows?.length) {\n @let resolvedSubTableConfig = row | zTableSubTableConfig: zConfig();\n <tr class=\"z-expanded-row\" animate.enter=\"z-expanded-row-enter\">\n <td [attr.colspan]=\"renderedColumnCount()\" class=\"p-0\">\n <!-- Animate \u1EDF wrapper n\u00E0y b\u1EB1ng clip-path/translate/opacity \u2014 xem z-expanded-row-reveal. -->\n <div class=\"z-expanded-row-content\">\n @if (zConfig().expandedRowTemplate) {\n <ng-container\n *ngTemplateOutlet=\"zConfig().expandedRowTemplate!; context: { $implicit: row }\" />\n } @else if (resolvedSubTableConfig) {\n <div class=\"z-sub-table-container\">\n <z-table [zConfig]=\"$any(resolvedSubTableConfig)\" zVariant=\"borderless\" />\n </div>\n }\n </div>\n </td>\n </tr>\n }\n </ng-template>\n\n <!-- Render Top Pinned Rows (hidden when filtered data is empty) -->\n @if (!isEmpty()) {\n @for (row of table.getTopRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\n }\n }\n\n <!-- Render Center Rows -->\n @for (item of groupedCenterRowItems(); track item.type === 'group' ? item.id : item.row.id) {\n @if (item.type === 'group') {\n <tr\n #groupRow\n class=\"z-group-row\"\n [class.z-group-row-has-totals]=\"item.totals\"\n [class.z-group-row-expanded]=\"item.expanded\"\n [class.z-group-row-sticky]=\"isStickyGroupHeaderEnabled()\"\n [class.z-group-row-sticky-shadow]=\"shadowGroupRowId() === item.id\"\n [style.top.px]=\"stickyGroupTopByDepth()[item.depth]\"\n [attr.data-group-id]=\"item.id\"\n [attr.data-group-depth]=\"item.depth\">\n @if (item.totals) {\n @let totalColumnMap = groupTotalColumnMap();\n @for (column of orderedLeafColumns(); track column.id; let isFirstGroupCell = $first) {\n <td\n [class.z-group-row-label-cell]=\"isFirstGroupCell\"\n [class.z-group-row-total-cell]=\"!isFirstGroupCell && totalColumnMap[column.id]\"\n [attr.data-column-id]=\"column.id\">\n @if (isFirstGroupCell) {\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + item.depth * 0.75\"\n [attr.aria-expanded]=\"item.expanded\"\n (click)=\"toggleGroupRow(item.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"item.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"(item.columnLabel ? item.columnLabel + ': ' : '') + item.label\">\n @if (item.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ item.columnLabel }}:</span>\n }\n {{ item.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ item.count }}</span>\n }\n @if (item.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n zSizeIcon=\"14\"\n [zWave]=\"false\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(item.columnId)\"></button>\n }\n </div>\n }\n @if (!isFirstGroupCell && totalColumnMap[column.id]) {\n @let totalConfig = groupTotalConfigMap()[column.id];\n @let totalTooltip = totalConfig.tooltip;\n @let totalPopover = totalConfig.popover;\n @let totalPopoverContent = totalPopover | zTablePopoverConfig: 'content';\n <ng-template #groupTotalPopoverTpl>\n @if (totalPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(totalPopoverContent)\" />\n }\n @if (!(totalPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(totalPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n <span\n class=\"z-group-row-total\"\n z-tooltip\n z-popover\n [class]=\"totalConfig.class\"\n [zContent]=\"\n $any((totalTooltip | zTableTooltipConfig: 'content') || item.totals[column.id])\n \"\n [zTooltipPosition]=\"$any(totalTooltip | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(totalTooltip | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(totalTooltip | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(totalTooltip | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(totalTooltip | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'showDelay')\"\n [zTooltipHideDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'hideDelay')\"\n [zTooltipArrow]=\"$any(totalTooltip | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(totalTooltip | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(totalTooltip | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(totalTooltip | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(totalTooltip | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"totalPopoverContent ? groupTotalPopoverTpl : null\"\n [zPosition]=\"$any(totalPopover | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(totalPopover | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(totalPopover | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(totalPopover | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(totalPopover | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(totalPopover | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(totalPopover | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(totalPopover | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(totalPopover | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"$any(totalPopover | zTablePopoverConfig: 'outsideClickClose')\"\n [zScrollClose]=\"$any(totalPopover | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(totalPopover | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(totalPopover | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(totalPopover | zTablePopoverConfig: 'keyboardSafe')\">\n {{ item.totals[column.id] }}\n </span>\n }\n </td>\n }\n } @else {\n <td [attr.colspan]=\"renderedColumnCount()\">\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + item.depth * 0.75\"\n [attr.aria-expanded]=\"item.expanded\"\n (click)=\"toggleGroupRow(item.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"item.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"(item.columnLabel ? item.columnLabel + ': ' : '') + item.label\">\n @if (item.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ item.columnLabel }}:</span>\n }\n {{ item.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ item.count }}</span>\n }\n @if (item.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n zSizeIcon=\"14\"\n [zWave]=\"false\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(item.columnId)\"></button>\n }\n </div>\n </td>\n }\n </tr>\n }\n @if (item.type === 'row') {\n <ng-container\n *ngTemplateOutlet=\"\n rowTemplate;\n context: {\n $implicit: item.row,\n isGroupChild: item.isGroupChild,\n groupDepth: item.groupDepth,\n }\n \" />\n }\n }\n\n <!-- Render Bottom Pinned Rows (hidden when filtered data is empty) -->\n @if (!isEmpty()) {\n @for (row of bottomRowsReversed(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\n }\n }\n </tbody>\n </table>\n }\n </ng-scrollbar>\n }\n <!-- end @else -->\n </div>\n\n <!-- Footer table -->\n @if (hasFooter()) {\n <div\n class=\"z-tfoot-wrapper\"\n [class.z-shadow-footer]=\"shouldFooterShowShadow()\"\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\"\n #tfootWrapper>\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tfoot>\n @for (footerGroup of orderedFooterGroups(); track footerGroup.id; let footerRowIndex = $index) {\n @if (footerGroup | zTableFooterContent: zConfig().columns : footerRowIndex) {\n <tr>\n @for (footer of footerGroup.headers; track footer.id) {\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n footer.column.id === firstVirtualCenterColumnId()\n ) {\n <th\n class=\"z-virtual-column-spacer z-virtual-footer-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></th>\n }\n @let rowSpan = footer | zTableSpan: zConfig().columns : 'footerRowSpan' : footerRowIndex;\n @let shouldRender =\n footer\n | zTableCellRender\n : footerGroup.headers\n : zConfig().columns\n : 'footer'\n : footerRowIndex\n : orderedFooterGroups();\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n footer.column.getIsPinned() !== false ||\n virtualCenterColumnVisibilityMap()[footer.column.id];\n @if (rowSpan && shouldRender && isVirtualColumnVisible) {\n <th\n [attr.data-column-id]=\"footer.column.id\"\n [ngStyle]=\"\n footer.column\n | zTablePinningStyles\n : footer\n : 'footer'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerClass' : footerRowIndex) +\n ' ' +\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex)\n \"\n [style]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerStyle' : footerRowIndex\n \"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (footer | zTableCellPin: 'isLeftPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-at-left-edge]=\"footer | zTableCellOffset: orderedLeafColumns()\"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"footer | zTableSpan: zConfig().columns : 'footerColSpan' : footerRowIndex\">\n @let configFooterContent =\n footer.column.id | zTableFooterRender: zConfig().columns : footerRowIndex;\n @if (configFooterContent !== undefined && configFooterContent !== '') {\n <ng-container *flexRender=\"configFooterContent; props: footer.getContext(); let footerContent\">\n <div\n class=\"flex w-full items-center\"\n [class.justify-center]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex) ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex) ===\n 'text-right'\n \">\n @if (footerContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n <div\n class=\"z-template-content\"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \">\n <ng-container\n *ngTemplateOutlet=\"footerContent; context: { $implicit: footer.getContext() }\" />\n </div>\n } @else if (footerContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n <z-table-icon-text\n [zText]=\"footerContent\"\n [zTooltip]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerTooltip' : footerRowIndex\n \"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \" />\n } @else {\n <!-- Default/string rendering -->\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerTooltip' : footerRowIndex) ||\n footerContent\n \"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \">\n {{ footerContent | translate }}\n </span>\n }\n </div>\n </ng-container>\n }\n </th>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n footer.column.id === lastVirtualCenterColumnId()\n ) {\n <th\n class=\"z-virtual-column-spacer z-virtual-footer-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></th>\n }\n }\n </tr>\n }\n }\n </tfoot>\n </table>\n </div>\n }\n</div>\n\n<!-- Pagination -->\n@if (zConfig().pagination?.enabled !== false) {\n <div class=\"mt-4 flex items-center justify-between gap-4\">\n <div class=\"truncate text-sm text-gray-500\">\n {{ 'i18n_z_ui_table_total_rows' | translate: { total: (paginationTotal() | zFormatNum) } }}\n </div>\n <z-pagination\n [zTotal]=\"paginationTotal()\"\n [(zPageIndex)]=\"pagination().pageIndex\"\n [(zPageSize)]=\"pagination().pageSize\"\n [zPageSizeOptions]=\"zConfig().pagination?.pageSizeOptions ?? [10, 20, 50, 100]\"\n [zShowSizeChanger]=\"zConfig().pagination?.showSizeChanger ?? true\"\n [zShowQuickJumper]=\"zConfig().pagination?.showQuickJumper ?? false\"\n [zShowTotal]=\"false\"\n [zDisabled]=\"zConfig().pagination?.disabled || isLoading() || isProcessing()\"\n (zOnPageChange)=\"onPageChange($event)\" />\n </div>\n}\n\n<!-- Floating Bulk Action Bar -->\n<ng-template #bulkBarTemplate>\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 [zBodyClass]=\"'mx-0! px-0!'\"\n [zShadow]=\"true\"\n [zOkText]=\"null\"\n [zCancelText]=\"'i18n_z_ui_drawer_close' | translate\">\n <div class=\"z-table-settings-drawer\">\n <!-- Display Settings -->\n <div class=\"mx-4 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=\"mx-4 mb-4\">\n <h4 class=\"text-foreground mb-2 text-sm font-semibold\">{{ 'i18n_z_ui_table_column_settings' | translate }}</h4>\n <p class=\"text-muted-foreground mb-3 text-xs\">{{ 'i18n_z_ui_table_column_settings_desc' | translate }}</p>\n\n <!-- Unpinned Columns (Draggable) -->\n <div\n cdkDropList\n #columnDropList=\"cdkDropList\"\n [cdkDropListAutoScrollDisabled]=\"true\"\n (cdkDropListDropped)=\"onPendingColumnDrop($event)\"\n class=\"z-column-drop-list space-y-1.5\">\n @for (columnId of columnOrder(); track columnId; let i = $index) {\n @if (columnId !== 'expand' && columnId !== 'select' && columnId !== 'rowDrag') {\n @let column = table.getColumn(columnId);\n @let isPinned = column?.getIsPinned();\n @let isVisible = pendingVisibleColumns().includes(columnId);\n @let isVisibilityDisabled = pendingColumnVisibilityDisabledMap()[columnId];\n @let isGroupedColumn = groupingColumnMap()[columnId];\n @let columnEnablePinningConfig = columnId | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let canPin =\n (columnEnablePinningConfig ?? zConfig().enableColumnPinning ?? true) && column?.getCanPin() !== false;\n @if (!isPinned) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"isGroupedColumn\"\n [cdkDragData]=\"columnId\"\n cdkDragLockAxis=\"y\"\n cdkDragPreviewContainer=\"global\"\n cdkDragPreviewClass=\"z-drag-preview\"\n class=\"z-drag-item border-border bg-card hover:border-primary flex cursor-default items-center gap-2 rounded-sm border px-2 py-1.5 text-sm\"\n [class.opacity-60]=\"!isVisible\">\n <!-- Drag Handle -->\n <z-icon\n cdkDragHandle\n zType=\"lucideGripVertical\"\n zSize=\"14\"\n class=\"text-muted-foreground shrink-0\"\n [class.cursor-pointer]=\"!isGroupedColumn\"\n [class.cursor-default]=\"isGroupedColumn\"\n [class.opacity-40]=\"isGroupedColumn\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n [disabled]=\"isVisibilityDisabled\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n (mousedown)=\"$event.stopPropagation()\"\n class=\"border-input h-4 w-4 shrink-0 cursor-default rounded-sm disabled:opacity-50\" />\n\n <!-- Column Name -->\n <span class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\" [class.text-muted-foreground]=\"!isVisible\">\n {{ columnId | zTableColumnHeader: zConfig().columns | translate }}\n </span>\n @let parents = columnId | zTableColumnParents: zConfig().columns;\n @if (parents) {\n <span class=\"text-muted-foreground truncate text-[0.625rem]\">({{ parents | translate }})</span>\n }\n </span>\n\n <!-- Pin Buttons -->\n @if (canPin) {\n <div class=\"flex shrink-0 items-center gap-0.5\" (mousedown)=\"$event.stopPropagation()\">\n <button\n type=\"button\"\n [disabled]=\"!isVisible || isGroupedColumn || !pinAvailabilityMap()[columnId]?.left\"\n (click)=\"onToggleColumnPin(columnId, 'left')\"\n class=\"text-muted-foreground hover:bg-muted cursor-pointer rounded-sm p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Pin Left\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"12\" />\n </button>\n <button\n type=\"button\"\n [disabled]=\"!isVisible || isGroupedColumn || !pinAvailabilityMap()[columnId]?.right\"\n (click)=\"onToggleColumnPin(columnId, 'right')\"\n class=\"text-muted-foreground hover:bg-muted cursor-pointer rounded-sm p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Pin Right\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"12\" />\n </button>\n </div>\n }\n </div>\n }\n }\n }\n </div>\n\n <!-- Pinned Columns Section -->\n @if (zConfig().enableColumnPinning ?? true) {\n @if (pinnedColumnIds().length > 0) {\n <div class=\"border-border mt-4 border-t pt-4\">\n <h5 class=\"text-muted-foreground mb-2 text-xs font-medium\">\n {{ 'i18n_z_ui_table_pinned_columns' | translate }}\n </h5>\n <div class=\"space-y-1.5\">\n @for (columnId of pinnedColumnIds(); track columnId) {\n @let column = table.getColumn(columnId);\n @let isPinned = column?.getIsPinned();\n @let isVisible = pendingVisibleColumns().includes(columnId);\n @let isVisibilityDisabled = pendingColumnVisibilityDisabledMap()[columnId];\n @let isGroupedColumn = groupingColumnMap()[columnId];\n <div\n class=\"border-border bg-muted/30 flex items-center gap-2 rounded-sm border px-2 py-1.5 text-sm\"\n [class.opacity-60]=\"!isVisible\">\n <!-- Pin Icon -->\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"text-primary shrink-0\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n [disabled]=\"isVisibilityDisabled\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n class=\"border-input h-4 w-4 shrink-0 cursor-default rounded-sm disabled:opacity-50\" />\n\n <!-- Column Name -->\n <span class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\" [class.text-muted-foreground]=\"!isVisible\">\n {{ columnId | zTableColumnHeader: zConfig().columns | translate }}\n </span>\n @let pinnedParents = columnId | zTableColumnParents: zConfig().columns;\n @if (pinnedParents) {\n <span class=\"text-muted-foreground truncate text-[0.625rem]\">\n ({{ pinnedParents | translate }})\n </span>\n }\n </span>\n\n <!-- Position Badge -->\n <span\n class=\"bg-primary/10 text-primary shrink-0 rounded-sm px-1.5 py-0.5 text-[0.625rem] font-medium\">\n {{\n isPinned === 'start'\n ? ('i18n_z_ui_table_left' | translate)\n : ('i18n_z_ui_table_right' | translate)\n }}\n </span>\n\n <!-- Unpin Button -->\n <button\n type=\"button\"\n [disabled]=\"isGroupedColumn\"\n (click)=\"onToggleColumnPin(columnId, isPinned === 'start' ? 'left' : 'right')\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground cursor-pointer rounded-sm p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Unpin\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </div>\n }\n </div>\n </div>\n }\n }\n </div>\n </div>\n</z-drawer>\n", styles: [":host{display:flex;flex-direction:column;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;overflow-x:visible;--scrollbar-track-thickness: 7px;--scrollbar-track-color: transparent;--scrollbar-thumb-shape: 3px;--z-shadow-left-right: -1.875rem;--z-shadow-left-width: 1.875rem;--z-shadow-left-opacity: 0;--z-shadow-right-left: -1.875rem;--z-shadow-right-width: 1.875rem;--z-shadow-right-opacity: 0;--z-sticky-left-border-color: transparent;--z-sticky-right-border-color: var(--border);--z-cell-selection-background: color-mix(in srgb, var(--primary) 12%, transparent);--z-cell-selection-background-opaque: color-mix(in srgb, var(--primary) 12%, var(--card))}.z-table-container{display:flex;flex-direction:column;position:relative;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;overflow:hidden;border-radius:var(--radius-sm);border:thin solid var(--border);background-color:var(--card)}.z-table-container:focus{outline:none}.z-table-container.z-table-borderless{border:none;border-radius:0;box-shadow:none!important;background-color:transparent}.z-table-container.z-hide-horizontal-border th,.z-table-container.z-hide-horizontal-border td{border-bottom:none!important;border-top:none!important}.z-table-container.z-hide-vertical-border th,.z-table-container.z-hide-vertical-border td{border-left:none!important}.z-table-container.z-hide-pinned-top-border tbody tr.z-pinned-top.z-shadow-bottom>td{border-bottom-color:var(--border)!important}.z-table-container.z-hide-pinned-bottom-border tbody.z-has-bottom-pinned td.z-at-bottom{border-bottom-color:transparent}table{width:fit-content;min-width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed;font-size:.875rem}.z-table-container.z-column-resizing table,.z-table-toolbar{min-width:0}.z-table-toolbar .z-settings-btn{transition:all .15s ease}.z-table-toolbar .z-settings-btn:hover{border-color:var(--muted-foreground)}.z-table-filter-header{min-width:0}.z-table-filter-header button{flex:none}.z-table-filter-header-overflow-chip{animation:z-table-filter-chip-enter .16s ease}@media(prefers-reduced-motion:reduce){.z-table-filter-header-overflow-chip{animation:none}}@keyframes z-table-filter-chip-enter{0%{opacity:0;transform:translate(-.25rem)}to{opacity:1;transform:translate(0)}}::ng-deep .z-bulk-action-bar-overlay{position:fixed!important;top:auto;left:50%;bottom:0;transform:translate(-50%);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:var(--radius-md);background:color-mix(in srgb,var(--card) 96%,var(--background));color:var(--foreground);box-shadow:0 1rem 2.5rem color-mix(in srgb,var(--foreground) 20%,transparent),0 .25rem .75rem color-mix(in srgb,var(--foreground) 12%,transparent),0 0 0 1px color-mix(in srgb,var(--background) 65%,transparent) inset;display:flex;align-items:center;gap:.5rem;width:max-content;min-height:2.25rem;max-width:calc(100vw - 2rem);padding:.5rem;transform-origin:center bottom;animation:z-bulk-action-bar-enter .18s cubic-bezier(.16,1,.3,1);will-change:opacity,transform}.z-bulk-action-bar-inner.z-leaving{pointer-events:none;animation:z-bulk-action-bar-exit .14s ease-in forwards}.z-bulk-action-bar-count{padding:0 .25rem;white-space:nowrap;font-size:.8125rem;font-weight:500;color:var(--foreground)}.z-bulk-action-bar-divider{width:1px;height:1.5rem;flex:none;background:color-mix(in srgb,var(--border) 88%,transparent)}.z-bulk-action-bar-button{flex:none}@keyframes z-bulk-action-bar-enter{0%{opacity:0;transform:translateY(.875rem)}to{opacity:1;transform:translateY(0)}}@keyframes z-bulk-action-bar-exit{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(.875rem)}}@media(prefers-reduced-motion:reduce){.z-bulk-action-bar-inner{animation:none}}:host ::ng-deep .z-table-cell-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;min-width:0;-webkit-user-select:text;user-select:text}:host ::ng-deep .z-table-cell-text>*,:host ::ng-deep .z-table-cell-text *{display:inline-block;max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}:host ::ng-deep .z-table-cell-content-trigger{display:inline-block;max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}.z-template-content{display:block;width:100%;min-width:0;max-width:100%;overflow:hidden}.z-template-content>*{min-width:0;max-width:100%}.z-template-content>[class*=flex]{min-width:0;max-width:100%}.z-template-content>[class*=flex]>*{min-width:0;flex-shrink:1}.z-template-content>[class*=grid]{min-width:0;max-width:100%}.z-thead-wrapper{flex-shrink:0;background:var(--muted);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;position:relative;z-index:4}.z-thead-wrapper::-webkit-scrollbar{display:none}.z-thead-wrapper th{height:auto;padding:.5rem;text-align:left;vertical-align:middle;font-weight:500;color:var(--foreground);white-space:nowrap;overflow:hidden;background:var(--muted);border-left:thin solid var(--border);border-bottom:thin solid var(--border);-webkit-user-select:none;user-select:none}.z-thead-wrapper th.z-at-left-edge{border-left:none}.z-thead-wrapper th[colspan]{text-align:center;background:var(--muted);font-weight:500;color:var(--foreground)}.z-thead-wrapper.z-shadow-header{box-shadow:0 1px 3px #00000014;position:relative;z-index:15}.z-thead-wrapper.z-shadow-header:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}.z-tbody-wrapper{flex:1;width:100%;max-width:100%;min-width:0;min-height:6.25rem;display:flex;flex-direction:column;overflow:hidden}.z-tbody-scrollbar{flex:1;width:100%;max-width:100%;min-width:0;height:100%}.z-empty-state,.z-loading-state{flex:1 1 0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;min-height:6.25rem;height:100%;color:var(--muted-foreground);font-size:.875rem;animation:z-fade-in .2s ease-out}.z-tbody-scrollbar,.z-tbody-scrollbar table{animation:z-fade-in .2s ease-out}@keyframes z-fade-in{0%{opacity:0;transform:translateY(.25rem)}to{opacity:1;transform:translateY(0)}}.z-tbody-wrapper tr{transition:background-color .15s ease}.z-tbody-wrapper tr:hover,.z-tbody-wrapper tr:hover td[style*=sticky]{background-color:var(--muted)}.z-tbody-wrapper tr.z-pinned-top td.z-sticky-left,.z-tbody-wrapper tr.z-pinned-top td.z-sticky-right,.z-tbody-wrapper tr.z-pinned-bottom td.z-sticky-left,.z-tbody-wrapper tr.z-pinned-bottom td.z-sticky-right{z-index:3}.z-tbody-wrapper tr.z-shadow-bottom{box-shadow:0 1px 3px #00000014!important;position:relative;z-index:15}.z-tbody-wrapper tr.z-shadow-bottom:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d!important}.z-tbody-wrapper tr.z-shadow-top{box-shadow:0 -2px 4px #0000000d!important;position:relative;z-index:15}.z-tbody-wrapper tr.z-shadow-top:where(.dark,.dark *){box-shadow:0 -2px 4px #0003!important}.z-tbody-wrapper td{padding:.5rem 12px;height:var(--z-row-height, 2.375rem);vertical-align:middle;color:var(--foreground);white-space:nowrap;overflow:hidden;background:var(--card);border-left:thin solid var(--border);border-bottom:thin solid var(--border);box-sizing:border-box}.z-tbody-wrapper tbody.z-has-vertical-scroll td.z-at-bottom,.z-tbody-wrapper tbody.z-last-row-touches-bottom td.z-at-bottom{border-bottom-color:transparent}.z-tbody-wrapper tbody.z-has-bottom-pinned td.z-at-bottom{border-bottom-color:var(--border)}.z-tbody-wrapper td.z-at-left-edge{border-left:none}.z-tbody-wrapper td i{color:var(--muted-foreground);font-style:italic}.z-tbody-wrapper td[rowspan]{vertical-align:top;padding-top:.75rem}.z-tbody-wrapper td.z-row-hover{background-color:var(--muted)!important}.z-tbody-wrapper td.z-col-select,.z-tbody-wrapper td.z-col-expand,.z-tbody-wrapper td.z-col-actions{padding:.5rem 4px!important;text-align:center}.z-tbody-wrapper tr.z-child-row td.z-col-select:first-child,.z-tbody-wrapper tr.z-child-row td.z-col-expand:first-child,.z-tbody-wrapper tr.z-child-row td.z-col-actions:first-child{padding-left:0!important}.z-virtual-scroll-inner{position:relative;box-sizing:border-box;width:100%}.z-virtual-row,.z-virtual-flow{position:absolute;top:0;left:0;width:100%}.z-virtual-row-flow{position:relative}.z-virtual-row-fixed{overflow:hidden}.z-virtual-row-group-header{z-index:2}.z-virtual-row-sticky-group{position:sticky}.z-virtual-row-sticky-group-shadow{box-shadow:0 1px 3px #00000014}.z-virtual-row-sticky-group-shadow:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}tr.z-group-row-sticky{position:sticky;z-index:2}tr.z-group-row-sticky>td{background:var(--card)}tr.z-group-row-sticky-shadow{box-shadow:0 1px 3px #00000014}tr.z-group-row-sticky-shadow:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}tr.z-child-row td:first-child{border-left:.125rem solid var(--primary)!important;padding-left:.75rem!important}tbody tr.z-context-menu-active,tbody tr.z-context-menu-active td{background-color:var(--muted)!important}tbody tr.z-selected,tbody tr.z-selected td{background-color:color-mix(in srgb,var(--primary) 15%,var(--background))!important}tbody tr.z-selected:hover,tbody tr.z-selected:hover td{background-color:color-mix(in srgb,var(--primary) 20%,var(--background))!important}tbody tr.z-indeterminate-selected,tbody tr.z-indeterminate-selected td{background-color:color-mix(in srgb,var(--primary) 10%,var(--background))!important}tbody tr.z-indeterminate-selected:hover,tbody tr.z-indeterminate-selected:hover td{background-color:color-mix(in srgb,var(--primary) 15%,var(--background))!important}tbody tr.z-pinned-top td{background-color:var(--card)!important}tbody tr.z-pinned-top:hover{background-color:var(--muted)}tbody tr.z-pinned-top:hover td{background-color:var(--muted)!important}tbody tr.z-pinned-bottom td{background-color:var(--card)!important}tbody tr.z-pinned-bottom:hover{background-color:var(--muted)}tbody tr.z-pinned-bottom:hover td{background-color:var(--muted)!important}tbody tr.z-pinned-bottom-last>td{border-bottom-color:transparent!important}tbody tr.z-pinned-bottom-first>td{border-top:thin solid var(--border)}:host .z-tbody-wrapper tbody tr:not(.z-pinned-top):not(.z-pinned-bottom):has(+tr.z-pinned-bottom)>td{border-bottom-color:transparent}tr.z-expanded-row>td{border-left:.125rem solid var(--primary);background-color:var(--background)!important}.z-expanded-row-content{transform-origin:top center}@keyframes z-expanded-row-reveal{0%{clip-path:inset(0 0 100% 0);translate:0 -.375rem;opacity:0}to{clip-path:inset(0 0 0 0);translate:none;opacity:1}}@keyframes z-expanded-row-fade-in{0%{opacity:0}to{opacity:1}}tr.z-expanded-row-enter{animation:z-expanded-row-fade-in .18s ease-out}tr.z-expanded-row-enter .z-expanded-row-content{animation:z-expanded-row-reveal .18s ease-out}@keyframes z-child-row-slide-in{0%{translate:0 -.375rem;opacity:0}to{translate:none;opacity:1}}tr.z-child-row.z-row-enter,tr.z-group-child-row.z-row-enter{animation:z-child-row-slide-in .18s ease-out}@media(prefers-reduced-motion:reduce){tr.z-expanded-row-enter,tr.z-child-row.z-row-enter,tr.z-group-child-row.z-row-enter,tr.z-expanded-row-enter .z-expanded-row-content,tr.z-child-row.z-row-enter .z-expanded-row-content,tr.z-group-child-row.z-row-enter .z-expanded-row-content{animation-duration:1ms}}.z-sub-table-container{padding:.75rem 1rem .75rem 3rem;background-color:var(--background)}.z-table-content-trigger{display:block;width:100%;min-width:0;min-height:1.5rem;padding:0;border:0;border-radius:0;background:transparent;color:inherit;font:inherit;line-height:1.5rem;text-align:inherit;outline:0;cursor:text}.z-table-content-trigger:hover{color:var(--primary)}.z-content-edit-active{position:relative;z-index:2}td:has(>.z-table-content-trigger:focus-visible){position:relative;z-index:2}td:has(>.z-table-content-trigger:focus-visible):after{position:absolute;z-index:3;inset:0;border:1px solid var(--primary);content:\"\";pointer-events:none}td.z-cell-selectable{-webkit-user-select:none;user-select:none}td.z-cell-range-selected{position:relative;isolation:isolate}td.z-cell-range-selected:before{position:absolute;z-index:0;box-sizing:border-box;top:var(--z-cell-range-top, 0);right:var(--z-cell-range-right, 0);bottom:var(--z-cell-range-bottom, 0);left:var(--z-cell-range-left, 0);background-color:var(--z-cell-selection-background);content:\"\";pointer-events:none}td.z-cell-range-selected>*{position:relative;z-index:1}td.z-cell-range-top:before{border-top:1px solid var(--primary)}td.z-cell-range-right:before{border-right:1px solid var(--primary)}td.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}td.z-cell-range-left:before{border-left:1px solid var(--primary)}td.z-cell-active{position:relative;z-index:3;background-color:var(--z-cell-selection-background)!important}td.z-cell-active:after{position:absolute;z-index:4;inset:0;border:1px solid var(--primary);content:\"\";pointer-events:none}td.z-content-edit-active{-webkit-user-select:text;user-select:text}td.z-cell-active.z-row-hover,td.z-content-edit-active.z-row-hover{background-color:var(--card)!important}thead th{position:relative}thead th .z-resizer{position:absolute;right:0;top:0;height:100%;width:.5rem;background:transparent;cursor:col-resize;-webkit-user-select:none;user-select:none;touch-action:none;z-index:5}thead th .z-resizer:after{content:\"\";position:absolute;right:0;top:0;height:100%;width:.1875rem;background:#0000001a;opacity:0;transition:opacity .2s ease}thead th .z-resizer:after:where(.dark,.dark *){background:#ffffff1a}thead th .z-resizer:hover:after{opacity:1;background:var(--primary);width:.1875rem}thead th .z-resizer.z-is-resizing:after{opacity:1;background:var(--primary);width:.1875rem}thead th .z-resizer.z-resizer-left{right:auto;left:0}thead th .z-resizer.z-resizer-left:after{right:auto;left:0}.z-thead-wrapper th.z-sticky-left,.z-thead-wrapper th.z-sticky-right,.z-tbody-wrapper th.z-sticky-left,.z-tbody-wrapper th.z-sticky-right,.z-tfoot-wrapper th.z-sticky-left,.z-tfoot-wrapper th.z-sticky-right{background-color:var(--muted);z-index:1;transform:translateZ(0);backface-visibility:hidden}.z-thead-wrapper td.z-sticky-left,.z-thead-wrapper td.z-sticky-right,.z-tbody-wrapper td.z-sticky-left,.z-tbody-wrapper td.z-sticky-right,.z-tfoot-wrapper td.z-sticky-left,.z-tfoot-wrapper td.z-sticky-right{background-color:var(--card);z-index:1;transform:translateZ(0);backface-visibility:hidden}.z-thead-wrapper th.z-sticky-left-last,.z-thead-wrapper td.z-sticky-left-last,.z-tbody-wrapper th.z-sticky-left-last,.z-tbody-wrapper td.z-sticky-left-last,.z-tfoot-wrapper th.z-sticky-left-last,.z-tfoot-wrapper td.z-sticky-left-last{position:relative;overflow:visible;border-right:thin solid var(--z-sticky-left-border-color)}.z-thead-wrapper th.z-sticky-left-last:after,.z-thead-wrapper td.z-sticky-left-last:after,.z-tbody-wrapper th.z-sticky-left-last:after,.z-tbody-wrapper td.z-sticky-left-last:after,.z-tfoot-wrapper th.z-sticky-left-last:after,.z-tfoot-wrapper td.z-sticky-left-last:after{content:\"\";position:absolute;top:0;bottom:0;right:var(--z-shadow-left-right);width:var(--z-shadow-left-width);pointer-events:none;box-shadow:inset 10px 0 8px -8px #0000001a;z-index:10;opacity:var(--z-shadow-left-opacity)}:host-context(.dark) .z-thead-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-thead-wrapper td.z-sticky-left-last:after,:host-context(.dark) .z-tbody-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-tbody-wrapper td.z-sticky-left-last:after,:host-context(.dark) .z-tfoot-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-tfoot-wrapper td.z-sticky-left-last:after{box-shadow:inset 10px 0 10px -8px #0000004d}.z-thead-wrapper.z-scroll-left,.z-tbody-wrapper.z-scroll-left,.z-tfoot-wrapper.z-scroll-left{--z-shadow-left-opacity: 1}.z-thead-wrapper.z-scroll-left:where(.dark,.dark *),.z-tbody-wrapper.z-scroll-left:where(.dark,.dark *),.z-tfoot-wrapper.z-scroll-left:where(.dark,.dark *){--z-sticky-left-border-color: var(--border)}.z-thead-wrapper th.z-sticky-right-first,.z-thead-wrapper td.z-sticky-right-first,.z-tbody-wrapper th.z-sticky-right-first,.z-tbody-wrapper td.z-sticky-right-first,.z-tfoot-wrapper th.z-sticky-right-first,.z-tfoot-wrapper td.z-sticky-right-first{position:relative;overflow:visible;border-left:thin solid var(--z-sticky-right-border-color)}.z-thead-wrapper th.z-sticky-right-first:before,.z-thead-wrapper td.z-sticky-right-first:before,.z-tbody-wrapper th.z-sticky-right-first:before,.z-tbody-wrapper td.z-sticky-right-first:before,.z-tfoot-wrapper th.z-sticky-right-first:before,.z-tfoot-wrapper td.z-sticky-right-first:before{content:\"\";position:absolute;top:0;bottom:0;left:var(--z-shadow-right-left);width:var(--z-shadow-right-width);pointer-events:none;box-shadow:inset -10px 0 8px -8px #0000001a;z-index:10;opacity:var(--z-shadow-right-opacity)}:host-context(.dark) .z-thead-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-thead-wrapper td.z-sticky-right-first:before,:host-context(.dark) .z-tbody-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-tbody-wrapper td.z-sticky-right-first:before,:host-context(.dark) .z-tfoot-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-tfoot-wrapper td.z-sticky-right-first:before{box-shadow:inset -10px 0 10px -8px #0000004d}.z-thead-wrapper.z-scroll-right,.z-tbody-wrapper.z-scroll-right,.z-tfoot-wrapper.z-scroll-right{--z-shadow-right-opacity: 1}.z-thead-wrapper.z-scroll-right:not(:where(.dark,.dark *)),.z-tbody-wrapper.z-scroll-right:not(:where(.dark,.dark *)),.z-tfoot-wrapper.z-scroll-right:not(:where(.dark,.dark *)){--z-sticky-right-border-color: transparent}.z-pinning-overflow{--z-shadow-left-opacity: 0 !important;--z-shadow-right-opacity: 0 !important;--z-sticky-left-border-color: transparent !important;--z-sticky-right-border-color: transparent !important}.z-pinning-overflow .z-sticky-left,.z-pinning-overflow .z-sticky-right{position:relative!important;right:auto!important;left:auto!important}.z-pinning-overflow .z-sticky-left-last:after,.z-pinning-overflow .z-sticky-right-first:before,.z-pinning-overflow .z-sticky-right-last:after{display:none!important}.z-thead-wrapper th.z-sticky-right-last,.z-tfoot-wrapper th.z-sticky-right-last{position:relative}.z-thead-wrapper th.z-sticky-right-last:after,.z-tfoot-wrapper th.z-sticky-right-last:after{content:\"\";position:absolute;top:0;bottom:0;right:-1.875rem;width:1.875rem;background:var(--muted);pointer-events:none}.z-tfoot-wrapper{flex-shrink:0;width:100%;max-width:100%;min-width:0;background:var(--muted);overflow-x:hidden;overflow-y:hidden;touch-action:pan-y pinch-zoom}.z-tfoot-wrapper th{height:auto;padding:.5rem 12px;text-align:left;vertical-align:middle;font-weight:500;font-size:.75rem;color:var(--muted-foreground);text-transform:uppercase;letter-spacing:.5px;background:var(--muted);border-left:thin solid var(--border);border-top:thin solid var(--border)}.z-tfoot-wrapper th.z-at-left-edge{border-left:none}.z-tfoot-wrapper.z-shadow-footer{box-shadow:0 -2px 4px #0000000d;position:relative;z-index:15}.z-tfoot-wrapper.z-shadow-footer:where(.dark,.dark *){box-shadow:0 -2px 4px #0003}.z-pin-btn{padding:.125rem 4px;border-radius:var(--radius-xs);color:var(--muted-foreground);transition:all .15s ease}.z-pin-btn:hover{background-color:var(--muted);color:var(--foreground)}.z-pin-btn.z-pin-btn-active{color:var(--primary);background-color:var(--primary)}.z-pin-btn.z-pin-btn-active:hover{background-color:var(--primary);opacity:.8}.z-row-pin-trigger{opacity:1}.z-row-pin-trigger:focus-visible,.z-row-pin-trigger.z-popover-open{background-color:color-mix(in srgb,var(--foreground) 8%,transparent);color:var(--foreground)}.z-row-pin-trigger:active{background-color:color-mix(in srgb,var(--foreground) 12%,transparent)}.z-row-pin-trigger.text-primary{color:var(--primary)}.z-row-pin-unpin-trigger{color:var(--muted-foreground);outline:none}.z-row-pin-unpin-trigger:hover{color:var(--destructive);background-color:color-mix(in srgb,var(--destructive) 10%,transparent)}.z-row-pin-unpin-trigger:focus,.z-row-pin-unpin-trigger:focus-visible{color:var(--muted-foreground);background-color:transparent;outline:none;box-shadow:none}.z-row-pin-unpin-trigger:active{color:var(--destructive);background-color:color-mix(in srgb,var(--destructive) 14%,transparent)}.z-header-pin-trigger{opacity:1}.z-header-pin-trigger.text-primary{color:var(--primary)}th{overflow:hidden}th .z-header-content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}th .z-header-text-wrapper{transition:background-color .15s ease;border-radius:var(--radius-xs);min-width:0;overflow:hidden;flex-shrink:1}th .z-header-text-wrapper.z-has-options:hover,th .z-header-text-wrapper.z-has-options:focus-visible,th .z-header-text-wrapper.z-has-options.z-popover-open{background-color:color-mix(in srgb,var(--foreground) 8%,transparent);outline:none}th .z-header-text-wrapper.z-has-options:active{background-color:color-mix(in srgb,var(--foreground) 12%,transparent)}.z-column-menu-item{position:relative;z-index:1;line-height:1.25rem;transition:background-color .15s ease,color .15s ease}.z-column-menu-item:focus-visible,.z-column-menu-item.z-popover-open{background-color:var(--muted);outline:none}.z-table-drag-preview{box-sizing:border-box;border-radius:var(--radius-md);background-color:var(--card);border:1px solid var(--primary);box-shadow:0 10px 24px #00000029;overflow:hidden;z-index:10000!important;pointer-events:none}.z-table-drag-preview:where(.dark,.dark *){box-shadow:0 5px 20px #00000080}.z-table-drag-preview-row{border:0;border-radius:var(--radius-xs);background-color:var(--background);box-shadow:0 8px 20px #0000001f,inset 0 0 0 1px color-mix(in srgb,var(--primary) 45%,var(--border))}.z-table-drag-preview-row table,.z-table-drag-preview-row tbody,.z-table-drag-preview-row tr{height:100%}.z-table-drag-preview-row td{vertical-align:middle!important;background-color:var(--background)}.z-table-drag-preview-virtual{border:0;border-radius:0;box-shadow:0 8px 20px #0000001f,inset 0 0 0 1px color-mix(in srgb,var(--primary) 45%,var(--border))}.z-table-drag-source{display:none!important}.z-virtual-row.z-table-drag-source{display:block!important;pointer-events:none;outline:1px solid var(--border);outline-offset:-1px}.z-virtual-row.z-table-drag-source td{color:color-mix(in srgb,var(--foreground) 45%,transparent);border-color:var(--border)!important;background-color:var(--card)!important}.z-virtual-row.z-table-drag-source td>*{opacity:.45}[data-z-table-drag-handle]{touch-action:none;-webkit-user-select:none;user-select:none}.z-column-drop-list{min-height:3.125rem;overscroll-behavior:contain}.cdk-drag-preview.z-drag-preview,.cdk-drag-placeholder.z-drag-item{border-radius:var(--radius-sm)}.z-table-drag-placeholder{width:100%;min-height:2.625rem;box-sizing:border-box;border:2px dashed var(--primary);border-radius:0;background-color:color-mix(in srgb,var(--primary) 10%,var(--background));pointer-events:none}.z-table-drag-placeholder-row>td{padding:0!important;border:0!important;background:transparent!important}.z-table-drag-placeholder-row .z-table-drag-placeholder{border-radius:0;background-color:color-mix(in srgb,var(--primary) 10%,transparent)}.z-table-drag-placeholder-virtual{position:absolute;top:0;left:0;z-index:20;border-radius:0}.z-tbody-wrapper tr.z-group-row td{background:var(--card);border-top:none;border-bottom:1px solid var(--border)}.z-virtual-row:not(.z-virtual-row-flow) tr.z-group-row td{background:var(--card);border-top:none;border-bottom:none}.z-group-row-sticky-wrapper{display:inline-flex;align-items:center;translate:var(--z-scroll-x, 0px) 0}.z-table-container:not(.z-hide-horizontal-border) .z-virtual-row:not(.z-virtual-row-flow):after,.z-table-container:not(.z-hide-horizontal-border) .z-virtual-row-flow.z-virtual-row-group-header:after{content:\"\";position:absolute;right:0;bottom:0;left:0;z-index:3;height:1px;background:var(--border);pointer-events:none}.z-tbody-wrapper tr.z-group-child-row td.z-at-left-edge,.z-virtual-row tr.z-group-child-row td.z-at-left-edge{border-left:2px solid var(--primary)!important;padding-left:var(--z-group-content-indent, .75rem)}.z-group-row-trigger{display:inline-flex;min-height:2rem;max-width:100%;align-items:center;gap:.5rem;padding:.25rem .5rem .25rem .75rem;color:var(--primary);font-size:.8125rem;font-weight:600;vertical-align:middle;cursor:pointer}.z-group-row-remove{margin-left:.125rem;color:var(--muted-foreground);vertical-align:middle}.z-group-row-remove:hover,.z-group-row-remove:focus-visible{color:var(--destructive);background:color-mix(in srgb,var(--destructive) 10%,transparent);outline:none}.z-group-row-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-column-label{color:color-mix(in srgb,var(--primary) 65%,var(--foreground));font-weight:500;margin-right:.25rem}.z-group-row-count{display:inline-flex;min-width:1.25rem;height:1.25rem;align-items:center;justify-content:center;padding:0 .375rem;border-radius:var(--radius-pill);background:var(--primary);color:var(--primary-foreground);font-size:.6875rem;font-weight:600}.z-group-row-loading{display:inline-flex;align-items:center;margin-left:.25rem}.z-group-row-has-totals td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-has-totals .z-group-row-label-cell{position:sticky;left:0;z-index:2;background:var(--card)}.z-group-row-has-totals .z-group-row-label-cell .z-group-row-sticky-wrapper{max-width:100%;translate:none}.z-group-row-total{display:inline-block;max-width:100%;color:var(--foreground);font-size:.8125rem;font-weight:600;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-total-cell{text-align:right}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-selected:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:before{position:absolute!important;z-index:0!important;box-sizing:border-box!important;top:var(--z-cell-range-top, 0)!important;right:var(--z-cell-range-right, 0)!important;bottom:var(--z-cell-range-bottom, 0)!important;left:var(--z-cell-range-left, 0)!important;width:auto!important;background-color:var(--z-cell-selection-background-opaque)!important;box-shadow:none!important;content:\"\"!important;pointer-events:none!important;opacity:1!important}:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:after{display:none!important}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-top:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-top:before{border-top:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-right:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-right:before{border-right:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-bottom:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-left:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-left:before{border-left:1px solid var(--primary)}:host-context(.z-table-pointer-dragging) .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-selected:before,:host-context(.z-table-pointer-dragging) .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:before{background-color:transparent!important}:host td.z-cell-range-selected:before{position:absolute;z-index:0;box-sizing:border-box;top:var(--z-cell-range-top, 0);right:var(--z-cell-range-right, 0);bottom:var(--z-cell-range-bottom, 0);left:var(--z-cell-range-left, 0);background-color:var(--z-cell-selection-background);box-shadow:none;content:\"\";pointer-events:none;opacity:1}:host td.z-cell-range-top:before{border-top:1px solid var(--primary)}:host td.z-cell-range-right:before{border-right:1px solid var(--primary)}:host td.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}:host td.z-cell-range-left:before{border-left:1px solid var(--primary)}:host-context(.z-table-pointer-dragging) td.z-row-hover{background-color:var(--background)!important}:host td.z-cell-active,:host td.z-cell-active.z-row-hover{background-color:var(--z-cell-selection-background)!important}:host td.z-content-edit-active.z-row-hover{background-color:var(--card)!important}:host tr.z-pinned-top td.z-cell-active,:host tr.z-pinned-top td.z-cell-active.z-row-hover,:host tr.z-pinned-bottom td.z-cell-active,:host tr.z-pinned-bottom td.z-cell-active.z-row-hover,:host td.z-cell-active.z-sticky-left,:host td.z-cell-active.z-sticky-left.z-row-hover,:host td.z-cell-active.z-sticky-right,:host td.z-cell-active.z-sticky-right.z-row-hover{background-color:var(--z-cell-selection-background-opaque)!important}:host tr.z-pinned-top td.z-cell-range-selected,:host tr.z-pinned-bottom td.z-cell-range-selected,:host td.z-cell-range-selected.z-sticky-left,:host td.z-cell-range-selected.z-sticky-right{background-color:var(--card)}:host tr.z-pinned-top td.z-cell-range-selected:before,:host tr.z-pinned-bottom td.z-cell-range-selected:before,:host td.z-cell-range-selected.z-sticky-left:before,:host td.z-cell-range-selected.z-sticky-right:before{background-color:var(--z-cell-selection-background-opaque)}:host-context(.z-table-pointer-dragging) td.z-cell-range-selected,:host-context(.z-table-pointer-dragging) td.z-cell-range-selected.z-row-hover,:host-context(.z-table-pointer-dragging) td.z-cell-active,:host-context(.z-table-pointer-dragging) td.z-cell-active.z-row-hover{background-color:var(--card)!important}:host-context(.z-table-pointer-dragging) td.z-cell-range-selected:before{background-color:transparent}:host .z-tbody-wrapper tbody tr.z-group-child-row:has(+tr.z-group-row)>td.z-at-bottom{border-bottom-color:var(--border)}:host .z-virtual-row:has(tr.z-group-child-row):has(+.z-virtual-row tr.z-group-row) tr.z-group-child-row>td.z-at-bottom{border-bottom-color:var(--border)}.z-thead-wrapper th.z-virtual-column-spacer,.z-tfoot-wrapper th.z-virtual-column-spacer{box-sizing:border-box;padding:0!important;background:var(--muted);border-left:thin solid var(--border)}.z-thead-wrapper th.z-virtual-header-spacer{border-bottom:thin solid var(--border)}.z-tfoot-wrapper th.z-virtual-footer-spacer{border-top:thin solid var(--border)}.z-tbody-wrapper td.z-virtual-column-spacer{box-sizing:border-box;height:auto;padding:0!important;background:var(--card);border-left:thin solid var(--border);border-bottom:thin solid var(--border)}.z-tbody-wrapper tr:hover td.z-virtual-column-spacer{background-color:var(--muted)}.z-table-settings-drawer input[type=checkbox]{appearance:none;-webkit-appearance:none;-moz-appearance:none;width:1rem;height:1rem;border:thin solid var(--input);border-radius:var(--radius-sm);background-color:var(--background);cursor:pointer;position:relative;transition:all .2s ease}.z-table-settings-drawer input[type=checkbox]:hover{border-color:var(--primary)}.z-table-settings-drawer input[type=checkbox]:checked{background-color:var(--primary);border-color:var(--primary)}.z-table-settings-drawer input[type=checkbox]:checked:after{content:\"\";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:.375rem;height:.625rem;border:solid var(--primary-foreground);border-width:0 .125rem .125rem 0;transform:translate(-50%,-60%) rotate(45deg)}.z-table-settings-drawer input[type=checkbox]:disabled{opacity:.5;cursor:not-allowed}.z-virtual-pinned-top{position:sticky;top:0;left:0;z-index:3;width:100%}.z-virtual-pinned-bottom{position:sticky;bottom:0;left:0;z-index:3;width:100%}\n"], dependencies: [{ kind: "component", type: ZTableComponent, selector: "z-table", inputs: ["zClass", "zConfig", "zLoading", "zKey", "zVariant"], outputs: ["zChange", "zControl"], exportAs: ["zTable"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "component", type: NgScrollbar, selector: "ng-scrollbar:not([externalViewport]), [ngScrollbar]", exportAs: ["ngScrollbar"] }, { kind: "directive", type: FlexRenderDirective, selector: "ng-template[flexRender]", inputs: ["flexRender", "flexRenderProps", "flexRenderInjector"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: ZTableDraggableDirective, selector: "[z-table-draggable]", inputs: ["z-table-draggable", "z-table-drag-table-id", "z-table-drag-item-id", "z-table-drag-disabled", "z-table-drag-handle"] }, { kind: "directive", type: ZTableDropTargetDirective, selector: "[z-table-drop-target]", inputs: ["z-table-drop-target", "z-table-drop-table-id", "z-table-drop-item-id", "z-table-drop-disabled"], outputs: ["zTableDropped"] }, { kind: "component", type: ZCheckboxComponent, selector: "z-checkbox", inputs: ["class", "zType", "zSize", "zLabel", "zText", "zDisabled", "zIndeterminate", "zValue", "zOptions", "zOrientation", "zCheckAll", "zCheckAllText", "zChecked", "zGroupValue"], outputs: ["zChange", "zGroupChange", "zOnBlur", "zOnFocus", "zControl", "zEvent", "zCheckedChange", "zGroupValueChange"] }, { kind: "component", type: ZEmptyComponent, selector: "z-empty", inputs: ["class", "zType", "zIcon", "zIconSize", "zSize", "zMessage", "zDescription"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zAnimatedType", "zAnimate", "zAnimationTrigger", "zSize", "zStrokeWidth", "zSvg"] }, { kind: "component", type: ZInputComponent, selector: "z-input", inputs: ["class", "zType", "zSize", "zAlign", "zLabel", "zLabelClass", "zPlaceholder", "zRequired", "zDisabled", "zReadonly", "zLoading", "zLoadingOutline", "zPrefix", "zSuffix", "zMin", "zMax", "zStep", "zShowArrows", "zMask", "zDecimalPlaces", "zAllowNegative", "zThousandSeparator", "zDecimalMarker", "zValidators", "zAsyncValidators", "zAsyncDebounce", "zAsyncValidateOn", "zShowPasswordToggle", "zSearch", "zDebounce", "zAutofocus", "zAutoComplete", "zAllowClear", "zAutoSizeContent", "zRows", "zResize", "zMaxLength", "zAutoSuggest", "zColorConfig"], outputs: ["zOnSearch", "zOnChange", "zOnBlur", "zOnFocus", "zOnKeydown", "zOnEnter", "zOnColorCollapse", "zControl", "zEvent"], exportAs: ["zInput"] }, { kind: "component", type: ZLoadingComponent, selector: "z-loading", inputs: ["class", "zSpinner", "zSize", "zColor", "zText", "zOverlay", "zOverlayType", "zFullscreen", "zLoading"] }, { kind: "directive", type: ZHoverGlideDirective, selector: "[zHoverGlide]", inputs: ["zHoverGlideSelector", "zHoverGlideClass", "zHoverGlideDisabled"] }, { kind: "component", type: ZSkeletonComponent, selector: "z-skeleton", inputs: ["class", "zType", "zSize", "zWidth", "zHeight", "zRows", "zGap", "zAnimated", "zRadius"] }, { kind: "component", type: ZDrawerComponent, selector: "z-drawer", inputs: ["class", "zBodyClass", "zVisible", "zTitle", "zDescription", "zWidth", "zHeight", "zPlacement", "zClosable", "zMaskClosable", "zDisableShadow", "zHeaderBorder", "zFooterBorder", "zHideFooter", "zHideHeader", "zOkText", "zCancelText", "zOkDestructive", "zOkDisabled", "zLoading", "zOverlay", "zShadow", "zShape", "zContentLoading", "zSkeletonRows", "zExpand", "zScrollMode"], outputs: ["zOnOk", "zOnCancel", "zAfterClose", "zScrollbar", "zVisibleChange"], exportAs: ["zDrawer"] }, { kind: "component", type: ZPaginationComponent, selector: "z-pagination", inputs: ["zPageIndex", "zPageSize", "zTotal", "zPageSizeOptions", "zShowSizeChanger", "zShowQuickJumper", "zShowTotal", "zSimple", "zSize", "zDisabled", "zTotalLabel", "zPerPageLabel", "zGoToLabel"], outputs: ["zOnPageChange", "zPageIndexChange", "zPageSizeChange"] }, { kind: "component", type: ZTableFilterComponent, selector: "z-table-filter", inputs: ["zColumn", "zTable", "zResetVersion", "zSortingState", "zEnableMultiSort"] }, { kind: "component", type: ZTableEditCellComponent, selector: "z-table-edit-cell", inputs: ["zRow", "zRowId", "zRowIndex", "zColumnId", "zValue", "zEditConfig", "zRowUpdate"], outputs: ["zChange"] }, { kind: "directive", type: ZPopoverDirective, selector: "[z-popover]", inputs: ["zPopoverContent", "zPosition", "zTrigger", "zPopoverTrigger", "zClass", "zShowDelay", "zHideDelay", "zDisabled", "zOffset", "zPopoverWidth", "zTriggerRef", "zManualClose", "zOutsideClickClose", "zScrollClose", "zSticky", "zShowArrow", "zKeyboardSafe"], outputs: ["zShow", "zHide", "zHideStart", "zControl", "zPositionChange", "zOutsideClick"], exportAs: ["zPopover"] }, { kind: "component", type: ZButtonComponent, selector: "z-button, button[z-button], a[z-button]", inputs: ["class", "zType", "zSize", "zShape", "zLabel", "zLoading", "zDisabled", "zTypeIcon", "zAnimatedTypeIcon", "zAnimateIcon", "zAnimationTriggerIcon", "zSizeIcon", "zStrokeWidthIcon", "zWave"], exportAs: ["zButton"] }, { kind: "directive", type: ZTooltipDirective, selector: "[z-tooltip], [zTooltip]", inputs: ["zContent", "zPosition", "zTooltipPosition", "zTrigger", "zTooltipTrigger", "zTooltipType", "zTooltipSize", "zClass", "zTooltipClass", "zShowDelay", "zTooltipShowDelay", "zHideDelay", "zTooltipHideDelay", "zArrow", "zTooltipArrow", "zDisabled", "zTooltipDisabled", "zOffset", "zTooltipOffset", "zAutoDetect", "zTriggerElement", "zAlwaysShow", "zMaxWidth"], outputs: ["zShow", "zHide"], exportAs: ["zTooltip"] }, { kind: "directive", type: ZTableResizeDirective, selector: "[z-table-resize],[zTableResize]", inputs: ["zTableResize"] }, { kind: "directive", type: ZTableRowHoverDirective, selector: "[z-table-row-hover], [zTableRowHover]", inputs: ["zTableRowHover"] }, { kind: "component", type: ZTableIconTextComponent, selector: "z-table-icon-text", inputs: ["zText", "zTooltip", "zTriggerElement"] }, { kind: "component", type: ZTableActionsComponent, selector: "z-table-actions", inputs: ["zConfig", "zRow", "zRowId", "zDropdownButtonSize"], outputs: ["zActionClick"] }, { kind: "component", type: ZTableContentEditorComponent, selector: "z-table-content-editor", inputs: ["zValue", "zConfig"], outputs: ["zCommit", "zCancel"] }, { kind: "pipe", type: ZTableIsTemplateRefPipe, name: "zTableIsTemplateRef" }, { kind: "pipe", type: ZTableHasIconPipe, name: "zTableHasIcon" }, { kind: "pipe", type: ZTableCellBottomPipe, name: "zTableCellBottom" }, { kind: "pipe", type: ZTableCellClickablePipe, name: "zTableCellClickable" }, { kind: "pipe", type: ZTableCellConfigPipe, name: "zTableCellConfig" }, { kind: "pipe", type: ZTableCellEditPipe, name: "zTableCellEdit" }, { kind: "pipe", type: ZTableCellOffsetPipe, name: "zTableCellOffset" }, { kind: "pipe", type: ZTableCellPinPipe, name: "zTableCellPin" }, { kind: "pipe", type: ZTableCellVisiblePipe, name: "zTableCellVisible" }, { kind: "pipe", type: ZTableColumnConfigPipe, name: "zTableColumnConfig" }, { kind: "pipe", type: ZTableColumnHeaderPipe, name: "zTableColumnHeader" }, { kind: "pipe", type: ZTableColumnParentsPipe, name: "zTableColumnParents" }, { kind: "pipe", type: ZTableFooterContentPipe, name: "zTableFooterContent" }, { kind: "pipe", type: ZTableFooterRenderPipe, name: "zTableFooterRender" }, { kind: "pipe", type: ZTablePinningStylesPipe, name: "zTablePinningStyles" }, { kind: "pipe", type: ZTablePopoverConfigPipe, name: "zTablePopoverConfig" }, { kind: "pipe", type: ZTableRowPipe, name: "zTableRow" }, { kind: "pipe", type: ZTableRowConfigPipe, name: "zTableRowConfig" }, { kind: "pipe", type: ZTableSpanPipe, name: "zTableSpan" }, { kind: "pipe", type: ZTableSubTableConfigPipe, name: "zTableSubTableConfig" }, { kind: "pipe", type: ZTableTooltipConfigPipe, name: "zTableTooltipConfig" }, { kind: "pipe", type: ZTableCellRenderPipe, name: "zTableCellRender" }, { kind: "pipe", type: ZFormatNumPipe, name: "zFormatNum" }, { kind: "pipe", type: ZSafeHtmlPipe, name: "zSafeHtml" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
11261
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ZTableComponent, isStandalone: true, selector: "z-table", inputs: { zClass: { classPropertyName: "zClass", publicName: "zClass", isSignal: true, isRequired: false, transformFunction: null }, zConfig: { classPropertyName: "zConfig", publicName: "zConfig", isSignal: true, isRequired: false, transformFunction: null }, zLoading: { classPropertyName: "zLoading", publicName: "zLoading", isSignal: true, isRequired: false, transformFunction: null }, zKey: { classPropertyName: "zKey", publicName: "zKey", isSignal: true, isRequired: false, transformFunction: null }, zVariant: { classPropertyName: "zVariant", publicName: "zVariant", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { zChange: "zChange", zControl: "zControl" }, host: { classAttribute: "z-table block relative py-1" }, providers: [TranslatePipe, ZTableDragService], viewQueries: [{ propertyName: "theadWrapper", first: true, predicate: ["theadWrapper"], descendants: true, isSignal: true }, { propertyName: "tableContainer", first: true, predicate: ["tableContainer"], descendants: true, isSignal: true }, { propertyName: "tbodyContainer", first: true, predicate: ["tbodyContainer"], descendants: true, isSignal: true }, { propertyName: "tbodyWrapper", first: true, predicate: ["tbodyWrapper"], descendants: true, isSignal: true }, { propertyName: "tbodyScrollbar", first: true, predicate: ["tbodyWrapper"], descendants: true, isSignal: true }, { propertyName: "tfootWrapper", first: true, predicate: ["tfootWrapper"], descendants: true, isSignal: true }, { propertyName: "expandedRowTemplate", first: true, predicate: ["expandedRowTemplate"], descendants: true, isSignal: true }, { propertyName: "virtualRowElements", predicate: ["virtualRow"], descendants: true, isSignal: true }, { propertyName: "groupRowElements", predicate: ["groupRow"], descendants: true, isSignal: true }, { propertyName: "bulkBarTemplateRef", first: true, predicate: ["bulkBarTemplate"], descendants: true, isSignal: true }], exportAs: ["zTable"], ngImport: i0, template: "<!-- Toolbar: Search & Settings -->\n@if (isSearchEnabled() || zConfig().enableSettings) {\n <div class=\"z-table-toolbar mb-2 flex items-center justify-between gap-4\">\n <!-- Search -->\n @if (isSearchEnabled()) {\n @let config = searchConfig();\n <z-input\n [class]=\"config?.width ?? 'w-64'\"\n [zSize]=\"config?.size ?? 'sm'\"\n [zPlaceholder]=\"config?.placeholder ?? 'i18n_z_ui_table_search' | translate\"\n [zSearch]=\"true\"\n [zDebounce]=\"config?.debounceTime ?? 300\"\n (zOnSearch)=\"onSearchChange($event)\" />\n } @else {\n <div></div>\n }\n\n <!-- Settings Button -->\n @if (zConfig().enableSettings) {\n <z-button zType=\"outline\" zSize=\"sm\" zTypeIcon=\"lucideSettings\" (click)=\"openSettingsDrawer()\">\n {{ 'i18n_z_ui_table_settings' | translate }}\n </z-button>\n }\n </div>\n}\n\n@if (zConfig().enableFilterHeader && appliedFilterChips().length > 0) {\n <div class=\"z-table-filter-header mb-2 flex min-w-0 items-center gap-2\">\n <div class=\"flex min-w-0 flex-1 flex-wrap items-center gap-1.5\">\n @for (chip of visibleAppliedFilterChips(); track chip.id) {\n <span\n class=\"border-border bg-muted/60 text-foreground inline-flex max-w-80 min-w-0 shrink-0 items-center gap-1 rounded-sm border px-2 py-1 text-[0.8125rem] shadow-xs\">\n <span class=\"font-medium whitespace-nowrap\">{{ chip.label }}</span>\n <span class=\"text-muted-foreground\">:</span>\n <span class=\"truncate\" z-tooltip [zContent]=\"chip.value\" zTooltipTrigger=\"hover\" zTooltipPosition=\"top\">\n {{ chip.value }}\n </span>\n <button\n type=\"button\"\n class=\"hover:bg-destructive/10 hover:text-destructive focus-visible:ring-ring -mr-1 inline-flex size-5 cursor-pointer items-center justify-center rounded-sm outline-none focus-visible:ring-2\"\n [attr.aria-label]=\"'i18n_z_ui_table_filter_remove' | translate\"\n (click)=\"clearAppliedFilterChip(chip)\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </span>\n }\n @if (hiddenAppliedFilterChipCount() > 0 && isFilterHeaderExpanded()) {\n @for (chip of overflowAppliedFilterChips(); track chip.id) {\n <span\n class=\"z-table-filter-header-overflow-chip border-border bg-muted/60 text-foreground inline-flex max-w-80 min-w-0 shrink-0 items-center gap-1 rounded-sm border px-2 py-1 text-[0.8125rem] shadow-xs\"\n [attr.aria-hidden]=\"!isFilterHeaderExpanded()\">\n <span class=\"font-medium whitespace-nowrap\">{{ chip.label }}</span>\n <span class=\"text-muted-foreground\">:</span>\n <span class=\"truncate\" z-tooltip [zContent]=\"chip.value\" zTooltipTrigger=\"hover\" zTooltipPosition=\"top\">\n {{ chip.value }}\n </span>\n <button\n type=\"button\"\n class=\"hover:bg-destructive/10 hover:text-destructive focus-visible:ring-ring -mr-1 inline-flex size-5 cursor-pointer items-center justify-center rounded-sm outline-none focus-visible:ring-2\"\n [attr.aria-label]=\"'i18n_z_ui_table_filter_remove' | translate\"\n (click)=\"clearAppliedFilterChip(chip)\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </span>\n }\n }\n @if (hiddenAppliedFilterChipCount() > 0) {\n <button\n type=\"button\"\n class=\"text-primary hover:bg-primary/10 focus-visible:ring-ring inline-flex h-7 cursor-pointer items-center rounded-sm px-2 text-xs font-medium outline-none focus-visible:ring-2\"\n (click)=\"toggleFilterHeaderExpanded()\">\n {{\n isFilterHeaderExpanded()\n ? ('i18n_z_ui_table_show_less' | translate)\n : ('i18n_z_ui_table_show_more' | translate: { count: hiddenAppliedFilterChipCount() })\n }}\n </button>\n }\n <button\n type=\"button\"\n class=\"bg-destructive/10 text-destructive hover:bg-destructive/20 dark:bg-destructive/15 dark:text-destructive-foreground dark:hover:bg-destructive/25 focus-visible:ring-destructive inline-flex h-7 cursor-pointer items-center gap-1 rounded-sm px-2 text-xs font-medium shadow-xs outline-none focus-visible:ring-2\"\n (click)=\"clearAppliedFilters()\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_clear_filter' | translate }}</span>\n </button>\n </div>\n </div>\n}\n\n<div\n #tableContainer\n [class]=\"classTable()\"\n [ngStyle]=\"columnSizeVars()\"\n [class.z-pinning-overflow]=\"!isPinnedLayoutWithinContainer()\"\n [class.z-hide-horizontal-border]=\"!showHorizontalBorder()\"\n [class.z-hide-vertical-border]=\"!showVerticalBorder()\"\n [class.z-hide-pinned-top-border]=\"hasScrollTop()\"\n [class.z-hide-pinned-bottom-border]=\"hasScrollBottom()\"\n [style.width]=\"zConfig().width\"\n [style.height]=\"zConfig().height\"\n [style.max-height]=\"zConfig().maxHeight\"\n [style.min-height]=\"zConfig().minHeight\"\n [attr.tabindex]=\"canUseContentRowInsert() || canUseCellSelection() ? 0 : null\"\n (keydown)=\"onContentTableKeydown($event)\">\n @let isColumnPinningActive = isPinnedLayoutWithinContainer();\n <ng-template #contentRowMenuContent>\n <div class=\"flex min-w-36 flex-col gap-0.5 p-1\">\n @if (contentRowMenu()?.columnId) {\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded-sm 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-sm 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-sm 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-sm 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-sm 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-sm 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-sm 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-sm 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-sm 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-sm px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canCopyCellMenuSelection()\"\n (click)=\"copySelectedCells(true)\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_cell_with_headers' | translate }}</span>\n </button>\n }\n </div>\n </ng-template>\n\n <div\n class=\"pointer-events-none fixed size-px opacity-0\"\n z-popover\n [zPopoverContent]=\"contentRowMenuContent\"\n zTrigger=\"manual\"\n zPosition=\"bottom-left\"\n zClass=\"z-table-content-row-menu\"\n [zOffset]=\"0\"\n [zManualClose]=\"true\"\n [zScrollClose]=\"true\"\n [style.left.px]=\"contentRowMenu()?.left ?? -9999\"\n [style.top.px]=\"contentRowMenu()?.top ?? -9999\"\n (zControl)=\"setContentRowMenuControl($event)\"\n (zHide)=\"clearContentRowMenu()\"></div>\n\n <div\n class=\"pointer-events-none fixed size-px opacity-0\"\n z-popover\n [zPopoverContent]=\"cellMenuContent\"\n zTrigger=\"manual\"\n zPosition=\"bottom-left\"\n zClass=\"z-table-cell-menu\"\n [zOffset]=\"0\"\n [zManualClose]=\"true\"\n [zScrollClose]=\"true\"\n [style.left.px]=\"cellMenu()?.left ?? -9999\"\n [style.top.px]=\"cellMenu()?.top ?? -9999\"\n (zControl)=\"setCellMenuControl($event)\"\n (zHide)=\"clearCellMenu()\"></div>\n\n <!-- Shared colgroup template -->\n <ng-template #colGroupTpl>\n <colgroup>\n @if (canUseVirtualColumns()) {\n @for (column of leftLeafColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <col [style.width.px]=\"virtualRenderedLeftSpacerWidth()\" />\n }\n @for (column of virtualCenterColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n @if (virtualRightSpacerWidth() > 0) {\n <col [style.width.px]=\"virtualRenderedRightSpacerWidth()\" />\n }\n @for (column of rightLeafColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n } @else {\n @for (column of orderedLeafColumns(); track column.id) {\n @if (column.getIsVisible()) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n }\n }\n </colgroup>\n </ng-template>\n\n <!-- Header table -->\n <div\n class=\"z-thead-wrapper shadow-card\"\n [class.z-shadow-header]=\"shouldHeaderShowShadow()\"\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\"\n (wheel)=\"onTheadWheel($event)\"\n #theadWrapper>\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <thead>\n @if (canUseVirtualColumns()) {\n <tr>\n @for (header of leftHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: leftHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div zHoverGlide zHoverGlideSelector=\".z-column-menu-item\" 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-sm 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-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm 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-sm 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-sm 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-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded-sm 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 zClass=\"rounded-(--radius-sm) overflow-hidden\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <th\n class=\"z-virtual-column-spacer z-virtual-header-spacer z-virtual-left-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></th>\n }\n @for (header of virtualCenterHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: virtualCenterHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div zHoverGlide zHoverGlideSelector=\".z-column-menu-item\" 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-sm 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-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm 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-sm 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-sm 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-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded-sm 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 zClass=\"rounded-(--radius-sm) overflow-hidden\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualRightSpacerWidth() > 0) {\n <th\n class=\"z-virtual-column-spacer z-virtual-header-spacer z-virtual-right-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></th>\n }\n @for (header of rightHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: rightHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <!-- Header Checkbox -->\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <!-- Expand All Button -->\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <!-- Header Content with Sort and Pin -->\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <!-- Column Options Popover Template -->\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div zHoverGlide zHoverGlideSelector=\".z-column-menu-item\" 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-sm 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-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm 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-sm 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-sm 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-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded-sm 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 zClass=\"rounded-(--radius-sm) overflow-hidden\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n <!-- Dropdown indicator when has options (between text and sort icon) -->\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n <!-- Sort Icon (outside wrapper, no hover background) -->\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n <!-- Column Resizer -->\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n </tr>\n } @else {\n @for (headerGroup of orderedHeaderGroups(); track headerGroup.id) {\n <tr>\n @for (header of headerGroup.headers; track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: headerGroup.headers : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div zHoverGlide zHoverGlideSelector=\".z-column-menu-item\" 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-sm 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-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"15\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"\n handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\n \"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"15\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm 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-sm 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-sm 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-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded-sm 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 zClass=\"rounded-(--radius-sm) overflow-hidden\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"\n header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\n \"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n </tr>\n }\n }\n </thead>\n </table>\n </div>\n\n <!-- Body table -->\n <div\n class=\"z-tbody-wrapper relative\"\n #tbodyContainer\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\">\n @if (isLoading() || isProcessing()) {\n <!-- Loading State -->\n @if (zConfig().useSkeleton) {\n <!-- Skeleton Loading -->\n <div class=\"animate-in fade-in flex h-full flex-col duration-200\">\n @for (i of skeletonRows(); track $index; let last = $last) {\n <div\n class=\"border-border box-border flex flex-1 flex-col items-start justify-center gap-1.5 px-2\"\n [class.border-b]=\"!last\">\n <z-skeleton zType=\"bar\" zWidth=\"100%\" zHeight=\"22px\" />\n <z-skeleton zType=\"bar\" zWidth=\"50%\" zHeight=\"14px\" />\n </div>\n }\n </div>\n } @else {\n <!-- Spinner Loading -->\n <div class=\"z-loading-state\">\n <z-loading [zLoading]=\"true\" zSize=\"lg\" [zText]=\"'i18n_z_ui_table_loading' | translate\" />\n </div>\n }\n } @else if (isEmpty()) {\n <div class=\"z-empty-state\">\n @if (isNoSearchResults()) {\n <z-empty zIcon=\"lucideSearchX\" zSize=\"sm\" [zMessage]=\"'i18n_z_ui_table_no_results' | translate\" />\n } @else {\n <z-empty zIcon=\"lucidePackageOpen\" zSize=\"sm\" [zMessage]=\"'i18n_z_ui_table_no_data' | translate\" />\n }\n </div>\n } @else {\n <ng-scrollbar class=\"z-tbody-scrollbar\" #tbodyWrapper (scroll)=\"onTbodyScroll($event)\">\n @if (isVirtual()) {\n <!-- Virtual Scroll Mode -->\n\n <div\n class=\"z-virtual-scroll-inner\"\n [style.height.px]=\"virtualizer.getTotalSize()\"\n [style.min-width.px]=\"table.getTotalSize()\">\n <!-- Pinned rows v\u00E0 center rows d\u00F9ng chung m\u1ED9t virtual canvas. -->\n @if (virtualPinnedTopRows().length > 0) {\n <div class=\"z-virtual-pinned-top\" [style.min-width.px]=\"table.getTotalSize()\">\n @for (row of virtualPinnedTopRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"virtualPinnedRowTpl; context: { $implicit: row }\" />\n }\n </div>\n }\n\n @if (usesFlowVirtualRows()) {\n <div\n class=\"z-virtual-flow\"\n [style.transform]=\"'translate3d(0,' + virtualFlowOffset() + 'px,0)'\"\n [style.min-width.px]=\"table.getTotalSize()\">\n <ng-container *ngTemplateOutlet=\"virtualRowsTpl\" />\n </div>\n } @else {\n <ng-container *ngTemplateOutlet=\"virtualRowsTpl\" />\n }\n\n <ng-template #virtualRowsTpl>\n @for (virtualItem of virtualizer.getVirtualItems(); track virtualItem.index) {\n @let groupRows = dynamicGroupRows()[virtualItem.index] || [];\n @let virtualFlatItem = virtualGroupedFlatItems()[virtualItem.index];\n @let stickyGroupState = stickyGroupHeaderState();\n @let stickyGroupTop = stickyGroupState.tops[virtualItem.index];\n @let isStickyGroupHeader = stickyGroupTop !== undefined;\n <div\n #virtualRow\n class=\"z-virtual-row\"\n [class.z-virtual-row-flow]=\"usesFlowVirtualRows()\"\n [class.z-virtual-row-fixed]=\"!effectiveDynamicRowSizing()\"\n [class.z-virtual-row-group-header]=\"virtualFlatItem?.type === 'group-header'\"\n [class.z-virtual-row-sticky-group]=\"isStickyGroupHeader\"\n [class.z-virtual-row-sticky-group-shadow]=\"stickyGroupState.shadowIndex === virtualItem.index\"\n [style.top.px]=\"stickyGroupTop\"\n z-table-draggable=\"row\"\n z-table-drop-target=\"row\"\n [z-table-drag-table-id]=\"dragInstanceId\"\n [z-table-drop-table-id]=\"dragInstanceId\"\n [z-table-drag-item-id]=\"groupRows.length > 0 ? groupRows[0].id : ''\"\n [z-table-drop-item-id]=\"groupRows.length > 0 ? groupRows[0].id : ''\"\n [z-table-drag-disabled]=\"!isVirtualRowDragEnabled() || groupRows.length !== 1\"\n [z-table-drop-disabled]=\"!isVirtualRowDragEnabled() || groupRows.length !== 1\"\n (zTableDropped)=\"_handleDragDrop($event)\"\n [attr.data-index]=\"virtualItem.index\"\n [style.height.px]=\"\n effectiveDynamicRowSizing()\n ? null\n : (dynamicGroupHeights()[virtualItem.index] ?? groupSize() * virtualRowHeight())\n \"\n [style.transform]=\"\n usesFlowVirtualRows() || isStickyGroupHeader ? null : 'translate3d(0,' + virtualItem.start + 'px,0)'\n \">\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-has-bottom-pinned]=\"table.getBottomRows().length > 0\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n @let groupHeaderItem = _getVirtualGroupHeader(virtualFlatItem);\n @if (groupHeaderItem) {\n <tr\n class=\"z-group-row\"\n [class.z-group-row-has-totals]=\"groupHeaderItem.totals\"\n [class.z-group-row-expanded]=\"groupHeaderItem.expanded\"\n [attr.data-group-id]=\"groupHeaderItem.id\"\n [attr.data-group-depth]=\"groupHeaderItem.depth\">\n @if (groupHeaderItem.totals) {\n @let totalColumnMap = groupTotalColumnMap();\n @for (column of orderedLeafColumns(); track column.id; let isFirstGroupCell = $first) {\n <td\n [class.z-group-row-label-cell]=\"isFirstGroupCell\"\n [class.z-group-row-total-cell]=\"!isFirstGroupCell && totalColumnMap[column.id]\"\n [attr.data-column-id]=\"column.id\">\n @if (isFirstGroupCell) {\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + groupHeaderItem.depth * 0.75\"\n [attr.aria-expanded]=\"groupHeaderItem.expanded\"\n (click)=\"toggleGroupRow(groupHeaderItem.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"groupHeaderItem.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"\n (groupHeaderItem.columnLabel ? groupHeaderItem.columnLabel + ': ' : '') +\n groupHeaderItem.label\n \">\n @if (groupHeaderItem.columnLabel) {\n <span class=\"z-group-row-column-label\">\n {{ groupHeaderItem.columnLabel }}:\n </span>\n }\n {{ groupHeaderItem.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ groupHeaderItem.count }}</span>\n }\n @if (groupHeaderItem.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n [zWave]=\"false\"\n z-tooltip\n zSizeIcon=\"14\"\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(groupHeaderItem.columnId)\"></button>\n }\n </div>\n }\n @if (!isFirstGroupCell && totalColumnMap[column.id]) {\n @let totalConfig = groupTotalConfigMap()[column.id];\n @let totalTooltip = totalConfig.tooltip;\n @let totalPopover = totalConfig.popover;\n @let totalPopoverContent = totalPopover | zTablePopoverConfig: 'content';\n <ng-template #groupTotalPopoverTpl>\n @if (totalPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(totalPopoverContent)\" />\n }\n @if (!(totalPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(totalPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n <span\n class=\"z-group-row-total\"\n z-tooltip\n z-popover\n [class]=\"totalConfig.class\"\n [zContent]=\"\n $any(\n (totalTooltip | zTableTooltipConfig: 'content') ||\n groupHeaderItem.totals[column.id]\n )\n \"\n [zTooltipPosition]=\"$any(totalTooltip | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(totalTooltip | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(totalTooltip | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(totalTooltip | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(totalTooltip | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'showDelay')\"\n [zTooltipHideDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'hideDelay')\"\n [zTooltipArrow]=\"$any(totalTooltip | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(totalTooltip | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(totalTooltip | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(totalTooltip | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(totalTooltip | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"totalPopoverContent ? groupTotalPopoverTpl : null\"\n [zPosition]=\"$any(totalPopover | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(totalPopover | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(totalPopover | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(totalPopover | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(totalPopover | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(totalPopover | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(totalPopover | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(totalPopover | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(totalPopover | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"$any(totalPopover | zTablePopoverConfig: 'outsideClickClose')\"\n [zScrollClose]=\"$any(totalPopover | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(totalPopover | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(totalPopover | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(totalPopover | zTablePopoverConfig: 'keyboardSafe')\">\n {{ groupHeaderItem.totals[column.id] }}\n </span>\n }\n </td>\n }\n } @else {\n <td [attr.colspan]=\"renderedColumnCount()\">\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + groupHeaderItem.depth * 0.75\"\n [attr.aria-expanded]=\"groupHeaderItem.expanded\"\n (click)=\"toggleGroupRow(groupHeaderItem.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"groupHeaderItem.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"\n (groupHeaderItem.columnLabel ? groupHeaderItem.columnLabel + ': ' : '') +\n groupHeaderItem.label\n \">\n @if (groupHeaderItem.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ groupHeaderItem.columnLabel }}:</span>\n }\n {{ groupHeaderItem.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ groupHeaderItem.count }}</span>\n }\n @if (groupHeaderItem.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n [zWave]=\"false\"\n z-tooltip\n zSizeIcon=\"14\"\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(groupHeaderItem.columnId)\"></button>\n }\n </div>\n </td>\n }\n </tr>\n }\n @for (row of groupRows; track row.id) {\n @let virtualGroupDepth = _getVirtualGroupDepth(virtualFlatItem);\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <tr\n z-table-row-hover\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"effectiveDynamicRowSizing() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"effectiveDynamicRowSizing() ? virtualRowHeight() : null\"\n [style.--z-row-height]=\"effectiveDynamicRowSizing() ? 'auto' : virtualRowHeight() + 'px'\"\n [class.z-child-row]=\"row.depth > 0\"\n [class.z-group-child-row]=\"_isVirtualGroupChild(virtualFlatItem)\"\n [style.--z-group-content-indent]=\"\n virtualGroupDepth > 0 ? 1.75 + (virtualGroupDepth - 1) * 0.75 + 'rem' : null\n \"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && row.id === firstTopPinnedRowId()\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"rowPinned === 'bottom' && row.id === lastBottomPinnedRowId()\"\n [class.z-pinned-bottom-first]=\"rowPinned === 'bottom' && row.id === firstBottomPinnedRowId()\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n row.id === lastTopPinnedRowId() &&\n !isStickyGroupHeaderEnabled()\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n row.id === firstBottomPinnedRowId()\n \"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : bodyRowSpanRows();\n @let shouldRenderColSpan =\n cell | zTableCellRender: visibleCells : zConfig().columns : 'body';\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (shouldRenderRowSpan && shouldRenderColSpan && isVirtualColumnVisible) {\n @let cellSelectionId = row.id + '::' + cell.column.id;\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"isColumnPinningActive && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActive && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell\n | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell\n | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"cell.column.id === actionColumnInfo()?.columnId\"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [class.z-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"cell | zTableCellBottom: zConfig().columns : renderedBodyRows()\"\n [attr.rowspan]=\"\n cell | zTableSpan: zConfig().columns : 'cellRowSpan' : bodyRowSpanRows()\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() &&\n cell.row.getIsSomeSelected() &&\n !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-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"cell.row.getIsExpanded()\" />\n </button>\n }\n </div>\n } @else if (\n (cell.column.id === 'actionRowPin' || cell.column.id === 'actions') &&\n cell.column.id !== actionColumnInfo()?.columnId\n ) {\n @if (cell.row.depth === 0 && !hasBodyRowSpan()) {\n <div class=\"flex items-center justify-center\">\n <ng-template #rowPinPopoverContent>\n <div\n zHoverGlide\n zHoverGlideSelector=\".z-column-menu-item\"\n class=\"flex flex-col gap-1 py-1\">\n @if (cell.row.getIsPinned() !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cell.row.getIsPinned() !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cell.row.getIsPinned()) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded-sm p-1 outline-none\"\n [class.text-primary]=\"cell.row.getIsPinned()\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n </div>\n }\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisible = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisible) {\n @let editInfoVirtual = cell.getContext() | zTableCellEdit: zConfig().columns;\n @if (editInfoVirtual.enabled) {\n <!-- Editable Cell (Virtual) -->\n <z-table-edit-cell\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n [zRowIndex]=\"cell.row.index\"\n [zColumnId]=\"cell.column.id\"\n [zValue]=\"cell.getValue()\"\n [zRowUpdate]=\"_rowUpdate()\"\n [zEditConfig]=\"$any(editInfoVirtual.config)\"\n (zChange)=\"onCellEdit($any($event))\" />\n } @else if (editInfoVirtual.contentEnabled) {\n @let contentConfigVirtual = editInfoVirtual.contentConfig!;\n @if (\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n ) {\n <z-table-content-editor\n [zValue]=\"cell.getValue()\"\n [zConfig]=\"contentConfigVirtual\"\n (zCommit)=\"onContentEditCommit($event, row, cell.column.id, cell.getValue())\"\n (zCancel)=\"onContentEditCancel()\" />\n } @else {\n <button\n type=\"button\"\n class=\"z-table-content-trigger\"\n [attr.data-z-table-edit-row]=\"row.id\"\n [attr.data-z-table-edit-column]=\"cell.column.id\"\n (keydown)=\"onContentEditKeydown($event, row.id, cell.column.id)\"\n (click)=\"onContentEditStart($event, row.id, cell.column.id)\">\n {{ contentConfigVirtual.displayValue }}\n </button>\n }\n } @else {\n <ng-container\n *flexRender=\"\n cell.column.columnDef.cell;\n props: cell.getContext();\n let cellContent\n \">\n @if (cellContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n @let isClickable = cell.column.id | zTableCellClickable: zConfig().columns;\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickable && onCellClick(row, cell.column.id, cell.getValue())\">\n <ng-container\n *ngTemplateOutlet=\"\n cellContent;\n context: { $implicit: cell.getContext() }\n \" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n @let isClickableIcon =\n cell.column.id | zTableCellClickable: zConfig().columns;\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"\n isClickableIcon && onCellClick(row, cell.column.id, cell.getValue())\n \" />\n } @else {\n <!-- Default/innerHTML rendering -->\n @let isClickableDefault =\n cell.column.id | zTableCellClickable: zConfig().columns;\n @let cellTooltipConfig =\n cell | zTableCellConfig: zConfig() : 'contentTooltip';\n @let cellPopoverConfig =\n cell | zTableCellConfig: zConfig() : 'contentPopover';\n @let cellPopoverContent = cellPopoverConfig | zTablePopoverConfig: 'content';\n <ng-template #cellPopoverTpl>\n @if (cellPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(cellPopoverContent)\" />\n }\n @if (!(cellPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(cellPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n @if (cellPopoverContent) {\n <div\n class=\"z-table-cell-text\"\n z-popover\n z-tooltip\n [zTriggerElement]=\"cellOverlayContent\"\n [zTriggerRef]=\"cellOverlayContent\"\n [zContent]=\"\n (cellTooltipConfig | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'position')\n \"\n [zTooltipTrigger]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'trigger')\n \"\n [zTooltipType]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'autoDetect')\n \"\n [zAlwaysShow]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'alwaysShow')\n \"\n [zMaxWidth]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"cellPopoverTpl\"\n [zPosition]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'trigger')\n \"\n [zClass]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'manualClose')\n \"\n [zOutsideClickClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'outsideClickClose')\n \"\n [zScrollClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'scrollClose')\n \"\n [zSticky]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'keyboardSafe')\n \"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellOverlayContent\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n } @else {\n <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zTriggerElement]=\"cellTooltipContent\"\n [zContent]=\"\n (cellTooltipConfig | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'position')\n \"\n [zTooltipTrigger]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'trigger')\n \"\n [zTooltipType]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'autoDetect')\n \"\n [zAlwaysShow]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'alwaysShow')\n \"\n [zMaxWidth]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'maxWidth')\"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellTooltipContent\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n }\n }\n </ng-container>\n }\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </ng-template>\n </div>\n\n <!--\n Bottom pinned rows: sibling AFTER the virtual canvas (not absolute like the\n center rows). The virtualizer reserves their height inside getTotalSize() via\n `paddingEnd`, leaving an empty band at the canvas bottom. `margin-top: -bottomHeight`\n pulls this real flow element back over that band, and `position: sticky; bottom: 0`\n floats it to the viewport bottom while scrolling.\n -->\n @if (virtualPinnedBottomRows().length > 0) {\n <div\n class=\"z-virtual-pinned-bottom\"\n [style.min-width.px]=\"table.getTotalSize()\"\n [style.margin-top.px]=\"-virtualPinnedBottomHeight()\">\n @for (row of virtualPinnedBottomRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"virtualPinnedRowTpl; context: { $implicit: row }\" />\n }\n </div>\n }\n\n <!-- Template for rendering pinned rows in virtual scroll mode -->\n <ng-template #virtualPinnedRowTpl let-row>\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody [class.z-has-vertical-scroll]=\"hasVerticalScroll()\">\n <tr\n z-table-row-hover\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"effectiveDynamicRowSizing() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"effectiveDynamicRowSizing() ? virtualRowHeight() : null\"\n [style.--z-row-height]=\"effectiveDynamicRowSizing() ? 'auto' : virtualRowHeight() + 'px'\"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && row.id === firstTopPinnedRowId()\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"rowPinned === 'bottom' && row.id === lastBottomPinnedRowId()\"\n [class.z-pinned-bottom-first]=\"rowPinned === 'bottom' && row.id === firstBottomPinnedRowId()\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n row.id === lastTopPinnedRowId() &&\n !isStickyGroupHeaderEnabled()\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n row.id === firstBottomPinnedRowId()\n \"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @let isColumnPinningActivePinned = isPinnedLayoutWithinContainer();\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @let cellSelectionId = row.id + '::' + cell.column.id;\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (isVirtualColumnVisible) {\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActivePinned\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"isColumnPinningActivePinned && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActivePinned && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"cell.column.id === actionColumnInfo()?.columnId\"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [style.--z-cell-range-top]=\"(selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"(selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'select') {\n <z-checkbox\n [zChecked]=\"rowSelected\"\n [zIndeterminate]=\"rowSomeSelected && !rowSelected\"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && row.toggleSelected()\" />\n } @else if (cell.column.id === 'expand') {\n <button\n type=\"button\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"row.toggleExpanded()\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"row.getIsExpanded()\" />\n </button>\n } @else if (cell.column.id === 'actionRowPin') {\n <div class=\"flex items-center justify-center\">\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisible = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisible) {\n <ng-container\n *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let cellContent\">\n @if (cellContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { $implicit: cell.getContext() }\" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"(cell | zTableCellConfig: zConfig() : 'contentTooltip') || cellContent\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"></span>\n }\n </ng-container>\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n </tbody>\n </table>\n </ng-template>\n } @else {\n <!-- Normal Scroll Mode -->\n\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n class=\"z-table-drag-body\"\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-has-bottom-pinned]=\"table.getBottomRows().length > 0\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n <!-- Row Template -->\n <ng-template #rowTemplate let-row let-isGroupChild=\"isGroupChild\" let-groupDepth=\"groupDepth\">\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <tr\n z-table-row-hover\n z-table-draggable=\"row\"\n z-table-drop-target=\"row\"\n [animate.enter]=\"row.depth > 0 || isGroupChild ? 'z-row-enter' : ''\"\n [z-table-drag-table-id]=\"dragInstanceId\"\n [z-table-drop-table-id]=\"dragInstanceId\"\n [z-table-drag-item-id]=\"row.id\"\n [z-table-drop-item-id]=\"row.id\"\n [z-table-drag-disabled]=\"!isRowDragEnabled()\"\n [z-table-drop-disabled]=\"!isRowDragEnabled()\"\n (zTableDropped)=\"_handleDragDrop($event)\"\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [ngStyle]=\"row | zTableRow: table : 'pinningStyles' : pinnedRowHeights() : virtualRowHeight()\"\n [class.z-child-row]=\"row.depth > 0\"\n [class.z-group-child-row]=\"isGroupChild\"\n [style.--z-group-content-indent]=\"groupDepth > 0 ? 1.75 + (groupDepth - 1) * 0.75 + 'rem' : null\"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && row.id === firstTopPinnedRowId()\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"rowPinned === 'bottom' && row.id === lastBottomPinnedRowId()\"\n [class.z-pinned-bottom-first]=\"rowPinned === 'bottom' && row.id === firstBottomPinnedRowId()\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n row.id === lastTopPinnedRowId() &&\n !isStickyGroupHeaderEnabled()\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n row.id === firstBottomPinnedRowId()\n \"\n [attr.data-depth]=\"row.depth\"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @let cellRowPinned = cell.row.getIsPinned();\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : bodyRowSpanRows();\n @let shouldRenderColSpan = cell | zTableCellRender: visibleCells : zConfig().columns : 'body';\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (shouldRenderRowSpan && shouldRenderColSpan && isVirtualColumnVisible) {\n @let cellSelectionId = row.id + '::' + cell.column.id;\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n [class.z-sticky-left]=\"isColumnPinningActive && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActive && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"\n cell.column.id === 'actions' || cell.column.id === actionColumnInfo()?.columnId\n \"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [class.z-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"cell | zTableCellBottom: zConfig().columns : renderedBodyRows()\"\n [attr.rowspan]=\"cell | zTableSpan: zConfig().columns : 'cellRowSpan' : bodyRowSpanRows()\"\n [attr.colspan]=\"cell | zTableSpan: zConfig().columns : 'cellColSpan'\"\n [style.--z-cell-range-top]=\"(selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"(selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <button\n data-z-table-drag-handle\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground inline-flex size-7 items-center justify-center rounded-md transition-colors\"\n [class.cursor-grab]=\"isRowDragEnabled()\"\n [class.cursor-not-allowed]=\"!isRowDragEnabled()\"\n [class.opacity-40]=\"!isRowDragEnabled()\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === 'select') {\n <!-- Row Checkbox with Pin Button -->\n <div class=\"flex items-center justify-center gap-1\">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && cell.row.getIsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && cell.row.getIsSomeSelected() && !cell.row.getIsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection() || !cell.row.getCanSelect()\"\n (zChange)=\"canUseRowSelection() && cell.row.toggleSelected()\" />\n @if (zConfig().enableRowPinning && cell.row.depth === 0 && !hasBodyRowSpan()) {\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div\n zHoverGlide\n zHoverGlideSelector=\".z-column-menu-item\"\n class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded-sm p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n }\n </div>\n } @else if (cell.column.id === 'expand') {\n <!-- Expand Button with Row Pin Popover -->\n <div class=\"flex items-center justify-center gap-1\">\n @if (cell.row.getCanExpand()) {\n <button\n type=\"button\"\n (click)=\"cell.row.toggleExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"cell.row.getIsExpanded()\" />\n </button>\n }\n @if (\n zConfig().enableRowPinning &&\n cell.row.depth === 0 &&\n !(cell.row.subRows && cell.row.subRows.length > 0) &&\n !hasBodyRowSpan()\n ) {\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div\n zHoverGlide\n zHoverGlideSelector=\".z-column-menu-item\"\n class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded-sm p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n }\n </div>\n } @else if (\n (cell.column.id === 'actionRowPin' || cell.column.id === 'actions') &&\n cell.column.id !== actionColumnInfo()?.columnId\n ) {\n <!-- Actions Column - Row Pin Only (for parent rows) -->\n @if (cell.row.depth === 0 && !hasBodyRowSpan()) {\n <div class=\"flex items-center justify-center\">\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div\n zHoverGlide\n zHoverGlideSelector=\".z-column-menu-item\"\n class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded-sm p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n </div>\n }\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisibleNormal = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisibleNormal) {\n @let editInfo = cell.getContext() | zTableCellEdit: zConfig().columns;\n @if (editInfo.enabled) {\n <!-- Editable Cell -->\n <z-table-edit-cell\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n [zRowIndex]=\"cell.row.index\"\n [zColumnId]=\"cell.column.id\"\n [zValue]=\"cell.getValue()\"\n [zRowUpdate]=\"_rowUpdate()\"\n [zEditConfig]=\"$any(editInfo.config)\"\n (zChange)=\"onCellEdit($any($event))\" />\n } @else if (editInfo.contentEnabled) {\n @let contentConfig = editInfo.contentConfig!;\n @if (\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n ) {\n <z-table-content-editor\n [zValue]=\"cell.getValue()\"\n [zConfig]=\"contentConfig\"\n (zCommit)=\"onContentEditCommit($event, row, cell.column.id, cell.getValue())\"\n (zCancel)=\"onContentEditCancel()\" />\n } @else {\n <button\n type=\"button\"\n class=\"z-table-content-trigger\"\n [attr.data-z-table-edit-row]=\"row.id\"\n [attr.data-z-table-edit-column]=\"cell.column.id\"\n (keydown)=\"onContentEditKeydown($event, row.id, cell.column.id)\"\n (click)=\"onContentEditStart($event, row.id, cell.column.id)\">\n {{ contentConfig.displayValue }}\n </button>\n }\n } @else {\n <ng-container\n *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let cellContent\">\n @if (cellContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n @let isClickableTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickableTpl && onCellClick(row, cell.column.id, cell.getValue())\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { $implicit: cell.getContext() }\" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n @let isClickableIconTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickableIconTpl && onCellClick(row, cell.column.id, cell.getValue())\" />\n } @else {\n <!-- Default/innerHTML rendering -->\n @let isClickableDefaultTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n @let cellTooltipConfigTpl = cell | zTableCellConfig: zConfig() : 'contentTooltip';\n @let cellPopoverConfigTpl = cell | zTableCellConfig: zConfig() : 'contentPopover';\n @let cellPopoverContentTpl = cellPopoverConfigTpl | zTablePopoverConfig: 'content';\n <ng-template #cellPopoverTplNormal>\n @if (cellPopoverContentTpl | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(cellPopoverContentTpl)\" />\n }\n @if (!(cellPopoverContentTpl | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(cellPopoverContentTpl) | zSafeHtml\"></div>\n }\n </ng-template>\n @if (cellPopoverContentTpl) {\n <div\n class=\"z-table-cell-text\"\n z-popover\n z-tooltip\n [zTriggerElement]=\"cellOverlayContentTpl\"\n [zTriggerRef]=\"cellOverlayContentTpl\"\n [zContent]=\"\n (cellTooltipConfigTpl | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"cellPopoverTplNormal\"\n [zPosition]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"\n $any(cellPopoverConfigTpl | zTablePopoverConfig: 'outsideClickClose')\n \"\n [zScrollClose]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'keyboardSafe')\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellOverlayContentTpl\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n } @else {\n <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zTriggerElement]=\"cellTooltipContentTpl\"\n [zContent]=\"\n (cellTooltipConfigTpl | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'maxWidth')\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellTooltipContentTpl\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n }\n }\n </ng-container>\n }\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n\n <!-- Expanded Row Detail -->\n @if (row.getIsExpanded() && row.depth === 0 && !row.subRows?.length) {\n @let resolvedSubTableConfig = row | zTableSubTableConfig: zConfig();\n <tr class=\"z-expanded-row\" animate.enter=\"z-expanded-row-enter\">\n <td [attr.colspan]=\"renderedColumnCount()\" class=\"p-0\">\n <!-- Animate \u1EDF wrapper n\u00E0y b\u1EB1ng clip-path/translate/opacity \u2014 xem z-expanded-row-reveal. -->\n <div class=\"z-expanded-row-content\">\n @if (zConfig().expandedRowTemplate) {\n <ng-container\n *ngTemplateOutlet=\"zConfig().expandedRowTemplate!; context: { $implicit: row }\" />\n } @else if (resolvedSubTableConfig) {\n <div class=\"z-sub-table-container\">\n <z-table [zConfig]=\"$any(resolvedSubTableConfig)\" zVariant=\"borderless\" />\n </div>\n }\n </div>\n </td>\n </tr>\n }\n </ng-template>\n\n <!-- Render Top Pinned Rows (hidden when filtered data is empty) -->\n @if (!isEmpty()) {\n @for (row of table.getTopRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\n }\n }\n\n <!-- Render Center Rows -->\n @for (item of groupedCenterRowItems(); track item.type === 'group' ? item.id : item.row.id) {\n @if (item.type === 'group') {\n <tr\n #groupRow\n class=\"z-group-row\"\n [class.z-group-row-has-totals]=\"item.totals\"\n [class.z-group-row-expanded]=\"item.expanded\"\n [class.z-group-row-sticky]=\"isStickyGroupHeaderEnabled()\"\n [class.z-group-row-sticky-shadow]=\"shadowGroupRowId() === item.id\"\n [style.top.px]=\"stickyGroupTopByDepth()[item.depth]\"\n [attr.data-group-id]=\"item.id\"\n [attr.data-group-depth]=\"item.depth\">\n @if (item.totals) {\n @let totalColumnMap = groupTotalColumnMap();\n @for (column of orderedLeafColumns(); track column.id; let isFirstGroupCell = $first) {\n <td\n [class.z-group-row-label-cell]=\"isFirstGroupCell\"\n [class.z-group-row-total-cell]=\"!isFirstGroupCell && totalColumnMap[column.id]\"\n [attr.data-column-id]=\"column.id\">\n @if (isFirstGroupCell) {\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + item.depth * 0.75\"\n [attr.aria-expanded]=\"item.expanded\"\n (click)=\"toggleGroupRow(item.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"item.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"(item.columnLabel ? item.columnLabel + ': ' : '') + item.label\">\n @if (item.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ item.columnLabel }}:</span>\n }\n {{ item.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ item.count }}</span>\n }\n @if (item.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n zSizeIcon=\"14\"\n [zWave]=\"false\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(item.columnId)\"></button>\n }\n </div>\n }\n @if (!isFirstGroupCell && totalColumnMap[column.id]) {\n @let totalConfig = groupTotalConfigMap()[column.id];\n @let totalTooltip = totalConfig.tooltip;\n @let totalPopover = totalConfig.popover;\n @let totalPopoverContent = totalPopover | zTablePopoverConfig: 'content';\n <ng-template #groupTotalPopoverTpl>\n @if (totalPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(totalPopoverContent)\" />\n }\n @if (!(totalPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(totalPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n <span\n class=\"z-group-row-total\"\n z-tooltip\n z-popover\n [class]=\"totalConfig.class\"\n [zContent]=\"\n $any((totalTooltip | zTableTooltipConfig: 'content') || item.totals[column.id])\n \"\n [zTooltipPosition]=\"$any(totalTooltip | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(totalTooltip | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(totalTooltip | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(totalTooltip | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(totalTooltip | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'showDelay')\"\n [zTooltipHideDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'hideDelay')\"\n [zTooltipArrow]=\"$any(totalTooltip | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(totalTooltip | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(totalTooltip | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(totalTooltip | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(totalTooltip | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"totalPopoverContent ? groupTotalPopoverTpl : null\"\n [zPosition]=\"$any(totalPopover | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(totalPopover | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(totalPopover | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(totalPopover | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(totalPopover | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(totalPopover | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(totalPopover | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(totalPopover | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(totalPopover | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"$any(totalPopover | zTablePopoverConfig: 'outsideClickClose')\"\n [zScrollClose]=\"$any(totalPopover | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(totalPopover | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(totalPopover | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(totalPopover | zTablePopoverConfig: 'keyboardSafe')\">\n {{ item.totals[column.id] }}\n </span>\n }\n </td>\n }\n } @else {\n <td [attr.colspan]=\"renderedColumnCount()\">\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + item.depth * 0.75\"\n [attr.aria-expanded]=\"item.expanded\"\n (click)=\"toggleGroupRow(item.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"item.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"(item.columnLabel ? item.columnLabel + ': ' : '') + item.label\">\n @if (item.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ item.columnLabel }}:</span>\n }\n {{ item.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ item.count }}</span>\n }\n @if (item.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n zSizeIcon=\"14\"\n [zWave]=\"false\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(item.columnId)\"></button>\n }\n </div>\n </td>\n }\n </tr>\n }\n @if (item.type === 'row') {\n <ng-container\n *ngTemplateOutlet=\"\n rowTemplate;\n context: {\n $implicit: item.row,\n isGroupChild: item.isGroupChild,\n groupDepth: item.groupDepth,\n }\n \" />\n }\n }\n\n <!-- Render Bottom Pinned Rows (hidden when filtered data is empty) -->\n @if (!isEmpty()) {\n @for (row of bottomRowsReversed(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\n }\n }\n </tbody>\n </table>\n }\n </ng-scrollbar>\n }\n <!-- end @else -->\n </div>\n\n <!-- Footer table -->\n @if (hasFooter()) {\n <div\n class=\"z-tfoot-wrapper\"\n [class.z-shadow-footer]=\"shouldFooterShowShadow()\"\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\"\n #tfootWrapper>\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tfoot>\n @for (footerGroup of orderedFooterGroups(); track footerGroup.id; let footerRowIndex = $index) {\n @if (footerGroup | zTableFooterContent: zConfig().columns : footerRowIndex) {\n <tr>\n @for (footer of footerGroup.headers; track footer.id) {\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n footer.column.id === firstVirtualCenterColumnId()\n ) {\n <th\n class=\"z-virtual-column-spacer z-virtual-footer-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></th>\n }\n @let rowSpan = footer | zTableSpan: zConfig().columns : 'footerRowSpan' : footerRowIndex;\n @let shouldRender =\n footer\n | zTableCellRender\n : footerGroup.headers\n : zConfig().columns\n : 'footer'\n : footerRowIndex\n : orderedFooterGroups();\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n footer.column.getIsPinned() !== false ||\n virtualCenterColumnVisibilityMap()[footer.column.id];\n @if (rowSpan && shouldRender && isVirtualColumnVisible) {\n <th\n [attr.data-column-id]=\"footer.column.id\"\n [ngStyle]=\"\n footer.column\n | zTablePinningStyles\n : footer\n : 'footer'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerClass' : footerRowIndex) +\n ' ' +\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex)\n \"\n [style]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerStyle' : footerRowIndex\n \"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (footer | zTableCellPin: 'isLeftPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-at-left-edge]=\"footer | zTableCellOffset: orderedLeafColumns()\"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"footer | zTableSpan: zConfig().columns : 'footerColSpan' : footerRowIndex\">\n @let configFooterContent =\n footer.column.id | zTableFooterRender: zConfig().columns : footerRowIndex;\n @if (configFooterContent !== undefined && configFooterContent !== '') {\n <ng-container *flexRender=\"configFooterContent; props: footer.getContext(); let footerContent\">\n <div\n class=\"flex w-full items-center\"\n [class.justify-center]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex) ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex) ===\n 'text-right'\n \">\n @if (footerContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n <div\n class=\"z-template-content\"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \">\n <ng-container\n *ngTemplateOutlet=\"footerContent; context: { $implicit: footer.getContext() }\" />\n </div>\n } @else if (footerContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n <z-table-icon-text\n [zText]=\"footerContent\"\n [zTooltip]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerTooltip' : footerRowIndex\n \"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \" />\n } @else {\n <!-- Default/string rendering -->\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerTooltip' : footerRowIndex) ||\n footerContent\n \"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \">\n {{ footerContent | translate }}\n </span>\n }\n </div>\n </ng-container>\n }\n </th>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n footer.column.id === lastVirtualCenterColumnId()\n ) {\n <th\n class=\"z-virtual-column-spacer z-virtual-footer-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></th>\n }\n }\n </tr>\n }\n }\n </tfoot>\n </table>\n </div>\n }\n</div>\n\n<!-- Pagination -->\n@if (zConfig().pagination?.enabled !== false) {\n <div class=\"mt-4 flex items-center justify-between gap-4\">\n <div class=\"truncate text-sm text-gray-500\">\n {{ 'i18n_z_ui_table_total_rows' | translate: { total: (paginationTotal() | zFormatNum) } }}\n </div>\n <z-pagination\n [zTotal]=\"paginationTotal()\"\n [(zPageIndex)]=\"pagination().pageIndex\"\n [(zPageSize)]=\"pagination().pageSize\"\n [zPageSizeOptions]=\"zConfig().pagination?.pageSizeOptions ?? [10, 20, 50, 100]\"\n [zShowSizeChanger]=\"zConfig().pagination?.showSizeChanger ?? true\"\n [zShowQuickJumper]=\"zConfig().pagination?.showQuickJumper ?? false\"\n [zShowTotal]=\"false\"\n [zDisabled]=\"zConfig().pagination?.disabled || isLoading() || isProcessing()\"\n (zOnPageChange)=\"onPageChange($event)\" />\n </div>\n}\n\n<!-- Floating Bulk Action Bar -->\n<ng-template #bulkBarTemplate>\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 [zBodyClass]=\"'mx-0! px-0!'\"\n [zShadow]=\"true\"\n [zOkText]=\"null\"\n [zCancelText]=\"'i18n_z_ui_drawer_close' | translate\">\n <div class=\"z-table-settings-drawer\">\n <!-- Display Settings -->\n <div class=\"mx-4 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=\"mx-4 mb-4\">\n <h4 class=\"text-foreground mb-2 text-sm font-semibold\">{{ 'i18n_z_ui_table_column_settings' | translate }}</h4>\n <p class=\"text-muted-foreground mb-3 text-xs\">{{ 'i18n_z_ui_table_column_settings_desc' | translate }}</p>\n\n <!-- Unpinned Columns (Draggable) -->\n <div\n cdkDropList\n #columnDropList=\"cdkDropList\"\n [cdkDropListAutoScrollDisabled]=\"true\"\n (cdkDropListDropped)=\"onPendingColumnDrop($event)\"\n class=\"z-column-drop-list space-y-1.5\">\n @for (columnId of columnOrder(); track columnId; let i = $index) {\n @if (columnId !== 'expand' && columnId !== 'select' && columnId !== 'rowDrag') {\n @let column = table.getColumn(columnId);\n @let isPinned = column?.getIsPinned();\n @let isVisible = pendingVisibleColumns().includes(columnId);\n @let isVisibilityDisabled = pendingColumnVisibilityDisabledMap()[columnId];\n @let isGroupedColumn = groupingColumnMap()[columnId];\n @let columnEnablePinningConfig = columnId | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let canPin =\n (columnEnablePinningConfig ?? zConfig().enableColumnPinning ?? true) && column?.getCanPin() !== false;\n @if (!isPinned) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"isGroupedColumn\"\n [cdkDragData]=\"columnId\"\n cdkDragLockAxis=\"y\"\n cdkDragPreviewContainer=\"global\"\n cdkDragPreviewClass=\"z-drag-preview\"\n class=\"z-drag-item border-border bg-card hover:border-primary flex cursor-default items-center gap-2 rounded-sm border px-2 py-1.5 text-sm\"\n [class.opacity-60]=\"!isVisible\">\n <!-- Drag Handle -->\n <z-icon\n cdkDragHandle\n zType=\"lucideGripVertical\"\n zSize=\"14\"\n class=\"text-muted-foreground shrink-0\"\n [class.cursor-pointer]=\"!isGroupedColumn\"\n [class.cursor-default]=\"isGroupedColumn\"\n [class.opacity-40]=\"isGroupedColumn\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n [disabled]=\"isVisibilityDisabled\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n (mousedown)=\"$event.stopPropagation()\"\n class=\"border-input h-4 w-4 shrink-0 cursor-default rounded-sm disabled:opacity-50\" />\n\n <!-- Column Name -->\n <span class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\" [class.text-muted-foreground]=\"!isVisible\">\n {{ columnId | zTableColumnHeader: zConfig().columns | translate }}\n </span>\n @let parents = columnId | zTableColumnParents: zConfig().columns;\n @if (parents) {\n <span class=\"text-muted-foreground truncate text-[0.625rem]\">({{ parents | translate }})</span>\n }\n </span>\n\n <!-- Pin Buttons -->\n @if (canPin) {\n <div class=\"flex shrink-0 items-center gap-0.5\" (mousedown)=\"$event.stopPropagation()\">\n <button\n type=\"button\"\n [disabled]=\"!isVisible || isGroupedColumn || !pinAvailabilityMap()[columnId]?.left\"\n (click)=\"onToggleColumnPin(columnId, 'left')\"\n class=\"text-muted-foreground hover:bg-muted cursor-pointer rounded-sm p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Pin Left\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"12\" />\n </button>\n <button\n type=\"button\"\n [disabled]=\"!isVisible || isGroupedColumn || !pinAvailabilityMap()[columnId]?.right\"\n (click)=\"onToggleColumnPin(columnId, 'right')\"\n class=\"text-muted-foreground hover:bg-muted cursor-pointer rounded-sm p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Pin Right\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"12\" />\n </button>\n </div>\n }\n </div>\n }\n }\n }\n </div>\n\n <!-- Pinned Columns Section -->\n @if (zConfig().enableColumnPinning ?? true) {\n @if (pinnedColumnIds().length > 0) {\n <div class=\"border-border mt-4 border-t pt-4\">\n <h5 class=\"text-muted-foreground mb-2 text-xs font-medium\">\n {{ 'i18n_z_ui_table_pinned_columns' | translate }}\n </h5>\n <div class=\"space-y-1.5\">\n @for (columnId of pinnedColumnIds(); track columnId) {\n @let column = table.getColumn(columnId);\n @let isPinned = column?.getIsPinned();\n @let isVisible = pendingVisibleColumns().includes(columnId);\n @let isVisibilityDisabled = pendingColumnVisibilityDisabledMap()[columnId];\n @let isGroupedColumn = groupingColumnMap()[columnId];\n <div\n class=\"border-border bg-muted/30 flex items-center gap-2 rounded-sm border px-2 py-1.5 text-sm\"\n [class.opacity-60]=\"!isVisible\">\n <!-- Pin Icon -->\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"text-primary shrink-0\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n [disabled]=\"isVisibilityDisabled\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n class=\"border-input h-4 w-4 shrink-0 cursor-default rounded-sm disabled:opacity-50\" />\n\n <!-- Column Name -->\n <span class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\" [class.text-muted-foreground]=\"!isVisible\">\n {{ columnId | zTableColumnHeader: zConfig().columns | translate }}\n </span>\n @let pinnedParents = columnId | zTableColumnParents: zConfig().columns;\n @if (pinnedParents) {\n <span class=\"text-muted-foreground truncate text-[0.625rem]\">\n ({{ pinnedParents | translate }})\n </span>\n }\n </span>\n\n <!-- Position Badge -->\n <span\n class=\"bg-primary/10 text-primary shrink-0 rounded-sm px-1.5 py-0.5 text-[0.625rem] font-medium\">\n {{\n isPinned === 'start'\n ? ('i18n_z_ui_table_left' | translate)\n : ('i18n_z_ui_table_right' | translate)\n }}\n </span>\n\n <!-- Unpin Button -->\n <button\n type=\"button\"\n [disabled]=\"isGroupedColumn\"\n (click)=\"onToggleColumnPin(columnId, isPinned === 'start' ? 'left' : 'right')\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground cursor-pointer rounded-sm p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Unpin\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </div>\n }\n </div>\n </div>\n }\n }\n </div>\n </div>\n</z-drawer>\n", styles: [":host{display:flex;flex-direction:column;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;overflow-x:visible;--scrollbar-track-thickness: 7px;--scrollbar-track-color: transparent;--scrollbar-thumb-shape: 3px;--z-shadow-left-right: -1.875rem;--z-shadow-left-width: 1.875rem;--z-shadow-left-opacity: 0;--z-shadow-right-left: -1.875rem;--z-shadow-right-width: 1.875rem;--z-shadow-right-opacity: 0;--z-sticky-left-border-color: transparent;--z-sticky-right-border-color: var(--border);--z-cell-selection-background: color-mix(in srgb, var(--primary) 12%, transparent);--z-cell-selection-background-opaque: color-mix(in srgb, var(--primary) 12%, var(--card))}.z-table-container{display:flex;flex-direction:column;position:relative;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;overflow:hidden;border-radius:var(--radius-sm);border:thin solid var(--border);background-color:var(--card)}.z-table-container:focus{outline:none}.z-table-container.z-table-borderless{border:none;border-radius:0;box-shadow:none!important;background-color:transparent}.z-table-container.z-hide-horizontal-border th,.z-table-container.z-hide-horizontal-border td{border-bottom:none!important;border-top:none!important}.z-table-container.z-hide-vertical-border th,.z-table-container.z-hide-vertical-border td{border-left:none!important}.z-table-container.z-hide-pinned-top-border tbody tr.z-pinned-top.z-shadow-bottom>td{border-bottom-color:var(--border)!important}.z-table-container.z-hide-pinned-bottom-border tbody.z-has-bottom-pinned td.z-at-bottom{border-bottom-color:transparent}table{width:fit-content;min-width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed;font-size:.875rem}.z-table-container.z-column-resizing table,.z-table-toolbar{min-width:0}.z-table-toolbar .z-settings-btn{transition:all .15s ease}.z-table-toolbar .z-settings-btn:hover{border-color:var(--muted-foreground)}.z-table-filter-header{min-width:0}.z-table-filter-header button{flex:none}.z-table-filter-header-overflow-chip{animation:z-table-filter-chip-enter .16s ease}@media(prefers-reduced-motion:reduce){.z-table-filter-header-overflow-chip{animation:none}}@keyframes z-table-filter-chip-enter{0%{opacity:0;transform:translate(-.25rem)}to{opacity:1;transform:translate(0)}}::ng-deep .z-bulk-action-bar-overlay{position:fixed!important;top:auto;left:50%;bottom:0;transform:translate(-50%);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:var(--radius-md);background:color-mix(in srgb,var(--card) 96%,var(--background));color:var(--foreground);box-shadow:0 1rem 2.5rem color-mix(in srgb,var(--foreground) 20%,transparent),0 .25rem .75rem color-mix(in srgb,var(--foreground) 12%,transparent),0 0 0 1px color-mix(in srgb,var(--background) 65%,transparent) inset;display:flex;align-items:center;gap:.5rem;width:max-content;min-height:2.25rem;max-width:calc(100vw - 2rem);padding:.5rem;transform-origin:center bottom;animation:z-bulk-action-bar-enter .18s cubic-bezier(.16,1,.3,1);will-change:opacity,transform}.z-bulk-action-bar-inner.z-leaving{pointer-events:none;animation:z-bulk-action-bar-exit .14s ease-in forwards}.z-bulk-action-bar-count{padding:0 .25rem;white-space:nowrap;font-size:.8125rem;font-weight:500;color:var(--foreground)}.z-bulk-action-bar-divider{width:1px;height:1.5rem;flex:none;background:color-mix(in srgb,var(--border) 88%,transparent)}.z-bulk-action-bar-button{flex:none}@keyframes z-bulk-action-bar-enter{0%{opacity:0;transform:translateY(.875rem)}to{opacity:1;transform:translateY(0)}}@keyframes z-bulk-action-bar-exit{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(.875rem)}}@media(prefers-reduced-motion:reduce){.z-bulk-action-bar-inner{animation:none}}:host ::ng-deep .z-table-cell-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;min-width:0;-webkit-user-select:text;user-select:text}:host ::ng-deep .z-table-cell-text>*,:host ::ng-deep .z-table-cell-text *{display:inline-block;max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}:host ::ng-deep .z-table-cell-content-trigger{display:inline-block;max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}.z-template-content{display:block;width:100%;min-width:0;max-width:100%;overflow:hidden}.z-template-content>*{min-width:0;max-width:100%}.z-template-content>[class*=flex]{min-width:0;max-width:100%}.z-template-content>[class*=flex]>*{min-width:0;flex-shrink:1}.z-template-content>[class*=grid]{min-width:0;max-width:100%}.z-thead-wrapper{flex-shrink:0;background:var(--muted);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;position:relative;z-index:4}.z-thead-wrapper::-webkit-scrollbar{display:none}.z-thead-wrapper th{height:auto;padding:.5rem;text-align:left;vertical-align:middle;font-weight:500;color:var(--foreground);white-space:nowrap;overflow:hidden;background:var(--muted);border-left:thin solid var(--border);border-bottom:thin solid var(--border);-webkit-user-select:none;user-select:none}.z-thead-wrapper th.z-at-left-edge{border-left:none}.z-thead-wrapper th[colspan]{text-align:center;background:var(--muted);font-weight:500;color:var(--foreground)}.z-thead-wrapper.z-shadow-header{box-shadow:0 1px 3px #00000014;position:relative;z-index:15}.z-thead-wrapper.z-shadow-header:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}.z-tbody-wrapper{flex:1;width:100%;max-width:100%;min-width:0;min-height:6.25rem;display:flex;flex-direction:column;overflow:hidden}.z-tbody-scrollbar{flex:1;width:100%;max-width:100%;min-width:0;height:100%}.z-empty-state,.z-loading-state{flex:1 1 0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;min-height:6.25rem;height:100%;color:var(--muted-foreground);font-size:.875rem;animation:z-fade-in .2s ease-out}.z-tbody-scrollbar,.z-tbody-scrollbar table{animation:z-fade-in .2s ease-out}@keyframes z-fade-in{0%{opacity:0;transform:translateY(.25rem)}to{opacity:1;transform:translateY(0)}}.z-tbody-wrapper tr{transition:background-color .15s ease}.z-tbody-wrapper tr:hover,.z-tbody-wrapper tr:hover td[style*=sticky]{background-color:var(--muted)}.z-tbody-wrapper tr.z-pinned-top td.z-sticky-left,.z-tbody-wrapper tr.z-pinned-top td.z-sticky-right,.z-tbody-wrapper tr.z-pinned-bottom td.z-sticky-left,.z-tbody-wrapper tr.z-pinned-bottom td.z-sticky-right{z-index:3}.z-tbody-wrapper tr.z-shadow-bottom{box-shadow:0 1px 3px #00000014!important;position:relative;z-index:15}.z-tbody-wrapper tr.z-shadow-bottom:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d!important}.z-tbody-wrapper tr.z-shadow-top{box-shadow:0 -2px 4px #0000000d!important;position:relative;z-index:15}.z-tbody-wrapper tr.z-shadow-top:where(.dark,.dark *){box-shadow:0 -2px 4px #0003!important}.z-tbody-wrapper td{padding:.5rem 12px;height:var(--z-row-height, 2.375rem);vertical-align:middle;color:var(--foreground);white-space:nowrap;overflow:hidden;background:var(--card);border-left:thin solid var(--border);border-bottom:thin solid var(--border);box-sizing:border-box}.z-tbody-wrapper tbody.z-has-vertical-scroll td.z-at-bottom,.z-tbody-wrapper tbody.z-last-row-touches-bottom td.z-at-bottom{border-bottom-color:transparent}.z-tbody-wrapper tbody.z-has-bottom-pinned td.z-at-bottom{border-bottom-color:var(--border)}.z-tbody-wrapper td.z-at-left-edge{border-left:none}.z-tbody-wrapper td i{color:var(--muted-foreground);font-style:italic}.z-tbody-wrapper td[rowspan]{vertical-align:top;padding-top:.75rem}.z-tbody-wrapper td.z-row-hover{background-color:var(--muted)!important}.z-tbody-wrapper td.z-col-select,.z-tbody-wrapper td.z-col-expand,.z-tbody-wrapper td.z-col-actions{padding:.5rem 4px!important;text-align:center}.z-tbody-wrapper tr.z-child-row td.z-col-select:first-child,.z-tbody-wrapper tr.z-child-row td.z-col-expand:first-child,.z-tbody-wrapper tr.z-child-row td.z-col-actions:first-child{padding-left:0!important}.z-virtual-scroll-inner{position:relative;box-sizing:border-box;width:100%}.z-virtual-row,.z-virtual-flow{position:absolute;top:0;left:0;width:100%}.z-virtual-row-flow{position:relative}.z-virtual-row-fixed{overflow:hidden}.z-virtual-row-group-header{z-index:2}.z-virtual-row-sticky-group{position:sticky}.z-virtual-row-sticky-group-shadow{box-shadow:0 1px 3px #00000014}.z-virtual-row-sticky-group-shadow:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}tr.z-group-row-sticky{position:sticky;z-index:2}tr.z-group-row-sticky>td{background:var(--card)}tr.z-group-row-sticky-shadow{box-shadow:0 1px 3px #00000014}tr.z-group-row-sticky-shadow:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}tr.z-child-row td:first-child{border-left:.125rem solid var(--primary)!important;padding-left:.75rem!important}tbody tr.z-context-menu-active,tbody tr.z-context-menu-active td{background-color:var(--muted)!important}tbody tr.z-selected,tbody tr.z-selected td{background-color:color-mix(in srgb,var(--primary) 15%,var(--background))!important}tbody tr.z-selected:hover,tbody tr.z-selected:hover td{background-color:color-mix(in srgb,var(--primary) 20%,var(--background))!important}tbody tr.z-indeterminate-selected,tbody tr.z-indeterminate-selected td{background-color:color-mix(in srgb,var(--primary) 10%,var(--background))!important}tbody tr.z-indeterminate-selected:hover,tbody tr.z-indeterminate-selected:hover td{background-color:color-mix(in srgb,var(--primary) 15%,var(--background))!important}tbody tr.z-pinned-top td{background-color:var(--card)!important}tbody tr.z-pinned-top:hover{background-color:var(--muted)}tbody tr.z-pinned-top:hover td{background-color:var(--muted)!important}tbody tr.z-pinned-bottom td{background-color:var(--card)!important}tbody tr.z-pinned-bottom:hover{background-color:var(--muted)}tbody tr.z-pinned-bottom:hover td{background-color:var(--muted)!important}tbody tr.z-pinned-bottom-last>td{border-bottom-color:transparent!important}tbody tr.z-pinned-bottom-first>td{border-top:thin solid var(--border)}:host .z-tbody-wrapper tbody tr:not(.z-pinned-top):not(.z-pinned-bottom):has(+tr.z-pinned-bottom)>td{border-bottom-color:transparent}tr.z-expanded-row>td{border-left:.125rem solid var(--primary);background-color:var(--background)!important}.z-expanded-row-content{transform-origin:top center}@keyframes z-expanded-row-reveal{0%{clip-path:inset(0 0 100% 0);translate:0 -.375rem;opacity:0}to{clip-path:inset(0 0 0 0);translate:none;opacity:1}}@keyframes z-expanded-row-fade-in{0%{opacity:0}to{opacity:1}}tr.z-expanded-row-enter{animation:z-expanded-row-fade-in .18s ease-out}tr.z-expanded-row-enter .z-expanded-row-content{animation:z-expanded-row-reveal .18s ease-out}@keyframes z-child-row-slide-in{0%{translate:0 -.375rem;opacity:0}to{translate:none;opacity:1}}tr.z-child-row.z-row-enter,tr.z-group-child-row.z-row-enter{animation:z-child-row-slide-in .18s ease-out}@media(prefers-reduced-motion:reduce){tr.z-expanded-row-enter,tr.z-child-row.z-row-enter,tr.z-group-child-row.z-row-enter,tr.z-expanded-row-enter .z-expanded-row-content,tr.z-child-row.z-row-enter .z-expanded-row-content,tr.z-group-child-row.z-row-enter .z-expanded-row-content{animation-duration:1ms}}.z-sub-table-container{padding:.75rem 1rem .75rem 3rem;background-color:var(--background)}.z-table-content-trigger{display:block;width:100%;min-width:0;min-height:1.5rem;padding:0;border:0;border-radius:0;background:transparent;color:inherit;font:inherit;line-height:1.5rem;text-align:inherit;outline:0;cursor:text}.z-table-content-trigger:hover{color:var(--primary)}.z-content-edit-active{position:relative;z-index:2}td:has(>.z-table-content-trigger:focus-visible){position:relative;z-index:2}td:has(>.z-table-content-trigger:focus-visible):after{position:absolute;z-index:3;inset:0;border:1px solid var(--primary);content:\"\";pointer-events:none}td.z-cell-selectable{-webkit-user-select:none;user-select:none}td.z-cell-range-selected{position:relative;isolation:isolate}td.z-cell-range-selected:before{position:absolute;z-index:0;box-sizing:border-box;top:var(--z-cell-range-top, 0);right:var(--z-cell-range-right, 0);bottom:var(--z-cell-range-bottom, 0);left:var(--z-cell-range-left, 0);background-color:var(--z-cell-selection-background);content:\"\";pointer-events:none}td.z-cell-range-selected>*{position:relative;z-index:1}td.z-cell-range-top:before{border-top:1px solid var(--primary)}td.z-cell-range-right:before{border-right:1px solid var(--primary)}td.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}td.z-cell-range-left:before{border-left:1px solid var(--primary)}td.z-cell-active{position:relative;z-index:3;background-color:var(--z-cell-selection-background)!important}td.z-cell-active:after{position:absolute;z-index:4;inset:0;border:1px solid var(--primary);content:\"\";pointer-events:none}td.z-content-edit-active{-webkit-user-select:text;user-select:text}td.z-cell-active.z-row-hover,td.z-content-edit-active.z-row-hover{background-color:var(--card)!important}thead th{position:relative}thead th .z-resizer{position:absolute;right:0;top:0;height:100%;width:.5rem;background:transparent;cursor:col-resize;-webkit-user-select:none;user-select:none;touch-action:none;z-index:5}thead th .z-resizer:after{content:\"\";position:absolute;right:0;top:0;height:100%;width:.1875rem;background:#0000001a;opacity:0;transition:opacity .2s ease}thead th .z-resizer:after:where(.dark,.dark *){background:#ffffff1a}thead th .z-resizer:hover:after{opacity:1;background:var(--primary);width:.1875rem}thead th .z-resizer.z-is-resizing:after{opacity:1;background:var(--primary);width:.1875rem}thead th .z-resizer.z-resizer-left{right:auto;left:0}thead th .z-resizer.z-resizer-left:after{right:auto;left:0}.z-thead-wrapper th.z-sticky-left,.z-thead-wrapper th.z-sticky-right,.z-tbody-wrapper th.z-sticky-left,.z-tbody-wrapper th.z-sticky-right,.z-tfoot-wrapper th.z-sticky-left,.z-tfoot-wrapper th.z-sticky-right{background-color:var(--muted);z-index:1;transform:translateZ(0);backface-visibility:hidden}.z-thead-wrapper td.z-sticky-left,.z-thead-wrapper td.z-sticky-right,.z-tbody-wrapper td.z-sticky-left,.z-tbody-wrapper td.z-sticky-right,.z-tfoot-wrapper td.z-sticky-left,.z-tfoot-wrapper td.z-sticky-right{background-color:var(--card);z-index:1;transform:translateZ(0);backface-visibility:hidden}.z-thead-wrapper th.z-sticky-left-last,.z-thead-wrapper td.z-sticky-left-last,.z-tbody-wrapper th.z-sticky-left-last,.z-tbody-wrapper td.z-sticky-left-last,.z-tfoot-wrapper th.z-sticky-left-last,.z-tfoot-wrapper td.z-sticky-left-last{position:relative;overflow:visible;border-right:thin solid var(--z-sticky-left-border-color)}.z-thead-wrapper th.z-sticky-left-last:after,.z-thead-wrapper td.z-sticky-left-last:after,.z-tbody-wrapper th.z-sticky-left-last:after,.z-tbody-wrapper td.z-sticky-left-last:after,.z-tfoot-wrapper th.z-sticky-left-last:after,.z-tfoot-wrapper td.z-sticky-left-last:after{content:\"\";position:absolute;top:0;bottom:0;right:var(--z-shadow-left-right);width:var(--z-shadow-left-width);pointer-events:none;box-shadow:inset 10px 0 8px -8px #0000001a;z-index:10;opacity:var(--z-shadow-left-opacity)}:host-context(.dark) .z-thead-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-thead-wrapper td.z-sticky-left-last:after,:host-context(.dark) .z-tbody-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-tbody-wrapper td.z-sticky-left-last:after,:host-context(.dark) .z-tfoot-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-tfoot-wrapper td.z-sticky-left-last:after{box-shadow:inset 10px 0 10px -8px #0000004d}.z-thead-wrapper.z-scroll-left,.z-tbody-wrapper.z-scroll-left,.z-tfoot-wrapper.z-scroll-left{--z-shadow-left-opacity: 1}.z-thead-wrapper.z-scroll-left:where(.dark,.dark *),.z-tbody-wrapper.z-scroll-left:where(.dark,.dark *),.z-tfoot-wrapper.z-scroll-left:where(.dark,.dark *){--z-sticky-left-border-color: var(--border)}.z-thead-wrapper th.z-sticky-right-first,.z-thead-wrapper td.z-sticky-right-first,.z-tbody-wrapper th.z-sticky-right-first,.z-tbody-wrapper td.z-sticky-right-first,.z-tfoot-wrapper th.z-sticky-right-first,.z-tfoot-wrapper td.z-sticky-right-first{position:relative;overflow:visible;border-left:thin solid var(--z-sticky-right-border-color)}.z-thead-wrapper th.z-sticky-right-first:before,.z-thead-wrapper td.z-sticky-right-first:before,.z-tbody-wrapper th.z-sticky-right-first:before,.z-tbody-wrapper td.z-sticky-right-first:before,.z-tfoot-wrapper th.z-sticky-right-first:before,.z-tfoot-wrapper td.z-sticky-right-first:before{content:\"\";position:absolute;top:0;bottom:0;left:var(--z-shadow-right-left);width:var(--z-shadow-right-width);pointer-events:none;box-shadow:inset -10px 0 8px -8px #0000001a;z-index:10;opacity:var(--z-shadow-right-opacity)}:host-context(.dark) .z-thead-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-thead-wrapper td.z-sticky-right-first:before,:host-context(.dark) .z-tbody-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-tbody-wrapper td.z-sticky-right-first:before,:host-context(.dark) .z-tfoot-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-tfoot-wrapper td.z-sticky-right-first:before{box-shadow:inset -10px 0 10px -8px #0000004d}.z-thead-wrapper.z-scroll-right,.z-tbody-wrapper.z-scroll-right,.z-tfoot-wrapper.z-scroll-right{--z-shadow-right-opacity: 1}.z-thead-wrapper.z-scroll-right:not(:where(.dark,.dark *)),.z-tbody-wrapper.z-scroll-right:not(:where(.dark,.dark *)),.z-tfoot-wrapper.z-scroll-right:not(:where(.dark,.dark *)){--z-sticky-right-border-color: transparent}.z-pinning-overflow{--z-shadow-left-opacity: 0 !important;--z-shadow-right-opacity: 0 !important;--z-sticky-left-border-color: transparent !important;--z-sticky-right-border-color: transparent !important}.z-pinning-overflow .z-sticky-left,.z-pinning-overflow .z-sticky-right{position:relative!important;right:auto!important;left:auto!important}.z-pinning-overflow .z-sticky-left-last:after,.z-pinning-overflow .z-sticky-right-first:before,.z-pinning-overflow .z-sticky-right-last:after{display:none!important}.z-thead-wrapper th.z-sticky-right-last,.z-tfoot-wrapper th.z-sticky-right-last{position:relative}.z-thead-wrapper th.z-sticky-right-last:after,.z-tfoot-wrapper th.z-sticky-right-last:after{content:\"\";position:absolute;top:0;bottom:0;right:-1.875rem;width:1.875rem;background:var(--muted);pointer-events:none}.z-tfoot-wrapper{flex-shrink:0;width:100%;max-width:100%;min-width:0;background:var(--muted);overflow-x:hidden;overflow-y:hidden;touch-action:pan-y pinch-zoom}.z-tfoot-wrapper th{height:auto;padding:.5rem 12px;text-align:left;vertical-align:middle;font-weight:500;font-size:.75rem;color:var(--muted-foreground);text-transform:uppercase;letter-spacing:.5px;background:var(--muted);border-left:thin solid var(--border);border-top:thin solid var(--border)}.z-tfoot-wrapper th.z-at-left-edge{border-left:none}.z-tfoot-wrapper.z-shadow-footer{box-shadow:0 -2px 4px #0000000d;position:relative;z-index:15}.z-tfoot-wrapper.z-shadow-footer:where(.dark,.dark *){box-shadow:0 -2px 4px #0003}.z-pin-btn{padding:.125rem 4px;border-radius:var(--radius-xs);color:var(--muted-foreground);transition:all .15s ease}.z-pin-btn:hover{background-color:var(--muted);color:var(--foreground)}.z-pin-btn.z-pin-btn-active{color:var(--primary);background-color:var(--primary)}.z-pin-btn.z-pin-btn-active:hover{background-color:var(--primary);opacity:.8}.z-row-pin-trigger{opacity:1}.z-row-pin-trigger:focus-visible,.z-row-pin-trigger.z-popover-open{background-color:color-mix(in srgb,var(--foreground) 8%,transparent);color:var(--foreground)}.z-row-pin-trigger:active{background-color:color-mix(in srgb,var(--foreground) 12%,transparent)}.z-row-pin-trigger.text-primary{color:var(--primary)}.z-row-pin-unpin-trigger{color:var(--muted-foreground);outline:none}.z-row-pin-unpin-trigger:hover{color:var(--destructive);background-color:color-mix(in srgb,var(--destructive) 10%,transparent)}.z-row-pin-unpin-trigger:focus,.z-row-pin-unpin-trigger:focus-visible{color:var(--muted-foreground);background-color:transparent;outline:none;box-shadow:none}.z-row-pin-unpin-trigger:active{color:var(--destructive);background-color:color-mix(in srgb,var(--destructive) 14%,transparent)}.z-header-pin-trigger{opacity:1}.z-header-pin-trigger.text-primary{color:var(--primary)}th{overflow:hidden}th .z-header-content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}th .z-header-text-wrapper{transition:background-color .15s ease;border-radius:var(--radius-sm);min-width:0;overflow:hidden;flex-shrink:1}th .z-header-text-wrapper.z-has-options:hover,th .z-header-text-wrapper.z-has-options:focus-visible,th .z-header-text-wrapper.z-has-options.z-popover-open{background-color:color-mix(in srgb,var(--foreground) 8%,transparent);outline:none}th .z-header-text-wrapper.z-has-options:active{background-color:color-mix(in srgb,var(--foreground) 12%,transparent)}.z-column-menu-item{position:relative;z-index:1;line-height:1.25rem;transition:background-color .15s ease,color .15s ease}.z-column-menu-item:focus-visible,.z-column-menu-item.z-popover-open{background-color:var(--muted);outline:none}.z-table-drag-preview{box-sizing:border-box;border-radius:var(--radius-md);background-color:var(--card);border:1px solid var(--primary);box-shadow:0 10px 24px #00000029;overflow:hidden;z-index:10000!important;pointer-events:none}.z-table-drag-preview:where(.dark,.dark *){box-shadow:0 5px 20px #00000080}.z-table-drag-preview-row{border:0;border-radius:var(--radius-xs);background-color:var(--background);box-shadow:0 8px 20px #0000001f,inset 0 0 0 1px color-mix(in srgb,var(--primary) 45%,var(--border))}.z-table-drag-preview-row table,.z-table-drag-preview-row tbody,.z-table-drag-preview-row tr{height:100%}.z-table-drag-preview-row td{vertical-align:middle!important;background-color:var(--background)}.z-table-drag-preview-virtual{border:0;border-radius:0;box-shadow:0 8px 20px #0000001f,inset 0 0 0 1px color-mix(in srgb,var(--primary) 45%,var(--border))}.z-table-drag-source{display:none!important}.z-virtual-row.z-table-drag-source{display:block!important;pointer-events:none;outline:1px solid var(--border);outline-offset:-1px}.z-virtual-row.z-table-drag-source td{color:color-mix(in srgb,var(--foreground) 45%,transparent);border-color:var(--border)!important;background-color:var(--card)!important}.z-virtual-row.z-table-drag-source td>*{opacity:.45}[data-z-table-drag-handle]{touch-action:none;-webkit-user-select:none;user-select:none}.z-column-drop-list{min-height:3.125rem;overscroll-behavior:contain}.cdk-drag-preview.z-drag-preview,.cdk-drag-placeholder.z-drag-item{border-radius:var(--radius-sm)}.z-table-drag-placeholder{width:100%;min-height:2.625rem;box-sizing:border-box;border:2px dashed var(--primary);border-radius:0;background-color:color-mix(in srgb,var(--primary) 10%,var(--background));pointer-events:none}.z-table-drag-placeholder-row>td{padding:0!important;border:0!important;background:transparent!important}.z-table-drag-placeholder-row .z-table-drag-placeholder{border-radius:0;background-color:color-mix(in srgb,var(--primary) 10%,transparent)}.z-table-drag-placeholder-virtual{position:absolute;top:0;left:0;z-index:20;border-radius:0}.z-tbody-wrapper tr.z-group-row td{background:var(--card);border-top:none;border-bottom:1px solid var(--border)}.z-virtual-row:not(.z-virtual-row-flow) tr.z-group-row td{background:var(--card);border-top:none;border-bottom:none}.z-group-row-sticky-wrapper{display:inline-flex;align-items:center;translate:var(--z-scroll-x, 0px) 0}.z-table-container:not(.z-hide-horizontal-border) .z-virtual-row:not(.z-virtual-row-flow):after,.z-table-container:not(.z-hide-horizontal-border) .z-virtual-row-flow.z-virtual-row-group-header:after{content:\"\";position:absolute;right:0;bottom:0;left:0;z-index:3;height:1px;background:var(--border);pointer-events:none}.z-tbody-wrapper tr.z-group-child-row td.z-at-left-edge,.z-virtual-row tr.z-group-child-row td.z-at-left-edge{border-left:2px solid var(--primary)!important;padding-left:var(--z-group-content-indent, .75rem)}.z-group-row-trigger{display:inline-flex;min-height:2rem;max-width:100%;align-items:center;gap:.5rem;padding:.25rem .5rem .25rem .75rem;color:var(--primary);font-size:.8125rem;font-weight:600;vertical-align:middle;cursor:pointer}.z-group-row-remove{margin-left:.125rem;color:var(--muted-foreground);vertical-align:middle}.z-group-row-remove:hover,.z-group-row-remove:focus-visible{color:var(--destructive);background:color-mix(in srgb,var(--destructive) 10%,transparent);outline:none}.z-group-row-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-column-label{color:color-mix(in srgb,var(--primary) 65%,var(--foreground));font-weight:500;margin-right:.25rem}.z-group-row-count{display:inline-flex;min-width:1.25rem;height:1.25rem;align-items:center;justify-content:center;padding:0 .375rem;border-radius:var(--radius-pill);background:var(--primary);color:var(--primary-foreground);font-size:.6875rem;font-weight:600}.z-group-row-loading{display:inline-flex;align-items:center;margin-left:.25rem}.z-group-row-has-totals td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-has-totals .z-group-row-label-cell{position:sticky;left:0;z-index:2;background:var(--card)}.z-group-row-has-totals .z-group-row-label-cell .z-group-row-sticky-wrapper{max-width:100%;translate:none}.z-group-row-total{display:inline-block;max-width:100%;color:var(--foreground);font-size:.8125rem;font-weight:600;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-total-cell{text-align:right}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-selected:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:before{position:absolute!important;z-index:0!important;box-sizing:border-box!important;top:var(--z-cell-range-top, 0)!important;right:var(--z-cell-range-right, 0)!important;bottom:var(--z-cell-range-bottom, 0)!important;left:var(--z-cell-range-left, 0)!important;width:auto!important;background-color:var(--z-cell-selection-background-opaque)!important;box-shadow:none!important;content:\"\"!important;pointer-events:none!important;opacity:1!important}:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:after{display:none!important}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-top:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-top:before{border-top:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-right:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-right:before{border-right:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-bottom:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-left:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-left:before{border-left:1px solid var(--primary)}:host-context(.z-table-pointer-dragging) .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-selected:before,:host-context(.z-table-pointer-dragging) .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:before{background-color:transparent!important}:host td.z-cell-range-selected:before{position:absolute;z-index:0;box-sizing:border-box;top:var(--z-cell-range-top, 0);right:var(--z-cell-range-right, 0);bottom:var(--z-cell-range-bottom, 0);left:var(--z-cell-range-left, 0);background-color:var(--z-cell-selection-background);box-shadow:none;content:\"\";pointer-events:none;opacity:1}:host td.z-cell-range-top:before{border-top:1px solid var(--primary)}:host td.z-cell-range-right:before{border-right:1px solid var(--primary)}:host td.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}:host td.z-cell-range-left:before{border-left:1px solid var(--primary)}:host-context(.z-table-pointer-dragging) .z-tbody-wrapper td{pointer-events:none}:host-context(.z-table-pointer-dragging) td.z-row-hover{background-color:var(--background)!important}:host td.z-cell-active,:host td.z-cell-active.z-row-hover{background-color:var(--z-cell-selection-background)!important}:host td.z-content-edit-active.z-row-hover{background-color:var(--card)!important}:host tr.z-pinned-top td.z-cell-active,:host tr.z-pinned-top td.z-cell-active.z-row-hover,:host tr.z-pinned-bottom td.z-cell-active,:host tr.z-pinned-bottom td.z-cell-active.z-row-hover,:host td.z-cell-active.z-sticky-left,:host td.z-cell-active.z-sticky-left.z-row-hover,:host td.z-cell-active.z-sticky-right,:host td.z-cell-active.z-sticky-right.z-row-hover{background-color:var(--z-cell-selection-background-opaque)!important}:host tr.z-pinned-top td.z-cell-range-selected,:host tr.z-pinned-bottom td.z-cell-range-selected,:host td.z-cell-range-selected.z-sticky-left,:host td.z-cell-range-selected.z-sticky-right{background-color:var(--card)}:host tr.z-pinned-top td.z-cell-range-selected:before,:host tr.z-pinned-bottom td.z-cell-range-selected:before,:host td.z-cell-range-selected.z-sticky-left:before,:host td.z-cell-range-selected.z-sticky-right:before{background-color:var(--z-cell-selection-background-opaque)}:host-context(.z-table-pointer-dragging) td.z-cell-range-selected,:host-context(.z-table-pointer-dragging) td.z-cell-range-selected.z-row-hover,:host-context(.z-table-pointer-dragging) td.z-cell-active,:host-context(.z-table-pointer-dragging) td.z-cell-active.z-row-hover{background-color:var(--card)!important}:host-context(.z-table-pointer-dragging) td.z-cell-range-selected:before{background-color:transparent}:host .z-tbody-wrapper tbody tr.z-group-child-row:has(+tr.z-group-row)>td.z-at-bottom{border-bottom-color:var(--border)}:host .z-virtual-row:has(tr.z-group-child-row):has(+.z-virtual-row tr.z-group-row) tr.z-group-child-row>td.z-at-bottom{border-bottom-color:var(--border)}.z-thead-wrapper th.z-virtual-column-spacer,.z-tfoot-wrapper th.z-virtual-column-spacer{box-sizing:border-box;padding:0!important;background:var(--muted);border-left:thin solid var(--border)}.z-thead-wrapper th.z-virtual-header-spacer{border-bottom:thin solid var(--border)}.z-tfoot-wrapper th.z-virtual-footer-spacer{border-top:thin solid var(--border)}.z-tbody-wrapper td.z-virtual-column-spacer{box-sizing:border-box;height:auto;padding:0!important;background:var(--card);border-left:thin solid var(--border);border-bottom:thin solid var(--border)}.z-tbody-wrapper tr:hover td.z-virtual-column-spacer{background-color:var(--muted)}.z-table-settings-drawer input[type=checkbox]{appearance:none;-webkit-appearance:none;-moz-appearance:none;width:1rem;height:1rem;border:thin solid var(--input);border-radius:var(--radius-sm);background-color:var(--background);cursor:pointer;position:relative;transition:all .2s ease}.z-table-settings-drawer input[type=checkbox]:hover{border-color:var(--primary)}.z-table-settings-drawer input[type=checkbox]:checked{background-color:var(--primary);border-color:var(--primary)}.z-table-settings-drawer input[type=checkbox]:checked:after{content:\"\";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:.375rem;height:.625rem;border:solid var(--primary-foreground);border-width:0 .125rem .125rem 0;transform:translate(-50%,-60%) rotate(45deg)}.z-table-settings-drawer input[type=checkbox]:disabled{opacity:.5;cursor:not-allowed}.z-virtual-pinned-top{position:sticky;top:0;left:0;z-index:3;width:100%}.z-virtual-pinned-bottom{position:sticky;bottom:0;left:0;z-index:3;width:100%}\n"], dependencies: [{ kind: "component", type: ZTableComponent, selector: "z-table", inputs: ["zClass", "zConfig", "zLoading", "zKey", "zVariant"], outputs: ["zChange", "zControl"], exportAs: ["zTable"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "component", type: NgScrollbar, selector: "ng-scrollbar:not([externalViewport]), [ngScrollbar]", exportAs: ["ngScrollbar"] }, { kind: "directive", type: FlexRenderDirective, selector: "ng-template[flexRender]", inputs: ["flexRender", "flexRenderProps", "flexRenderInjector"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: ZTableDraggableDirective, selector: "[z-table-draggable]", inputs: ["z-table-draggable", "z-table-drag-table-id", "z-table-drag-item-id", "z-table-drag-disabled", "z-table-drag-handle"] }, { kind: "directive", type: ZTableDropTargetDirective, selector: "[z-table-drop-target]", inputs: ["z-table-drop-target", "z-table-drop-table-id", "z-table-drop-item-id", "z-table-drop-disabled"], outputs: ["zTableDropped"] }, { kind: "component", type: ZCheckboxComponent, selector: "z-checkbox", inputs: ["class", "zType", "zSize", "zLabel", "zText", "zDisabled", "zIndeterminate", "zValue", "zOptions", "zOrientation", "zCheckAll", "zCheckAllText", "zChecked", "zGroupValue"], outputs: ["zChange", "zGroupChange", "zOnBlur", "zOnFocus", "zControl", "zEvent", "zCheckedChange", "zGroupValueChange"] }, { kind: "component", type: ZEmptyComponent, selector: "z-empty", inputs: ["class", "zType", "zIcon", "zIconSize", "zSize", "zMessage", "zDescription"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zAnimatedType", "zAnimate", "zAnimationTrigger", "zSize", "zStrokeWidth", "zSvg"] }, { kind: "component", type: ZInputComponent, selector: "z-input", inputs: ["class", "zType", "zSize", "zAlign", "zLabel", "zLabelClass", "zPlaceholder", "zRequired", "zDisabled", "zReadonly", "zLoading", "zLoadingOutline", "zPrefix", "zSuffix", "zMin", "zMax", "zStep", "zShowArrows", "zMask", "zDecimalPlaces", "zAllowNegative", "zThousandSeparator", "zDecimalMarker", "zValidators", "zAsyncValidators", "zAsyncDebounce", "zAsyncValidateOn", "zShowPasswordToggle", "zSearch", "zDebounce", "zAutofocus", "zAutoComplete", "zAllowClear", "zAutoSizeContent", "zRows", "zResize", "zMaxLength", "zAutoSuggest", "zColorConfig"], outputs: ["zOnSearch", "zOnChange", "zOnBlur", "zOnFocus", "zOnKeydown", "zOnEnter", "zOnColorCollapse", "zControl", "zEvent"], exportAs: ["zInput"] }, { kind: "component", type: ZLoadingComponent, selector: "z-loading", inputs: ["class", "zSpinner", "zSize", "zColor", "zText", "zOverlay", "zOverlayType", "zFullscreen", "zLoading"] }, { kind: "directive", type: ZHoverGlideDirective, selector: "[zHoverGlide]", inputs: ["zHoverGlideSelector", "zHoverGlideClass", "zHoverGlideDisabled"] }, { kind: "component", type: ZSkeletonComponent, selector: "z-skeleton", inputs: ["class", "zType", "zSize", "zWidth", "zHeight", "zRows", "zGap", "zAnimated", "zRadius"] }, { kind: "component", type: ZDrawerComponent, selector: "z-drawer", inputs: ["class", "zBodyClass", "zVisible", "zTitle", "zDescription", "zWidth", "zHeight", "zPlacement", "zClosable", "zMaskClosable", "zDisableShadow", "zHeaderBorder", "zFooterBorder", "zHideFooter", "zHideHeader", "zOkText", "zCancelText", "zOkDestructive", "zOkDisabled", "zLoading", "zOverlay", "zShadow", "zShape", "zContentLoading", "zSkeletonRows", "zExpand", "zScrollMode"], outputs: ["zOnOk", "zOnCancel", "zAfterClose", "zScrollbar", "zVisibleChange"], exportAs: ["zDrawer"] }, { kind: "component", type: ZPaginationComponent, selector: "z-pagination", inputs: ["zPageIndex", "zPageSize", "zTotal", "zPageSizeOptions", "zShowSizeChanger", "zShowQuickJumper", "zShowTotal", "zSimple", "zSize", "zDisabled", "zTotalLabel", "zPerPageLabel", "zGoToLabel"], outputs: ["zOnPageChange", "zPageIndexChange", "zPageSizeChange"] }, { kind: "component", type: ZTableFilterComponent, selector: "z-table-filter", inputs: ["zColumn", "zTable", "zResetVersion", "zSortingState", "zEnableMultiSort"] }, { kind: "component", type: ZTableEditCellComponent, selector: "z-table-edit-cell", inputs: ["zRow", "zRowId", "zRowIndex", "zColumnId", "zValue", "zEditConfig", "zRowUpdate"], outputs: ["zChange"] }, { kind: "directive", type: ZPopoverDirective, selector: "[z-popover]", inputs: ["zPopoverContent", "zPosition", "zTrigger", "zPopoverTrigger", "zClass", "zShowDelay", "zHideDelay", "zDisabled", "zOffset", "zPopoverWidth", "zTriggerRef", "zManualClose", "zOutsideClickClose", "zScrollClose", "zSticky", "zShowArrow", "zKeyboardSafe"], outputs: ["zShow", "zHide", "zHideStart", "zControl", "zPositionChange", "zOutsideClick"], exportAs: ["zPopover"] }, { kind: "component", type: ZButtonComponent, selector: "z-button, button[z-button], a[z-button]", inputs: ["class", "zType", "zSize", "zShape", "zLabel", "zLoading", "zDisabled", "zTypeIcon", "zAnimatedTypeIcon", "zAnimateIcon", "zAnimationTriggerIcon", "zSizeIcon", "zStrokeWidthIcon", "zWave"], exportAs: ["zButton"] }, { kind: "directive", type: ZTooltipDirective, selector: "[z-tooltip], [zTooltip]", inputs: ["zContent", "zPosition", "zTooltipPosition", "zTrigger", "zTooltipTrigger", "zTooltipType", "zTooltipSize", "zClass", "zTooltipClass", "zShowDelay", "zTooltipShowDelay", "zHideDelay", "zTooltipHideDelay", "zArrow", "zTooltipArrow", "zDisabled", "zTooltipDisabled", "zOffset", "zTooltipOffset", "zAutoDetect", "zTriggerElement", "zAlwaysShow", "zMaxWidth"], outputs: ["zShow", "zHide"], exportAs: ["zTooltip"] }, { kind: "directive", type: ZTableResizeDirective, selector: "[z-table-resize],[zTableResize]", inputs: ["zTableResize"] }, { kind: "directive", type: ZTableRowHoverDirective, selector: "[z-table-row-hover], [zTableRowHover]", inputs: ["zTableRowHover"] }, { kind: "component", type: ZTableIconTextComponent, selector: "z-table-icon-text", inputs: ["zText", "zTooltip", "zTriggerElement"] }, { kind: "component", type: ZTableActionsComponent, selector: "z-table-actions", inputs: ["zConfig", "zRow", "zRowId", "zDropdownButtonSize"], outputs: ["zActionClick"] }, { kind: "component", type: ZTableContentEditorComponent, selector: "z-table-content-editor", inputs: ["zValue", "zConfig"], outputs: ["zCommit", "zCancel"] }, { kind: "pipe", type: ZTableIsTemplateRefPipe, name: "zTableIsTemplateRef" }, { kind: "pipe", type: ZTableHasIconPipe, name: "zTableHasIcon" }, { kind: "pipe", type: ZTableCellBottomPipe, name: "zTableCellBottom" }, { kind: "pipe", type: ZTableCellClickablePipe, name: "zTableCellClickable" }, { kind: "pipe", type: ZTableCellConfigPipe, name: "zTableCellConfig" }, { kind: "pipe", type: ZTableCellEditPipe, name: "zTableCellEdit" }, { kind: "pipe", type: ZTableCellOffsetPipe, name: "zTableCellOffset" }, { kind: "pipe", type: ZTableCellPinPipe, name: "zTableCellPin" }, { kind: "pipe", type: ZTableCellVisiblePipe, name: "zTableCellVisible" }, { kind: "pipe", type: ZTableColumnConfigPipe, name: "zTableColumnConfig" }, { kind: "pipe", type: ZTableColumnHeaderPipe, name: "zTableColumnHeader" }, { kind: "pipe", type: ZTableColumnParentsPipe, name: "zTableColumnParents" }, { kind: "pipe", type: ZTableFooterContentPipe, name: "zTableFooterContent" }, { kind: "pipe", type: ZTableFooterRenderPipe, name: "zTableFooterRender" }, { kind: "pipe", type: ZTablePinningStylesPipe, name: "zTablePinningStyles" }, { kind: "pipe", type: ZTablePopoverConfigPipe, name: "zTablePopoverConfig" }, { kind: "pipe", type: ZTableRowPipe, name: "zTableRow" }, { kind: "pipe", type: ZTableRowConfigPipe, name: "zTableRowConfig" }, { kind: "pipe", type: ZTableSpanPipe, name: "zTableSpan" }, { kind: "pipe", type: ZTableSubTableConfigPipe, name: "zTableSubTableConfig" }, { kind: "pipe", type: ZTableTooltipConfigPipe, name: "zTableTooltipConfig" }, { kind: "pipe", type: ZTableCellRenderPipe, name: "zTableCellRender" }, { kind: "pipe", type: ZFormatNumPipe, name: "zFormatNum" }, { kind: "pipe", type: ZSafeHtmlPipe, name: "zSafeHtml" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
11204
11262
  }
11205
11263
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ZTableComponent, decorators: [{
11206
11264
  type: Component,
@@ -11260,7 +11318,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
11260
11318
  TranslatePipe,
11261
11319
  ], standalone: true, providers: [TranslatePipe, ZTableDragService], changeDetection: ChangeDetectionStrategy.OnPush, host: {
11262
11320
  class: 'z-table block relative py-1',
11263
- }, exportAs: 'zTable', template: "<!-- Toolbar: Search & Settings -->\n@if (isSearchEnabled() || zConfig().enableSettings) {\n <div class=\"z-table-toolbar mb-2 flex items-center justify-between gap-4\">\n <!-- Search -->\n @if (isSearchEnabled()) {\n @let config = searchConfig();\n <z-input\n [class]=\"config?.width ?? 'w-64'\"\n [zSize]=\"config?.size ?? 'sm'\"\n [zPlaceholder]=\"config?.placeholder ?? 'i18n_z_ui_table_search' | translate\"\n [zSearch]=\"true\"\n [zDebounce]=\"config?.debounceTime ?? 300\"\n (zOnSearch)=\"onSearchChange($event)\" />\n } @else {\n <div></div>\n }\n\n <!-- Settings Button -->\n @if (zConfig().enableSettings) {\n <z-button zType=\"outline\" zSize=\"sm\" zTypeIcon=\"lucideSettings\" (click)=\"openSettingsDrawer()\">\n {{ 'i18n_z_ui_table_settings' | translate }}\n </z-button>\n }\n </div>\n}\n\n@if (zConfig().enableFilterHeader && appliedFilterChips().length > 0) {\n <div class=\"z-table-filter-header mb-2 flex min-w-0 items-center gap-2\">\n <div class=\"flex min-w-0 flex-1 flex-wrap items-center gap-1.5\">\n @for (chip of visibleAppliedFilterChips(); track chip.id) {\n <span\n class=\"border-border bg-muted/60 text-foreground inline-flex max-w-80 min-w-0 shrink-0 items-center gap-1 rounded-sm border px-2 py-1 text-[0.8125rem] shadow-xs\">\n <span class=\"font-medium whitespace-nowrap\">{{ chip.label }}</span>\n <span class=\"text-muted-foreground\">:</span>\n <span class=\"truncate\" z-tooltip [zContent]=\"chip.value\" zTooltipTrigger=\"hover\" zTooltipPosition=\"top\">\n {{ chip.value }}\n </span>\n <button\n type=\"button\"\n class=\"hover:bg-destructive/10 hover:text-destructive focus-visible:ring-ring -mr-1 inline-flex size-5 cursor-pointer items-center justify-center rounded-sm outline-none focus-visible:ring-2\"\n [attr.aria-label]=\"'i18n_z_ui_table_filter_remove' | translate\"\n (click)=\"clearAppliedFilterChip(chip)\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </span>\n }\n @if (hiddenAppliedFilterChipCount() > 0 && isFilterHeaderExpanded()) {\n @for (chip of overflowAppliedFilterChips(); track chip.id) {\n <span\n class=\"z-table-filter-header-overflow-chip border-border bg-muted/60 text-foreground inline-flex max-w-80 min-w-0 shrink-0 items-center gap-1 rounded-sm border px-2 py-1 text-[0.8125rem] shadow-xs\"\n [attr.aria-hidden]=\"!isFilterHeaderExpanded()\">\n <span class=\"font-medium whitespace-nowrap\">{{ chip.label }}</span>\n <span class=\"text-muted-foreground\">:</span>\n <span class=\"truncate\" z-tooltip [zContent]=\"chip.value\" zTooltipTrigger=\"hover\" zTooltipPosition=\"top\">\n {{ chip.value }}\n </span>\n <button\n type=\"button\"\n class=\"hover:bg-destructive/10 hover:text-destructive focus-visible:ring-ring -mr-1 inline-flex size-5 cursor-pointer items-center justify-center rounded-sm outline-none focus-visible:ring-2\"\n [attr.aria-label]=\"'i18n_z_ui_table_filter_remove' | translate\"\n (click)=\"clearAppliedFilterChip(chip)\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </span>\n }\n }\n @if (hiddenAppliedFilterChipCount() > 0) {\n <button\n type=\"button\"\n class=\"text-primary hover:bg-primary/10 focus-visible:ring-ring inline-flex h-7 cursor-pointer items-center rounded-sm px-2 text-xs font-medium outline-none focus-visible:ring-2\"\n (click)=\"toggleFilterHeaderExpanded()\">\n {{\n isFilterHeaderExpanded()\n ? ('i18n_z_ui_table_show_less' | translate)\n : ('i18n_z_ui_table_show_more' | translate: { count: hiddenAppliedFilterChipCount() })\n }}\n </button>\n }\n <button\n type=\"button\"\n class=\"bg-destructive/10 text-destructive hover:bg-destructive/20 dark:bg-destructive/15 dark:text-destructive-foreground dark:hover:bg-destructive/25 focus-visible:ring-destructive inline-flex h-7 cursor-pointer items-center gap-1 rounded-sm px-2 text-xs font-medium shadow-xs outline-none focus-visible:ring-2\"\n (click)=\"clearAppliedFilters()\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_clear_filter' | translate }}</span>\n </button>\n </div>\n </div>\n}\n\n<div\n #tableContainer\n [class]=\"classTable()\"\n [ngStyle]=\"columnSizeVars()\"\n [class.z-pinning-overflow]=\"!isPinnedLayoutWithinContainer()\"\n [class.z-hide-horizontal-border]=\"!showHorizontalBorder()\"\n [class.z-hide-vertical-border]=\"!showVerticalBorder()\"\n [class.z-hide-pinned-top-border]=\"hasScrollTop()\"\n [class.z-hide-pinned-bottom-border]=\"hasScrollBottom()\"\n [style.width]=\"zConfig().width\"\n [style.height]=\"zConfig().height\"\n [style.max-height]=\"zConfig().maxHeight\"\n [style.min-height]=\"zConfig().minHeight\"\n [attr.tabindex]=\"canUseContentRowInsert() || canUseCellSelection() ? 0 : null\"\n (keydown)=\"onContentTableKeydown($event)\">\n @let isColumnPinningActive = isPinnedLayoutWithinContainer();\n <ng-template #contentRowMenuContent>\n <div class=\"flex min-w-36 flex-col gap-0.5 p-1\">\n @if (contentRowMenu()?.columnId) {\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded-sm 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-sm 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-sm 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-sm 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-sm 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-sm 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-sm 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-sm 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-sm 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-sm px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canCopyCellMenuSelection()\"\n (click)=\"copySelectedCells(true)\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_cell_with_headers' | translate }}</span>\n </button>\n }\n </div>\n </ng-template>\n\n <div\n class=\"pointer-events-none fixed size-px opacity-0\"\n z-popover\n [zPopoverContent]=\"contentRowMenuContent\"\n zTrigger=\"manual\"\n zPosition=\"bottom-left\"\n zClass=\"z-table-content-row-menu\"\n [zOffset]=\"0\"\n [zManualClose]=\"true\"\n [zScrollClose]=\"true\"\n [style.left.px]=\"contentRowMenu()?.left ?? -9999\"\n [style.top.px]=\"contentRowMenu()?.top ?? -9999\"\n (zControl)=\"setContentRowMenuControl($event)\"\n (zHide)=\"clearContentRowMenu()\"></div>\n\n <div\n class=\"pointer-events-none fixed size-px opacity-0\"\n z-popover\n [zPopoverContent]=\"cellMenuContent\"\n zTrigger=\"manual\"\n zPosition=\"bottom-left\"\n zClass=\"z-table-cell-menu\"\n [zOffset]=\"0\"\n [zManualClose]=\"true\"\n [zScrollClose]=\"true\"\n [style.left.px]=\"cellMenu()?.left ?? -9999\"\n [style.top.px]=\"cellMenu()?.top ?? -9999\"\n (zControl)=\"setCellMenuControl($event)\"\n (zHide)=\"clearCellMenu()\"></div>\n\n <!-- Shared colgroup template -->\n <ng-template #colGroupTpl>\n <colgroup>\n @if (canUseVirtualColumns()) {\n @for (column of leftLeafColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <col [style.width.px]=\"virtualRenderedLeftSpacerWidth()\" />\n }\n @for (column of virtualCenterColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n @if (virtualRightSpacerWidth() > 0) {\n <col [style.width.px]=\"virtualRenderedRightSpacerWidth()\" />\n }\n @for (column of rightLeafColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n } @else {\n @for (column of orderedLeafColumns(); track column.id) {\n @if (column.getIsVisible()) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n }\n }\n </colgroup>\n </ng-template>\n\n <!-- Header table -->\n <div\n class=\"z-thead-wrapper shadow-card\"\n [class.z-shadow-header]=\"shouldHeaderShowShadow()\"\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\"\n (wheel)=\"onTheadWheel($event)\"\n #theadWrapper>\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <thead>\n @if (canUseVirtualColumns()) {\n <tr>\n @for (header of leftHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: leftHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div zHoverGlide zHoverGlideSelector=\".z-column-menu-item\" 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-sm 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-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm 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-sm 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-sm 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-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded-sm 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 zClass=\"rounded-lg overflow-hidden\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <th\n class=\"z-virtual-column-spacer z-virtual-header-spacer z-virtual-left-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></th>\n }\n @for (header of virtualCenterHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: virtualCenterHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div zHoverGlide zHoverGlideSelector=\".z-column-menu-item\" 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-sm 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-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm 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-sm 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-sm 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-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded-sm 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 zClass=\"rounded-lg overflow-hidden\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualRightSpacerWidth() > 0) {\n <th\n class=\"z-virtual-column-spacer z-virtual-header-spacer z-virtual-right-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></th>\n }\n @for (header of rightHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: rightHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <!-- Header Checkbox -->\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <!-- Expand All Button -->\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <!-- Header Content with Sort and Pin -->\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <!-- Column Options Popover Template -->\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div zHoverGlide zHoverGlideSelector=\".z-column-menu-item\" 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-sm 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-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm 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-sm 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-sm 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-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded-sm 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 zClass=\"rounded-lg overflow-hidden\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n <!-- Dropdown indicator when has options (between text and sort icon) -->\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n <!-- Sort Icon (outside wrapper, no hover background) -->\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n <!-- Column Resizer -->\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n </tr>\n } @else {\n @for (headerGroup of orderedHeaderGroups(); track headerGroup.id) {\n <tr>\n @for (header of headerGroup.headers; track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: headerGroup.headers : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div zHoverGlide zHoverGlideSelector=\".z-column-menu-item\" 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-sm 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-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"15\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"\n handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\n \"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"15\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm 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-sm 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-sm 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-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded-sm 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 zClass=\"rounded-lg overflow-hidden\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"\n header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\n \"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n </tr>\n }\n }\n </thead>\n </table>\n </div>\n\n <!-- Body table -->\n <div\n class=\"z-tbody-wrapper relative\"\n #tbodyContainer\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\">\n @if (isLoading() || isProcessing()) {\n <!-- Loading State -->\n @if (zConfig().useSkeleton) {\n <!-- Skeleton Loading -->\n <div class=\"animate-in fade-in flex h-full flex-col duration-200\">\n @for (i of skeletonRows(); track $index; let last = $last) {\n <div\n class=\"border-border box-border flex flex-1 flex-col items-start justify-center gap-1.5 px-2\"\n [class.border-b]=\"!last\">\n <z-skeleton zType=\"bar\" zWidth=\"100%\" zHeight=\"22px\" />\n <z-skeleton zType=\"bar\" zWidth=\"50%\" zHeight=\"14px\" />\n </div>\n }\n </div>\n } @else {\n <!-- Spinner Loading -->\n <div class=\"z-loading-state\">\n <z-loading [zLoading]=\"true\" zSize=\"lg\" [zText]=\"'i18n_z_ui_table_loading' | translate\" />\n </div>\n }\n } @else if (isEmpty()) {\n <div class=\"z-empty-state\">\n @if (isNoSearchResults()) {\n <z-empty zIcon=\"lucideSearchX\" zSize=\"sm\" [zMessage]=\"'i18n_z_ui_table_no_results' | translate\" />\n } @else {\n <z-empty zIcon=\"lucidePackageOpen\" zSize=\"sm\" [zMessage]=\"'i18n_z_ui_table_no_data' | translate\" />\n }\n </div>\n } @else {\n <ng-scrollbar class=\"z-tbody-scrollbar\" #tbodyWrapper (scroll)=\"onTbodyScroll($event)\">\n @if (isVirtual()) {\n <!-- Virtual Scroll Mode -->\n\n <div\n class=\"z-virtual-scroll-inner\"\n [style.height.px]=\"virtualizer.getTotalSize()\"\n [style.min-width.px]=\"table.getTotalSize()\">\n <!-- Pinned rows v\u00E0 center rows d\u00F9ng chung m\u1ED9t virtual canvas. -->\n @if (virtualPinnedTopRows().length > 0) {\n <div class=\"z-virtual-pinned-top\" [style.min-width.px]=\"table.getTotalSize()\">\n @for (row of virtualPinnedTopRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"virtualPinnedRowTpl; context: { $implicit: row }\" />\n }\n </div>\n }\n\n @if (usesFlowVirtualRows()) {\n <div\n class=\"z-virtual-flow\"\n [style.transform]=\"'translate3d(0,' + virtualFlowOffset() + 'px,0)'\"\n [style.min-width.px]=\"table.getTotalSize()\">\n <ng-container *ngTemplateOutlet=\"virtualRowsTpl\" />\n </div>\n } @else {\n <ng-container *ngTemplateOutlet=\"virtualRowsTpl\" />\n }\n\n <ng-template #virtualRowsTpl>\n @for (virtualItem of virtualizer.getVirtualItems(); track virtualItem.index) {\n @let groupRows = dynamicGroupRows()[virtualItem.index] || [];\n @let virtualFlatItem = virtualGroupedFlatItems()[virtualItem.index];\n @let stickyGroupState = stickyGroupHeaderState();\n @let stickyGroupTop = stickyGroupState.tops[virtualItem.index];\n @let isStickyGroupHeader = stickyGroupTop !== undefined;\n <div\n #virtualRow\n class=\"z-virtual-row\"\n [class.z-virtual-row-flow]=\"usesFlowVirtualRows()\"\n [class.z-virtual-row-fixed]=\"!effectiveDynamicRowSizing()\"\n [class.z-virtual-row-group-header]=\"virtualFlatItem?.type === 'group-header'\"\n [class.z-virtual-row-sticky-group]=\"isStickyGroupHeader\"\n [class.z-virtual-row-sticky-group-shadow]=\"stickyGroupState.shadowIndex === virtualItem.index\"\n [style.top.px]=\"stickyGroupTop\"\n z-table-draggable=\"row\"\n z-table-drop-target=\"row\"\n [z-table-drag-table-id]=\"dragInstanceId\"\n [z-table-drop-table-id]=\"dragInstanceId\"\n [z-table-drag-item-id]=\"groupRows.length > 0 ? groupRows[0].id : ''\"\n [z-table-drop-item-id]=\"groupRows.length > 0 ? groupRows[0].id : ''\"\n [z-table-drag-disabled]=\"!isVirtualRowDragEnabled() || groupRows.length !== 1\"\n [z-table-drop-disabled]=\"!isVirtualRowDragEnabled() || groupRows.length !== 1\"\n (zTableDropped)=\"_handleDragDrop($event)\"\n [attr.data-index]=\"virtualItem.index\"\n [style.height.px]=\"\n effectiveDynamicRowSizing()\n ? null\n : (dynamicGroupHeights()[virtualItem.index] ?? groupSize() * virtualRowHeight())\n \"\n [style.transform]=\"\n usesFlowVirtualRows() || isStickyGroupHeader ? null : 'translate3d(0,' + virtualItem.start + 'px,0)'\n \">\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-has-bottom-pinned]=\"table.getBottomRows().length > 0\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n @let groupHeaderItem = _getVirtualGroupHeader(virtualFlatItem);\n @if (groupHeaderItem) {\n <tr\n class=\"z-group-row\"\n [class.z-group-row-has-totals]=\"groupHeaderItem.totals\"\n [class.z-group-row-expanded]=\"groupHeaderItem.expanded\"\n [attr.data-group-id]=\"groupHeaderItem.id\"\n [attr.data-group-depth]=\"groupHeaderItem.depth\">\n @if (groupHeaderItem.totals) {\n @let totalColumnMap = groupTotalColumnMap();\n @for (column of orderedLeafColumns(); track column.id; let isFirstGroupCell = $first) {\n <td\n [class.z-group-row-label-cell]=\"isFirstGroupCell\"\n [class.z-group-row-total-cell]=\"!isFirstGroupCell && totalColumnMap[column.id]\"\n [attr.data-column-id]=\"column.id\">\n @if (isFirstGroupCell) {\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + groupHeaderItem.depth * 0.75\"\n [attr.aria-expanded]=\"groupHeaderItem.expanded\"\n (click)=\"toggleGroupRow(groupHeaderItem.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"groupHeaderItem.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"\n (groupHeaderItem.columnLabel ? groupHeaderItem.columnLabel + ': ' : '') +\n groupHeaderItem.label\n \">\n @if (groupHeaderItem.columnLabel) {\n <span class=\"z-group-row-column-label\">\n {{ groupHeaderItem.columnLabel }}:\n </span>\n }\n {{ groupHeaderItem.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ groupHeaderItem.count }}</span>\n }\n @if (groupHeaderItem.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n [zWave]=\"false\"\n z-tooltip\n zSizeIcon=\"14\"\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(groupHeaderItem.columnId)\"></button>\n }\n </div>\n }\n @if (!isFirstGroupCell && totalColumnMap[column.id]) {\n @let totalConfig = groupTotalConfigMap()[column.id];\n @let totalTooltip = totalConfig.tooltip;\n @let totalPopover = totalConfig.popover;\n @let totalPopoverContent = totalPopover | zTablePopoverConfig: 'content';\n <ng-template #groupTotalPopoverTpl>\n @if (totalPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(totalPopoverContent)\" />\n }\n @if (!(totalPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(totalPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n <span\n class=\"z-group-row-total\"\n z-tooltip\n z-popover\n [class]=\"totalConfig.class\"\n [zContent]=\"\n $any(\n (totalTooltip | zTableTooltipConfig: 'content') ||\n groupHeaderItem.totals[column.id]\n )\n \"\n [zTooltipPosition]=\"$any(totalTooltip | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(totalTooltip | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(totalTooltip | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(totalTooltip | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(totalTooltip | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'showDelay')\"\n [zTooltipHideDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'hideDelay')\"\n [zTooltipArrow]=\"$any(totalTooltip | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(totalTooltip | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(totalTooltip | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(totalTooltip | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(totalTooltip | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"totalPopoverContent ? groupTotalPopoverTpl : null\"\n [zPosition]=\"$any(totalPopover | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(totalPopover | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(totalPopover | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(totalPopover | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(totalPopover | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(totalPopover | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(totalPopover | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(totalPopover | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(totalPopover | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"$any(totalPopover | zTablePopoverConfig: 'outsideClickClose')\"\n [zScrollClose]=\"$any(totalPopover | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(totalPopover | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(totalPopover | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(totalPopover | zTablePopoverConfig: 'keyboardSafe')\">\n {{ groupHeaderItem.totals[column.id] }}\n </span>\n }\n </td>\n }\n } @else {\n <td [attr.colspan]=\"renderedColumnCount()\">\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + groupHeaderItem.depth * 0.75\"\n [attr.aria-expanded]=\"groupHeaderItem.expanded\"\n (click)=\"toggleGroupRow(groupHeaderItem.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"groupHeaderItem.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"\n (groupHeaderItem.columnLabel ? groupHeaderItem.columnLabel + ': ' : '') +\n groupHeaderItem.label\n \">\n @if (groupHeaderItem.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ groupHeaderItem.columnLabel }}:</span>\n }\n {{ groupHeaderItem.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ groupHeaderItem.count }}</span>\n }\n @if (groupHeaderItem.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n [zWave]=\"false\"\n z-tooltip\n zSizeIcon=\"14\"\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(groupHeaderItem.columnId)\"></button>\n }\n </div>\n </td>\n }\n </tr>\n }\n @for (row of groupRows; track row.id) {\n @let virtualGroupDepth = _getVirtualGroupDepth(virtualFlatItem);\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <tr\n z-table-row-hover\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"effectiveDynamicRowSizing() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"effectiveDynamicRowSizing() ? virtualRowHeight() : null\"\n [style.--z-row-height]=\"effectiveDynamicRowSizing() ? 'auto' : virtualRowHeight() + 'px'\"\n [class.z-child-row]=\"row.depth > 0\"\n [class.z-group-child-row]=\"_isVirtualGroupChild(virtualFlatItem)\"\n [style.--z-group-content-indent]=\"\n virtualGroupDepth > 0 ? 1.75 + (virtualGroupDepth - 1) * 0.75 + 'rem' : null\n \"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && row.id === firstTopPinnedRowId()\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"rowPinned === 'bottom' && row.id === lastBottomPinnedRowId()\"\n [class.z-pinned-bottom-first]=\"rowPinned === 'bottom' && row.id === firstBottomPinnedRowId()\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n row.id === lastTopPinnedRowId() &&\n !isStickyGroupHeaderEnabled()\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n row.id === firstBottomPinnedRowId()\n \"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : bodyRowSpanRows();\n @let shouldRenderColSpan =\n cell | zTableCellRender: visibleCells : zConfig().columns : 'body';\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (shouldRenderRowSpan && shouldRenderColSpan && isVirtualColumnVisible) {\n @let cellSelectionId = row.id + '::' + cell.column.id;\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"isColumnPinningActive && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActive && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell\n | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell\n | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"cell.column.id === actionColumnInfo()?.columnId\"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [class.z-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"cell | zTableCellBottom: zConfig().columns : renderedBodyRows()\"\n [attr.rowspan]=\"\n cell | zTableSpan: zConfig().columns : 'cellRowSpan' : bodyRowSpanRows()\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() &&\n cell.row.getIsSomeSelected() &&\n !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-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"cell.row.getIsExpanded()\" />\n </button>\n }\n </div>\n } @else if (\n (cell.column.id === 'actionRowPin' || cell.column.id === 'actions') &&\n cell.column.id !== actionColumnInfo()?.columnId\n ) {\n @if (cell.row.depth === 0 && !hasBodyRowSpan()) {\n <div class=\"flex items-center justify-center\">\n <ng-template #rowPinPopoverContent>\n <div\n zHoverGlide\n zHoverGlideSelector=\".z-column-menu-item\"\n class=\"flex flex-col gap-1 py-1\">\n @if (cell.row.getIsPinned() !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cell.row.getIsPinned() !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cell.row.getIsPinned()) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded-sm p-1 outline-none\"\n [class.text-primary]=\"cell.row.getIsPinned()\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n </div>\n }\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisible = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisible) {\n @let editInfoVirtual = cell.getContext() | zTableCellEdit: zConfig().columns;\n @if (editInfoVirtual.enabled) {\n <!-- Editable Cell (Virtual) -->\n <z-table-edit-cell\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n [zRowIndex]=\"cell.row.index\"\n [zColumnId]=\"cell.column.id\"\n [zValue]=\"cell.getValue()\"\n [zRowUpdate]=\"_rowUpdate()\"\n [zEditConfig]=\"$any(editInfoVirtual.config)\"\n (zChange)=\"onCellEdit($any($event))\" />\n } @else if (editInfoVirtual.contentEnabled) {\n @let contentConfigVirtual = editInfoVirtual.contentConfig!;\n @if (\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n ) {\n <z-table-content-editor\n [zValue]=\"cell.getValue()\"\n [zConfig]=\"contentConfigVirtual\"\n (zCommit)=\"onContentEditCommit($event, row, cell.column.id, cell.getValue())\"\n (zCancel)=\"onContentEditCancel()\" />\n } @else {\n <button\n type=\"button\"\n class=\"z-table-content-trigger\"\n [attr.data-z-table-edit-row]=\"row.id\"\n [attr.data-z-table-edit-column]=\"cell.column.id\"\n (keydown)=\"onContentEditKeydown($event, row.id, cell.column.id)\"\n (click)=\"onContentEditStart($event, row.id, cell.column.id)\">\n {{ contentConfigVirtual.displayValue }}\n </button>\n }\n } @else {\n <ng-container\n *flexRender=\"\n cell.column.columnDef.cell;\n props: cell.getContext();\n let cellContent\n \">\n @if (cellContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n @let isClickable = cell.column.id | zTableCellClickable: zConfig().columns;\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickable && onCellClick(row, cell.column.id, cell.getValue())\">\n <ng-container\n *ngTemplateOutlet=\"\n cellContent;\n context: { $implicit: cell.getContext() }\n \" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n @let isClickableIcon =\n cell.column.id | zTableCellClickable: zConfig().columns;\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"\n isClickableIcon && onCellClick(row, cell.column.id, cell.getValue())\n \" />\n } @else {\n <!-- Default/innerHTML rendering -->\n @let isClickableDefault =\n cell.column.id | zTableCellClickable: zConfig().columns;\n @let cellTooltipConfig =\n cell | zTableCellConfig: zConfig() : 'contentTooltip';\n @let cellPopoverConfig =\n cell | zTableCellConfig: zConfig() : 'contentPopover';\n @let cellPopoverContent = cellPopoverConfig | zTablePopoverConfig: 'content';\n <ng-template #cellPopoverTpl>\n @if (cellPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(cellPopoverContent)\" />\n }\n @if (!(cellPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(cellPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n @if (cellPopoverContent) {\n <div\n class=\"z-table-cell-text\"\n z-popover\n z-tooltip\n [zTriggerElement]=\"cellOverlayContent\"\n [zTriggerRef]=\"cellOverlayContent\"\n [zContent]=\"\n (cellTooltipConfig | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'position')\n \"\n [zTooltipTrigger]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'trigger')\n \"\n [zTooltipType]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'autoDetect')\n \"\n [zAlwaysShow]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'alwaysShow')\n \"\n [zMaxWidth]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"cellPopoverTpl\"\n [zPosition]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'trigger')\n \"\n [zClass]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'manualClose')\n \"\n [zOutsideClickClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'outsideClickClose')\n \"\n [zScrollClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'scrollClose')\n \"\n [zSticky]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'keyboardSafe')\n \"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellOverlayContent\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n } @else {\n <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zTriggerElement]=\"cellTooltipContent\"\n [zContent]=\"\n (cellTooltipConfig | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'position')\n \"\n [zTooltipTrigger]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'trigger')\n \"\n [zTooltipType]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'autoDetect')\n \"\n [zAlwaysShow]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'alwaysShow')\n \"\n [zMaxWidth]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'maxWidth')\"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellTooltipContent\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n }\n }\n </ng-container>\n }\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </ng-template>\n </div>\n\n <!--\n Bottom pinned rows: sibling AFTER the virtual canvas (not absolute like the\n center rows). The virtualizer reserves their height inside getTotalSize() via\n `paddingEnd`, leaving an empty band at the canvas bottom. `margin-top: -bottomHeight`\n pulls this real flow element back over that band, and `position: sticky; bottom: 0`\n floats it to the viewport bottom while scrolling.\n -->\n @if (virtualPinnedBottomRows().length > 0) {\n <div\n class=\"z-virtual-pinned-bottom\"\n [style.min-width.px]=\"table.getTotalSize()\"\n [style.margin-top.px]=\"-virtualPinnedBottomHeight()\">\n @for (row of virtualPinnedBottomRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"virtualPinnedRowTpl; context: { $implicit: row }\" />\n }\n </div>\n }\n\n <!-- Template for rendering pinned rows in virtual scroll mode -->\n <ng-template #virtualPinnedRowTpl let-row>\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody [class.z-has-vertical-scroll]=\"hasVerticalScroll()\">\n <tr\n z-table-row-hover\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"effectiveDynamicRowSizing() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"effectiveDynamicRowSizing() ? virtualRowHeight() : null\"\n [style.--z-row-height]=\"effectiveDynamicRowSizing() ? 'auto' : virtualRowHeight() + 'px'\"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && row.id === firstTopPinnedRowId()\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"rowPinned === 'bottom' && row.id === lastBottomPinnedRowId()\"\n [class.z-pinned-bottom-first]=\"rowPinned === 'bottom' && row.id === firstBottomPinnedRowId()\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n row.id === lastTopPinnedRowId() &&\n !isStickyGroupHeaderEnabled()\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n row.id === firstBottomPinnedRowId()\n \"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @let isColumnPinningActivePinned = isPinnedLayoutWithinContainer();\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @let cellSelectionId = row.id + '::' + cell.column.id;\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (isVirtualColumnVisible) {\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActivePinned\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"isColumnPinningActivePinned && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActivePinned && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"cell.column.id === actionColumnInfo()?.columnId\"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [style.--z-cell-range-top]=\"(selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"(selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'select') {\n <z-checkbox\n [zChecked]=\"rowSelected\"\n [zIndeterminate]=\"rowSomeSelected && !rowSelected\"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && row.toggleSelected()\" />\n } @else if (cell.column.id === 'expand') {\n <button\n type=\"button\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"row.toggleExpanded()\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"row.getIsExpanded()\" />\n </button>\n } @else if (cell.column.id === 'actionRowPin') {\n <div class=\"flex items-center justify-center\">\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisible = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisible) {\n <ng-container\n *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let cellContent\">\n @if (cellContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { $implicit: cell.getContext() }\" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"(cell | zTableCellConfig: zConfig() : 'contentTooltip') || cellContent\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"></span>\n }\n </ng-container>\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n </tbody>\n </table>\n </ng-template>\n } @else {\n <!-- Normal Scroll Mode -->\n\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n class=\"z-table-drag-body\"\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-has-bottom-pinned]=\"table.getBottomRows().length > 0\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n <!-- Row Template -->\n <ng-template #rowTemplate let-row let-isGroupChild=\"isGroupChild\" let-groupDepth=\"groupDepth\">\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <tr\n z-table-row-hover\n z-table-draggable=\"row\"\n z-table-drop-target=\"row\"\n [animate.enter]=\"row.depth > 0 || isGroupChild ? 'z-row-enter' : ''\"\n [z-table-drag-table-id]=\"dragInstanceId\"\n [z-table-drop-table-id]=\"dragInstanceId\"\n [z-table-drag-item-id]=\"row.id\"\n [z-table-drop-item-id]=\"row.id\"\n [z-table-drag-disabled]=\"!isRowDragEnabled()\"\n [z-table-drop-disabled]=\"!isRowDragEnabled()\"\n (zTableDropped)=\"_handleDragDrop($event)\"\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [ngStyle]=\"row | zTableRow: table : 'pinningStyles' : pinnedRowHeights() : virtualRowHeight()\"\n [class.z-child-row]=\"row.depth > 0\"\n [class.z-group-child-row]=\"isGroupChild\"\n [style.--z-group-content-indent]=\"groupDepth > 0 ? 1.75 + (groupDepth - 1) * 0.75 + 'rem' : null\"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && row.id === firstTopPinnedRowId()\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"rowPinned === 'bottom' && row.id === lastBottomPinnedRowId()\"\n [class.z-pinned-bottom-first]=\"rowPinned === 'bottom' && row.id === firstBottomPinnedRowId()\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n row.id === lastTopPinnedRowId() &&\n !isStickyGroupHeaderEnabled()\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n row.id === firstBottomPinnedRowId()\n \"\n [attr.data-depth]=\"row.depth\"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @let cellRowPinned = cell.row.getIsPinned();\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : bodyRowSpanRows();\n @let shouldRenderColSpan = cell | zTableCellRender: visibleCells : zConfig().columns : 'body';\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (shouldRenderRowSpan && shouldRenderColSpan && isVirtualColumnVisible) {\n @let cellSelectionId = row.id + '::' + cell.column.id;\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n [class.z-sticky-left]=\"isColumnPinningActive && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActive && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"\n cell.column.id === 'actions' || cell.column.id === actionColumnInfo()?.columnId\n \"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [class.z-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"cell | zTableCellBottom: zConfig().columns : renderedBodyRows()\"\n [attr.rowspan]=\"cell | zTableSpan: zConfig().columns : 'cellRowSpan' : bodyRowSpanRows()\"\n [attr.colspan]=\"cell | zTableSpan: zConfig().columns : 'cellColSpan'\"\n [style.--z-cell-range-top]=\"(selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"(selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <button\n data-z-table-drag-handle\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground inline-flex size-7 items-center justify-center rounded-md transition-colors\"\n [class.cursor-grab]=\"isRowDragEnabled()\"\n [class.cursor-not-allowed]=\"!isRowDragEnabled()\"\n [class.opacity-40]=\"!isRowDragEnabled()\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === 'select') {\n <!-- Row Checkbox with Pin Button -->\n <div class=\"flex items-center justify-center gap-1\">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && cell.row.getIsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && cell.row.getIsSomeSelected() && !cell.row.getIsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection() || !cell.row.getCanSelect()\"\n (zChange)=\"canUseRowSelection() && cell.row.toggleSelected()\" />\n @if (zConfig().enableRowPinning && cell.row.depth === 0 && !hasBodyRowSpan()) {\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div\n zHoverGlide\n zHoverGlideSelector=\".z-column-menu-item\"\n class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded-sm p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n }\n </div>\n } @else if (cell.column.id === 'expand') {\n <!-- Expand Button with Row Pin Popover -->\n <div class=\"flex items-center justify-center gap-1\">\n @if (cell.row.getCanExpand()) {\n <button\n type=\"button\"\n (click)=\"cell.row.toggleExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"cell.row.getIsExpanded()\" />\n </button>\n }\n @if (\n zConfig().enableRowPinning &&\n cell.row.depth === 0 &&\n !(cell.row.subRows && cell.row.subRows.length > 0) &&\n !hasBodyRowSpan()\n ) {\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div\n zHoverGlide\n zHoverGlideSelector=\".z-column-menu-item\"\n class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded-sm p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n }\n </div>\n } @else if (\n (cell.column.id === 'actionRowPin' || cell.column.id === 'actions') &&\n cell.column.id !== actionColumnInfo()?.columnId\n ) {\n <!-- Actions Column - Row Pin Only (for parent rows) -->\n @if (cell.row.depth === 0 && !hasBodyRowSpan()) {\n <div class=\"flex items-center justify-center\">\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div\n zHoverGlide\n zHoverGlideSelector=\".z-column-menu-item\"\n class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded-sm p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n </div>\n }\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisibleNormal = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisibleNormal) {\n @let editInfo = cell.getContext() | zTableCellEdit: zConfig().columns;\n @if (editInfo.enabled) {\n <!-- Editable Cell -->\n <z-table-edit-cell\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n [zRowIndex]=\"cell.row.index\"\n [zColumnId]=\"cell.column.id\"\n [zValue]=\"cell.getValue()\"\n [zRowUpdate]=\"_rowUpdate()\"\n [zEditConfig]=\"$any(editInfo.config)\"\n (zChange)=\"onCellEdit($any($event))\" />\n } @else if (editInfo.contentEnabled) {\n @let contentConfig = editInfo.contentConfig!;\n @if (\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n ) {\n <z-table-content-editor\n [zValue]=\"cell.getValue()\"\n [zConfig]=\"contentConfig\"\n (zCommit)=\"onContentEditCommit($event, row, cell.column.id, cell.getValue())\"\n (zCancel)=\"onContentEditCancel()\" />\n } @else {\n <button\n type=\"button\"\n class=\"z-table-content-trigger\"\n [attr.data-z-table-edit-row]=\"row.id\"\n [attr.data-z-table-edit-column]=\"cell.column.id\"\n (keydown)=\"onContentEditKeydown($event, row.id, cell.column.id)\"\n (click)=\"onContentEditStart($event, row.id, cell.column.id)\">\n {{ contentConfig.displayValue }}\n </button>\n }\n } @else {\n <ng-container\n *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let cellContent\">\n @if (cellContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n @let isClickableTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickableTpl && onCellClick(row, cell.column.id, cell.getValue())\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { $implicit: cell.getContext() }\" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n @let isClickableIconTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickableIconTpl && onCellClick(row, cell.column.id, cell.getValue())\" />\n } @else {\n <!-- Default/innerHTML rendering -->\n @let isClickableDefaultTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n @let cellTooltipConfigTpl = cell | zTableCellConfig: zConfig() : 'contentTooltip';\n @let cellPopoverConfigTpl = cell | zTableCellConfig: zConfig() : 'contentPopover';\n @let cellPopoverContentTpl = cellPopoverConfigTpl | zTablePopoverConfig: 'content';\n <ng-template #cellPopoverTplNormal>\n @if (cellPopoverContentTpl | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(cellPopoverContentTpl)\" />\n }\n @if (!(cellPopoverContentTpl | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(cellPopoverContentTpl) | zSafeHtml\"></div>\n }\n </ng-template>\n @if (cellPopoverContentTpl) {\n <div\n class=\"z-table-cell-text\"\n z-popover\n z-tooltip\n [zTriggerElement]=\"cellOverlayContentTpl\"\n [zTriggerRef]=\"cellOverlayContentTpl\"\n [zContent]=\"\n (cellTooltipConfigTpl | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"cellPopoverTplNormal\"\n [zPosition]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"\n $any(cellPopoverConfigTpl | zTablePopoverConfig: 'outsideClickClose')\n \"\n [zScrollClose]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'keyboardSafe')\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellOverlayContentTpl\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n } @else {\n <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zTriggerElement]=\"cellTooltipContentTpl\"\n [zContent]=\"\n (cellTooltipConfigTpl | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'maxWidth')\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellTooltipContentTpl\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n }\n }\n </ng-container>\n }\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n\n <!-- Expanded Row Detail -->\n @if (row.getIsExpanded() && row.depth === 0 && !row.subRows?.length) {\n @let resolvedSubTableConfig = row | zTableSubTableConfig: zConfig();\n <tr class=\"z-expanded-row\" animate.enter=\"z-expanded-row-enter\">\n <td [attr.colspan]=\"renderedColumnCount()\" class=\"p-0\">\n <!-- Animate \u1EDF wrapper n\u00E0y b\u1EB1ng clip-path/translate/opacity \u2014 xem z-expanded-row-reveal. -->\n <div class=\"z-expanded-row-content\">\n @if (zConfig().expandedRowTemplate) {\n <ng-container\n *ngTemplateOutlet=\"zConfig().expandedRowTemplate!; context: { $implicit: row }\" />\n } @else if (resolvedSubTableConfig) {\n <div class=\"z-sub-table-container\">\n <z-table [zConfig]=\"$any(resolvedSubTableConfig)\" zVariant=\"borderless\" />\n </div>\n }\n </div>\n </td>\n </tr>\n }\n </ng-template>\n\n <!-- Render Top Pinned Rows (hidden when filtered data is empty) -->\n @if (!isEmpty()) {\n @for (row of table.getTopRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\n }\n }\n\n <!-- Render Center Rows -->\n @for (item of groupedCenterRowItems(); track item.type === 'group' ? item.id : item.row.id) {\n @if (item.type === 'group') {\n <tr\n #groupRow\n class=\"z-group-row\"\n [class.z-group-row-has-totals]=\"item.totals\"\n [class.z-group-row-expanded]=\"item.expanded\"\n [class.z-group-row-sticky]=\"isStickyGroupHeaderEnabled()\"\n [class.z-group-row-sticky-shadow]=\"shadowGroupRowId() === item.id\"\n [style.top.px]=\"stickyGroupTopByDepth()[item.depth]\"\n [attr.data-group-id]=\"item.id\"\n [attr.data-group-depth]=\"item.depth\">\n @if (item.totals) {\n @let totalColumnMap = groupTotalColumnMap();\n @for (column of orderedLeafColumns(); track column.id; let isFirstGroupCell = $first) {\n <td\n [class.z-group-row-label-cell]=\"isFirstGroupCell\"\n [class.z-group-row-total-cell]=\"!isFirstGroupCell && totalColumnMap[column.id]\"\n [attr.data-column-id]=\"column.id\">\n @if (isFirstGroupCell) {\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + item.depth * 0.75\"\n [attr.aria-expanded]=\"item.expanded\"\n (click)=\"toggleGroupRow(item.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"item.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"(item.columnLabel ? item.columnLabel + ': ' : '') + item.label\">\n @if (item.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ item.columnLabel }}:</span>\n }\n {{ item.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ item.count }}</span>\n }\n @if (item.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n zSizeIcon=\"14\"\n [zWave]=\"false\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(item.columnId)\"></button>\n }\n </div>\n }\n @if (!isFirstGroupCell && totalColumnMap[column.id]) {\n @let totalConfig = groupTotalConfigMap()[column.id];\n @let totalTooltip = totalConfig.tooltip;\n @let totalPopover = totalConfig.popover;\n @let totalPopoverContent = totalPopover | zTablePopoverConfig: 'content';\n <ng-template #groupTotalPopoverTpl>\n @if (totalPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(totalPopoverContent)\" />\n }\n @if (!(totalPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(totalPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n <span\n class=\"z-group-row-total\"\n z-tooltip\n z-popover\n [class]=\"totalConfig.class\"\n [zContent]=\"\n $any((totalTooltip | zTableTooltipConfig: 'content') || item.totals[column.id])\n \"\n [zTooltipPosition]=\"$any(totalTooltip | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(totalTooltip | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(totalTooltip | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(totalTooltip | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(totalTooltip | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'showDelay')\"\n [zTooltipHideDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'hideDelay')\"\n [zTooltipArrow]=\"$any(totalTooltip | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(totalTooltip | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(totalTooltip | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(totalTooltip | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(totalTooltip | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"totalPopoverContent ? groupTotalPopoverTpl : null\"\n [zPosition]=\"$any(totalPopover | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(totalPopover | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(totalPopover | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(totalPopover | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(totalPopover | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(totalPopover | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(totalPopover | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(totalPopover | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(totalPopover | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"$any(totalPopover | zTablePopoverConfig: 'outsideClickClose')\"\n [zScrollClose]=\"$any(totalPopover | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(totalPopover | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(totalPopover | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(totalPopover | zTablePopoverConfig: 'keyboardSafe')\">\n {{ item.totals[column.id] }}\n </span>\n }\n </td>\n }\n } @else {\n <td [attr.colspan]=\"renderedColumnCount()\">\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + item.depth * 0.75\"\n [attr.aria-expanded]=\"item.expanded\"\n (click)=\"toggleGroupRow(item.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"item.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"(item.columnLabel ? item.columnLabel + ': ' : '') + item.label\">\n @if (item.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ item.columnLabel }}:</span>\n }\n {{ item.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ item.count }}</span>\n }\n @if (item.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n zSizeIcon=\"14\"\n [zWave]=\"false\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(item.columnId)\"></button>\n }\n </div>\n </td>\n }\n </tr>\n }\n @if (item.type === 'row') {\n <ng-container\n *ngTemplateOutlet=\"\n rowTemplate;\n context: {\n $implicit: item.row,\n isGroupChild: item.isGroupChild,\n groupDepth: item.groupDepth,\n }\n \" />\n }\n }\n\n <!-- Render Bottom Pinned Rows (hidden when filtered data is empty) -->\n @if (!isEmpty()) {\n @for (row of bottomRowsReversed(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\n }\n }\n </tbody>\n </table>\n }\n </ng-scrollbar>\n }\n <!-- end @else -->\n </div>\n\n <!-- Footer table -->\n @if (hasFooter()) {\n <div\n class=\"z-tfoot-wrapper\"\n [class.z-shadow-footer]=\"shouldFooterShowShadow()\"\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\"\n #tfootWrapper>\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tfoot>\n @for (footerGroup of orderedFooterGroups(); track footerGroup.id; let footerRowIndex = $index) {\n @if (footerGroup | zTableFooterContent: zConfig().columns : footerRowIndex) {\n <tr>\n @for (footer of footerGroup.headers; track footer.id) {\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n footer.column.id === firstVirtualCenterColumnId()\n ) {\n <th\n class=\"z-virtual-column-spacer z-virtual-footer-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></th>\n }\n @let rowSpan = footer | zTableSpan: zConfig().columns : 'footerRowSpan' : footerRowIndex;\n @let shouldRender =\n footer\n | zTableCellRender\n : footerGroup.headers\n : zConfig().columns\n : 'footer'\n : footerRowIndex\n : orderedFooterGroups();\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n footer.column.getIsPinned() !== false ||\n virtualCenterColumnVisibilityMap()[footer.column.id];\n @if (rowSpan && shouldRender && isVirtualColumnVisible) {\n <th\n [attr.data-column-id]=\"footer.column.id\"\n [ngStyle]=\"\n footer.column\n | zTablePinningStyles\n : footer\n : 'footer'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerClass' : footerRowIndex) +\n ' ' +\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex)\n \"\n [style]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerStyle' : footerRowIndex\n \"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (footer | zTableCellPin: 'isLeftPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-at-left-edge]=\"footer | zTableCellOffset: orderedLeafColumns()\"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"footer | zTableSpan: zConfig().columns : 'footerColSpan' : footerRowIndex\">\n @let configFooterContent =\n footer.column.id | zTableFooterRender: zConfig().columns : footerRowIndex;\n @if (configFooterContent !== undefined && configFooterContent !== '') {\n <ng-container *flexRender=\"configFooterContent; props: footer.getContext(); let footerContent\">\n <div\n class=\"flex w-full items-center\"\n [class.justify-center]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex) ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex) ===\n 'text-right'\n \">\n @if (footerContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n <div\n class=\"z-template-content\"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \">\n <ng-container\n *ngTemplateOutlet=\"footerContent; context: { $implicit: footer.getContext() }\" />\n </div>\n } @else if (footerContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n <z-table-icon-text\n [zText]=\"footerContent\"\n [zTooltip]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerTooltip' : footerRowIndex\n \"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \" />\n } @else {\n <!-- Default/string rendering -->\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerTooltip' : footerRowIndex) ||\n footerContent\n \"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \">\n {{ footerContent | translate }}\n </span>\n }\n </div>\n </ng-container>\n }\n </th>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n footer.column.id === lastVirtualCenterColumnId()\n ) {\n <th\n class=\"z-virtual-column-spacer z-virtual-footer-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></th>\n }\n }\n </tr>\n }\n }\n </tfoot>\n </table>\n </div>\n }\n</div>\n\n<!-- Pagination -->\n@if (zConfig().pagination?.enabled !== false) {\n <div class=\"mt-4 flex items-center justify-between gap-4\">\n <div class=\"truncate text-sm text-gray-500\">\n {{ 'i18n_z_ui_table_total_rows' | translate: { total: (paginationTotal() | zFormatNum) } }}\n </div>\n <z-pagination\n [zTotal]=\"paginationTotal()\"\n [(zPageIndex)]=\"pagination().pageIndex\"\n [(zPageSize)]=\"pagination().pageSize\"\n [zPageSizeOptions]=\"zConfig().pagination?.pageSizeOptions ?? [10, 20, 50, 100]\"\n [zShowSizeChanger]=\"zConfig().pagination?.showSizeChanger ?? true\"\n [zShowQuickJumper]=\"zConfig().pagination?.showQuickJumper ?? false\"\n [zShowTotal]=\"false\"\n [zDisabled]=\"zConfig().pagination?.disabled || isLoading() || isProcessing()\"\n (zOnPageChange)=\"onPageChange($event)\" />\n </div>\n}\n\n<!-- Floating Bulk Action Bar -->\n<ng-template #bulkBarTemplate>\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 [zBodyClass]=\"'mx-0! px-0!'\"\n [zShadow]=\"true\"\n [zOkText]=\"null\"\n [zCancelText]=\"'i18n_z_ui_drawer_close' | translate\">\n <div class=\"z-table-settings-drawer\">\n <!-- Display Settings -->\n <div class=\"mx-4 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=\"mx-4 mb-4\">\n <h4 class=\"text-foreground mb-2 text-sm font-semibold\">{{ 'i18n_z_ui_table_column_settings' | translate }}</h4>\n <p class=\"text-muted-foreground mb-3 text-xs\">{{ 'i18n_z_ui_table_column_settings_desc' | translate }}</p>\n\n <!-- Unpinned Columns (Draggable) -->\n <div\n cdkDropList\n #columnDropList=\"cdkDropList\"\n [cdkDropListAutoScrollDisabled]=\"true\"\n (cdkDropListDropped)=\"onPendingColumnDrop($event)\"\n class=\"z-column-drop-list space-y-1.5\">\n @for (columnId of columnOrder(); track columnId; let i = $index) {\n @if (columnId !== 'expand' && columnId !== 'select' && columnId !== 'rowDrag') {\n @let column = table.getColumn(columnId);\n @let isPinned = column?.getIsPinned();\n @let isVisible = pendingVisibleColumns().includes(columnId);\n @let isVisibilityDisabled = pendingColumnVisibilityDisabledMap()[columnId];\n @let isGroupedColumn = groupingColumnMap()[columnId];\n @let columnEnablePinningConfig = columnId | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let canPin =\n (columnEnablePinningConfig ?? zConfig().enableColumnPinning ?? true) && column?.getCanPin() !== false;\n @if (!isPinned) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"isGroupedColumn\"\n [cdkDragData]=\"columnId\"\n cdkDragLockAxis=\"y\"\n cdkDragPreviewContainer=\"global\"\n cdkDragPreviewClass=\"z-drag-preview\"\n class=\"z-drag-item border-border bg-card hover:border-primary flex cursor-default items-center gap-2 rounded-sm border px-2 py-1.5 text-sm\"\n [class.opacity-60]=\"!isVisible\">\n <!-- Drag Handle -->\n <z-icon\n cdkDragHandle\n zType=\"lucideGripVertical\"\n zSize=\"14\"\n class=\"text-muted-foreground shrink-0\"\n [class.cursor-pointer]=\"!isGroupedColumn\"\n [class.cursor-default]=\"isGroupedColumn\"\n [class.opacity-40]=\"isGroupedColumn\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n [disabled]=\"isVisibilityDisabled\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n (mousedown)=\"$event.stopPropagation()\"\n class=\"border-input h-4 w-4 shrink-0 cursor-default rounded-sm disabled:opacity-50\" />\n\n <!-- Column Name -->\n <span class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\" [class.text-muted-foreground]=\"!isVisible\">\n {{ columnId | zTableColumnHeader: zConfig().columns | translate }}\n </span>\n @let parents = columnId | zTableColumnParents: zConfig().columns;\n @if (parents) {\n <span class=\"text-muted-foreground truncate text-[0.625rem]\">({{ parents | translate }})</span>\n }\n </span>\n\n <!-- Pin Buttons -->\n @if (canPin) {\n <div class=\"flex shrink-0 items-center gap-0.5\" (mousedown)=\"$event.stopPropagation()\">\n <button\n type=\"button\"\n [disabled]=\"!isVisible || isGroupedColumn || !pinAvailabilityMap()[columnId]?.left\"\n (click)=\"onToggleColumnPin(columnId, 'left')\"\n class=\"text-muted-foreground hover:bg-muted cursor-pointer rounded-sm p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Pin Left\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"12\" />\n </button>\n <button\n type=\"button\"\n [disabled]=\"!isVisible || isGroupedColumn || !pinAvailabilityMap()[columnId]?.right\"\n (click)=\"onToggleColumnPin(columnId, 'right')\"\n class=\"text-muted-foreground hover:bg-muted cursor-pointer rounded-sm p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Pin Right\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"12\" />\n </button>\n </div>\n }\n </div>\n }\n }\n }\n </div>\n\n <!-- Pinned Columns Section -->\n @if (zConfig().enableColumnPinning ?? true) {\n @if (pinnedColumnIds().length > 0) {\n <div class=\"border-border mt-4 border-t pt-4\">\n <h5 class=\"text-muted-foreground mb-2 text-xs font-medium\">\n {{ 'i18n_z_ui_table_pinned_columns' | translate }}\n </h5>\n <div class=\"space-y-1.5\">\n @for (columnId of pinnedColumnIds(); track columnId) {\n @let column = table.getColumn(columnId);\n @let isPinned = column?.getIsPinned();\n @let isVisible = pendingVisibleColumns().includes(columnId);\n @let isVisibilityDisabled = pendingColumnVisibilityDisabledMap()[columnId];\n @let isGroupedColumn = groupingColumnMap()[columnId];\n <div\n class=\"border-border bg-muted/30 flex items-center gap-2 rounded-sm border px-2 py-1.5 text-sm\"\n [class.opacity-60]=\"!isVisible\">\n <!-- Pin Icon -->\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"text-primary shrink-0\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n [disabled]=\"isVisibilityDisabled\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n class=\"border-input h-4 w-4 shrink-0 cursor-default rounded-sm disabled:opacity-50\" />\n\n <!-- Column Name -->\n <span class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\" [class.text-muted-foreground]=\"!isVisible\">\n {{ columnId | zTableColumnHeader: zConfig().columns | translate }}\n </span>\n @let pinnedParents = columnId | zTableColumnParents: zConfig().columns;\n @if (pinnedParents) {\n <span class=\"text-muted-foreground truncate text-[0.625rem]\">\n ({{ pinnedParents | translate }})\n </span>\n }\n </span>\n\n <!-- Position Badge -->\n <span\n class=\"bg-primary/10 text-primary shrink-0 rounded-sm px-1.5 py-0.5 text-[0.625rem] font-medium\">\n {{\n isPinned === 'start'\n ? ('i18n_z_ui_table_left' | translate)\n : ('i18n_z_ui_table_right' | translate)\n }}\n </span>\n\n <!-- Unpin Button -->\n <button\n type=\"button\"\n [disabled]=\"isGroupedColumn\"\n (click)=\"onToggleColumnPin(columnId, isPinned === 'start' ? 'left' : 'right')\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground cursor-pointer rounded-sm p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Unpin\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </div>\n }\n </div>\n </div>\n }\n }\n </div>\n </div>\n</z-drawer>\n", styles: [":host{display:flex;flex-direction:column;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;overflow-x:visible;--scrollbar-track-thickness: 7px;--scrollbar-track-color: transparent;--scrollbar-thumb-shape: 3px;--z-shadow-left-right: -1.875rem;--z-shadow-left-width: 1.875rem;--z-shadow-left-opacity: 0;--z-shadow-right-left: -1.875rem;--z-shadow-right-width: 1.875rem;--z-shadow-right-opacity: 0;--z-sticky-left-border-color: transparent;--z-sticky-right-border-color: var(--border);--z-cell-selection-background: color-mix(in srgb, var(--primary) 12%, transparent);--z-cell-selection-background-opaque: color-mix(in srgb, var(--primary) 12%, var(--card))}.z-table-container{display:flex;flex-direction:column;position:relative;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;overflow:hidden;border-radius:var(--radius-sm);border:thin solid var(--border);background-color:var(--card)}.z-table-container:focus{outline:none}.z-table-container.z-table-borderless{border:none;border-radius:0;box-shadow:none!important;background-color:transparent}.z-table-container.z-hide-horizontal-border th,.z-table-container.z-hide-horizontal-border td{border-bottom:none!important;border-top:none!important}.z-table-container.z-hide-vertical-border th,.z-table-container.z-hide-vertical-border td{border-left:none!important}.z-table-container.z-hide-pinned-top-border tbody tr.z-pinned-top.z-shadow-bottom>td{border-bottom-color:var(--border)!important}.z-table-container.z-hide-pinned-bottom-border tbody.z-has-bottom-pinned td.z-at-bottom{border-bottom-color:transparent}table{width:fit-content;min-width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed;font-size:.875rem}.z-table-container.z-column-resizing table,.z-table-toolbar{min-width:0}.z-table-toolbar .z-settings-btn{transition:all .15s ease}.z-table-toolbar .z-settings-btn:hover{border-color:var(--muted-foreground)}.z-table-filter-header{min-width:0}.z-table-filter-header button{flex:none}.z-table-filter-header-overflow-chip{animation:z-table-filter-chip-enter .16s ease}@media(prefers-reduced-motion:reduce){.z-table-filter-header-overflow-chip{animation:none}}@keyframes z-table-filter-chip-enter{0%{opacity:0;transform:translate(-.25rem)}to{opacity:1;transform:translate(0)}}::ng-deep .z-bulk-action-bar-overlay{position:fixed!important;top:auto;left:50%;bottom:0;transform:translate(-50%);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:var(--radius-md);background:color-mix(in srgb,var(--card) 96%,var(--background));color:var(--foreground);box-shadow:0 1rem 2.5rem color-mix(in srgb,var(--foreground) 20%,transparent),0 .25rem .75rem color-mix(in srgb,var(--foreground) 12%,transparent),0 0 0 1px color-mix(in srgb,var(--background) 65%,transparent) inset;display:flex;align-items:center;gap:.5rem;width:max-content;min-height:2.25rem;max-width:calc(100vw - 2rem);padding:.5rem;transform-origin:center bottom;animation:z-bulk-action-bar-enter .18s cubic-bezier(.16,1,.3,1);will-change:opacity,transform}.z-bulk-action-bar-inner.z-leaving{pointer-events:none;animation:z-bulk-action-bar-exit .14s ease-in forwards}.z-bulk-action-bar-count{padding:0 .25rem;white-space:nowrap;font-size:.8125rem;font-weight:500;color:var(--foreground)}.z-bulk-action-bar-divider{width:1px;height:1.5rem;flex:none;background:color-mix(in srgb,var(--border) 88%,transparent)}.z-bulk-action-bar-button{flex:none}@keyframes z-bulk-action-bar-enter{0%{opacity:0;transform:translateY(.875rem)}to{opacity:1;transform:translateY(0)}}@keyframes z-bulk-action-bar-exit{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(.875rem)}}@media(prefers-reduced-motion:reduce){.z-bulk-action-bar-inner{animation:none}}:host ::ng-deep .z-table-cell-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;min-width:0;-webkit-user-select:text;user-select:text}:host ::ng-deep .z-table-cell-text>*,:host ::ng-deep .z-table-cell-text *{display:inline-block;max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}:host ::ng-deep .z-table-cell-content-trigger{display:inline-block;max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}.z-template-content{display:block;width:100%;min-width:0;max-width:100%;overflow:hidden}.z-template-content>*{min-width:0;max-width:100%}.z-template-content>[class*=flex]{min-width:0;max-width:100%}.z-template-content>[class*=flex]>*{min-width:0;flex-shrink:1}.z-template-content>[class*=grid]{min-width:0;max-width:100%}.z-thead-wrapper{flex-shrink:0;background:var(--muted);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;position:relative;z-index:4}.z-thead-wrapper::-webkit-scrollbar{display:none}.z-thead-wrapper th{height:auto;padding:.5rem;text-align:left;vertical-align:middle;font-weight:500;color:var(--foreground);white-space:nowrap;overflow:hidden;background:var(--muted);border-left:thin solid var(--border);border-bottom:thin solid var(--border);-webkit-user-select:none;user-select:none}.z-thead-wrapper th.z-at-left-edge{border-left:none}.z-thead-wrapper th[colspan]{text-align:center;background:var(--muted);font-weight:500;color:var(--foreground)}.z-thead-wrapper.z-shadow-header{box-shadow:0 1px 3px #00000014;position:relative;z-index:15}.z-thead-wrapper.z-shadow-header:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}.z-tbody-wrapper{flex:1;width:100%;max-width:100%;min-width:0;min-height:6.25rem;display:flex;flex-direction:column;overflow:hidden}.z-tbody-scrollbar{flex:1;width:100%;max-width:100%;min-width:0;height:100%}.z-empty-state,.z-loading-state{flex:1 1 0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;min-height:6.25rem;height:100%;color:var(--muted-foreground);font-size:.875rem;animation:z-fade-in .2s ease-out}.z-tbody-scrollbar,.z-tbody-scrollbar table{animation:z-fade-in .2s ease-out}@keyframes z-fade-in{0%{opacity:0;transform:translateY(.25rem)}to{opacity:1;transform:translateY(0)}}.z-tbody-wrapper tr{transition:background-color .15s ease}.z-tbody-wrapper tr:hover,.z-tbody-wrapper tr:hover td[style*=sticky]{background-color:var(--muted)}.z-tbody-wrapper tr.z-pinned-top td.z-sticky-left,.z-tbody-wrapper tr.z-pinned-top td.z-sticky-right,.z-tbody-wrapper tr.z-pinned-bottom td.z-sticky-left,.z-tbody-wrapper tr.z-pinned-bottom td.z-sticky-right{z-index:3}.z-tbody-wrapper tr.z-shadow-bottom{box-shadow:0 1px 3px #00000014!important;position:relative;z-index:15}.z-tbody-wrapper tr.z-shadow-bottom:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d!important}.z-tbody-wrapper tr.z-shadow-top{box-shadow:0 -2px 4px #0000000d!important;position:relative;z-index:15}.z-tbody-wrapper tr.z-shadow-top:where(.dark,.dark *){box-shadow:0 -2px 4px #0003!important}.z-tbody-wrapper td{padding:.5rem 12px;height:var(--z-row-height, 2.375rem);vertical-align:middle;color:var(--foreground);white-space:nowrap;overflow:hidden;background:var(--card);border-left:thin solid var(--border);border-bottom:thin solid var(--border);box-sizing:border-box}.z-tbody-wrapper tbody.z-has-vertical-scroll td.z-at-bottom,.z-tbody-wrapper tbody.z-last-row-touches-bottom td.z-at-bottom{border-bottom-color:transparent}.z-tbody-wrapper tbody.z-has-bottom-pinned td.z-at-bottom{border-bottom-color:var(--border)}.z-tbody-wrapper td.z-at-left-edge{border-left:none}.z-tbody-wrapper td i{color:var(--muted-foreground);font-style:italic}.z-tbody-wrapper td[rowspan]{vertical-align:top;padding-top:.75rem}.z-tbody-wrapper td.z-row-hover{background-color:var(--muted)!important}.z-tbody-wrapper td.z-col-select,.z-tbody-wrapper td.z-col-expand,.z-tbody-wrapper td.z-col-actions{padding:.5rem 4px!important;text-align:center}.z-tbody-wrapper tr.z-child-row td.z-col-select:first-child,.z-tbody-wrapper tr.z-child-row td.z-col-expand:first-child,.z-tbody-wrapper tr.z-child-row td.z-col-actions:first-child{padding-left:0!important}.z-virtual-scroll-inner{position:relative;box-sizing:border-box;width:100%}.z-virtual-row,.z-virtual-flow{position:absolute;top:0;left:0;width:100%}.z-virtual-row-flow{position:relative}.z-virtual-row-fixed{overflow:hidden}.z-virtual-row-group-header{z-index:2}.z-virtual-row-sticky-group{position:sticky}.z-virtual-row-sticky-group-shadow{box-shadow:0 1px 3px #00000014}.z-virtual-row-sticky-group-shadow:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}tr.z-group-row-sticky{position:sticky;z-index:2}tr.z-group-row-sticky>td{background:var(--card)}tr.z-group-row-sticky-shadow{box-shadow:0 1px 3px #00000014}tr.z-group-row-sticky-shadow:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}tr.z-child-row td:first-child{border-left:.125rem solid var(--primary)!important;padding-left:.75rem!important}tbody tr.z-context-menu-active,tbody tr.z-context-menu-active td{background-color:var(--muted)!important}tbody tr.z-selected,tbody tr.z-selected td{background-color:color-mix(in srgb,var(--primary) 15%,var(--background))!important}tbody tr.z-selected:hover,tbody tr.z-selected:hover td{background-color:color-mix(in srgb,var(--primary) 20%,var(--background))!important}tbody tr.z-indeterminate-selected,tbody tr.z-indeterminate-selected td{background-color:color-mix(in srgb,var(--primary) 10%,var(--background))!important}tbody tr.z-indeterminate-selected:hover,tbody tr.z-indeterminate-selected:hover td{background-color:color-mix(in srgb,var(--primary) 15%,var(--background))!important}tbody tr.z-pinned-top td{background-color:var(--card)!important}tbody tr.z-pinned-top:hover{background-color:var(--muted)}tbody tr.z-pinned-top:hover td{background-color:var(--muted)!important}tbody tr.z-pinned-bottom td{background-color:var(--card)!important}tbody tr.z-pinned-bottom:hover{background-color:var(--muted)}tbody tr.z-pinned-bottom:hover td{background-color:var(--muted)!important}tbody tr.z-pinned-bottom-last>td{border-bottom-color:transparent!important}tbody tr.z-pinned-bottom-first>td{border-top:thin solid var(--border)}:host .z-tbody-wrapper tbody tr:not(.z-pinned-top):not(.z-pinned-bottom):has(+tr.z-pinned-bottom)>td{border-bottom-color:transparent}tr.z-expanded-row>td{border-left:.125rem solid var(--primary);background-color:var(--background)!important}.z-expanded-row-content{transform-origin:top center}@keyframes z-expanded-row-reveal{0%{clip-path:inset(0 0 100% 0);translate:0 -.375rem;opacity:0}to{clip-path:inset(0 0 0 0);translate:none;opacity:1}}@keyframes z-expanded-row-fade-in{0%{opacity:0}to{opacity:1}}tr.z-expanded-row-enter{animation:z-expanded-row-fade-in .18s ease-out}tr.z-expanded-row-enter .z-expanded-row-content{animation:z-expanded-row-reveal .18s ease-out}@keyframes z-child-row-slide-in{0%{translate:0 -.375rem;opacity:0}to{translate:none;opacity:1}}tr.z-child-row.z-row-enter,tr.z-group-child-row.z-row-enter{animation:z-child-row-slide-in .18s ease-out}@media(prefers-reduced-motion:reduce){tr.z-expanded-row-enter,tr.z-child-row.z-row-enter,tr.z-group-child-row.z-row-enter,tr.z-expanded-row-enter .z-expanded-row-content,tr.z-child-row.z-row-enter .z-expanded-row-content,tr.z-group-child-row.z-row-enter .z-expanded-row-content{animation-duration:1ms}}.z-sub-table-container{padding:.75rem 1rem .75rem 3rem;background-color:var(--background)}.z-table-content-trigger{display:block;width:100%;min-width:0;min-height:1.5rem;padding:0;border:0;border-radius:0;background:transparent;color:inherit;font:inherit;line-height:1.5rem;text-align:inherit;outline:0;cursor:text}.z-table-content-trigger:hover{color:var(--primary)}.z-content-edit-active{position:relative;z-index:2}td:has(>.z-table-content-trigger:focus-visible){position:relative;z-index:2}td:has(>.z-table-content-trigger:focus-visible):after{position:absolute;z-index:3;inset:0;border:1px solid var(--primary);content:\"\";pointer-events:none}td.z-cell-selectable{-webkit-user-select:none;user-select:none}td.z-cell-range-selected{position:relative;isolation:isolate}td.z-cell-range-selected:before{position:absolute;z-index:0;box-sizing:border-box;top:var(--z-cell-range-top, 0);right:var(--z-cell-range-right, 0);bottom:var(--z-cell-range-bottom, 0);left:var(--z-cell-range-left, 0);background-color:var(--z-cell-selection-background);content:\"\";pointer-events:none}td.z-cell-range-selected>*{position:relative;z-index:1}td.z-cell-range-top:before{border-top:1px solid var(--primary)}td.z-cell-range-right:before{border-right:1px solid var(--primary)}td.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}td.z-cell-range-left:before{border-left:1px solid var(--primary)}td.z-cell-active{position:relative;z-index:3;background-color:var(--z-cell-selection-background)!important}td.z-cell-active:after{position:absolute;z-index:4;inset:0;border:1px solid var(--primary);content:\"\";pointer-events:none}td.z-content-edit-active{-webkit-user-select:text;user-select:text}td.z-cell-active.z-row-hover,td.z-content-edit-active.z-row-hover{background-color:var(--card)!important}thead th{position:relative}thead th .z-resizer{position:absolute;right:0;top:0;height:100%;width:.5rem;background:transparent;cursor:col-resize;-webkit-user-select:none;user-select:none;touch-action:none;z-index:5}thead th .z-resizer:after{content:\"\";position:absolute;right:0;top:0;height:100%;width:.1875rem;background:#0000001a;opacity:0;transition:opacity .2s ease}thead th .z-resizer:after:where(.dark,.dark *){background:#ffffff1a}thead th .z-resizer:hover:after{opacity:1;background:var(--primary);width:.1875rem}thead th .z-resizer.z-is-resizing:after{opacity:1;background:var(--primary);width:.1875rem}thead th .z-resizer.z-resizer-left{right:auto;left:0}thead th .z-resizer.z-resizer-left:after{right:auto;left:0}.z-thead-wrapper th.z-sticky-left,.z-thead-wrapper th.z-sticky-right,.z-tbody-wrapper th.z-sticky-left,.z-tbody-wrapper th.z-sticky-right,.z-tfoot-wrapper th.z-sticky-left,.z-tfoot-wrapper th.z-sticky-right{background-color:var(--muted);z-index:1;transform:translateZ(0);backface-visibility:hidden}.z-thead-wrapper td.z-sticky-left,.z-thead-wrapper td.z-sticky-right,.z-tbody-wrapper td.z-sticky-left,.z-tbody-wrapper td.z-sticky-right,.z-tfoot-wrapper td.z-sticky-left,.z-tfoot-wrapper td.z-sticky-right{background-color:var(--card);z-index:1;transform:translateZ(0);backface-visibility:hidden}.z-thead-wrapper th.z-sticky-left-last,.z-thead-wrapper td.z-sticky-left-last,.z-tbody-wrapper th.z-sticky-left-last,.z-tbody-wrapper td.z-sticky-left-last,.z-tfoot-wrapper th.z-sticky-left-last,.z-tfoot-wrapper td.z-sticky-left-last{position:relative;overflow:visible;border-right:thin solid var(--z-sticky-left-border-color)}.z-thead-wrapper th.z-sticky-left-last:after,.z-thead-wrapper td.z-sticky-left-last:after,.z-tbody-wrapper th.z-sticky-left-last:after,.z-tbody-wrapper td.z-sticky-left-last:after,.z-tfoot-wrapper th.z-sticky-left-last:after,.z-tfoot-wrapper td.z-sticky-left-last:after{content:\"\";position:absolute;top:0;bottom:0;right:var(--z-shadow-left-right);width:var(--z-shadow-left-width);pointer-events:none;box-shadow:inset 10px 0 8px -8px #0000001a;z-index:10;opacity:var(--z-shadow-left-opacity)}:host-context(.dark) .z-thead-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-thead-wrapper td.z-sticky-left-last:after,:host-context(.dark) .z-tbody-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-tbody-wrapper td.z-sticky-left-last:after,:host-context(.dark) .z-tfoot-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-tfoot-wrapper td.z-sticky-left-last:after{box-shadow:inset 10px 0 10px -8px #0000004d}.z-thead-wrapper.z-scroll-left,.z-tbody-wrapper.z-scroll-left,.z-tfoot-wrapper.z-scroll-left{--z-shadow-left-opacity: 1}.z-thead-wrapper.z-scroll-left:where(.dark,.dark *),.z-tbody-wrapper.z-scroll-left:where(.dark,.dark *),.z-tfoot-wrapper.z-scroll-left:where(.dark,.dark *){--z-sticky-left-border-color: var(--border)}.z-thead-wrapper th.z-sticky-right-first,.z-thead-wrapper td.z-sticky-right-first,.z-tbody-wrapper th.z-sticky-right-first,.z-tbody-wrapper td.z-sticky-right-first,.z-tfoot-wrapper th.z-sticky-right-first,.z-tfoot-wrapper td.z-sticky-right-first{position:relative;overflow:visible;border-left:thin solid var(--z-sticky-right-border-color)}.z-thead-wrapper th.z-sticky-right-first:before,.z-thead-wrapper td.z-sticky-right-first:before,.z-tbody-wrapper th.z-sticky-right-first:before,.z-tbody-wrapper td.z-sticky-right-first:before,.z-tfoot-wrapper th.z-sticky-right-first:before,.z-tfoot-wrapper td.z-sticky-right-first:before{content:\"\";position:absolute;top:0;bottom:0;left:var(--z-shadow-right-left);width:var(--z-shadow-right-width);pointer-events:none;box-shadow:inset -10px 0 8px -8px #0000001a;z-index:10;opacity:var(--z-shadow-right-opacity)}:host-context(.dark) .z-thead-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-thead-wrapper td.z-sticky-right-first:before,:host-context(.dark) .z-tbody-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-tbody-wrapper td.z-sticky-right-first:before,:host-context(.dark) .z-tfoot-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-tfoot-wrapper td.z-sticky-right-first:before{box-shadow:inset -10px 0 10px -8px #0000004d}.z-thead-wrapper.z-scroll-right,.z-tbody-wrapper.z-scroll-right,.z-tfoot-wrapper.z-scroll-right{--z-shadow-right-opacity: 1}.z-thead-wrapper.z-scroll-right:not(:where(.dark,.dark *)),.z-tbody-wrapper.z-scroll-right:not(:where(.dark,.dark *)),.z-tfoot-wrapper.z-scroll-right:not(:where(.dark,.dark *)){--z-sticky-right-border-color: transparent}.z-pinning-overflow{--z-shadow-left-opacity: 0 !important;--z-shadow-right-opacity: 0 !important;--z-sticky-left-border-color: transparent !important;--z-sticky-right-border-color: transparent !important}.z-pinning-overflow .z-sticky-left,.z-pinning-overflow .z-sticky-right{position:relative!important;right:auto!important;left:auto!important}.z-pinning-overflow .z-sticky-left-last:after,.z-pinning-overflow .z-sticky-right-first:before,.z-pinning-overflow .z-sticky-right-last:after{display:none!important}.z-thead-wrapper th.z-sticky-right-last,.z-tfoot-wrapper th.z-sticky-right-last{position:relative}.z-thead-wrapper th.z-sticky-right-last:after,.z-tfoot-wrapper th.z-sticky-right-last:after{content:\"\";position:absolute;top:0;bottom:0;right:-1.875rem;width:1.875rem;background:var(--muted);pointer-events:none}.z-tfoot-wrapper{flex-shrink:0;width:100%;max-width:100%;min-width:0;background:var(--muted);overflow-x:hidden;overflow-y:hidden;touch-action:pan-y pinch-zoom}.z-tfoot-wrapper th{height:auto;padding:.5rem 12px;text-align:left;vertical-align:middle;font-weight:500;font-size:.75rem;color:var(--muted-foreground);text-transform:uppercase;letter-spacing:.5px;background:var(--muted);border-left:thin solid var(--border);border-top:thin solid var(--border)}.z-tfoot-wrapper th.z-at-left-edge{border-left:none}.z-tfoot-wrapper.z-shadow-footer{box-shadow:0 -2px 4px #0000000d;position:relative;z-index:15}.z-tfoot-wrapper.z-shadow-footer:where(.dark,.dark *){box-shadow:0 -2px 4px #0003}.z-pin-btn{padding:.125rem 4px;border-radius:var(--radius-xs);color:var(--muted-foreground);transition:all .15s ease}.z-pin-btn:hover{background-color:var(--muted);color:var(--foreground)}.z-pin-btn.z-pin-btn-active{color:var(--primary);background-color:var(--primary)}.z-pin-btn.z-pin-btn-active:hover{background-color:var(--primary);opacity:.8}.z-row-pin-trigger{opacity:1}.z-row-pin-trigger:focus-visible,.z-row-pin-trigger.z-popover-open{background-color:color-mix(in srgb,var(--foreground) 8%,transparent);color:var(--foreground)}.z-row-pin-trigger:active{background-color:color-mix(in srgb,var(--foreground) 12%,transparent)}.z-row-pin-trigger.text-primary{color:var(--primary)}.z-row-pin-unpin-trigger{color:var(--muted-foreground);outline:none}.z-row-pin-unpin-trigger:hover{color:var(--destructive);background-color:color-mix(in srgb,var(--destructive) 10%,transparent)}.z-row-pin-unpin-trigger:focus,.z-row-pin-unpin-trigger:focus-visible{color:var(--muted-foreground);background-color:transparent;outline:none;box-shadow:none}.z-row-pin-unpin-trigger:active{color:var(--destructive);background-color:color-mix(in srgb,var(--destructive) 14%,transparent)}.z-header-pin-trigger{opacity:1}.z-header-pin-trigger.text-primary{color:var(--primary)}th{overflow:hidden}th .z-header-content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}th .z-header-text-wrapper{transition:background-color .15s ease;border-radius:var(--radius-xs);min-width:0;overflow:hidden;flex-shrink:1}th .z-header-text-wrapper.z-has-options:hover,th .z-header-text-wrapper.z-has-options:focus-visible,th .z-header-text-wrapper.z-has-options.z-popover-open{background-color:color-mix(in srgb,var(--foreground) 8%,transparent);outline:none}th .z-header-text-wrapper.z-has-options:active{background-color:color-mix(in srgb,var(--foreground) 12%,transparent)}.z-column-menu-item{position:relative;z-index:1;line-height:1.25rem;transition:background-color .15s ease,color .15s ease}.z-column-menu-item:focus-visible,.z-column-menu-item.z-popover-open{background-color:var(--muted);outline:none}.z-table-drag-preview{box-sizing:border-box;border-radius:var(--radius-md);background-color:var(--card);border:1px solid var(--primary);box-shadow:0 10px 24px #00000029;overflow:hidden;z-index:10000!important;pointer-events:none}.z-table-drag-preview:where(.dark,.dark *){box-shadow:0 5px 20px #00000080}.z-table-drag-preview-row{border:0;border-radius:var(--radius-xs);background-color:var(--background);box-shadow:0 8px 20px #0000001f,inset 0 0 0 1px color-mix(in srgb,var(--primary) 45%,var(--border))}.z-table-drag-preview-row table,.z-table-drag-preview-row tbody,.z-table-drag-preview-row tr{height:100%}.z-table-drag-preview-row td{vertical-align:middle!important;background-color:var(--background)}.z-table-drag-preview-virtual{border:0;border-radius:0;box-shadow:0 8px 20px #0000001f,inset 0 0 0 1px color-mix(in srgb,var(--primary) 45%,var(--border))}.z-table-drag-source{display:none!important}.z-virtual-row.z-table-drag-source{display:block!important;pointer-events:none;outline:1px solid var(--border);outline-offset:-1px}.z-virtual-row.z-table-drag-source td{color:color-mix(in srgb,var(--foreground) 45%,transparent);border-color:var(--border)!important;background-color:var(--card)!important}.z-virtual-row.z-table-drag-source td>*{opacity:.45}[data-z-table-drag-handle]{touch-action:none;-webkit-user-select:none;user-select:none}.z-column-drop-list{min-height:3.125rem;overscroll-behavior:contain}.cdk-drag-preview.z-drag-preview,.cdk-drag-placeholder.z-drag-item{border-radius:var(--radius-sm)}.z-table-drag-placeholder{width:100%;min-height:2.625rem;box-sizing:border-box;border:2px dashed var(--primary);border-radius:0;background-color:color-mix(in srgb,var(--primary) 10%,var(--background));pointer-events:none}.z-table-drag-placeholder-row>td{padding:0!important;border:0!important;background:transparent!important}.z-table-drag-placeholder-row .z-table-drag-placeholder{border-radius:0;background-color:color-mix(in srgb,var(--primary) 10%,transparent)}.z-table-drag-placeholder-virtual{position:absolute;top:0;left:0;z-index:20;border-radius:0}.z-tbody-wrapper tr.z-group-row td{background:var(--card);border-top:none;border-bottom:1px solid var(--border)}.z-virtual-row:not(.z-virtual-row-flow) tr.z-group-row td{background:var(--card);border-top:none;border-bottom:none}.z-group-row-sticky-wrapper{display:inline-flex;align-items:center;translate:var(--z-scroll-x, 0px) 0}.z-table-container:not(.z-hide-horizontal-border) .z-virtual-row:not(.z-virtual-row-flow):after,.z-table-container:not(.z-hide-horizontal-border) .z-virtual-row-flow.z-virtual-row-group-header:after{content:\"\";position:absolute;right:0;bottom:0;left:0;z-index:3;height:1px;background:var(--border);pointer-events:none}.z-tbody-wrapper tr.z-group-child-row td.z-at-left-edge,.z-virtual-row tr.z-group-child-row td.z-at-left-edge{border-left:2px solid var(--primary)!important;padding-left:var(--z-group-content-indent, .75rem)}.z-group-row-trigger{display:inline-flex;min-height:2rem;max-width:100%;align-items:center;gap:.5rem;padding:.25rem .5rem .25rem .75rem;color:var(--primary);font-size:.8125rem;font-weight:600;vertical-align:middle;cursor:pointer}.z-group-row-remove{margin-left:.125rem;color:var(--muted-foreground);vertical-align:middle}.z-group-row-remove:hover,.z-group-row-remove:focus-visible{color:var(--destructive);background:color-mix(in srgb,var(--destructive) 10%,transparent);outline:none}.z-group-row-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-column-label{color:color-mix(in srgb,var(--primary) 65%,var(--foreground));font-weight:500;margin-right:.25rem}.z-group-row-count{display:inline-flex;min-width:1.25rem;height:1.25rem;align-items:center;justify-content:center;padding:0 .375rem;border-radius:var(--radius-pill);background:var(--primary);color:var(--primary-foreground);font-size:.6875rem;font-weight:600}.z-group-row-loading{display:inline-flex;align-items:center;margin-left:.25rem}.z-group-row-has-totals td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-has-totals .z-group-row-label-cell{position:sticky;left:0;z-index:2;background:var(--card)}.z-group-row-has-totals .z-group-row-label-cell .z-group-row-sticky-wrapper{max-width:100%;translate:none}.z-group-row-total{display:inline-block;max-width:100%;color:var(--foreground);font-size:.8125rem;font-weight:600;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-total-cell{text-align:right}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-selected:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:before{position:absolute!important;z-index:0!important;box-sizing:border-box!important;top:var(--z-cell-range-top, 0)!important;right:var(--z-cell-range-right, 0)!important;bottom:var(--z-cell-range-bottom, 0)!important;left:var(--z-cell-range-left, 0)!important;width:auto!important;background-color:var(--z-cell-selection-background-opaque)!important;box-shadow:none!important;content:\"\"!important;pointer-events:none!important;opacity:1!important}:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:after{display:none!important}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-top:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-top:before{border-top:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-right:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-right:before{border-right:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-bottom:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-left:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-left:before{border-left:1px solid var(--primary)}:host-context(.z-table-pointer-dragging) .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-selected:before,:host-context(.z-table-pointer-dragging) .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:before{background-color:transparent!important}:host td.z-cell-range-selected:before{position:absolute;z-index:0;box-sizing:border-box;top:var(--z-cell-range-top, 0);right:var(--z-cell-range-right, 0);bottom:var(--z-cell-range-bottom, 0);left:var(--z-cell-range-left, 0);background-color:var(--z-cell-selection-background);box-shadow:none;content:\"\";pointer-events:none;opacity:1}:host td.z-cell-range-top:before{border-top:1px solid var(--primary)}:host td.z-cell-range-right:before{border-right:1px solid var(--primary)}:host td.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}:host td.z-cell-range-left:before{border-left:1px solid var(--primary)}:host-context(.z-table-pointer-dragging) td.z-row-hover{background-color:var(--background)!important}:host td.z-cell-active,:host td.z-cell-active.z-row-hover{background-color:var(--z-cell-selection-background)!important}:host td.z-content-edit-active.z-row-hover{background-color:var(--card)!important}:host tr.z-pinned-top td.z-cell-active,:host tr.z-pinned-top td.z-cell-active.z-row-hover,:host tr.z-pinned-bottom td.z-cell-active,:host tr.z-pinned-bottom td.z-cell-active.z-row-hover,:host td.z-cell-active.z-sticky-left,:host td.z-cell-active.z-sticky-left.z-row-hover,:host td.z-cell-active.z-sticky-right,:host td.z-cell-active.z-sticky-right.z-row-hover{background-color:var(--z-cell-selection-background-opaque)!important}:host tr.z-pinned-top td.z-cell-range-selected,:host tr.z-pinned-bottom td.z-cell-range-selected,:host td.z-cell-range-selected.z-sticky-left,:host td.z-cell-range-selected.z-sticky-right{background-color:var(--card)}:host tr.z-pinned-top td.z-cell-range-selected:before,:host tr.z-pinned-bottom td.z-cell-range-selected:before,:host td.z-cell-range-selected.z-sticky-left:before,:host td.z-cell-range-selected.z-sticky-right:before{background-color:var(--z-cell-selection-background-opaque)}:host-context(.z-table-pointer-dragging) td.z-cell-range-selected,:host-context(.z-table-pointer-dragging) td.z-cell-range-selected.z-row-hover,:host-context(.z-table-pointer-dragging) td.z-cell-active,:host-context(.z-table-pointer-dragging) td.z-cell-active.z-row-hover{background-color:var(--card)!important}:host-context(.z-table-pointer-dragging) td.z-cell-range-selected:before{background-color:transparent}:host .z-tbody-wrapper tbody tr.z-group-child-row:has(+tr.z-group-row)>td.z-at-bottom{border-bottom-color:var(--border)}:host .z-virtual-row:has(tr.z-group-child-row):has(+.z-virtual-row tr.z-group-row) tr.z-group-child-row>td.z-at-bottom{border-bottom-color:var(--border)}.z-thead-wrapper th.z-virtual-column-spacer,.z-tfoot-wrapper th.z-virtual-column-spacer{box-sizing:border-box;padding:0!important;background:var(--muted);border-left:thin solid var(--border)}.z-thead-wrapper th.z-virtual-header-spacer{border-bottom:thin solid var(--border)}.z-tfoot-wrapper th.z-virtual-footer-spacer{border-top:thin solid var(--border)}.z-tbody-wrapper td.z-virtual-column-spacer{box-sizing:border-box;height:auto;padding:0!important;background:var(--card);border-left:thin solid var(--border);border-bottom:thin solid var(--border)}.z-tbody-wrapper tr:hover td.z-virtual-column-spacer{background-color:var(--muted)}.z-table-settings-drawer input[type=checkbox]{appearance:none;-webkit-appearance:none;-moz-appearance:none;width:1rem;height:1rem;border:thin solid var(--input);border-radius:var(--radius-sm);background-color:var(--background);cursor:pointer;position:relative;transition:all .2s ease}.z-table-settings-drawer input[type=checkbox]:hover{border-color:var(--primary)}.z-table-settings-drawer input[type=checkbox]:checked{background-color:var(--primary);border-color:var(--primary)}.z-table-settings-drawer input[type=checkbox]:checked:after{content:\"\";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:.375rem;height:.625rem;border:solid var(--primary-foreground);border-width:0 .125rem .125rem 0;transform:translate(-50%,-60%) rotate(45deg)}.z-table-settings-drawer input[type=checkbox]:disabled{opacity:.5;cursor:not-allowed}.z-virtual-pinned-top{position:sticky;top:0;left:0;z-index:3;width:100%}.z-virtual-pinned-bottom{position:sticky;bottom:0;left:0;z-index:3;width:100%}\n"] }]
11321
+ }, exportAs: 'zTable', template: "<!-- Toolbar: Search & Settings -->\n@if (isSearchEnabled() || zConfig().enableSettings) {\n <div class=\"z-table-toolbar mb-2 flex items-center justify-between gap-4\">\n <!-- Search -->\n @if (isSearchEnabled()) {\n @let config = searchConfig();\n <z-input\n [class]=\"config?.width ?? 'w-64'\"\n [zSize]=\"config?.size ?? 'sm'\"\n [zPlaceholder]=\"config?.placeholder ?? 'i18n_z_ui_table_search' | translate\"\n [zSearch]=\"true\"\n [zDebounce]=\"config?.debounceTime ?? 300\"\n (zOnSearch)=\"onSearchChange($event)\" />\n } @else {\n <div></div>\n }\n\n <!-- Settings Button -->\n @if (zConfig().enableSettings) {\n <z-button zType=\"outline\" zSize=\"sm\" zTypeIcon=\"lucideSettings\" (click)=\"openSettingsDrawer()\">\n {{ 'i18n_z_ui_table_settings' | translate }}\n </z-button>\n }\n </div>\n}\n\n@if (zConfig().enableFilterHeader && appliedFilterChips().length > 0) {\n <div class=\"z-table-filter-header mb-2 flex min-w-0 items-center gap-2\">\n <div class=\"flex min-w-0 flex-1 flex-wrap items-center gap-1.5\">\n @for (chip of visibleAppliedFilterChips(); track chip.id) {\n <span\n class=\"border-border bg-muted/60 text-foreground inline-flex max-w-80 min-w-0 shrink-0 items-center gap-1 rounded-sm border px-2 py-1 text-[0.8125rem] shadow-xs\">\n <span class=\"font-medium whitespace-nowrap\">{{ chip.label }}</span>\n <span class=\"text-muted-foreground\">:</span>\n <span class=\"truncate\" z-tooltip [zContent]=\"chip.value\" zTooltipTrigger=\"hover\" zTooltipPosition=\"top\">\n {{ chip.value }}\n </span>\n <button\n type=\"button\"\n class=\"hover:bg-destructive/10 hover:text-destructive focus-visible:ring-ring -mr-1 inline-flex size-5 cursor-pointer items-center justify-center rounded-sm outline-none focus-visible:ring-2\"\n [attr.aria-label]=\"'i18n_z_ui_table_filter_remove' | translate\"\n (click)=\"clearAppliedFilterChip(chip)\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </span>\n }\n @if (hiddenAppliedFilterChipCount() > 0 && isFilterHeaderExpanded()) {\n @for (chip of overflowAppliedFilterChips(); track chip.id) {\n <span\n class=\"z-table-filter-header-overflow-chip border-border bg-muted/60 text-foreground inline-flex max-w-80 min-w-0 shrink-0 items-center gap-1 rounded-sm border px-2 py-1 text-[0.8125rem] shadow-xs\"\n [attr.aria-hidden]=\"!isFilterHeaderExpanded()\">\n <span class=\"font-medium whitespace-nowrap\">{{ chip.label }}</span>\n <span class=\"text-muted-foreground\">:</span>\n <span class=\"truncate\" z-tooltip [zContent]=\"chip.value\" zTooltipTrigger=\"hover\" zTooltipPosition=\"top\">\n {{ chip.value }}\n </span>\n <button\n type=\"button\"\n class=\"hover:bg-destructive/10 hover:text-destructive focus-visible:ring-ring -mr-1 inline-flex size-5 cursor-pointer items-center justify-center rounded-sm outline-none focus-visible:ring-2\"\n [attr.aria-label]=\"'i18n_z_ui_table_filter_remove' | translate\"\n (click)=\"clearAppliedFilterChip(chip)\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </span>\n }\n }\n @if (hiddenAppliedFilterChipCount() > 0) {\n <button\n type=\"button\"\n class=\"text-primary hover:bg-primary/10 focus-visible:ring-ring inline-flex h-7 cursor-pointer items-center rounded-sm px-2 text-xs font-medium outline-none focus-visible:ring-2\"\n (click)=\"toggleFilterHeaderExpanded()\">\n {{\n isFilterHeaderExpanded()\n ? ('i18n_z_ui_table_show_less' | translate)\n : ('i18n_z_ui_table_show_more' | translate: { count: hiddenAppliedFilterChipCount() })\n }}\n </button>\n }\n <button\n type=\"button\"\n class=\"bg-destructive/10 text-destructive hover:bg-destructive/20 dark:bg-destructive/15 dark:text-destructive-foreground dark:hover:bg-destructive/25 focus-visible:ring-destructive inline-flex h-7 cursor-pointer items-center gap-1 rounded-sm px-2 text-xs font-medium shadow-xs outline-none focus-visible:ring-2\"\n (click)=\"clearAppliedFilters()\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_clear_filter' | translate }}</span>\n </button>\n </div>\n </div>\n}\n\n<div\n #tableContainer\n [class]=\"classTable()\"\n [ngStyle]=\"columnSizeVars()\"\n [class.z-pinning-overflow]=\"!isPinnedLayoutWithinContainer()\"\n [class.z-hide-horizontal-border]=\"!showHorizontalBorder()\"\n [class.z-hide-vertical-border]=\"!showVerticalBorder()\"\n [class.z-hide-pinned-top-border]=\"hasScrollTop()\"\n [class.z-hide-pinned-bottom-border]=\"hasScrollBottom()\"\n [style.width]=\"zConfig().width\"\n [style.height]=\"zConfig().height\"\n [style.max-height]=\"zConfig().maxHeight\"\n [style.min-height]=\"zConfig().minHeight\"\n [attr.tabindex]=\"canUseContentRowInsert() || canUseCellSelection() ? 0 : null\"\n (keydown)=\"onContentTableKeydown($event)\">\n @let isColumnPinningActive = isPinnedLayoutWithinContainer();\n <ng-template #contentRowMenuContent>\n <div class=\"flex min-w-36 flex-col gap-0.5 p-1\">\n @if (contentRowMenu()?.columnId) {\n <button\n type=\"button\"\n class=\"text-foreground hover:bg-muted focus:bg-muted flex min-h-6 cursor-pointer items-center gap-1.5 rounded-sm 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-sm 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-sm 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-sm 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-sm 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-sm 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-sm 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-sm 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-sm 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-sm px-1.5 py-0.5 text-[0.6875rem] outline-none disabled:pointer-events-none disabled:opacity-40\"\n [disabled]=\"!canCopyCellMenuSelection()\"\n (click)=\"copySelectedCells(true)\">\n <z-icon zType=\"lucideCopy\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_copy_cell_with_headers' | translate }}</span>\n </button>\n }\n </div>\n </ng-template>\n\n <div\n class=\"pointer-events-none fixed size-px opacity-0\"\n z-popover\n [zPopoverContent]=\"contentRowMenuContent\"\n zTrigger=\"manual\"\n zPosition=\"bottom-left\"\n zClass=\"z-table-content-row-menu\"\n [zOffset]=\"0\"\n [zManualClose]=\"true\"\n [zScrollClose]=\"true\"\n [style.left.px]=\"contentRowMenu()?.left ?? -9999\"\n [style.top.px]=\"contentRowMenu()?.top ?? -9999\"\n (zControl)=\"setContentRowMenuControl($event)\"\n (zHide)=\"clearContentRowMenu()\"></div>\n\n <div\n class=\"pointer-events-none fixed size-px opacity-0\"\n z-popover\n [zPopoverContent]=\"cellMenuContent\"\n zTrigger=\"manual\"\n zPosition=\"bottom-left\"\n zClass=\"z-table-cell-menu\"\n [zOffset]=\"0\"\n [zManualClose]=\"true\"\n [zScrollClose]=\"true\"\n [style.left.px]=\"cellMenu()?.left ?? -9999\"\n [style.top.px]=\"cellMenu()?.top ?? -9999\"\n (zControl)=\"setCellMenuControl($event)\"\n (zHide)=\"clearCellMenu()\"></div>\n\n <!-- Shared colgroup template -->\n <ng-template #colGroupTpl>\n <colgroup>\n @if (canUseVirtualColumns()) {\n @for (column of leftLeafColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <col [style.width.px]=\"virtualRenderedLeftSpacerWidth()\" />\n }\n @for (column of virtualCenterColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n @if (virtualRightSpacerWidth() > 0) {\n <col [style.width.px]=\"virtualRenderedRightSpacerWidth()\" />\n }\n @for (column of rightLeafColumns(); track column.id) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n } @else {\n @for (column of orderedLeafColumns(); track column.id) {\n @if (column.getIsVisible()) {\n @let customWidth = column.id | zTableColumnConfig: zConfig().columns : 'width';\n <col [style.width]=\"customWidth || 'calc(var(--col-' + column.id + '-size) * 1px)'\" />\n }\n }\n }\n </colgroup>\n </ng-template>\n\n <!-- Header table -->\n <div\n class=\"z-thead-wrapper shadow-card\"\n [class.z-shadow-header]=\"shouldHeaderShowShadow()\"\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\"\n (wheel)=\"onTheadWheel($event)\"\n #theadWrapper>\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <thead>\n @if (canUseVirtualColumns()) {\n <tr>\n @for (header of leftHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: leftHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div zHoverGlide zHoverGlideSelector=\".z-column-menu-item\" 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-sm 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-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm 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-sm 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-sm 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-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded-sm 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 zClass=\"rounded-(--radius-sm) overflow-hidden\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualLeftSpacerWidth() > 0) {\n <th\n class=\"z-virtual-column-spacer z-virtual-header-spacer z-virtual-left-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></th>\n }\n @for (header of virtualCenterHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: virtualCenterHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div zHoverGlide zHoverGlideSelector=\".z-column-menu-item\" 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-sm 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-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm 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-sm 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-sm 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-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded-sm 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 zClass=\"rounded-(--radius-sm) overflow-hidden\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n @if (virtualRightSpacerWidth() > 0) {\n <th\n class=\"z-virtual-column-spacer z-virtual-header-spacer z-virtual-right-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></th>\n }\n @for (header of rightHeaderRow(); track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: rightHeaderRow() : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <!-- Header Checkbox -->\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <!-- Expand All Button -->\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <!-- Header Content with Sort and Pin -->\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') === 'text-right'\n \">\n <!-- Column Options Popover Template -->\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div zHoverGlide zHoverGlideSelector=\".z-column-menu-item\" 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-sm 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-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"14\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm 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-sm 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-sm 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-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded-sm 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 zClass=\"rounded-(--radius-sm) overflow-hidden\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n <!-- Dropdown indicator when has options (between text and sort icon) -->\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n <!-- Sort Icon (outside wrapper, no hover background) -->\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n <!-- Column Resizer -->\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n </tr>\n } @else {\n @for (headerGroup of orderedHeaderGroups(); track headerGroup.id) {\n <tr>\n @for (header of headerGroup.headers; track header.id) {\n @let rowSpan = header | zTableSpan: zConfig().columns : 'headerRowSpan';\n @let shouldRender = header | zTableCellRender: headerGroup.headers : zConfig().columns : 'header';\n @if (rowSpan && shouldRender) {\n <th\n [attr.id]=\"header.column.id\"\n [ngStyle]=\"\n header.column\n | zTablePinningStyles\n : header\n : 'header'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerClass') +\n ' ' +\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass')\n \"\n [style]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerStyle'\"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastLeftPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isFirstRightPinned' : zConfig().columns)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive && (header | zTableCellPin: 'isLastRightPinned' : zConfig().columns)\n \"\n [class.z-at-left-edge]=\"header | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"header.column.id === 'rowDrag'\"\n [class.z-col-select]=\"header.column.id === 'select'\"\n [class.z-col-expand]=\"header.column.id === 'expand'\"\n [class.z-col-actions]=\"\n header.column.id === 'actions' || header.column.id === actionColumnInfo()?.columnId\n \"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"header | zTableSpan: zConfig().columns : 'headerColSpan'\">\n @if (header.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" class=\"text-muted-foreground opacity-70\" />\n </div>\n } @else if (header.column.id === 'select') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && table.getIsAllRowsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && table.toggleAllRowsSelected()\" />\n </div>\n } @else if (header.column.id === 'expand') {\n <div\n class=\"flex items-center\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n <button\n type=\"button\"\n (click)=\"table.toggleAllRowsExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"table.getIsSomeRowsExpanded()\" />\n </button>\n </div>\n } @else {\n <div\n class=\"flex w-full items-center gap-1\"\n [class.justify-center]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerAlignClass') ===\n 'text-right'\n \">\n @let columnEnableOrdering =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableOrdering';\n @let columnEnablePinning =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let effectiveEnableOrdering = columnEnableOrdering || zConfig().enableColumnOrdering;\n @let effectiveEnablePinning = columnEnablePinning ?? zConfig().enableColumnPinning ?? true;\n <ng-template #colOptionsPopoverContent>\n <div zHoverGlide zHoverGlideSelector=\".z-column-menu-item\" 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-sm 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-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_move_right' | translate }}</span>\n </button>\n }\n @if (effectiveEnableOrdering && header.column.getCanPin() && effectiveEnablePinning) {\n <div class=\"border-border my-0.5 border-t\"></div>\n }\n @if (header.column.getCanPin() && effectiveEnablePinning) {\n @if (header.column.getIsPinned() !== 'start') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.left\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, 'left'); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"15\" class=\"rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_left' | translate }}</span>\n </button>\n }\n @if (header.column.getIsPinned() !== 'end') {\n <button\n type=\"button\"\n [disabled]=\"!pinAvailabilityMap()[header.column.id]?.right\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"\n handleColumnPin(header.column.id, 'right'); colOptionsPopover.hideImmediate()\n \"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none disabled:pointer-events-none disabled:opacity-40\">\n <z-icon zType=\"lucidePin\" zSize=\"15\" class=\"-rotate-90\" />\n <span>{{ 'i18n_z_ui_table_pin_right' | translate }}</span>\n </button>\n }\n @if (\n header.column.getIsPinned() &&\n header.column.id !== 'expand' &&\n header.column.id !== actionColumnInfo()?.columnId\n ) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"handleColumnPin(header.column.id, false); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n }\n @if (groupingHeaderMenuMap()[header.id]) {\n @let isActiveGroupingColumn = groupingColumnMap()[header.column.id];\n <div class=\"border-border my-0.5 border-t\"></div>\n @if (!isActiveGroupingColumn) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"groupByColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideRows3\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n <span>{{ 'i18n_z_ui_table_group_by_column' | translate }}</span>\n </button>\n }\n @let groupMenuStateBoundary = isActiveGroupingColumn;\n @if (groupMenuStateBoundary) {\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"removeGroupingColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideUngroup\" zSize=\"15\" />\n <span>{{ 'i18n_z_ui_table_clear_grouping' | translate }}</span>\n </button>\n }\n }\n <div class=\"border-border my-0.5 border-t\"></div>\n <button\n type=\"button\"\n (mouseenter)=\"hideActiveColumnVisibilityPopover()\"\n (click)=\"autosizeColumn(header.column.id); colOptionsPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm 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-sm 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-sm 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-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideColumns3\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">\n {{ 'i18n_z_ui_table_choose_columns' | translate }}\n </span>\n </button>\n }\n </div>\n </ng-template>\n\n @let columnEnableHeaderMenu =\n header.column.id | zTableColumnConfig: zConfig().columns : 'enableHeaderMenu';\n @let hasColumnOptions =\n header.column.id !== 'actionRowPin' &&\n columnEnableHeaderMenu !== false &&\n (groupingHeaderMenuMap()[header.id] ||\n (header.column.getCanPin() && effectiveEnablePinning) ||\n effectiveEnableOrdering ||\n hideableColumns().length > 0);\n <div\n class=\"z-header-text-wrapper inline-flex max-w-full items-center gap-1 rounded-sm 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 zClass=\"rounded-(--radius-sm) overflow-hidden\"\n [zOffset]=\"5\"\n (zOutsideClick)=\"hideColumnPopoversOnOutsideClick(colOptionsPopover)\"\n (mousedown)=\"$event.preventDefault()\"\n [attr.tabindex]=\"hasColumnOptions ? 0 : null\"\n [attr.role]=\"hasColumnOptions ? 'button' : null\"\n [attr.aria-haspopup]=\"hasColumnOptions ? 'menu' : null\">\n <ng-container\n *flexRender=\"header.column.columnDef.header; props: header.getContext(); let headerContent\">\n @if (headerContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \">\n <ng-container\n *ngTemplateOutlet=\"headerContent; context: { $implicit: header.getContext() }\" />\n </div>\n } @else if (headerContent | zTableHasIcon) {\n <z-table-icon-text\n class=\"min-w-0 truncate\"\n [zText]=\"headerContent\"\n [zTooltip]=\"header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip'\"\n [zTriggerElement]=\"headerTextWrapper\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (header.column.id | zTableColumnConfig: zConfig().columns : 'headerTooltip') ||\n headerContent\n \"\n [zTriggerElement]=\"headerTextWrapper\"\n [innerHTML]=\"headerContent | translate | zSafeHtml\"\n [class]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentClass'\n \"\n [ngStyle]=\"\n header.column.id | zTableColumnConfig: zConfig().columns : 'headerContentStyle'\n \"></span>\n }\n </ng-container>\n @if (hasColumnOptions) {\n <z-icon zType=\"lucideChevronDown\" zSize=\"15\" class=\"text-muted-foreground shrink-0\" />\n }\n </div>\n @if ((header.column.getCanSort() && !hasBodyRowSpan()) || header.column.getCanFilter()) {\n <z-table-filter\n [zColumn]=\"$any(header.column)\"\n [zTable]=\"$any(table)\"\n [zResetVersion]=\"filterResetVersion()\"\n [zSortingState]=\"sorting()\"\n [zEnableMultiSort]=\"zConfig().enableMultiSort ?? true\" />\n }\n </div>\n }\n @if (header.column.getCanResize() && zConfig().enableColumnResizing !== false) {\n <div\n class=\"z-resizer\"\n [class.z-is-resizing]=\"header.column.getIsResizing()\"\n [class.z-resizer-left]=\"\n header.column.getIsPinned() === 'end' || header.column.getIsLastColumn()\n \"\n (dblclick)=\"header.column.resetSize()\"\n [zTableResize]=\"header\"></div>\n }\n </th>\n }\n }\n </tr>\n }\n }\n </thead>\n </table>\n </div>\n\n <!-- Body table -->\n <div\n class=\"z-tbody-wrapper relative\"\n #tbodyContainer\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\">\n @if (isLoading() || isProcessing()) {\n <!-- Loading State -->\n @if (zConfig().useSkeleton) {\n <!-- Skeleton Loading -->\n <div class=\"animate-in fade-in flex h-full flex-col duration-200\">\n @for (i of skeletonRows(); track $index; let last = $last) {\n <div\n class=\"border-border box-border flex flex-1 flex-col items-start justify-center gap-1.5 px-2\"\n [class.border-b]=\"!last\">\n <z-skeleton zType=\"bar\" zWidth=\"100%\" zHeight=\"22px\" />\n <z-skeleton zType=\"bar\" zWidth=\"50%\" zHeight=\"14px\" />\n </div>\n }\n </div>\n } @else {\n <!-- Spinner Loading -->\n <div class=\"z-loading-state\">\n <z-loading [zLoading]=\"true\" zSize=\"lg\" [zText]=\"'i18n_z_ui_table_loading' | translate\" />\n </div>\n }\n } @else if (isEmpty()) {\n <div class=\"z-empty-state\">\n @if (isNoSearchResults()) {\n <z-empty zIcon=\"lucideSearchX\" zSize=\"sm\" [zMessage]=\"'i18n_z_ui_table_no_results' | translate\" />\n } @else {\n <z-empty zIcon=\"lucidePackageOpen\" zSize=\"sm\" [zMessage]=\"'i18n_z_ui_table_no_data' | translate\" />\n }\n </div>\n } @else {\n <ng-scrollbar class=\"z-tbody-scrollbar\" #tbodyWrapper (scroll)=\"onTbodyScroll($event)\">\n @if (isVirtual()) {\n <!-- Virtual Scroll Mode -->\n\n <div\n class=\"z-virtual-scroll-inner\"\n [style.height.px]=\"virtualizer.getTotalSize()\"\n [style.min-width.px]=\"table.getTotalSize()\">\n <!-- Pinned rows v\u00E0 center rows d\u00F9ng chung m\u1ED9t virtual canvas. -->\n @if (virtualPinnedTopRows().length > 0) {\n <div class=\"z-virtual-pinned-top\" [style.min-width.px]=\"table.getTotalSize()\">\n @for (row of virtualPinnedTopRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"virtualPinnedRowTpl; context: { $implicit: row }\" />\n }\n </div>\n }\n\n @if (usesFlowVirtualRows()) {\n <div\n class=\"z-virtual-flow\"\n [style.transform]=\"'translate3d(0,' + virtualFlowOffset() + 'px,0)'\"\n [style.min-width.px]=\"table.getTotalSize()\">\n <ng-container *ngTemplateOutlet=\"virtualRowsTpl\" />\n </div>\n } @else {\n <ng-container *ngTemplateOutlet=\"virtualRowsTpl\" />\n }\n\n <ng-template #virtualRowsTpl>\n @for (virtualItem of virtualizer.getVirtualItems(); track virtualItem.index) {\n @let groupRows = dynamicGroupRows()[virtualItem.index] || [];\n @let virtualFlatItem = virtualGroupedFlatItems()[virtualItem.index];\n @let stickyGroupState = stickyGroupHeaderState();\n @let stickyGroupTop = stickyGroupState.tops[virtualItem.index];\n @let isStickyGroupHeader = stickyGroupTop !== undefined;\n <div\n #virtualRow\n class=\"z-virtual-row\"\n [class.z-virtual-row-flow]=\"usesFlowVirtualRows()\"\n [class.z-virtual-row-fixed]=\"!effectiveDynamicRowSizing()\"\n [class.z-virtual-row-group-header]=\"virtualFlatItem?.type === 'group-header'\"\n [class.z-virtual-row-sticky-group]=\"isStickyGroupHeader\"\n [class.z-virtual-row-sticky-group-shadow]=\"stickyGroupState.shadowIndex === virtualItem.index\"\n [style.top.px]=\"stickyGroupTop\"\n z-table-draggable=\"row\"\n z-table-drop-target=\"row\"\n [z-table-drag-table-id]=\"dragInstanceId\"\n [z-table-drop-table-id]=\"dragInstanceId\"\n [z-table-drag-item-id]=\"groupRows.length > 0 ? groupRows[0].id : ''\"\n [z-table-drop-item-id]=\"groupRows.length > 0 ? groupRows[0].id : ''\"\n [z-table-drag-disabled]=\"!isVirtualRowDragEnabled() || groupRows.length !== 1\"\n [z-table-drop-disabled]=\"!isVirtualRowDragEnabled() || groupRows.length !== 1\"\n (zTableDropped)=\"_handleDragDrop($event)\"\n [attr.data-index]=\"virtualItem.index\"\n [style.height.px]=\"\n effectiveDynamicRowSizing()\n ? null\n : (dynamicGroupHeights()[virtualItem.index] ?? groupSize() * virtualRowHeight())\n \"\n [style.transform]=\"\n usesFlowVirtualRows() || isStickyGroupHeader ? null : 'translate3d(0,' + virtualItem.start + 'px,0)'\n \">\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-has-bottom-pinned]=\"table.getBottomRows().length > 0\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n @let groupHeaderItem = _getVirtualGroupHeader(virtualFlatItem);\n @if (groupHeaderItem) {\n <tr\n class=\"z-group-row\"\n [class.z-group-row-has-totals]=\"groupHeaderItem.totals\"\n [class.z-group-row-expanded]=\"groupHeaderItem.expanded\"\n [attr.data-group-id]=\"groupHeaderItem.id\"\n [attr.data-group-depth]=\"groupHeaderItem.depth\">\n @if (groupHeaderItem.totals) {\n @let totalColumnMap = groupTotalColumnMap();\n @for (column of orderedLeafColumns(); track column.id; let isFirstGroupCell = $first) {\n <td\n [class.z-group-row-label-cell]=\"isFirstGroupCell\"\n [class.z-group-row-total-cell]=\"!isFirstGroupCell && totalColumnMap[column.id]\"\n [attr.data-column-id]=\"column.id\">\n @if (isFirstGroupCell) {\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + groupHeaderItem.depth * 0.75\"\n [attr.aria-expanded]=\"groupHeaderItem.expanded\"\n (click)=\"toggleGroupRow(groupHeaderItem.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"groupHeaderItem.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"\n (groupHeaderItem.columnLabel ? groupHeaderItem.columnLabel + ': ' : '') +\n groupHeaderItem.label\n \">\n @if (groupHeaderItem.columnLabel) {\n <span class=\"z-group-row-column-label\">\n {{ groupHeaderItem.columnLabel }}:\n </span>\n }\n {{ groupHeaderItem.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ groupHeaderItem.count }}</span>\n }\n @if (groupHeaderItem.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n [zWave]=\"false\"\n z-tooltip\n zSizeIcon=\"14\"\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(groupHeaderItem.columnId)\"></button>\n }\n </div>\n }\n @if (!isFirstGroupCell && totalColumnMap[column.id]) {\n @let totalConfig = groupTotalConfigMap()[column.id];\n @let totalTooltip = totalConfig.tooltip;\n @let totalPopover = totalConfig.popover;\n @let totalPopoverContent = totalPopover | zTablePopoverConfig: 'content';\n <ng-template #groupTotalPopoverTpl>\n @if (totalPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(totalPopoverContent)\" />\n }\n @if (!(totalPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(totalPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n <span\n class=\"z-group-row-total\"\n z-tooltip\n z-popover\n [class]=\"totalConfig.class\"\n [zContent]=\"\n $any(\n (totalTooltip | zTableTooltipConfig: 'content') ||\n groupHeaderItem.totals[column.id]\n )\n \"\n [zTooltipPosition]=\"$any(totalTooltip | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(totalTooltip | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(totalTooltip | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(totalTooltip | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(totalTooltip | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'showDelay')\"\n [zTooltipHideDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'hideDelay')\"\n [zTooltipArrow]=\"$any(totalTooltip | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(totalTooltip | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(totalTooltip | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(totalTooltip | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(totalTooltip | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"totalPopoverContent ? groupTotalPopoverTpl : null\"\n [zPosition]=\"$any(totalPopover | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(totalPopover | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(totalPopover | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(totalPopover | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(totalPopover | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(totalPopover | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(totalPopover | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(totalPopover | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(totalPopover | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"$any(totalPopover | zTablePopoverConfig: 'outsideClickClose')\"\n [zScrollClose]=\"$any(totalPopover | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(totalPopover | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(totalPopover | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(totalPopover | zTablePopoverConfig: 'keyboardSafe')\">\n {{ groupHeaderItem.totals[column.id] }}\n </span>\n }\n </td>\n }\n } @else {\n <td [attr.colspan]=\"renderedColumnCount()\">\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + groupHeaderItem.depth * 0.75\"\n [attr.aria-expanded]=\"groupHeaderItem.expanded\"\n (click)=\"toggleGroupRow(groupHeaderItem.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"groupHeaderItem.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"\n (groupHeaderItem.columnLabel ? groupHeaderItem.columnLabel + ': ' : '') +\n groupHeaderItem.label\n \">\n @if (groupHeaderItem.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ groupHeaderItem.columnLabel }}:</span>\n }\n {{ groupHeaderItem.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ groupHeaderItem.count }}</span>\n }\n @if (groupHeaderItem.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n [zWave]=\"false\"\n z-tooltip\n zSizeIcon=\"14\"\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(groupHeaderItem.columnId)\"></button>\n }\n </div>\n </td>\n }\n </tr>\n }\n @for (row of groupRows; track row.id) {\n @let virtualGroupDepth = _getVirtualGroupDepth(virtualFlatItem);\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <tr\n z-table-row-hover\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"effectiveDynamicRowSizing() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"effectiveDynamicRowSizing() ? virtualRowHeight() : null\"\n [style.--z-row-height]=\"effectiveDynamicRowSizing() ? 'auto' : virtualRowHeight() + 'px'\"\n [class.z-child-row]=\"row.depth > 0\"\n [class.z-group-child-row]=\"_isVirtualGroupChild(virtualFlatItem)\"\n [style.--z-group-content-indent]=\"\n virtualGroupDepth > 0 ? 1.75 + (virtualGroupDepth - 1) * 0.75 + 'rem' : null\n \"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && row.id === firstTopPinnedRowId()\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"rowPinned === 'bottom' && row.id === lastBottomPinnedRowId()\"\n [class.z-pinned-bottom-first]=\"rowPinned === 'bottom' && row.id === firstBottomPinnedRowId()\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n row.id === lastTopPinnedRowId() &&\n !isStickyGroupHeaderEnabled()\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n row.id === firstBottomPinnedRowId()\n \"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : bodyRowSpanRows();\n @let shouldRenderColSpan =\n cell | zTableCellRender: visibleCells : zConfig().columns : 'body';\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (shouldRenderRowSpan && shouldRenderColSpan && isVirtualColumnVisible) {\n @let cellSelectionId = row.id + '::' + cell.column.id;\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"isColumnPinningActive && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActive && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell\n | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell\n | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"cell.column.id === actionColumnInfo()?.columnId\"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [class.z-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"cell | zTableCellBottom: zConfig().columns : renderedBodyRows()\"\n [attr.rowspan]=\"\n cell | zTableSpan: zConfig().columns : 'cellRowSpan' : bodyRowSpanRows()\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() &&\n cell.row.getIsSomeSelected() &&\n !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-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"cell.row.getIsExpanded()\" />\n </button>\n }\n </div>\n } @else if (\n (cell.column.id === 'actionRowPin' || cell.column.id === 'actions') &&\n cell.column.id !== actionColumnInfo()?.columnId\n ) {\n @if (cell.row.depth === 0 && !hasBodyRowSpan()) {\n <div class=\"flex items-center justify-center\">\n <ng-template #rowPinPopoverContent>\n <div\n zHoverGlide\n zHoverGlideSelector=\".z-column-menu-item\"\n class=\"flex flex-col gap-1 py-1\">\n @if (cell.row.getIsPinned() !== 'top') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n }\n @if (cell.row.getIsPinned() !== 'bottom') {\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n }\n @if (cell.row.getIsPinned()) {\n <button\n type=\"button\"\n (click)=\"cell.row.pin(false); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-destructive hover:bg-destructive/10 focus:bg-destructive/10 mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_unpin' | translate }}</span>\n </button>\n }\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded-sm p-1 outline-none\"\n [class.text-primary]=\"cell.row.getIsPinned()\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n </div>\n }\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisible = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisible) {\n @let editInfoVirtual = cell.getContext() | zTableCellEdit: zConfig().columns;\n @if (editInfoVirtual.enabled) {\n <!-- Editable Cell (Virtual) -->\n <z-table-edit-cell\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n [zRowIndex]=\"cell.row.index\"\n [zColumnId]=\"cell.column.id\"\n [zValue]=\"cell.getValue()\"\n [zRowUpdate]=\"_rowUpdate()\"\n [zEditConfig]=\"$any(editInfoVirtual.config)\"\n (zChange)=\"onCellEdit($any($event))\" />\n } @else if (editInfoVirtual.contentEnabled) {\n @let contentConfigVirtual = editInfoVirtual.contentConfig!;\n @if (\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n ) {\n <z-table-content-editor\n [zValue]=\"cell.getValue()\"\n [zConfig]=\"contentConfigVirtual\"\n (zCommit)=\"onContentEditCommit($event, row, cell.column.id, cell.getValue())\"\n (zCancel)=\"onContentEditCancel()\" />\n } @else {\n <button\n type=\"button\"\n class=\"z-table-content-trigger\"\n [attr.data-z-table-edit-row]=\"row.id\"\n [attr.data-z-table-edit-column]=\"cell.column.id\"\n (keydown)=\"onContentEditKeydown($event, row.id, cell.column.id)\"\n (click)=\"onContentEditStart($event, row.id, cell.column.id)\">\n {{ contentConfigVirtual.displayValue }}\n </button>\n }\n } @else {\n <ng-container\n *flexRender=\"\n cell.column.columnDef.cell;\n props: cell.getContext();\n let cellContent\n \">\n @if (cellContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n @let isClickable = cell.column.id | zTableCellClickable: zConfig().columns;\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickable && onCellClick(row, cell.column.id, cell.getValue())\">\n <ng-container\n *ngTemplateOutlet=\"\n cellContent;\n context: { $implicit: cell.getContext() }\n \" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n @let isClickableIcon =\n cell.column.id | zTableCellClickable: zConfig().columns;\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"\n isClickableIcon && onCellClick(row, cell.column.id, cell.getValue())\n \" />\n } @else {\n <!-- Default/innerHTML rendering -->\n @let isClickableDefault =\n cell.column.id | zTableCellClickable: zConfig().columns;\n @let cellTooltipConfig =\n cell | zTableCellConfig: zConfig() : 'contentTooltip';\n @let cellPopoverConfig =\n cell | zTableCellConfig: zConfig() : 'contentPopover';\n @let cellPopoverContent = cellPopoverConfig | zTablePopoverConfig: 'content';\n <ng-template #cellPopoverTpl>\n @if (cellPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(cellPopoverContent)\" />\n }\n @if (!(cellPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(cellPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n @if (cellPopoverContent) {\n <div\n class=\"z-table-cell-text\"\n z-popover\n z-tooltip\n [zTriggerElement]=\"cellOverlayContent\"\n [zTriggerRef]=\"cellOverlayContent\"\n [zContent]=\"\n (cellTooltipConfig | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'position')\n \"\n [zTooltipTrigger]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'trigger')\n \"\n [zTooltipType]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'autoDetect')\n \"\n [zAlwaysShow]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'alwaysShow')\n \"\n [zMaxWidth]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"cellPopoverTpl\"\n [zPosition]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'trigger')\n \"\n [zClass]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'manualClose')\n \"\n [zOutsideClickClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'outsideClickClose')\n \"\n [zScrollClose]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'scrollClose')\n \"\n [zSticky]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(cellPopoverConfig | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"\n $any(cellPopoverConfig | zTablePopoverConfig: 'keyboardSafe')\n \"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellOverlayContent\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n } @else {\n <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zTriggerElement]=\"cellTooltipContent\"\n [zContent]=\"\n (cellTooltipConfig | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'position')\n \"\n [zTooltipTrigger]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'trigger')\n \"\n [zTooltipType]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'autoDetect')\n \"\n [zAlwaysShow]=\"\n $any(cellTooltipConfig | zTableTooltipConfig: 'alwaysShow')\n \"\n [zMaxWidth]=\"$any(cellTooltipConfig | zTableTooltipConfig: 'maxWidth')\"\n (click)=\"\n isClickableDefault && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellTooltipContent\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n }\n }\n </ng-container>\n }\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </ng-template>\n </div>\n\n <!--\n Bottom pinned rows: sibling AFTER the virtual canvas (not absolute like the\n center rows). The virtualizer reserves their height inside getTotalSize() via\n `paddingEnd`, leaving an empty band at the canvas bottom. `margin-top: -bottomHeight`\n pulls this real flow element back over that band, and `position: sticky; bottom: 0`\n floats it to the viewport bottom while scrolling.\n -->\n @if (virtualPinnedBottomRows().length > 0) {\n <div\n class=\"z-virtual-pinned-bottom\"\n [style.min-width.px]=\"table.getTotalSize()\"\n [style.margin-top.px]=\"-virtualPinnedBottomHeight()\">\n @for (row of virtualPinnedBottomRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"virtualPinnedRowTpl; context: { $implicit: row }\" />\n }\n </div>\n }\n\n <!-- Template for rendering pinned rows in virtual scroll mode -->\n <ng-template #virtualPinnedRowTpl let-row>\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody [class.z-has-vertical-scroll]=\"hasVerticalScroll()\">\n <tr\n z-table-row-hover\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [style.height.px]=\"effectiveDynamicRowSizing() ? null : virtualRowHeight()\"\n [style.min-height.px]=\"effectiveDynamicRowSizing() ? virtualRowHeight() : null\"\n [style.--z-row-height]=\"effectiveDynamicRowSizing() ? 'auto' : virtualRowHeight() + 'px'\"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && row.id === firstTopPinnedRowId()\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"rowPinned === 'bottom' && row.id === lastBottomPinnedRowId()\"\n [class.z-pinned-bottom-first]=\"rowPinned === 'bottom' && row.id === firstBottomPinnedRowId()\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n row.id === lastTopPinnedRowId() &&\n !isStickyGroupHeaderEnabled()\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n row.id === firstBottomPinnedRowId()\n \"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @let isColumnPinningActivePinned = isPinnedLayoutWithinContainer();\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @let cellSelectionId = row.id + '::' + cell.column.id;\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (isVirtualColumnVisible) {\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActivePinned\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [class.z-sticky-left]=\"isColumnPinningActivePinned && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActivePinned && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActivePinned &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"cell.column.id === actionColumnInfo()?.columnId\"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [style.--z-cell-range-top]=\"(selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"(selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'select') {\n <z-checkbox\n [zChecked]=\"rowSelected\"\n [zIndeterminate]=\"rowSomeSelected && !rowSelected\"\n [zDisabled]=\"!canUseRowSelection()\"\n (zChange)=\"canUseRowSelection() && row.toggleSelected()\" />\n } @else if (cell.column.id === 'expand') {\n <button\n type=\"button\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"row.toggleExpanded()\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"row.getIsExpanded()\" />\n </button>\n } @else if (cell.column.id === 'actionRowPin') {\n <div class=\"flex items-center justify-center\">\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisible = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisible) {\n <ng-container\n *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let cellContent\">\n @if (cellContent | zTableIsTemplateRef) {\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { $implicit: cell.getContext() }\" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\" />\n } @else {\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"(cell | zTableCellConfig: zConfig() : 'contentTooltip') || cellContent\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"></span>\n }\n </ng-container>\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n </tbody>\n </table>\n </ng-template>\n } @else {\n <!-- Normal Scroll Mode -->\n\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tbody\n class=\"z-table-drag-body\"\n [class.z-has-vertical-scroll]=\"hasVerticalScroll()\"\n [class.z-has-bottom-pinned]=\"table.getBottomRows().length > 0\"\n [class.z-last-row-touches-bottom]=\"lastRowTouchesBottom()\">\n <!-- Row Template -->\n <ng-template #rowTemplate let-row let-isGroupChild=\"isGroupChild\" let-groupDepth=\"groupDepth\">\n @let visibleCells = row.getVisibleCells();\n @let rowSelected = canUseRowSelection() && row.getIsSelected();\n @let rowSomeSelected = canUseRowSelection() && row.getIsSomeSelected();\n @let rowPinned = row.getIsPinned();\n <tr\n z-table-row-hover\n z-table-draggable=\"row\"\n z-table-drop-target=\"row\"\n [animate.enter]=\"row.depth > 0 || isGroupChild ? 'z-row-enter' : ''\"\n [z-table-drag-table-id]=\"dragInstanceId\"\n [z-table-drop-table-id]=\"dragInstanceId\"\n [z-table-drag-item-id]=\"row.id\"\n [z-table-drop-item-id]=\"row.id\"\n [z-table-drag-disabled]=\"!isRowDragEnabled()\"\n [z-table-drop-disabled]=\"!isRowDragEnabled()\"\n (zTableDropped)=\"_handleDragDrop($event)\"\n [attr.data-row-id]=\"row.id\"\n [class]=\"row | zTableRowConfig: zConfig() : 'rowClass'\"\n [style]=\"row | zTableRowConfig: zConfig() : 'rowStyle'\"\n [ngStyle]=\"row | zTableRow: table : 'pinningStyles' : pinnedRowHeights() : virtualRowHeight()\"\n [class.z-child-row]=\"row.depth > 0\"\n [class.z-group-child-row]=\"isGroupChild\"\n [style.--z-group-content-indent]=\"groupDepth > 0 ? 1.75 + (groupDepth - 1) * 0.75 + 'rem' : null\"\n [class.z-selected]=\"rowSelected\"\n [class.z-indeterminate-selected]=\"rowSomeSelected && !rowSelected\"\n [class.z-context-menu-active]=\"contentRowMenu()?.row?.id === row.id\"\n [class.z-pinned-top]=\"rowPinned === 'top'\"\n [class.z-pinned-top-first]=\"rowPinned === 'top' && row.id === firstTopPinnedRowId()\"\n [class.z-pinned-bottom]=\"rowPinned === 'bottom'\"\n [class.z-pinned-bottom-last]=\"rowPinned === 'bottom' && row.id === lastBottomPinnedRowId()\"\n [class.z-pinned-bottom-first]=\"rowPinned === 'bottom' && row.id === firstBottomPinnedRowId()\"\n [class.z-shadow-bottom]=\"\n showHeaderFooterShadow() &&\n hasScrollTop() &&\n rowPinned === 'top' &&\n row.id === lastTopPinnedRowId() &&\n !isStickyGroupHeaderEnabled()\n \"\n [class.z-shadow-top]=\"\n showHeaderFooterShadow() &&\n hasScrollBottom() &&\n rowPinned === 'bottom' &&\n row.id === firstBottomPinnedRowId()\n \"\n [attr.data-depth]=\"row.depth\"\n (contextmenu)=\"openContentRowMenu($event, row)\">\n @for (cell of visibleCells; track cell.id) {\n @let cellPinned = cell.column.getIsPinned();\n @let cellRowPinned = cell.row.getIsPinned();\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n cell.column.id === firstVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></td>\n }\n @let shouldRenderRowSpan =\n cell | zTableSpan: zConfig().columns : 'shouldRender' : bodyRowSpanRows();\n @let shouldRenderColSpan = cell | zTableCellRender: visibleCells : zConfig().columns : 'body';\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n cellPinned !== false ||\n virtualCenterColumnVisibilityMap()[cell.column.id];\n @if (shouldRenderRowSpan && shouldRenderColSpan && isVirtualColumnVisible) {\n @let cellSelectionId = row.id + '::' + cell.column.id;\n <td\n [attr.data-column-id]=\"cell.column.id\"\n [ngStyle]=\"\n cell.column\n | zTablePinningStyles\n : cell\n : 'body'\n : visibleCells\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n : bodyRowSpanRows()\n \"\n [class]=\"cell | zTableCellConfig: zConfig() : 'cellClass'\"\n [style]=\"cell | zTableCellConfig: zConfig() : 'cellStyle'\"\n [class.z-sticky-left]=\"isColumnPinningActive && cellPinned === 'start'\"\n [class.z-sticky-right]=\"isColumnPinningActive && cellPinned === 'end'\"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n cellPinned === 'start' &&\n (cell | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n cellPinned === 'end' &&\n (cell | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'body' : visibleCells)\n \"\n [class.z-at-left-edge]=\"cell | zTableCellOffset: orderedLeafColumns()\"\n [class.z-col-drag]=\"cell.column.id === 'rowDrag'\"\n [class.z-col-select]=\"cell.column.id === 'select'\"\n [class.z-col-expand]=\"cell.column.id === 'expand'\"\n [class.z-col-actions]=\"\n cell.column.id === 'actions' || cell.column.id === actionColumnInfo()?.columnId\n \"\n [class.z-cell-selectable]=\"canUseCellSelection()\"\n [class.z-cell-active]=\"\n !hasMultipleSelectedCells() &&\n activeCell()?.rowId === row.id &&\n activeCell()?.columnId === cell.column.id\n \"\n [class.z-cell-range-selected]=\"visualSelectedCellIds().has(cellSelectionId)\"\n [class.z-cell-range-top]=\"selectedCellEdgeIds().top.has(cellSelectionId)\"\n [class.z-cell-range-right]=\"selectedCellEdgeIds().right.has(cellSelectionId)\"\n [class.z-cell-range-bottom]=\"selectedCellEdgeIds().bottom.has(cellSelectionId)\"\n [class.z-cell-range-left]=\"selectedCellEdgeIds().left.has(cellSelectionId)\"\n [class.z-content-edit-active]=\"\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n \"\n [class.z-at-bottom]=\"cell | zTableCellBottom: zConfig().columns : renderedBodyRows()\"\n [attr.rowspan]=\"cell | zTableSpan: zConfig().columns : 'cellRowSpan' : bodyRowSpanRows()\"\n [attr.colspan]=\"cell | zTableSpan: zConfig().columns : 'cellColSpan'\"\n [style.--z-cell-range-top]=\"(selectedCellRangeInsets().get(cellSelectionId)?.top ?? 0) + '%'\"\n [style.--z-cell-range-right]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.right ?? 0) + '%'\n \"\n [style.--z-cell-range-bottom]=\"\n (selectedCellRangeInsets().get(cellSelectionId)?.bottom ?? 0) + '%'\n \"\n [style.--z-cell-range-left]=\"(selectedCellRangeInsets().get(cellSelectionId)?.left ?? 0) + '%'\"\n (pointerdown)=\"onCellPointerDown($event, row, cell.column.id)\"\n (pointerenter)=\"onCellPointerEnter($event, row, cell.column.id)\"\n (contextmenu)=\"openCellMenu($event, row, cell.column.id)\">\n @if (cell.column.id === 'rowDrag') {\n <div class=\"flex items-center justify-center\">\n <button\n data-z-table-drag-handle\n type=\"button\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground inline-flex size-7 items-center justify-center rounded-md transition-colors\"\n [class.cursor-grab]=\"isRowDragEnabled()\"\n [class.cursor-not-allowed]=\"!isRowDragEnabled()\"\n [class.opacity-40]=\"!isRowDragEnabled()\">\n <z-icon zType=\"lucideGripVertical\" zSize=\"14\" />\n </button>\n </div>\n } @else if (cell.column.id === 'select') {\n <!-- Row Checkbox with Pin Button -->\n <div class=\"flex items-center justify-center gap-1\">\n <z-checkbox\n [zChecked]=\"canUseRowSelection() && cell.row.getIsSelected()\"\n [zIndeterminate]=\"\n canUseRowSelection() && cell.row.getIsSomeSelected() && !cell.row.getIsSelected()\n \"\n [zDisabled]=\"!canUseRowSelection() || !cell.row.getCanSelect()\"\n (zChange)=\"canUseRowSelection() && cell.row.toggleSelected()\" />\n @if (zConfig().enableRowPinning && cell.row.depth === 0 && !hasBodyRowSpan()) {\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div\n zHoverGlide\n zHoverGlideSelector=\".z-column-menu-item\"\n class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded-sm p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n }\n </div>\n } @else if (cell.column.id === 'expand') {\n <!-- Expand Button with Row Pin Popover -->\n <div class=\"flex items-center justify-center gap-1\">\n @if (cell.row.getCanExpand()) {\n <button\n type=\"button\"\n (click)=\"cell.row.toggleExpanded()\"\n class=\"hover:bg-muted flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"cell.row.getIsExpanded()\" />\n </button>\n }\n @if (\n zConfig().enableRowPinning &&\n cell.row.depth === 0 &&\n !(cell.row.subRows && cell.row.subRows.length > 0) &&\n !hasBodyRowSpan()\n ) {\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div\n zHoverGlide\n zHoverGlideSelector=\".z-column-menu-item\"\n class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded-sm p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n }\n </div>\n } @else if (\n (cell.column.id === 'actionRowPin' || cell.column.id === 'actions') &&\n cell.column.id !== actionColumnInfo()?.columnId\n ) {\n <!-- Actions Column - Row Pin Only (for parent rows) -->\n @if (cell.row.depth === 0 && !hasBodyRowSpan()) {\n <div class=\"flex items-center justify-center\">\n @if (cellRowPinned) {\n <button\n type=\"button\"\n class=\"z-row-pin-trigger z-row-pin-unpin-trigger flex h-6 w-6 cursor-pointer items-center justify-center rounded-sm\"\n (click)=\"cell.row.pin(false)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n } @else {\n <ng-template #rowPinPopoverContent>\n <div\n zHoverGlide\n zHoverGlideSelector=\".z-column-menu-item\"\n class=\"flex flex-col gap-1 py-1\">\n <button\n type=\"button\"\n (click)=\"cell.row.pin('top'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowUp\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_top' | translate }}</span>\n </button>\n <button\n type=\"button\"\n (click)=\"cell.row.pin('bottom'); rowPinPopover.hideImmediate()\"\n class=\"z-column-menu-item text-foreground hover:bg-muted focus:bg-muted mx-1 flex min-h-7 cursor-pointer items-center gap-2 rounded-sm px-2 py-1 text-xs outline-none\">\n <z-icon zType=\"lucideArrowDown\" zSize=\"12\" />\n <span>{{ 'i18n_z_ui_table_pin_bottom' | translate }}</span>\n </button>\n </div>\n </ng-template>\n <button\n type=\"button\"\n z-popover\n #rowPinPopover=\"zPopover\"\n [zPopoverContent]=\"rowPinPopoverContent\"\n zTrigger=\"click\"\n zPosition=\"bottom\"\n class=\"z-row-pin-trigger text-muted-foreground hover:bg-muted hover:text-foreground flex cursor-pointer items-center justify-center rounded-sm p-1 outline-none\">\n <z-icon zType=\"lucideEllipsis\" zSize=\"14\" class=\"rotate-90\" />\n </button>\n }\n </div>\n }\n } @else if (cell.column.id === actionColumnInfo()?.columnId && actionColumnInfo()) {\n <z-table-actions\n [zConfig]=\"$any(actionColumnInfo()!.config)\"\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n (zActionClick)=\"onActionClick($event)\" />\n } @else {\n @let isCellVisibleNormal = cell | zTableCellVisible: zConfig().columns;\n @if (isCellVisibleNormal) {\n @let editInfo = cell.getContext() | zTableCellEdit: zConfig().columns;\n @if (editInfo.enabled) {\n <!-- Editable Cell -->\n <z-table-edit-cell\n [zRow]=\"cell.row.original\"\n [zRowId]=\"cell.row.id\"\n [zRowIndex]=\"cell.row.index\"\n [zColumnId]=\"cell.column.id\"\n [zValue]=\"cell.getValue()\"\n [zRowUpdate]=\"_rowUpdate()\"\n [zEditConfig]=\"$any(editInfo.config)\"\n (zChange)=\"onCellEdit($any($event))\" />\n } @else if (editInfo.contentEnabled) {\n @let contentConfig = editInfo.contentConfig!;\n @if (\n activeContentEditCell()?.rowId === row.id &&\n activeContentEditCell()?.columnId === cell.column.id\n ) {\n <z-table-content-editor\n [zValue]=\"cell.getValue()\"\n [zConfig]=\"contentConfig\"\n (zCommit)=\"onContentEditCommit($event, row, cell.column.id, cell.getValue())\"\n (zCancel)=\"onContentEditCancel()\" />\n } @else {\n <button\n type=\"button\"\n class=\"z-table-content-trigger\"\n [attr.data-z-table-edit-row]=\"row.id\"\n [attr.data-z-table-edit-column]=\"cell.column.id\"\n (keydown)=\"onContentEditKeydown($event, row.id, cell.column.id)\"\n (click)=\"onContentEditStart($event, row.id, cell.column.id)\">\n {{ contentConfig.displayValue }}\n </button>\n }\n } @else {\n <ng-container\n *flexRender=\"cell.column.columnDef.cell; props: cell.getContext(); let cellContent\">\n @if (cellContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n @let isClickableTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n <div\n class=\"z-template-content\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickableTpl && onCellClick(row, cell.column.id, cell.getValue())\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { $implicit: cell.getContext() }\" />\n </div>\n } @else if (cellContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n @let isClickableIconTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n <z-table-icon-text\n [zText]=\"cellContent\"\n [zTooltip]=\"cell | zTableCellConfig: zConfig() : 'contentTooltip'\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n (click)=\"isClickableIconTpl && onCellClick(row, cell.column.id, cell.getValue())\" />\n } @else {\n <!-- Default/innerHTML rendering -->\n @let isClickableDefaultTpl = cell.column.id | zTableCellClickable: zConfig().columns;\n @let cellTooltipConfigTpl = cell | zTableCellConfig: zConfig() : 'contentTooltip';\n @let cellPopoverConfigTpl = cell | zTableCellConfig: zConfig() : 'contentPopover';\n @let cellPopoverContentTpl = cellPopoverConfigTpl | zTablePopoverConfig: 'content';\n <ng-template #cellPopoverTplNormal>\n @if (cellPopoverContentTpl | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(cellPopoverContentTpl)\" />\n }\n @if (!(cellPopoverContentTpl | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(cellPopoverContentTpl) | zSafeHtml\"></div>\n }\n </ng-template>\n @if (cellPopoverContentTpl) {\n <div\n class=\"z-table-cell-text\"\n z-popover\n z-tooltip\n [zTriggerElement]=\"cellOverlayContentTpl\"\n [zTriggerRef]=\"cellOverlayContentTpl\"\n [zContent]=\"\n (cellTooltipConfigTpl | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"cellPopoverTplNormal\"\n [zPosition]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"\n $any(cellPopoverConfigTpl | zTablePopoverConfig: 'outsideClickClose')\n \"\n [zScrollClose]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(cellPopoverConfigTpl | zTablePopoverConfig: 'keyboardSafe')\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellOverlayContentTpl\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n } @else {\n <div\n class=\"z-table-cell-text\"\n z-tooltip\n [zTriggerElement]=\"cellTooltipContentTpl\"\n [zContent]=\"\n (cellTooltipConfigTpl | zTableTooltipConfig: 'content') || cellContent\n \"\n [zTooltipPosition]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'showDelay')\n \"\n [zTooltipHideDelay]=\"\n $any(cellTooltipConfigTpl | zTableTooltipConfig: 'hideDelay')\n \"\n [zTooltipArrow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(cellTooltipConfigTpl | zTableTooltipConfig: 'maxWidth')\"\n (click)=\"\n isClickableDefaultTpl && onCellClick(row, cell.column.id, cell.getValue())\n \">\n <span\n #cellTooltipContentTpl\n class=\"z-table-cell-content-trigger\"\n [class]=\"cell | zTableCellConfig: zConfig() : 'contentClass'\"\n [ngStyle]=\"cell | zTableCellConfig: zConfig() : 'contentStyle'\"\n [innerHTML]=\"cellContent | translate | zSafeHtml\"></span>\n </div>\n }\n }\n </ng-container>\n }\n }\n }\n </td>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n cell.column.id === lastVirtualCenterColumnId()\n ) {\n <td\n class=\"z-virtual-column-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></td>\n }\n }\n </tr>\n\n <!-- Expanded Row Detail -->\n @if (row.getIsExpanded() && row.depth === 0 && !row.subRows?.length) {\n @let resolvedSubTableConfig = row | zTableSubTableConfig: zConfig();\n <tr class=\"z-expanded-row\" animate.enter=\"z-expanded-row-enter\">\n <td [attr.colspan]=\"renderedColumnCount()\" class=\"p-0\">\n <!-- Animate \u1EDF wrapper n\u00E0y b\u1EB1ng clip-path/translate/opacity \u2014 xem z-expanded-row-reveal. -->\n <div class=\"z-expanded-row-content\">\n @if (zConfig().expandedRowTemplate) {\n <ng-container\n *ngTemplateOutlet=\"zConfig().expandedRowTemplate!; context: { $implicit: row }\" />\n } @else if (resolvedSubTableConfig) {\n <div class=\"z-sub-table-container\">\n <z-table [zConfig]=\"$any(resolvedSubTableConfig)\" zVariant=\"borderless\" />\n </div>\n }\n </div>\n </td>\n </tr>\n }\n </ng-template>\n\n <!-- Render Top Pinned Rows (hidden when filtered data is empty) -->\n @if (!isEmpty()) {\n @for (row of table.getTopRows(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\n }\n }\n\n <!-- Render Center Rows -->\n @for (item of groupedCenterRowItems(); track item.type === 'group' ? item.id : item.row.id) {\n @if (item.type === 'group') {\n <tr\n #groupRow\n class=\"z-group-row\"\n [class.z-group-row-has-totals]=\"item.totals\"\n [class.z-group-row-expanded]=\"item.expanded\"\n [class.z-group-row-sticky]=\"isStickyGroupHeaderEnabled()\"\n [class.z-group-row-sticky-shadow]=\"shadowGroupRowId() === item.id\"\n [style.top.px]=\"stickyGroupTopByDepth()[item.depth]\"\n [attr.data-group-id]=\"item.id\"\n [attr.data-group-depth]=\"item.depth\">\n @if (item.totals) {\n @let totalColumnMap = groupTotalColumnMap();\n @for (column of orderedLeafColumns(); track column.id; let isFirstGroupCell = $first) {\n <td\n [class.z-group-row-label-cell]=\"isFirstGroupCell\"\n [class.z-group-row-total-cell]=\"!isFirstGroupCell && totalColumnMap[column.id]\"\n [attr.data-column-id]=\"column.id\">\n @if (isFirstGroupCell) {\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + item.depth * 0.75\"\n [attr.aria-expanded]=\"item.expanded\"\n (click)=\"toggleGroupRow(item.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"item.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"(item.columnLabel ? item.columnLabel + ': ' : '') + item.label\">\n @if (item.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ item.columnLabel }}:</span>\n }\n {{ item.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ item.count }}</span>\n }\n @if (item.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n zSizeIcon=\"14\"\n [zWave]=\"false\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(item.columnId)\"></button>\n }\n </div>\n }\n @if (!isFirstGroupCell && totalColumnMap[column.id]) {\n @let totalConfig = groupTotalConfigMap()[column.id];\n @let totalTooltip = totalConfig.tooltip;\n @let totalPopover = totalConfig.popover;\n @let totalPopoverContent = totalPopover | zTablePopoverConfig: 'content';\n <ng-template #groupTotalPopoverTpl>\n @if (totalPopoverContent | zTableIsTemplateRef) {\n <ng-container *ngTemplateOutlet=\"$any(totalPopoverContent)\" />\n }\n @if (!(totalPopoverContent | zTableIsTemplateRef)) {\n <div [innerHTML]=\"$any(totalPopoverContent) | zSafeHtml\"></div>\n }\n </ng-template>\n <span\n class=\"z-group-row-total\"\n z-tooltip\n z-popover\n [class]=\"totalConfig.class\"\n [zContent]=\"\n $any((totalTooltip | zTableTooltipConfig: 'content') || item.totals[column.id])\n \"\n [zTooltipPosition]=\"$any(totalTooltip | zTableTooltipConfig: 'position')\"\n [zTooltipTrigger]=\"$any(totalTooltip | zTableTooltipConfig: 'trigger')\"\n [zTooltipType]=\"$any(totalTooltip | zTableTooltipConfig: 'type')\"\n [zTooltipSize]=\"$any(totalTooltip | zTableTooltipConfig: 'size')\"\n [zTooltipClass]=\"$any(totalTooltip | zTableTooltipConfig: 'class')\"\n [zTooltipShowDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'showDelay')\"\n [zTooltipHideDelay]=\"$any(totalTooltip | zTableTooltipConfig: 'hideDelay')\"\n [zTooltipArrow]=\"$any(totalTooltip | zTableTooltipConfig: 'arrow')\"\n [zTooltipOffset]=\"$any(totalTooltip | zTableTooltipConfig: 'offset')\"\n [zAutoDetect]=\"$any(totalTooltip | zTableTooltipConfig: 'autoDetect')\"\n [zAlwaysShow]=\"$any(totalTooltip | zTableTooltipConfig: 'alwaysShow')\"\n [zMaxWidth]=\"$any(totalTooltip | zTableTooltipConfig: 'maxWidth')\"\n [zPopoverContent]=\"totalPopoverContent ? groupTotalPopoverTpl : null\"\n [zPosition]=\"$any(totalPopover | zTablePopoverConfig: 'position')\"\n [zPopoverTrigger]=\"$any(totalPopover | zTablePopoverConfig: 'trigger')\"\n [zClass]=\"$any(totalPopover | zTablePopoverConfig: 'class')\"\n [zShowDelay]=\"$any(totalPopover | zTablePopoverConfig: 'showDelay')\"\n [zHideDelay]=\"$any(totalPopover | zTablePopoverConfig: 'hideDelay')\"\n [zDisabled]=\"$any(totalPopover | zTablePopoverConfig: 'disabled')\"\n [zOffset]=\"$any(totalPopover | zTablePopoverConfig: 'offset')\"\n [zPopoverWidth]=\"$any(totalPopover | zTablePopoverConfig: 'width')\"\n [zManualClose]=\"$any(totalPopover | zTablePopoverConfig: 'manualClose')\"\n [zOutsideClickClose]=\"$any(totalPopover | zTablePopoverConfig: 'outsideClickClose')\"\n [zScrollClose]=\"$any(totalPopover | zTablePopoverConfig: 'scrollClose')\"\n [zSticky]=\"$any(totalPopover | zTablePopoverConfig: 'sticky')\"\n [zShowArrow]=\"$any(totalPopover | zTablePopoverConfig: 'showArrow')\"\n [zKeyboardSafe]=\"$any(totalPopover | zTablePopoverConfig: 'keyboardSafe')\">\n {{ item.totals[column.id] }}\n </span>\n }\n </td>\n }\n } @else {\n <td [attr.colspan]=\"renderedColumnCount()\">\n <div class=\"z-group-row-sticky-wrapper\">\n <button\n type=\"button\"\n class=\"z-group-row-trigger\"\n [style.padding-left.rem]=\"0.75 + item.depth * 0.75\"\n [attr.aria-expanded]=\"item.expanded\"\n (click)=\"toggleGroupRow(item.id)\">\n <z-icon\n zType=\"lucideChevronRight\"\n zSize=\"14\"\n class=\"transition-transform duration-200\"\n [class.rotate-90]=\"item.expanded\" />\n <span\n class=\"z-group-row-label\"\n z-tooltip\n [zContent]=\"(item.columnLabel ? item.columnLabel + ': ' : '') + item.label\">\n @if (item.columnLabel) {\n <span class=\"z-group-row-column-label\">{{ item.columnLabel }}:</span>\n }\n {{ item.label }}\n </span>\n @if (groupingConfig().showCount !== false) {\n <span class=\"z-group-row-count\">{{ item.count }}</span>\n }\n @if (item.loading) {\n <z-loading class=\"z-group-row-loading\" [zLoading]=\"true\" zSize=\"xs\" />\n }\n </button>\n @if (!isServerGrouping()) {\n <button\n type=\"button\"\n z-button\n zType=\"ghost\"\n zSize=\"sm\"\n zTypeIcon=\"lucideX\"\n zSizeIcon=\"14\"\n [zWave]=\"false\"\n z-tooltip\n [zContent]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [attr.aria-label]=\"'i18n_z_ui_table_clear_grouping' | translate\"\n [zAlwaysShow]=\"true\"\n zTooltipPosition=\"top\"\n class=\"z-group-row-remove\"\n (click)=\"removeGroupingColumn(item.columnId)\"></button>\n }\n </div>\n </td>\n }\n </tr>\n }\n @if (item.type === 'row') {\n <ng-container\n *ngTemplateOutlet=\"\n rowTemplate;\n context: {\n $implicit: item.row,\n isGroupChild: item.isGroupChild,\n groupDepth: item.groupDepth,\n }\n \" />\n }\n }\n\n <!-- Render Bottom Pinned Rows (hidden when filtered data is empty) -->\n @if (!isEmpty()) {\n @for (row of bottomRowsReversed(); track row.id) {\n <ng-container *ngTemplateOutlet=\"rowTemplate; context: { $implicit: row }\" />\n }\n }\n </tbody>\n </table>\n }\n </ng-scrollbar>\n }\n <!-- end @else -->\n </div>\n\n <!-- Footer table -->\n @if (hasFooter()) {\n <div\n class=\"z-tfoot-wrapper\"\n [class.z-shadow-footer]=\"shouldFooterShowShadow()\"\n [class.z-scroll-left]=\"hasScrollLeft()\"\n [class.z-scroll-right]=\"hasScrollRight()\"\n #tfootWrapper>\n <table [style.width.px]=\"renderedTableWidth()\">\n <ng-container *ngTemplateOutlet=\"colGroupTpl\" />\n <tfoot>\n @for (footerGroup of orderedFooterGroups(); track footerGroup.id; let footerRowIndex = $index) {\n @if (footerGroup | zTableFooterContent: zConfig().columns : footerRowIndex) {\n <tr>\n @for (footer of footerGroup.headers; track footer.id) {\n @if (\n canUseVirtualColumns() &&\n virtualLeftSpacerWidth() > 0 &&\n footer.column.id === firstVirtualCenterColumnId()\n ) {\n <th\n class=\"z-virtual-column-spacer z-virtual-footer-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedLeftSpacerWidth()\"></th>\n }\n @let rowSpan = footer | zTableSpan: zConfig().columns : 'footerRowSpan' : footerRowIndex;\n @let shouldRender =\n footer\n | zTableCellRender\n : footerGroup.headers\n : zConfig().columns\n : 'footer'\n : footerRowIndex\n : orderedFooterGroups();\n @let isVirtualColumnVisible =\n !canUseVirtualColumns() ||\n footer.column.getIsPinned() !== false ||\n virtualCenterColumnVisibilityMap()[footer.column.id];\n @if (rowSpan && shouldRender && isVirtualColumnVisible) {\n <th\n [attr.data-column-id]=\"footer.column.id\"\n [ngStyle]=\"\n footer.column\n | zTablePinningStyles\n : footer\n : 'footer'\n : table\n : zConfig().columns\n : columnResizing()\n : colDomWidthMap()\n : isColumnPinningActive\n \"\n [class]=\"\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerClass' : footerRowIndex) +\n ' ' +\n (footer.column.id | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex)\n \"\n [style]=\"\n footer.column.id | zTableColumnConfig: zConfig().columns : 'footerStyle' : footerRowIndex\n \"\n [class.z-sticky-left]=\"\n isColumnPinningActive && (footer | zTableCellPin: 'isLeftPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-left-last]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isLastLeftPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right-first]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isFirstRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-sticky-right-last]=\"\n isColumnPinningActive &&\n (footer | zTableCellPin: 'isLastRightPinned' : zConfig().columns : 'footer')\n \"\n [class.z-at-left-edge]=\"footer | zTableCellOffset: orderedLeafColumns()\"\n [attr.rowspan]=\"rowSpan\"\n [attr.colspan]=\"footer | zTableSpan: zConfig().columns : 'footerColSpan' : footerRowIndex\">\n @let configFooterContent =\n footer.column.id | zTableFooterRender: zConfig().columns : footerRowIndex;\n @if (configFooterContent !== undefined && configFooterContent !== '') {\n <ng-container *flexRender=\"configFooterContent; props: footer.getContext(); let footerContent\">\n <div\n class=\"flex w-full items-center\"\n [class.justify-center]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex) ===\n 'text-center'\n \"\n [class.justify-end]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerAlignClass' : footerRowIndex) ===\n 'text-right'\n \">\n @if (footerContent | zTableIsTemplateRef) {\n <!-- TemplateRef rendering -->\n <div\n class=\"z-template-content\"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \">\n <ng-container\n *ngTemplateOutlet=\"footerContent; context: { $implicit: footer.getContext() }\" />\n </div>\n } @else if (footerContent | zTableHasIcon) {\n <!-- Icon syntax rendering -->\n <z-table-icon-text\n [zText]=\"footerContent\"\n [zTooltip]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerTooltip' : footerRowIndex\n \"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \" />\n } @else {\n <!-- Default/string rendering -->\n <span\n class=\"z-table-cell-text\"\n z-tooltip\n [zContent]=\"\n (footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerTooltip' : footerRowIndex) ||\n footerContent\n \"\n [class]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentClass' : footerRowIndex\n \"\n [ngStyle]=\"\n footer.column.id\n | zTableColumnConfig: zConfig().columns : 'footerContentStyle' : footerRowIndex\n \">\n {{ footerContent | translate }}\n </span>\n }\n </div>\n </ng-container>\n }\n </th>\n }\n @if (\n canUseVirtualColumns() &&\n virtualRightSpacerWidth() > 0 &&\n footer.column.id === lastVirtualCenterColumnId()\n ) {\n <th\n class=\"z-virtual-column-spacer z-virtual-footer-spacer pointer-events-none p-0\"\n [style.width.px]=\"virtualRenderedRightSpacerWidth()\"></th>\n }\n }\n </tr>\n }\n }\n </tfoot>\n </table>\n </div>\n }\n</div>\n\n<!-- Pagination -->\n@if (zConfig().pagination?.enabled !== false) {\n <div class=\"mt-4 flex items-center justify-between gap-4\">\n <div class=\"truncate text-sm text-gray-500\">\n {{ 'i18n_z_ui_table_total_rows' | translate: { total: (paginationTotal() | zFormatNum) } }}\n </div>\n <z-pagination\n [zTotal]=\"paginationTotal()\"\n [(zPageIndex)]=\"pagination().pageIndex\"\n [(zPageSize)]=\"pagination().pageSize\"\n [zPageSizeOptions]=\"zConfig().pagination?.pageSizeOptions ?? [10, 20, 50, 100]\"\n [zShowSizeChanger]=\"zConfig().pagination?.showSizeChanger ?? true\"\n [zShowQuickJumper]=\"zConfig().pagination?.showQuickJumper ?? false\"\n [zShowTotal]=\"false\"\n [zDisabled]=\"zConfig().pagination?.disabled || isLoading() || isProcessing()\"\n (zOnPageChange)=\"onPageChange($event)\" />\n </div>\n}\n\n<!-- Floating Bulk Action Bar -->\n<ng-template #bulkBarTemplate>\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 [zBodyClass]=\"'mx-0! px-0!'\"\n [zShadow]=\"true\"\n [zOkText]=\"null\"\n [zCancelText]=\"'i18n_z_ui_drawer_close' | translate\">\n <div class=\"z-table-settings-drawer\">\n <!-- Display Settings -->\n <div class=\"mx-4 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=\"mx-4 mb-4\">\n <h4 class=\"text-foreground mb-2 text-sm font-semibold\">{{ 'i18n_z_ui_table_column_settings' | translate }}</h4>\n <p class=\"text-muted-foreground mb-3 text-xs\">{{ 'i18n_z_ui_table_column_settings_desc' | translate }}</p>\n\n <!-- Unpinned Columns (Draggable) -->\n <div\n cdkDropList\n #columnDropList=\"cdkDropList\"\n [cdkDropListAutoScrollDisabled]=\"true\"\n (cdkDropListDropped)=\"onPendingColumnDrop($event)\"\n class=\"z-column-drop-list space-y-1.5\">\n @for (columnId of columnOrder(); track columnId; let i = $index) {\n @if (columnId !== 'expand' && columnId !== 'select' && columnId !== 'rowDrag') {\n @let column = table.getColumn(columnId);\n @let isPinned = column?.getIsPinned();\n @let isVisible = pendingVisibleColumns().includes(columnId);\n @let isVisibilityDisabled = pendingColumnVisibilityDisabledMap()[columnId];\n @let isGroupedColumn = groupingColumnMap()[columnId];\n @let columnEnablePinningConfig = columnId | zTableColumnConfig: zConfig().columns : 'enablePinning';\n @let canPin =\n (columnEnablePinningConfig ?? zConfig().enableColumnPinning ?? true) && column?.getCanPin() !== false;\n @if (!isPinned) {\n <div\n cdkDrag\n [cdkDragDisabled]=\"isGroupedColumn\"\n [cdkDragData]=\"columnId\"\n cdkDragLockAxis=\"y\"\n cdkDragPreviewContainer=\"global\"\n cdkDragPreviewClass=\"z-drag-preview\"\n class=\"z-drag-item border-border bg-card hover:border-primary flex cursor-default items-center gap-2 rounded-sm border px-2 py-1.5 text-sm\"\n [class.opacity-60]=\"!isVisible\">\n <!-- Drag Handle -->\n <z-icon\n cdkDragHandle\n zType=\"lucideGripVertical\"\n zSize=\"14\"\n class=\"text-muted-foreground shrink-0\"\n [class.cursor-pointer]=\"!isGroupedColumn\"\n [class.cursor-default]=\"isGroupedColumn\"\n [class.opacity-40]=\"isGroupedColumn\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n [disabled]=\"isVisibilityDisabled\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n (mousedown)=\"$event.stopPropagation()\"\n class=\"border-input h-4 w-4 shrink-0 cursor-default rounded-sm disabled:opacity-50\" />\n\n <!-- Column Name -->\n <span class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\" [class.text-muted-foreground]=\"!isVisible\">\n {{ columnId | zTableColumnHeader: zConfig().columns | translate }}\n </span>\n @let parents = columnId | zTableColumnParents: zConfig().columns;\n @if (parents) {\n <span class=\"text-muted-foreground truncate text-[0.625rem]\">({{ parents | translate }})</span>\n }\n </span>\n\n <!-- Pin Buttons -->\n @if (canPin) {\n <div class=\"flex shrink-0 items-center gap-0.5\" (mousedown)=\"$event.stopPropagation()\">\n <button\n type=\"button\"\n [disabled]=\"!isVisible || isGroupedColumn || !pinAvailabilityMap()[columnId]?.left\"\n (click)=\"onToggleColumnPin(columnId, 'left')\"\n class=\"text-muted-foreground hover:bg-muted cursor-pointer rounded-sm p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Pin Left\">\n <z-icon zType=\"lucideArrowLeft\" zSize=\"12\" />\n </button>\n <button\n type=\"button\"\n [disabled]=\"!isVisible || isGroupedColumn || !pinAvailabilityMap()[columnId]?.right\"\n (click)=\"onToggleColumnPin(columnId, 'right')\"\n class=\"text-muted-foreground hover:bg-muted cursor-pointer rounded-sm p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Pin Right\">\n <z-icon zType=\"lucideArrowRight\" zSize=\"12\" />\n </button>\n </div>\n }\n </div>\n }\n }\n }\n </div>\n\n <!-- Pinned Columns Section -->\n @if (zConfig().enableColumnPinning ?? true) {\n @if (pinnedColumnIds().length > 0) {\n <div class=\"border-border mt-4 border-t pt-4\">\n <h5 class=\"text-muted-foreground mb-2 text-xs font-medium\">\n {{ 'i18n_z_ui_table_pinned_columns' | translate }}\n </h5>\n <div class=\"space-y-1.5\">\n @for (columnId of pinnedColumnIds(); track columnId) {\n @let column = table.getColumn(columnId);\n @let isPinned = column?.getIsPinned();\n @let isVisible = pendingVisibleColumns().includes(columnId);\n @let isVisibilityDisabled = pendingColumnVisibilityDisabledMap()[columnId];\n @let isGroupedColumn = groupingColumnMap()[columnId];\n <div\n class=\"border-border bg-muted/30 flex items-center gap-2 rounded-sm border px-2 py-1.5 text-sm\"\n [class.opacity-60]=\"!isVisible\">\n <!-- Pin Icon -->\n <z-icon zType=\"lucidePin\" zSize=\"14\" class=\"text-primary shrink-0\" />\n\n <!-- Visibility Checkbox -->\n <input\n type=\"checkbox\"\n [checked]=\"isVisible\"\n [disabled]=\"isVisibilityDisabled\"\n (change)=\"onToggleColumnVisibility(columnId)\"\n class=\"border-input h-4 w-4 shrink-0 cursor-default rounded-sm disabled:opacity-50\" />\n\n <!-- Column Name -->\n <span class=\"flex min-w-0 flex-1 flex-col\">\n <span class=\"truncate\" [class.text-muted-foreground]=\"!isVisible\">\n {{ columnId | zTableColumnHeader: zConfig().columns | translate }}\n </span>\n @let pinnedParents = columnId | zTableColumnParents: zConfig().columns;\n @if (pinnedParents) {\n <span class=\"text-muted-foreground truncate text-[0.625rem]\">\n ({{ pinnedParents | translate }})\n </span>\n }\n </span>\n\n <!-- Position Badge -->\n <span\n class=\"bg-primary/10 text-primary shrink-0 rounded-sm px-1.5 py-0.5 text-[0.625rem] font-medium\">\n {{\n isPinned === 'start'\n ? ('i18n_z_ui_table_left' | translate)\n : ('i18n_z_ui_table_right' | translate)\n }}\n </span>\n\n <!-- Unpin Button -->\n <button\n type=\"button\"\n [disabled]=\"isGroupedColumn\"\n (click)=\"onToggleColumnPin(columnId, isPinned === 'start' ? 'left' : 'right')\"\n class=\"text-muted-foreground hover:bg-muted hover:text-foreground cursor-pointer rounded-sm p-1 text-xs transition-colors disabled:cursor-not-allowed disabled:opacity-40\"\n title=\"Unpin\">\n <z-icon zType=\"lucideX\" zSize=\"12\" />\n </button>\n </div>\n }\n </div>\n </div>\n }\n }\n </div>\n </div>\n</z-drawer>\n", styles: [":host{display:flex;flex-direction:column;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;overflow-x:visible;--scrollbar-track-thickness: 7px;--scrollbar-track-color: transparent;--scrollbar-thumb-shape: 3px;--z-shadow-left-right: -1.875rem;--z-shadow-left-width: 1.875rem;--z-shadow-left-opacity: 0;--z-shadow-right-left: -1.875rem;--z-shadow-right-width: 1.875rem;--z-shadow-right-opacity: 0;--z-sticky-left-border-color: transparent;--z-sticky-right-border-color: var(--border);--z-cell-selection-background: color-mix(in srgb, var(--primary) 12%, transparent);--z-cell-selection-background-opaque: color-mix(in srgb, var(--primary) 12%, var(--card))}.z-table-container{display:flex;flex-direction:column;position:relative;box-sizing:border-box;contain:inline-size;width:100%;max-width:100%;min-width:0;height:100%;overflow:hidden;border-radius:var(--radius-sm);border:thin solid var(--border);background-color:var(--card)}.z-table-container:focus{outline:none}.z-table-container.z-table-borderless{border:none;border-radius:0;box-shadow:none!important;background-color:transparent}.z-table-container.z-hide-horizontal-border th,.z-table-container.z-hide-horizontal-border td{border-bottom:none!important;border-top:none!important}.z-table-container.z-hide-vertical-border th,.z-table-container.z-hide-vertical-border td{border-left:none!important}.z-table-container.z-hide-pinned-top-border tbody tr.z-pinned-top.z-shadow-bottom>td{border-bottom-color:var(--border)!important}.z-table-container.z-hide-pinned-bottom-border tbody.z-has-bottom-pinned td.z-at-bottom{border-bottom-color:transparent}table{width:fit-content;min-width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed;font-size:.875rem}.z-table-container.z-column-resizing table,.z-table-toolbar{min-width:0}.z-table-toolbar .z-settings-btn{transition:all .15s ease}.z-table-toolbar .z-settings-btn:hover{border-color:var(--muted-foreground)}.z-table-filter-header{min-width:0}.z-table-filter-header button{flex:none}.z-table-filter-header-overflow-chip{animation:z-table-filter-chip-enter .16s ease}@media(prefers-reduced-motion:reduce){.z-table-filter-header-overflow-chip{animation:none}}@keyframes z-table-filter-chip-enter{0%{opacity:0;transform:translate(-.25rem)}to{opacity:1;transform:translate(0)}}::ng-deep .z-bulk-action-bar-overlay{position:fixed!important;top:auto;left:50%;bottom:0;transform:translate(-50%);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:var(--radius-md);background:color-mix(in srgb,var(--card) 96%,var(--background));color:var(--foreground);box-shadow:0 1rem 2.5rem color-mix(in srgb,var(--foreground) 20%,transparent),0 .25rem .75rem color-mix(in srgb,var(--foreground) 12%,transparent),0 0 0 1px color-mix(in srgb,var(--background) 65%,transparent) inset;display:flex;align-items:center;gap:.5rem;width:max-content;min-height:2.25rem;max-width:calc(100vw - 2rem);padding:.5rem;transform-origin:center bottom;animation:z-bulk-action-bar-enter .18s cubic-bezier(.16,1,.3,1);will-change:opacity,transform}.z-bulk-action-bar-inner.z-leaving{pointer-events:none;animation:z-bulk-action-bar-exit .14s ease-in forwards}.z-bulk-action-bar-count{padding:0 .25rem;white-space:nowrap;font-size:.8125rem;font-weight:500;color:var(--foreground)}.z-bulk-action-bar-divider{width:1px;height:1.5rem;flex:none;background:color-mix(in srgb,var(--border) 88%,transparent)}.z-bulk-action-bar-button{flex:none}@keyframes z-bulk-action-bar-enter{0%{opacity:0;transform:translateY(.875rem)}to{opacity:1;transform:translateY(0)}}@keyframes z-bulk-action-bar-exit{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(.875rem)}}@media(prefers-reduced-motion:reduce){.z-bulk-action-bar-inner{animation:none}}:host ::ng-deep .z-table-cell-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;min-width:0;-webkit-user-select:text;user-select:text}:host ::ng-deep .z-table-cell-text>*,:host ::ng-deep .z-table-cell-text *{display:inline-block;max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}:host ::ng-deep .z-table-cell-content-trigger{display:inline-block;max-width:100%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}.z-template-content{display:block;width:100%;min-width:0;max-width:100%;overflow:hidden}.z-template-content>*{min-width:0;max-width:100%}.z-template-content>[class*=flex]{min-width:0;max-width:100%}.z-template-content>[class*=flex]>*{min-width:0;flex-shrink:1}.z-template-content>[class*=grid]{min-width:0;max-width:100%}.z-thead-wrapper{flex-shrink:0;background:var(--muted);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;position:relative;z-index:4}.z-thead-wrapper::-webkit-scrollbar{display:none}.z-thead-wrapper th{height:auto;padding:.5rem;text-align:left;vertical-align:middle;font-weight:500;color:var(--foreground);white-space:nowrap;overflow:hidden;background:var(--muted);border-left:thin solid var(--border);border-bottom:thin solid var(--border);-webkit-user-select:none;user-select:none}.z-thead-wrapper th.z-at-left-edge{border-left:none}.z-thead-wrapper th[colspan]{text-align:center;background:var(--muted);font-weight:500;color:var(--foreground)}.z-thead-wrapper.z-shadow-header{box-shadow:0 1px 3px #00000014;position:relative;z-index:15}.z-thead-wrapper.z-shadow-header:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}.z-tbody-wrapper{flex:1;width:100%;max-width:100%;min-width:0;min-height:6.25rem;display:flex;flex-direction:column;overflow:hidden}.z-tbody-scrollbar{flex:1;width:100%;max-width:100%;min-width:0;height:100%}.z-empty-state,.z-loading-state{flex:1 1 0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;min-height:6.25rem;height:100%;color:var(--muted-foreground);font-size:.875rem;animation:z-fade-in .2s ease-out}.z-tbody-scrollbar,.z-tbody-scrollbar table{animation:z-fade-in .2s ease-out}@keyframes z-fade-in{0%{opacity:0;transform:translateY(.25rem)}to{opacity:1;transform:translateY(0)}}.z-tbody-wrapper tr{transition:background-color .15s ease}.z-tbody-wrapper tr:hover,.z-tbody-wrapper tr:hover td[style*=sticky]{background-color:var(--muted)}.z-tbody-wrapper tr.z-pinned-top td.z-sticky-left,.z-tbody-wrapper tr.z-pinned-top td.z-sticky-right,.z-tbody-wrapper tr.z-pinned-bottom td.z-sticky-left,.z-tbody-wrapper tr.z-pinned-bottom td.z-sticky-right{z-index:3}.z-tbody-wrapper tr.z-shadow-bottom{box-shadow:0 1px 3px #00000014!important;position:relative;z-index:15}.z-tbody-wrapper tr.z-shadow-bottom:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d!important}.z-tbody-wrapper tr.z-shadow-top{box-shadow:0 -2px 4px #0000000d!important;position:relative;z-index:15}.z-tbody-wrapper tr.z-shadow-top:where(.dark,.dark *){box-shadow:0 -2px 4px #0003!important}.z-tbody-wrapper td{padding:.5rem 12px;height:var(--z-row-height, 2.375rem);vertical-align:middle;color:var(--foreground);white-space:nowrap;overflow:hidden;background:var(--card);border-left:thin solid var(--border);border-bottom:thin solid var(--border);box-sizing:border-box}.z-tbody-wrapper tbody.z-has-vertical-scroll td.z-at-bottom,.z-tbody-wrapper tbody.z-last-row-touches-bottom td.z-at-bottom{border-bottom-color:transparent}.z-tbody-wrapper tbody.z-has-bottom-pinned td.z-at-bottom{border-bottom-color:var(--border)}.z-tbody-wrapper td.z-at-left-edge{border-left:none}.z-tbody-wrapper td i{color:var(--muted-foreground);font-style:italic}.z-tbody-wrapper td[rowspan]{vertical-align:top;padding-top:.75rem}.z-tbody-wrapper td.z-row-hover{background-color:var(--muted)!important}.z-tbody-wrapper td.z-col-select,.z-tbody-wrapper td.z-col-expand,.z-tbody-wrapper td.z-col-actions{padding:.5rem 4px!important;text-align:center}.z-tbody-wrapper tr.z-child-row td.z-col-select:first-child,.z-tbody-wrapper tr.z-child-row td.z-col-expand:first-child,.z-tbody-wrapper tr.z-child-row td.z-col-actions:first-child{padding-left:0!important}.z-virtual-scroll-inner{position:relative;box-sizing:border-box;width:100%}.z-virtual-row,.z-virtual-flow{position:absolute;top:0;left:0;width:100%}.z-virtual-row-flow{position:relative}.z-virtual-row-fixed{overflow:hidden}.z-virtual-row-group-header{z-index:2}.z-virtual-row-sticky-group{position:sticky}.z-virtual-row-sticky-group-shadow{box-shadow:0 1px 3px #00000014}.z-virtual-row-sticky-group-shadow:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}tr.z-group-row-sticky{position:sticky;z-index:2}tr.z-group-row-sticky>td{background:var(--card)}tr.z-group-row-sticky-shadow{box-shadow:0 1px 3px #00000014}tr.z-group-row-sticky-shadow:where(.dark,.dark *){box-shadow:0 1px 3px #0000004d}tr.z-child-row td:first-child{border-left:.125rem solid var(--primary)!important;padding-left:.75rem!important}tbody tr.z-context-menu-active,tbody tr.z-context-menu-active td{background-color:var(--muted)!important}tbody tr.z-selected,tbody tr.z-selected td{background-color:color-mix(in srgb,var(--primary) 15%,var(--background))!important}tbody tr.z-selected:hover,tbody tr.z-selected:hover td{background-color:color-mix(in srgb,var(--primary) 20%,var(--background))!important}tbody tr.z-indeterminate-selected,tbody tr.z-indeterminate-selected td{background-color:color-mix(in srgb,var(--primary) 10%,var(--background))!important}tbody tr.z-indeterminate-selected:hover,tbody tr.z-indeterminate-selected:hover td{background-color:color-mix(in srgb,var(--primary) 15%,var(--background))!important}tbody tr.z-pinned-top td{background-color:var(--card)!important}tbody tr.z-pinned-top:hover{background-color:var(--muted)}tbody tr.z-pinned-top:hover td{background-color:var(--muted)!important}tbody tr.z-pinned-bottom td{background-color:var(--card)!important}tbody tr.z-pinned-bottom:hover{background-color:var(--muted)}tbody tr.z-pinned-bottom:hover td{background-color:var(--muted)!important}tbody tr.z-pinned-bottom-last>td{border-bottom-color:transparent!important}tbody tr.z-pinned-bottom-first>td{border-top:thin solid var(--border)}:host .z-tbody-wrapper tbody tr:not(.z-pinned-top):not(.z-pinned-bottom):has(+tr.z-pinned-bottom)>td{border-bottom-color:transparent}tr.z-expanded-row>td{border-left:.125rem solid var(--primary);background-color:var(--background)!important}.z-expanded-row-content{transform-origin:top center}@keyframes z-expanded-row-reveal{0%{clip-path:inset(0 0 100% 0);translate:0 -.375rem;opacity:0}to{clip-path:inset(0 0 0 0);translate:none;opacity:1}}@keyframes z-expanded-row-fade-in{0%{opacity:0}to{opacity:1}}tr.z-expanded-row-enter{animation:z-expanded-row-fade-in .18s ease-out}tr.z-expanded-row-enter .z-expanded-row-content{animation:z-expanded-row-reveal .18s ease-out}@keyframes z-child-row-slide-in{0%{translate:0 -.375rem;opacity:0}to{translate:none;opacity:1}}tr.z-child-row.z-row-enter,tr.z-group-child-row.z-row-enter{animation:z-child-row-slide-in .18s ease-out}@media(prefers-reduced-motion:reduce){tr.z-expanded-row-enter,tr.z-child-row.z-row-enter,tr.z-group-child-row.z-row-enter,tr.z-expanded-row-enter .z-expanded-row-content,tr.z-child-row.z-row-enter .z-expanded-row-content,tr.z-group-child-row.z-row-enter .z-expanded-row-content{animation-duration:1ms}}.z-sub-table-container{padding:.75rem 1rem .75rem 3rem;background-color:var(--background)}.z-table-content-trigger{display:block;width:100%;min-width:0;min-height:1.5rem;padding:0;border:0;border-radius:0;background:transparent;color:inherit;font:inherit;line-height:1.5rem;text-align:inherit;outline:0;cursor:text}.z-table-content-trigger:hover{color:var(--primary)}.z-content-edit-active{position:relative;z-index:2}td:has(>.z-table-content-trigger:focus-visible){position:relative;z-index:2}td:has(>.z-table-content-trigger:focus-visible):after{position:absolute;z-index:3;inset:0;border:1px solid var(--primary);content:\"\";pointer-events:none}td.z-cell-selectable{-webkit-user-select:none;user-select:none}td.z-cell-range-selected{position:relative;isolation:isolate}td.z-cell-range-selected:before{position:absolute;z-index:0;box-sizing:border-box;top:var(--z-cell-range-top, 0);right:var(--z-cell-range-right, 0);bottom:var(--z-cell-range-bottom, 0);left:var(--z-cell-range-left, 0);background-color:var(--z-cell-selection-background);content:\"\";pointer-events:none}td.z-cell-range-selected>*{position:relative;z-index:1}td.z-cell-range-top:before{border-top:1px solid var(--primary)}td.z-cell-range-right:before{border-right:1px solid var(--primary)}td.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}td.z-cell-range-left:before{border-left:1px solid var(--primary)}td.z-cell-active{position:relative;z-index:3;background-color:var(--z-cell-selection-background)!important}td.z-cell-active:after{position:absolute;z-index:4;inset:0;border:1px solid var(--primary);content:\"\";pointer-events:none}td.z-content-edit-active{-webkit-user-select:text;user-select:text}td.z-cell-active.z-row-hover,td.z-content-edit-active.z-row-hover{background-color:var(--card)!important}thead th{position:relative}thead th .z-resizer{position:absolute;right:0;top:0;height:100%;width:.5rem;background:transparent;cursor:col-resize;-webkit-user-select:none;user-select:none;touch-action:none;z-index:5}thead th .z-resizer:after{content:\"\";position:absolute;right:0;top:0;height:100%;width:.1875rem;background:#0000001a;opacity:0;transition:opacity .2s ease}thead th .z-resizer:after:where(.dark,.dark *){background:#ffffff1a}thead th .z-resizer:hover:after{opacity:1;background:var(--primary);width:.1875rem}thead th .z-resizer.z-is-resizing:after{opacity:1;background:var(--primary);width:.1875rem}thead th .z-resizer.z-resizer-left{right:auto;left:0}thead th .z-resizer.z-resizer-left:after{right:auto;left:0}.z-thead-wrapper th.z-sticky-left,.z-thead-wrapper th.z-sticky-right,.z-tbody-wrapper th.z-sticky-left,.z-tbody-wrapper th.z-sticky-right,.z-tfoot-wrapper th.z-sticky-left,.z-tfoot-wrapper th.z-sticky-right{background-color:var(--muted);z-index:1;transform:translateZ(0);backface-visibility:hidden}.z-thead-wrapper td.z-sticky-left,.z-thead-wrapper td.z-sticky-right,.z-tbody-wrapper td.z-sticky-left,.z-tbody-wrapper td.z-sticky-right,.z-tfoot-wrapper td.z-sticky-left,.z-tfoot-wrapper td.z-sticky-right{background-color:var(--card);z-index:1;transform:translateZ(0);backface-visibility:hidden}.z-thead-wrapper th.z-sticky-left-last,.z-thead-wrapper td.z-sticky-left-last,.z-tbody-wrapper th.z-sticky-left-last,.z-tbody-wrapper td.z-sticky-left-last,.z-tfoot-wrapper th.z-sticky-left-last,.z-tfoot-wrapper td.z-sticky-left-last{position:relative;overflow:visible;border-right:thin solid var(--z-sticky-left-border-color)}.z-thead-wrapper th.z-sticky-left-last:after,.z-thead-wrapper td.z-sticky-left-last:after,.z-tbody-wrapper th.z-sticky-left-last:after,.z-tbody-wrapper td.z-sticky-left-last:after,.z-tfoot-wrapper th.z-sticky-left-last:after,.z-tfoot-wrapper td.z-sticky-left-last:after{content:\"\";position:absolute;top:0;bottom:0;right:var(--z-shadow-left-right);width:var(--z-shadow-left-width);pointer-events:none;box-shadow:inset 10px 0 8px -8px #0000001a;z-index:10;opacity:var(--z-shadow-left-opacity)}:host-context(.dark) .z-thead-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-thead-wrapper td.z-sticky-left-last:after,:host-context(.dark) .z-tbody-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-tbody-wrapper td.z-sticky-left-last:after,:host-context(.dark) .z-tfoot-wrapper th.z-sticky-left-last:after,:host-context(.dark) .z-tfoot-wrapper td.z-sticky-left-last:after{box-shadow:inset 10px 0 10px -8px #0000004d}.z-thead-wrapper.z-scroll-left,.z-tbody-wrapper.z-scroll-left,.z-tfoot-wrapper.z-scroll-left{--z-shadow-left-opacity: 1}.z-thead-wrapper.z-scroll-left:where(.dark,.dark *),.z-tbody-wrapper.z-scroll-left:where(.dark,.dark *),.z-tfoot-wrapper.z-scroll-left:where(.dark,.dark *){--z-sticky-left-border-color: var(--border)}.z-thead-wrapper th.z-sticky-right-first,.z-thead-wrapper td.z-sticky-right-first,.z-tbody-wrapper th.z-sticky-right-first,.z-tbody-wrapper td.z-sticky-right-first,.z-tfoot-wrapper th.z-sticky-right-first,.z-tfoot-wrapper td.z-sticky-right-first{position:relative;overflow:visible;border-left:thin solid var(--z-sticky-right-border-color)}.z-thead-wrapper th.z-sticky-right-first:before,.z-thead-wrapper td.z-sticky-right-first:before,.z-tbody-wrapper th.z-sticky-right-first:before,.z-tbody-wrapper td.z-sticky-right-first:before,.z-tfoot-wrapper th.z-sticky-right-first:before,.z-tfoot-wrapper td.z-sticky-right-first:before{content:\"\";position:absolute;top:0;bottom:0;left:var(--z-shadow-right-left);width:var(--z-shadow-right-width);pointer-events:none;box-shadow:inset -10px 0 8px -8px #0000001a;z-index:10;opacity:var(--z-shadow-right-opacity)}:host-context(.dark) .z-thead-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-thead-wrapper td.z-sticky-right-first:before,:host-context(.dark) .z-tbody-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-tbody-wrapper td.z-sticky-right-first:before,:host-context(.dark) .z-tfoot-wrapper th.z-sticky-right-first:before,:host-context(.dark) .z-tfoot-wrapper td.z-sticky-right-first:before{box-shadow:inset -10px 0 10px -8px #0000004d}.z-thead-wrapper.z-scroll-right,.z-tbody-wrapper.z-scroll-right,.z-tfoot-wrapper.z-scroll-right{--z-shadow-right-opacity: 1}.z-thead-wrapper.z-scroll-right:not(:where(.dark,.dark *)),.z-tbody-wrapper.z-scroll-right:not(:where(.dark,.dark *)),.z-tfoot-wrapper.z-scroll-right:not(:where(.dark,.dark *)){--z-sticky-right-border-color: transparent}.z-pinning-overflow{--z-shadow-left-opacity: 0 !important;--z-shadow-right-opacity: 0 !important;--z-sticky-left-border-color: transparent !important;--z-sticky-right-border-color: transparent !important}.z-pinning-overflow .z-sticky-left,.z-pinning-overflow .z-sticky-right{position:relative!important;right:auto!important;left:auto!important}.z-pinning-overflow .z-sticky-left-last:after,.z-pinning-overflow .z-sticky-right-first:before,.z-pinning-overflow .z-sticky-right-last:after{display:none!important}.z-thead-wrapper th.z-sticky-right-last,.z-tfoot-wrapper th.z-sticky-right-last{position:relative}.z-thead-wrapper th.z-sticky-right-last:after,.z-tfoot-wrapper th.z-sticky-right-last:after{content:\"\";position:absolute;top:0;bottom:0;right:-1.875rem;width:1.875rem;background:var(--muted);pointer-events:none}.z-tfoot-wrapper{flex-shrink:0;width:100%;max-width:100%;min-width:0;background:var(--muted);overflow-x:hidden;overflow-y:hidden;touch-action:pan-y pinch-zoom}.z-tfoot-wrapper th{height:auto;padding:.5rem 12px;text-align:left;vertical-align:middle;font-weight:500;font-size:.75rem;color:var(--muted-foreground);text-transform:uppercase;letter-spacing:.5px;background:var(--muted);border-left:thin solid var(--border);border-top:thin solid var(--border)}.z-tfoot-wrapper th.z-at-left-edge{border-left:none}.z-tfoot-wrapper.z-shadow-footer{box-shadow:0 -2px 4px #0000000d;position:relative;z-index:15}.z-tfoot-wrapper.z-shadow-footer:where(.dark,.dark *){box-shadow:0 -2px 4px #0003}.z-pin-btn{padding:.125rem 4px;border-radius:var(--radius-xs);color:var(--muted-foreground);transition:all .15s ease}.z-pin-btn:hover{background-color:var(--muted);color:var(--foreground)}.z-pin-btn.z-pin-btn-active{color:var(--primary);background-color:var(--primary)}.z-pin-btn.z-pin-btn-active:hover{background-color:var(--primary);opacity:.8}.z-row-pin-trigger{opacity:1}.z-row-pin-trigger:focus-visible,.z-row-pin-trigger.z-popover-open{background-color:color-mix(in srgb,var(--foreground) 8%,transparent);color:var(--foreground)}.z-row-pin-trigger:active{background-color:color-mix(in srgb,var(--foreground) 12%,transparent)}.z-row-pin-trigger.text-primary{color:var(--primary)}.z-row-pin-unpin-trigger{color:var(--muted-foreground);outline:none}.z-row-pin-unpin-trigger:hover{color:var(--destructive);background-color:color-mix(in srgb,var(--destructive) 10%,transparent)}.z-row-pin-unpin-trigger:focus,.z-row-pin-unpin-trigger:focus-visible{color:var(--muted-foreground);background-color:transparent;outline:none;box-shadow:none}.z-row-pin-unpin-trigger:active{color:var(--destructive);background-color:color-mix(in srgb,var(--destructive) 14%,transparent)}.z-header-pin-trigger{opacity:1}.z-header-pin-trigger.text-primary{color:var(--primary)}th{overflow:hidden}th .z-header-content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}th .z-header-text-wrapper{transition:background-color .15s ease;border-radius:var(--radius-sm);min-width:0;overflow:hidden;flex-shrink:1}th .z-header-text-wrapper.z-has-options:hover,th .z-header-text-wrapper.z-has-options:focus-visible,th .z-header-text-wrapper.z-has-options.z-popover-open{background-color:color-mix(in srgb,var(--foreground) 8%,transparent);outline:none}th .z-header-text-wrapper.z-has-options:active{background-color:color-mix(in srgb,var(--foreground) 12%,transparent)}.z-column-menu-item{position:relative;z-index:1;line-height:1.25rem;transition:background-color .15s ease,color .15s ease}.z-column-menu-item:focus-visible,.z-column-menu-item.z-popover-open{background-color:var(--muted);outline:none}.z-table-drag-preview{box-sizing:border-box;border-radius:var(--radius-md);background-color:var(--card);border:1px solid var(--primary);box-shadow:0 10px 24px #00000029;overflow:hidden;z-index:10000!important;pointer-events:none}.z-table-drag-preview:where(.dark,.dark *){box-shadow:0 5px 20px #00000080}.z-table-drag-preview-row{border:0;border-radius:var(--radius-xs);background-color:var(--background);box-shadow:0 8px 20px #0000001f,inset 0 0 0 1px color-mix(in srgb,var(--primary) 45%,var(--border))}.z-table-drag-preview-row table,.z-table-drag-preview-row tbody,.z-table-drag-preview-row tr{height:100%}.z-table-drag-preview-row td{vertical-align:middle!important;background-color:var(--background)}.z-table-drag-preview-virtual{border:0;border-radius:0;box-shadow:0 8px 20px #0000001f,inset 0 0 0 1px color-mix(in srgb,var(--primary) 45%,var(--border))}.z-table-drag-source{display:none!important}.z-virtual-row.z-table-drag-source{display:block!important;pointer-events:none;outline:1px solid var(--border);outline-offset:-1px}.z-virtual-row.z-table-drag-source td{color:color-mix(in srgb,var(--foreground) 45%,transparent);border-color:var(--border)!important;background-color:var(--card)!important}.z-virtual-row.z-table-drag-source td>*{opacity:.45}[data-z-table-drag-handle]{touch-action:none;-webkit-user-select:none;user-select:none}.z-column-drop-list{min-height:3.125rem;overscroll-behavior:contain}.cdk-drag-preview.z-drag-preview,.cdk-drag-placeholder.z-drag-item{border-radius:var(--radius-sm)}.z-table-drag-placeholder{width:100%;min-height:2.625rem;box-sizing:border-box;border:2px dashed var(--primary);border-radius:0;background-color:color-mix(in srgb,var(--primary) 10%,var(--background));pointer-events:none}.z-table-drag-placeholder-row>td{padding:0!important;border:0!important;background:transparent!important}.z-table-drag-placeholder-row .z-table-drag-placeholder{border-radius:0;background-color:color-mix(in srgb,var(--primary) 10%,transparent)}.z-table-drag-placeholder-virtual{position:absolute;top:0;left:0;z-index:20;border-radius:0}.z-tbody-wrapper tr.z-group-row td{background:var(--card);border-top:none;border-bottom:1px solid var(--border)}.z-virtual-row:not(.z-virtual-row-flow) tr.z-group-row td{background:var(--card);border-top:none;border-bottom:none}.z-group-row-sticky-wrapper{display:inline-flex;align-items:center;translate:var(--z-scroll-x, 0px) 0}.z-table-container:not(.z-hide-horizontal-border) .z-virtual-row:not(.z-virtual-row-flow):after,.z-table-container:not(.z-hide-horizontal-border) .z-virtual-row-flow.z-virtual-row-group-header:after{content:\"\";position:absolute;right:0;bottom:0;left:0;z-index:3;height:1px;background:var(--border);pointer-events:none}.z-tbody-wrapper tr.z-group-child-row td.z-at-left-edge,.z-virtual-row tr.z-group-child-row td.z-at-left-edge{border-left:2px solid var(--primary)!important;padding-left:var(--z-group-content-indent, .75rem)}.z-group-row-trigger{display:inline-flex;min-height:2rem;max-width:100%;align-items:center;gap:.5rem;padding:.25rem .5rem .25rem .75rem;color:var(--primary);font-size:.8125rem;font-weight:600;vertical-align:middle;cursor:pointer}.z-group-row-remove{margin-left:.125rem;color:var(--muted-foreground);vertical-align:middle}.z-group-row-remove:hover,.z-group-row-remove:focus-visible{color:var(--destructive);background:color-mix(in srgb,var(--destructive) 10%,transparent);outline:none}.z-group-row-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-column-label{color:color-mix(in srgb,var(--primary) 65%,var(--foreground));font-weight:500;margin-right:.25rem}.z-group-row-count{display:inline-flex;min-width:1.25rem;height:1.25rem;align-items:center;justify-content:center;padding:0 .375rem;border-radius:var(--radius-pill);background:var(--primary);color:var(--primary-foreground);font-size:.6875rem;font-weight:600}.z-group-row-loading{display:inline-flex;align-items:center;margin-left:.25rem}.z-group-row-has-totals td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-has-totals .z-group-row-label-cell{position:sticky;left:0;z-index:2;background:var(--card)}.z-group-row-has-totals .z-group-row-label-cell .z-group-row-sticky-wrapper{max-width:100%;translate:none}.z-group-row-total{display:inline-block;max-width:100%;color:var(--foreground);font-size:.8125rem;font-weight:600;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.z-group-row-total-cell{text-align:right}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-selected:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:before{position:absolute!important;z-index:0!important;box-sizing:border-box!important;top:var(--z-cell-range-top, 0)!important;right:var(--z-cell-range-right, 0)!important;bottom:var(--z-cell-range-bottom, 0)!important;left:var(--z-cell-range-left, 0)!important;width:auto!important;background-color:var(--z-cell-selection-background-opaque)!important;box-shadow:none!important;content:\"\"!important;pointer-events:none!important;opacity:1!important}:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:after{display:none!important}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-top:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-top:before{border-top:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-right:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-right:before{border-right:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-bottom:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}:host .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-left:before,:host .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-left:before{border-left:1px solid var(--primary)}:host-context(.z-table-pointer-dragging) .z-tbody-wrapper td.z-sticky-right-first.z-cell-range-selected:before,:host-context(.z-table-pointer-dragging) .z-tbody-wrapper td.z-sticky-left-last.z-cell-range-selected:before{background-color:transparent!important}:host td.z-cell-range-selected:before{position:absolute;z-index:0;box-sizing:border-box;top:var(--z-cell-range-top, 0);right:var(--z-cell-range-right, 0);bottom:var(--z-cell-range-bottom, 0);left:var(--z-cell-range-left, 0);background-color:var(--z-cell-selection-background);box-shadow:none;content:\"\";pointer-events:none;opacity:1}:host td.z-cell-range-top:before{border-top:1px solid var(--primary)}:host td.z-cell-range-right:before{border-right:1px solid var(--primary)}:host td.z-cell-range-bottom:before{border-bottom:1px solid var(--primary)}:host td.z-cell-range-left:before{border-left:1px solid var(--primary)}:host-context(.z-table-pointer-dragging) .z-tbody-wrapper td{pointer-events:none}:host-context(.z-table-pointer-dragging) td.z-row-hover{background-color:var(--background)!important}:host td.z-cell-active,:host td.z-cell-active.z-row-hover{background-color:var(--z-cell-selection-background)!important}:host td.z-content-edit-active.z-row-hover{background-color:var(--card)!important}:host tr.z-pinned-top td.z-cell-active,:host tr.z-pinned-top td.z-cell-active.z-row-hover,:host tr.z-pinned-bottom td.z-cell-active,:host tr.z-pinned-bottom td.z-cell-active.z-row-hover,:host td.z-cell-active.z-sticky-left,:host td.z-cell-active.z-sticky-left.z-row-hover,:host td.z-cell-active.z-sticky-right,:host td.z-cell-active.z-sticky-right.z-row-hover{background-color:var(--z-cell-selection-background-opaque)!important}:host tr.z-pinned-top td.z-cell-range-selected,:host tr.z-pinned-bottom td.z-cell-range-selected,:host td.z-cell-range-selected.z-sticky-left,:host td.z-cell-range-selected.z-sticky-right{background-color:var(--card)}:host tr.z-pinned-top td.z-cell-range-selected:before,:host tr.z-pinned-bottom td.z-cell-range-selected:before,:host td.z-cell-range-selected.z-sticky-left:before,:host td.z-cell-range-selected.z-sticky-right:before{background-color:var(--z-cell-selection-background-opaque)}:host-context(.z-table-pointer-dragging) td.z-cell-range-selected,:host-context(.z-table-pointer-dragging) td.z-cell-range-selected.z-row-hover,:host-context(.z-table-pointer-dragging) td.z-cell-active,:host-context(.z-table-pointer-dragging) td.z-cell-active.z-row-hover{background-color:var(--card)!important}:host-context(.z-table-pointer-dragging) td.z-cell-range-selected:before{background-color:transparent}:host .z-tbody-wrapper tbody tr.z-group-child-row:has(+tr.z-group-row)>td.z-at-bottom{border-bottom-color:var(--border)}:host .z-virtual-row:has(tr.z-group-child-row):has(+.z-virtual-row tr.z-group-row) tr.z-group-child-row>td.z-at-bottom{border-bottom-color:var(--border)}.z-thead-wrapper th.z-virtual-column-spacer,.z-tfoot-wrapper th.z-virtual-column-spacer{box-sizing:border-box;padding:0!important;background:var(--muted);border-left:thin solid var(--border)}.z-thead-wrapper th.z-virtual-header-spacer{border-bottom:thin solid var(--border)}.z-tfoot-wrapper th.z-virtual-footer-spacer{border-top:thin solid var(--border)}.z-tbody-wrapper td.z-virtual-column-spacer{box-sizing:border-box;height:auto;padding:0!important;background:var(--card);border-left:thin solid var(--border);border-bottom:thin solid var(--border)}.z-tbody-wrapper tr:hover td.z-virtual-column-spacer{background-color:var(--muted)}.z-table-settings-drawer input[type=checkbox]{appearance:none;-webkit-appearance:none;-moz-appearance:none;width:1rem;height:1rem;border:thin solid var(--input);border-radius:var(--radius-sm);background-color:var(--background);cursor:pointer;position:relative;transition:all .2s ease}.z-table-settings-drawer input[type=checkbox]:hover{border-color:var(--primary)}.z-table-settings-drawer input[type=checkbox]:checked{background-color:var(--primary);border-color:var(--primary)}.z-table-settings-drawer input[type=checkbox]:checked:after{content:\"\";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:.375rem;height:.625rem;border:solid var(--primary-foreground);border-width:0 .125rem .125rem 0;transform:translate(-50%,-60%) rotate(45deg)}.z-table-settings-drawer input[type=checkbox]:disabled{opacity:.5;cursor:not-allowed}.z-virtual-pinned-top{position:sticky;top:0;left:0;z-index:3;width:100%}.z-virtual-pinned-bottom{position:sticky;bottom:0;left:0;z-index:3;width:100%}\n"] }]
11264
11322
  }], ctorParameters: () => [], propDecorators: { zChange: [{ type: i0.Output, args: ["zChange"] }], zControl: [{ type: i0.Output, args: ["zControl"] }], zClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "zClass", required: false }] }], zConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "zConfig", required: false }] }], zLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "zLoading", required: false }] }], zKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "zKey", required: false }] }], zVariant: [{ type: i0.Input, args: [{ isSignal: true, alias: "zVariant", required: false }] }], theadWrapper: [{ type: i0.ViewChild, args: ['theadWrapper', { isSignal: true }] }], tableContainer: [{ type: i0.ViewChild, args: ['tableContainer', { isSignal: true }] }], tbodyContainer: [{ type: i0.ViewChild, args: ['tbodyContainer', { isSignal: true }] }], tbodyWrapper: [{ type: i0.ViewChild, args: ['tbodyWrapper', { isSignal: true }] }], tbodyScrollbar: [{ type: i0.ViewChild, args: ['tbodyWrapper', { isSignal: true }] }], tfootWrapper: [{ type: i0.ViewChild, args: ['tfootWrapper', { isSignal: true }] }], expandedRowTemplate: [{ type: i0.ViewChild, args: ['expandedRowTemplate', { isSignal: true }] }], virtualRowElements: [{ type: i0.ViewChildren, args: ['virtualRow', { isSignal: true }] }], groupRowElements: [{ type: i0.ViewChildren, args: ['groupRow', { isSignal: true }] }], bulkBarTemplateRef: [{ type: i0.ViewChild, args: ['bulkBarTemplate', { isSignal: true }] }] } });
11265
11323
 
11266
11324
  /**