@akcelik/strct 0.30.0 → 1.0.0

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, DOCUMENT, signal, computed, Injectable, input, ViewEncapsulation, ChangeDetectionStrategy, Component, ElementRef, NgZone, afterNextRender, Directive, model, output, booleanAttribute, HostListener, contentChildren, effect, ApplicationRef, EnvironmentInjector, createComponent, forwardRef, DestroyRef, contentChild, viewChild, viewChildren, TemplateRef, untracked, Renderer2 } from '@angular/core';
2
+ import { inject, DOCUMENT, signal, computed, Injectable, input, ViewEncapsulation, ChangeDetectionStrategy, Component, ElementRef, NgZone, afterNextRender, Directive, model, output, booleanAttribute, HostListener, contentChildren, effect, ApplicationRef, EnvironmentInjector, createComponent, forwardRef, DestroyRef, contentChild, viewChild, viewChildren, untracked, TemplateRef, Renderer2 } from '@angular/core';
3
3
  import { DomSanitizer } from '@angular/platform-browser';
4
4
  import { NgTemplateOutlet, DOCUMENT as DOCUMENT$1 } from '@angular/common';
5
5
  import { RouterLink, RouterLinkActive } from '@angular/router';
@@ -642,7 +642,7 @@ class StrctIcon {
642
642
  </svg>
643
643
  }
644
644
  </span>
645
- }`, isInline: true, styles: [".strct-icon{position:relative;display:inline-flex;align-items:center;justify-content:center;line-height:0}.strct-icon__raw{display:inline-flex}.strct-icon__raw>svg{width:100%;height:100%;display:block}.strct-icon__badge{position:absolute;right:-3px;bottom:-3px;width:50%;height:50%;min-width:8px;min-height:8px;max-width:12px;max-height:12px;border-radius:50%;box-shadow:0 0 0 1.5px var(--bg-1)}.strct-icon__badge--success,.strct-icon__badge--critical,.strct-icon__badge--info,.strct-icon__badge--off,.strct-icon__badge--paused,.strct-icon__badge--running{display:flex;align-items:center;justify-content:center;font-size:clamp(6px,68%,10px);font-weight:800;line-height:1;color:var(--inv)}.strct-icon__badge--success{background:var(--success)}.strct-icon__badge--success:before{content:\"\\2713\"}.strct-icon__badge--warning{background:var(--warning);border-radius:1px;clip-path:polygon(50% 10%,92% 90%,8% 90%);box-shadow:none;filter:drop-shadow(0 0 1.5px var(--bg-1));right:-2px;bottom:-2px;width:60%;height:60%;min-width:11px;min-height:11px;max-width:18px;max-height:18px;display:flex;align-items:center;justify-content:center;font-size:clamp(6px,70%,10px);font-weight:800;color:var(--inv);line-height:1}.strct-icon__badge--warning:before{content:\"!\"}.strct-icon__badge--critical{background:var(--critical);border-radius:1px;clip-path:polygon(50% 0%,100% 50%,50% 100%,0% 50%);box-shadow:none;filter:drop-shadow(0 0 1.5px var(--bg-1));width:58%;height:58%;min-width:10px;min-height:10px;max-width:15px;max-height:15px;font-size:clamp(6px,56%,9px)}.strct-icon__badge--critical:before{content:\"\\d7\"}.strct-icon__badge--running{background:var(--success)}.strct-icon__badge--running:before{content:\"\";width:46%;height:46%;min-width:4px;min-height:4px;background:var(--inv);clip-path:polygon(15% 2%,100% 50%,15% 98%);transform:translate(9%)}.strct-icon__badge--paused{background:var(--warning)}.strct-icon__badge--paused:before{content:\"\";width:1.6px;height:42%;min-height:4px;background:var(--inv);box-shadow:2.6px 0 0 var(--inv);transform:translate(-1.3px)}.strct-icon__badge--off{background:var(--t3)}.strct-icon__badge--off:before{content:\"\";width:40%;height:40%;min-width:3.5px;min-height:3.5px;background:var(--inv);border-radius:1px}.strct-icon__badge--info{background:var(--acc)}.strct-icon__badge--info:before{content:\"i\"}.strct-icon__badge--maintenance{background:var(--warning);right:-2px;bottom:-2px;width:58%;height:58%;min-width:10px;min-height:10px;max-width:16px;max-height:16px;display:flex;align-items:center;justify-content:center;padding:1px;box-shadow:0 0 0 1.5px var(--bg-1)}.strct-icon__badge--maintenance svg{width:84%;height:84%;color:var(--inv)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
645
+ }`, isInline: true, styles: [".strct-icon{position:relative;display:inline-flex;align-items:center;justify-content:center;line-height:0}.strct-icon__raw{display:inline-flex}.strct-icon__raw>svg{width:100%;height:100%;display:block}.strct-icon__badge{position:absolute;inset-inline-end:-3px;bottom:-3px;width:50%;height:50%;min-width:8px;min-height:8px;max-width:12px;max-height:12px;border-radius:50%;box-shadow:0 0 0 1.5px var(--bg-1)}.strct-icon__badge--success,.strct-icon__badge--critical,.strct-icon__badge--info,.strct-icon__badge--off,.strct-icon__badge--paused,.strct-icon__badge--running{display:flex;align-items:center;justify-content:center;font-size:clamp(6px,68%,10px);font-weight:800;line-height:1;color:var(--inv)}.strct-icon__badge--success{background:var(--success)}.strct-icon__badge--success:before{content:\"\\2713\"}.strct-icon__badge--warning{background:var(--warning);border-radius:1px;clip-path:polygon(50% 10%,92% 90%,8% 90%);box-shadow:none;filter:drop-shadow(0 0 1.5px var(--bg-1));inset-inline-end:-2px;bottom:-2px;width:60%;height:60%;min-width:11px;min-height:11px;max-width:18px;max-height:18px;display:flex;align-items:center;justify-content:center;font-size:clamp(6px,70%,10px);font-weight:800;color:var(--inv);line-height:1}.strct-icon__badge--warning:before{content:\"!\"}.strct-icon__badge--critical{background:var(--critical);border-radius:1px;clip-path:polygon(50% 0%,100% 50%,50% 100%,0% 50%);box-shadow:none;filter:drop-shadow(0 0 1.5px var(--bg-1));width:58%;height:58%;min-width:10px;min-height:10px;max-width:15px;max-height:15px;font-size:clamp(6px,56%,9px)}.strct-icon__badge--critical:before{content:\"\\d7\"}.strct-icon__badge--running{background:var(--success)}.strct-icon__badge--running:before{content:\"\";width:46%;height:46%;min-width:4px;min-height:4px;background:var(--inv);clip-path:polygon(15% 2%,100% 50%,15% 98%);transform:translate(9%)}.strct-icon__badge--paused{background:var(--warning)}.strct-icon__badge--paused:before{content:\"\";width:1.6px;height:42%;min-height:4px;background:var(--inv);box-shadow:2.6px 0 0 var(--inv);transform:translate(-1.3px)}.strct-icon__badge--off{background:var(--t3)}.strct-icon__badge--off:before{content:\"\";width:40%;height:40%;min-width:3.5px;min-height:3.5px;background:var(--inv);border-radius:1px}.strct-icon__badge--info{background:var(--acc)}.strct-icon__badge--info:before{content:\"i\"}.strct-icon__badge--maintenance{background:var(--warning);inset-inline-end:-2px;bottom:-2px;width:58%;height:58%;min-width:10px;min-height:10px;max-width:16px;max-height:16px;display:flex;align-items:center;justify-content:center;padding:1px;box-shadow:0 0 0 1.5px var(--bg-1)}.strct-icon__badge--maintenance svg{width:84%;height:84%;color:var(--inv)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
646
646
  }
647
647
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctIcon, decorators: [{
648
648
  type: Component,
@@ -686,7 +686,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
686
686
  </svg>
687
687
  }
688
688
  </span>
689
- }`, host: { class: 'strct-icon' }, styles: [".strct-icon{position:relative;display:inline-flex;align-items:center;justify-content:center;line-height:0}.strct-icon__raw{display:inline-flex}.strct-icon__raw>svg{width:100%;height:100%;display:block}.strct-icon__badge{position:absolute;right:-3px;bottom:-3px;width:50%;height:50%;min-width:8px;min-height:8px;max-width:12px;max-height:12px;border-radius:50%;box-shadow:0 0 0 1.5px var(--bg-1)}.strct-icon__badge--success,.strct-icon__badge--critical,.strct-icon__badge--info,.strct-icon__badge--off,.strct-icon__badge--paused,.strct-icon__badge--running{display:flex;align-items:center;justify-content:center;font-size:clamp(6px,68%,10px);font-weight:800;line-height:1;color:var(--inv)}.strct-icon__badge--success{background:var(--success)}.strct-icon__badge--success:before{content:\"\\2713\"}.strct-icon__badge--warning{background:var(--warning);border-radius:1px;clip-path:polygon(50% 10%,92% 90%,8% 90%);box-shadow:none;filter:drop-shadow(0 0 1.5px var(--bg-1));right:-2px;bottom:-2px;width:60%;height:60%;min-width:11px;min-height:11px;max-width:18px;max-height:18px;display:flex;align-items:center;justify-content:center;font-size:clamp(6px,70%,10px);font-weight:800;color:var(--inv);line-height:1}.strct-icon__badge--warning:before{content:\"!\"}.strct-icon__badge--critical{background:var(--critical);border-radius:1px;clip-path:polygon(50% 0%,100% 50%,50% 100%,0% 50%);box-shadow:none;filter:drop-shadow(0 0 1.5px var(--bg-1));width:58%;height:58%;min-width:10px;min-height:10px;max-width:15px;max-height:15px;font-size:clamp(6px,56%,9px)}.strct-icon__badge--critical:before{content:\"\\d7\"}.strct-icon__badge--running{background:var(--success)}.strct-icon__badge--running:before{content:\"\";width:46%;height:46%;min-width:4px;min-height:4px;background:var(--inv);clip-path:polygon(15% 2%,100% 50%,15% 98%);transform:translate(9%)}.strct-icon__badge--paused{background:var(--warning)}.strct-icon__badge--paused:before{content:\"\";width:1.6px;height:42%;min-height:4px;background:var(--inv);box-shadow:2.6px 0 0 var(--inv);transform:translate(-1.3px)}.strct-icon__badge--off{background:var(--t3)}.strct-icon__badge--off:before{content:\"\";width:40%;height:40%;min-width:3.5px;min-height:3.5px;background:var(--inv);border-radius:1px}.strct-icon__badge--info{background:var(--acc)}.strct-icon__badge--info:before{content:\"i\"}.strct-icon__badge--maintenance{background:var(--warning);right:-2px;bottom:-2px;width:58%;height:58%;min-width:10px;min-height:10px;max-width:16px;max-height:16px;display:flex;align-items:center;justify-content:center;padding:1px;box-shadow:0 0 0 1.5px var(--bg-1)}.strct-icon__badge--maintenance svg{width:84%;height:84%;color:var(--inv)}\n"] }]
689
+ }`, host: { class: 'strct-icon' }, styles: [".strct-icon{position:relative;display:inline-flex;align-items:center;justify-content:center;line-height:0}.strct-icon__raw{display:inline-flex}.strct-icon__raw>svg{width:100%;height:100%;display:block}.strct-icon__badge{position:absolute;inset-inline-end:-3px;bottom:-3px;width:50%;height:50%;min-width:8px;min-height:8px;max-width:12px;max-height:12px;border-radius:50%;box-shadow:0 0 0 1.5px var(--bg-1)}.strct-icon__badge--success,.strct-icon__badge--critical,.strct-icon__badge--info,.strct-icon__badge--off,.strct-icon__badge--paused,.strct-icon__badge--running{display:flex;align-items:center;justify-content:center;font-size:clamp(6px,68%,10px);font-weight:800;line-height:1;color:var(--inv)}.strct-icon__badge--success{background:var(--success)}.strct-icon__badge--success:before{content:\"\\2713\"}.strct-icon__badge--warning{background:var(--warning);border-radius:1px;clip-path:polygon(50% 10%,92% 90%,8% 90%);box-shadow:none;filter:drop-shadow(0 0 1.5px var(--bg-1));inset-inline-end:-2px;bottom:-2px;width:60%;height:60%;min-width:11px;min-height:11px;max-width:18px;max-height:18px;display:flex;align-items:center;justify-content:center;font-size:clamp(6px,70%,10px);font-weight:800;color:var(--inv);line-height:1}.strct-icon__badge--warning:before{content:\"!\"}.strct-icon__badge--critical{background:var(--critical);border-radius:1px;clip-path:polygon(50% 0%,100% 50%,50% 100%,0% 50%);box-shadow:none;filter:drop-shadow(0 0 1.5px var(--bg-1));width:58%;height:58%;min-width:10px;min-height:10px;max-width:15px;max-height:15px;font-size:clamp(6px,56%,9px)}.strct-icon__badge--critical:before{content:\"\\d7\"}.strct-icon__badge--running{background:var(--success)}.strct-icon__badge--running:before{content:\"\";width:46%;height:46%;min-width:4px;min-height:4px;background:var(--inv);clip-path:polygon(15% 2%,100% 50%,15% 98%);transform:translate(9%)}.strct-icon__badge--paused{background:var(--warning)}.strct-icon__badge--paused:before{content:\"\";width:1.6px;height:42%;min-height:4px;background:var(--inv);box-shadow:2.6px 0 0 var(--inv);transform:translate(-1.3px)}.strct-icon__badge--off{background:var(--t3)}.strct-icon__badge--off:before{content:\"\";width:40%;height:40%;min-width:3.5px;min-height:3.5px;background:var(--inv);border-radius:1px}.strct-icon__badge--info{background:var(--acc)}.strct-icon__badge--info:before{content:\"i\"}.strct-icon__badge--maintenance{background:var(--warning);inset-inline-end:-2px;bottom:-2px;width:58%;height:58%;min-width:10px;min-height:10px;max-width:16px;max-height:16px;display:flex;align-items:center;justify-content:center;padding:1px;box-shadow:0 0 0 1.5px var(--bg-1)}.strct-icon__badge--maintenance svg{width:84%;height:84%;color:var(--inv)}\n"] }]
690
690
  }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], strokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeWidth", required: false }] }], badge: [{ type: i0.Input, args: [{ isSignal: true, alias: "badge", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
691
691
 
692
692
  /** Palette dots + light/dark pill, wired to {@link StrctThemeService}. */
@@ -966,7 +966,7 @@ class StrctVerticalNav {
966
966
  ></div>
967
967
  }
968
968
  <ng-content />
969
- `, isInline: true, styles: [".strct-vnav{display:flex;flex-direction:column;width:264px;flex-shrink:0;background:var(--bg-1);border-inline-end:1px solid var(--b2);overflow:hidden}@media(max-width:768px){.strct-vnav{position:fixed;top:0;left:0;bottom:0;z-index:300;transform:translate(-100%);transition:transform .2s ease}.strct-vnav--open{transform:translate(0)}.strct-vnav__backdrop{position:fixed;inset:0;z-index:299;background:#00000080;animation:strct-vnav-backdrop-in .2s ease}}@media(min-width:769px){.strct-vnav__backdrop{display:none}}@keyframes strct-vnav-backdrop-in{0%{opacity:0}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
969
+ `, isInline: true, styles: [".strct-vnav{display:flex;flex-direction:column;width:264px;flex-shrink:0;background:var(--bg-1);border-inline-end:1px solid var(--b2);overflow:hidden}@media(max-width:768px){.strct-vnav{position:fixed;top:0;inset-inline-start:0;bottom:0;z-index:300;transform:translate(-100%);transition:transform .2s ease}[dir=rtl] .strct-vnav{transform:translate(100%)}.strct-vnav--open,[dir=rtl] .strct-vnav--open{transform:translate(0)}.strct-vnav__backdrop{position:fixed;inset:0;z-index:299;background:#00000080;animation:strct-vnav-backdrop-in .2s ease}}@media(min-width:769px){.strct-vnav__backdrop{display:none}}@keyframes strct-vnav-backdrop-in{0%{opacity:0}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
970
970
  }
971
971
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctVerticalNav, decorators: [{
972
972
  type: Component,
@@ -986,7 +986,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
986
986
  `, host: {
987
987
  class: 'strct-vnav',
988
988
  '[class.strct-vnav--open]': 'shell.mobileNavOpen()',
989
- }, styles: [".strct-vnav{display:flex;flex-direction:column;width:264px;flex-shrink:0;background:var(--bg-1);border-inline-end:1px solid var(--b2);overflow:hidden}@media(max-width:768px){.strct-vnav{position:fixed;top:0;left:0;bottom:0;z-index:300;transform:translate(-100%);transition:transform .2s ease}.strct-vnav--open{transform:translate(0)}.strct-vnav__backdrop{position:fixed;inset:0;z-index:299;background:#00000080;animation:strct-vnav-backdrop-in .2s ease}}@media(min-width:769px){.strct-vnav__backdrop{display:none}}@keyframes strct-vnav-backdrop-in{0%{opacity:0}}\n"] }]
989
+ }, styles: [".strct-vnav{display:flex;flex-direction:column;width:264px;flex-shrink:0;background:var(--bg-1);border-inline-end:1px solid var(--b2);overflow:hidden}@media(max-width:768px){.strct-vnav{position:fixed;top:0;inset-inline-start:0;bottom:0;z-index:300;transform:translate(-100%);transition:transform .2s ease}[dir=rtl] .strct-vnav{transform:translate(100%)}.strct-vnav--open,[dir=rtl] .strct-vnav--open{transform:translate(0)}.strct-vnav__backdrop{position:fixed;inset:0;z-index:299;background:#00000080;animation:strct-vnav-backdrop-in .2s ease}}@media(min-width:769px){.strct-vnav__backdrop{display:none}}@keyframes strct-vnav-backdrop-in{0%{opacity:0}}\n"] }]
990
990
  }] });
991
991
  /** Horizontal strip of icon tabs (e.g. section switcher at the top of a sidebar). */
992
992
  class StrctNav {
@@ -1167,7 +1167,7 @@ class StrctRail {
1167
1167
  }
1168
1168
  </button>
1169
1169
  }
1170
- `, isInline: true, styles: [".strct-rail{display:flex;flex-direction:column;width:232px;flex-shrink:0;background:var(--bg-1);border-inline-end:1px solid var(--b2);overflow:hidden;transition:width .16s ease}.strct-rail--collapsed{width:60px}.strct-rail__nav{flex:1;min-height:0;display:flex;flex-direction:column;padding:8px}.strct-rail__group{display:flex;flex-direction:column;gap:2px}.strct-rail__group--top{flex:1;min-height:0;overflow-y:auto}.strct-rail__group--bottom{margin-top:8px;padding-top:8px;border-top:1px solid var(--b1)}.strct-rail__item{position:relative;display:flex;align-items:center;gap:11px;width:100%;box-sizing:border-box;padding:8px 10px;border:0;border-radius:8px;background:transparent;color:var(--t2);cursor:pointer;font-size:13.5px;font-family:var(--font);text-align:start;text-decoration:none;white-space:nowrap;transition:background .14s ease,color .14s ease}.strct-rail--collapsed .strct-rail__item{justify-content:center;padding:8px}.strct-rail__item:hover:not(:disabled){background:var(--bg-3);color:var(--t1)}.strct-rail__item--active{background:var(--acc-m);color:var(--acc)}.strct-rail__item--active .strct-rail__icon{color:var(--acc)}.strct-rail__item:disabled{opacity:.5;cursor:not-allowed}.strct-rail__item:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-rail__icon{flex-shrink:0}.strct-rail__label{flex:1;overflow:hidden;text-overflow:ellipsis}.strct-rail__badge{flex-shrink:0;min-width:18px;height:18px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;line-height:1;border-radius:9px;font-variant-numeric:tabular-nums}.strct-rail__badge--dot{position:absolute;top:5px;right:7px;min-width:8px;width:8px;height:8px;padding:0;border-radius:50%}.strct-rail__badge--accent{background:var(--acc-m);color:var(--acc)}.strct-rail__badge--success{background:var(--success-bg);color:var(--success)}.strct-rail__badge--warning{background:var(--warning-bg);color:var(--warning)}.strct-rail__badge--critical{background:var(--critical-bg);color:var(--critical)}.strct-rail__badge--dot.strct-rail__badge--accent{background:var(--acc)}.strct-rail__badge--dot.strct-rail__badge--success{background:var(--success)}.strct-rail__badge--dot.strct-rail__badge--warning{background:var(--warning)}.strct-rail__badge--dot.strct-rail__badge--critical{background:var(--critical)}.strct-rail__trailing{flex-shrink:0;color:var(--t3)}.strct-rail__dot{flex-shrink:0;width:7px;height:7px;border-radius:50%}.strct-rail--collapsed .strct-rail__dot{position:absolute;top:5px;right:7px}.strct-rail__dot--accent{background:var(--acc)}.strct-rail__dot--success{background:var(--success)}.strct-rail__dot--warning{background:var(--warning)}.strct-rail__dot--critical{background:var(--critical)}.strct-rail__toggle{display:flex;align-items:center;gap:10px;padding:9px 14px;border:0;border-top:1px solid var(--b1);background:transparent;color:var(--t3);cursor:pointer;font-size:12.5px;font-family:var(--font)}.strct-rail--collapsed .strct-rail__toggle{justify-content:center;padding:9px}.strct-rail__toggle:hover{color:var(--t1);background:var(--bg-3)}.strct-rail__toggle-icon{transition:transform .16s ease}.strct-rail:not(.strct-rail--collapsed) .strct-rail__toggle-icon{transform:rotate(180deg)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "size", "strokeWidth", "badge", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1170
+ `, isInline: true, styles: [".strct-rail{display:flex;flex-direction:column;width:232px;flex-shrink:0;background:var(--bg-1);border-inline-end:1px solid var(--b2);overflow:hidden;transition:width .16s ease}.strct-rail--collapsed{width:60px}.strct-rail__nav{flex:1;min-height:0;display:flex;flex-direction:column;padding:8px}.strct-rail__group{display:flex;flex-direction:column;gap:2px}.strct-rail__group--top{flex:1;min-height:0;overflow-y:auto}.strct-rail__group--bottom{margin-top:8px;padding-top:8px;border-top:1px solid var(--b1)}.strct-rail__item{position:relative;display:flex;align-items:center;gap:11px;width:100%;box-sizing:border-box;padding:8px 10px;border:0;border-radius:8px;background:transparent;color:var(--t2);cursor:pointer;font-size:13.5px;font-family:var(--font);text-align:start;text-decoration:none;white-space:nowrap;transition:background .14s ease,color .14s ease}.strct-rail--collapsed .strct-rail__item{justify-content:center;padding:8px}.strct-rail__item:hover:not(:disabled){background:var(--bg-3);color:var(--t1)}.strct-rail__item--active{background:var(--acc-m);color:var(--acc)}.strct-rail__item--active .strct-rail__icon{color:var(--acc)}.strct-rail__item:disabled{opacity:.5;cursor:not-allowed}.strct-rail__item:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-rail__icon{flex-shrink:0}.strct-rail__label{flex:1;overflow:hidden;text-overflow:ellipsis}.strct-rail__badge{flex-shrink:0;min-width:18px;height:18px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;line-height:1;border-radius:9px;font-variant-numeric:tabular-nums}.strct-rail__badge--dot{position:absolute;top:5px;inset-inline-end:7px;min-width:8px;width:8px;height:8px;padding:0;border-radius:50%}.strct-rail__badge--accent{background:var(--acc-m);color:var(--acc)}.strct-rail__badge--success{background:var(--success-bg);color:var(--success)}.strct-rail__badge--warning{background:var(--warning-bg);color:var(--warning)}.strct-rail__badge--critical{background:var(--critical-bg);color:var(--critical)}.strct-rail__badge--dot.strct-rail__badge--accent{background:var(--acc)}.strct-rail__badge--dot.strct-rail__badge--success{background:var(--success)}.strct-rail__badge--dot.strct-rail__badge--warning{background:var(--warning)}.strct-rail__badge--dot.strct-rail__badge--critical{background:var(--critical)}.strct-rail__trailing{flex-shrink:0;color:var(--t3)}.strct-rail__dot{flex-shrink:0;width:7px;height:7px;border-radius:50%}.strct-rail--collapsed .strct-rail__dot{position:absolute;top:5px;inset-inline-end:7px}.strct-rail__dot--accent{background:var(--acc)}.strct-rail__dot--success{background:var(--success)}.strct-rail__dot--warning{background:var(--warning)}.strct-rail__dot--critical{background:var(--critical)}.strct-rail__toggle{display:flex;align-items:center;gap:10px;padding:9px 14px;border:0;border-top:1px solid var(--b1);background:transparent;color:var(--t3);cursor:pointer;font-size:12.5px;font-family:var(--font)}.strct-rail--collapsed .strct-rail__toggle{justify-content:center;padding:9px}.strct-rail__toggle:hover{color:var(--t1);background:var(--bg-3)}.strct-rail__toggle-icon{transition:transform .16s ease}.strct-rail:not(.strct-rail--collapsed) .strct-rail__toggle-icon{transform:rotate(180deg)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "size", "strokeWidth", "badge", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1171
1171
  }
1172
1172
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctRail, decorators: [{
1173
1173
  type: Component,
@@ -1273,7 +1273,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
1273
1273
  `, host: {
1274
1274
  class: 'strct-rail',
1275
1275
  '[class.strct-rail--collapsed]': 'collapsed()',
1276
- }, styles: [".strct-rail{display:flex;flex-direction:column;width:232px;flex-shrink:0;background:var(--bg-1);border-inline-end:1px solid var(--b2);overflow:hidden;transition:width .16s ease}.strct-rail--collapsed{width:60px}.strct-rail__nav{flex:1;min-height:0;display:flex;flex-direction:column;padding:8px}.strct-rail__group{display:flex;flex-direction:column;gap:2px}.strct-rail__group--top{flex:1;min-height:0;overflow-y:auto}.strct-rail__group--bottom{margin-top:8px;padding-top:8px;border-top:1px solid var(--b1)}.strct-rail__item{position:relative;display:flex;align-items:center;gap:11px;width:100%;box-sizing:border-box;padding:8px 10px;border:0;border-radius:8px;background:transparent;color:var(--t2);cursor:pointer;font-size:13.5px;font-family:var(--font);text-align:start;text-decoration:none;white-space:nowrap;transition:background .14s ease,color .14s ease}.strct-rail--collapsed .strct-rail__item{justify-content:center;padding:8px}.strct-rail__item:hover:not(:disabled){background:var(--bg-3);color:var(--t1)}.strct-rail__item--active{background:var(--acc-m);color:var(--acc)}.strct-rail__item--active .strct-rail__icon{color:var(--acc)}.strct-rail__item:disabled{opacity:.5;cursor:not-allowed}.strct-rail__item:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-rail__icon{flex-shrink:0}.strct-rail__label{flex:1;overflow:hidden;text-overflow:ellipsis}.strct-rail__badge{flex-shrink:0;min-width:18px;height:18px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;line-height:1;border-radius:9px;font-variant-numeric:tabular-nums}.strct-rail__badge--dot{position:absolute;top:5px;right:7px;min-width:8px;width:8px;height:8px;padding:0;border-radius:50%}.strct-rail__badge--accent{background:var(--acc-m);color:var(--acc)}.strct-rail__badge--success{background:var(--success-bg);color:var(--success)}.strct-rail__badge--warning{background:var(--warning-bg);color:var(--warning)}.strct-rail__badge--critical{background:var(--critical-bg);color:var(--critical)}.strct-rail__badge--dot.strct-rail__badge--accent{background:var(--acc)}.strct-rail__badge--dot.strct-rail__badge--success{background:var(--success)}.strct-rail__badge--dot.strct-rail__badge--warning{background:var(--warning)}.strct-rail__badge--dot.strct-rail__badge--critical{background:var(--critical)}.strct-rail__trailing{flex-shrink:0;color:var(--t3)}.strct-rail__dot{flex-shrink:0;width:7px;height:7px;border-radius:50%}.strct-rail--collapsed .strct-rail__dot{position:absolute;top:5px;right:7px}.strct-rail__dot--accent{background:var(--acc)}.strct-rail__dot--success{background:var(--success)}.strct-rail__dot--warning{background:var(--warning)}.strct-rail__dot--critical{background:var(--critical)}.strct-rail__toggle{display:flex;align-items:center;gap:10px;padding:9px 14px;border:0;border-top:1px solid var(--b1);background:transparent;color:var(--t3);cursor:pointer;font-size:12.5px;font-family:var(--font)}.strct-rail--collapsed .strct-rail__toggle{justify-content:center;padding:9px}.strct-rail__toggle:hover{color:var(--t1);background:var(--bg-3)}.strct-rail__toggle-icon{transition:transform .16s ease}.strct-rail:not(.strct-rail--collapsed) .strct-rail__toggle-icon{transform:rotate(180deg)}\n"] }]
1276
+ }, styles: [".strct-rail{display:flex;flex-direction:column;width:232px;flex-shrink:0;background:var(--bg-1);border-inline-end:1px solid var(--b2);overflow:hidden;transition:width .16s ease}.strct-rail--collapsed{width:60px}.strct-rail__nav{flex:1;min-height:0;display:flex;flex-direction:column;padding:8px}.strct-rail__group{display:flex;flex-direction:column;gap:2px}.strct-rail__group--top{flex:1;min-height:0;overflow-y:auto}.strct-rail__group--bottom{margin-top:8px;padding-top:8px;border-top:1px solid var(--b1)}.strct-rail__item{position:relative;display:flex;align-items:center;gap:11px;width:100%;box-sizing:border-box;padding:8px 10px;border:0;border-radius:8px;background:transparent;color:var(--t2);cursor:pointer;font-size:13.5px;font-family:var(--font);text-align:start;text-decoration:none;white-space:nowrap;transition:background .14s ease,color .14s ease}.strct-rail--collapsed .strct-rail__item{justify-content:center;padding:8px}.strct-rail__item:hover:not(:disabled){background:var(--bg-3);color:var(--t1)}.strct-rail__item--active{background:var(--acc-m);color:var(--acc)}.strct-rail__item--active .strct-rail__icon{color:var(--acc)}.strct-rail__item:disabled{opacity:.5;cursor:not-allowed}.strct-rail__item:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-rail__icon{flex-shrink:0}.strct-rail__label{flex:1;overflow:hidden;text-overflow:ellipsis}.strct-rail__badge{flex-shrink:0;min-width:18px;height:18px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;line-height:1;border-radius:9px;font-variant-numeric:tabular-nums}.strct-rail__badge--dot{position:absolute;top:5px;inset-inline-end:7px;min-width:8px;width:8px;height:8px;padding:0;border-radius:50%}.strct-rail__badge--accent{background:var(--acc-m);color:var(--acc)}.strct-rail__badge--success{background:var(--success-bg);color:var(--success)}.strct-rail__badge--warning{background:var(--warning-bg);color:var(--warning)}.strct-rail__badge--critical{background:var(--critical-bg);color:var(--critical)}.strct-rail__badge--dot.strct-rail__badge--accent{background:var(--acc)}.strct-rail__badge--dot.strct-rail__badge--success{background:var(--success)}.strct-rail__badge--dot.strct-rail__badge--warning{background:var(--warning)}.strct-rail__badge--dot.strct-rail__badge--critical{background:var(--critical)}.strct-rail__trailing{flex-shrink:0;color:var(--t3)}.strct-rail__dot{flex-shrink:0;width:7px;height:7px;border-radius:50%}.strct-rail--collapsed .strct-rail__dot{position:absolute;top:5px;inset-inline-end:7px}.strct-rail__dot--accent{background:var(--acc)}.strct-rail__dot--success{background:var(--success)}.strct-rail__dot--warning{background:var(--warning)}.strct-rail__dot--critical{background:var(--critical)}.strct-rail__toggle{display:flex;align-items:center;gap:10px;padding:9px 14px;border:0;border-top:1px solid var(--b1);background:transparent;color:var(--t3);cursor:pointer;font-size:12.5px;font-family:var(--font)}.strct-rail--collapsed .strct-rail__toggle{justify-content:center;padding:9px}.strct-rail__toggle:hover{color:var(--t1);background:var(--bg-3)}.strct-rail__toggle-icon{transition:transform .16s ease}.strct-rail:not(.strct-rail--collapsed) .strct-rail__toggle-icon{transform:rotate(180deg)}\n"] }]
1277
1277
  }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], activeId: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeId", required: false }] }, { type: i0.Output, args: ["activeIdChange"] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], select: [{ type: i0.Output, args: ["select"] }] } });
1278
1278
 
1279
1279
  /**
@@ -3206,7 +3206,7 @@ class StrctDrawer {
3206
3206
  }
3207
3207
  </aside>
3208
3208
  }
3209
- `, isInline: true, styles: [".strct-drawer__backdrop{position:fixed;inset:0;z-index:1100;background:#00000070;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px);animation:strct-drawer-fade .16s ease}.strct-drawer__backdrop--bare{background:transparent;-webkit-backdrop-filter:none;backdrop-filter:none}.strct-drawer{position:fixed;z-index:1101;display:flex;flex-direction:column;background:var(--bg-1);box-shadow:var(--shh)}.strct-drawer--start,.strct-drawer--end{top:0;bottom:0;border-radius:0}.strct-drawer--start{left:0;border-inline-end:1px solid var(--b2);animation:strct-drawer-in-start .18s ease}.strct-drawer--end{right:0;border-inline-start:1px solid var(--b2);animation:strct-drawer-in-end .18s ease}.strct-drawer--top,.strct-drawer--bottom{left:0;right:0}.strct-drawer--top{top:0;border-bottom:1px solid var(--b2);animation:strct-drawer-in-top .18s ease}.strct-drawer--bottom{bottom:0;border-top:1px solid var(--b2);animation:strct-drawer-in-bottom .18s ease}.strct-drawer--start.strct-drawer--sm,.strct-drawer--end.strct-drawer--sm{width:300px}.strct-drawer--start.strct-drawer--md,.strct-drawer--end.strct-drawer--md{width:420px}.strct-drawer--start.strct-drawer--lg,.strct-drawer--end.strct-drawer--lg{width:600px}.strct-drawer--top.strct-drawer--sm,.strct-drawer--bottom.strct-drawer--sm{height:220px}.strct-drawer--top.strct-drawer--md,.strct-drawer--bottom.strct-drawer--md{height:340px}.strct-drawer--top.strct-drawer--lg,.strct-drawer--bottom.strct-drawer--lg{height:480px}.strct-drawer{max-width:100vw;max-height:100vh}.strct-drawer__head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 18px;border-bottom:1px solid var(--b1);flex-shrink:0}.strct-drawer__title{font-size:15px;font-weight:600;color:var(--t1)}.strct-drawer__close{display:inline-flex;padding:4px;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-drawer__close:hover{color:var(--t1);background:var(--bg-3)}.strct-drawer__body{flex:1;min-height:0;overflow-y:auto;padding:16px 18px;font-size:13px;color:var(--t1)}.strct-drawer__foot{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:12px 18px;border-top:1px solid var(--b1);flex-shrink:0}@keyframes strct-drawer-fade{0%{opacity:0}}@keyframes strct-drawer-in-start{0%{transform:translate(-100%)}}@keyframes strct-drawer-in-end{0%{transform:translate(100%)}}@keyframes strct-drawer-in-top{0%{transform:translateY(-100%)}}@keyframes strct-drawer-in-bottom{0%{transform:translateY(100%)}}@media(prefers-reduced-motion:reduce){.strct-drawer__backdrop,.strct-drawer{animation:none}}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "size", "strokeWidth", "badge", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
3209
+ `, isInline: true, styles: [".strct-drawer__backdrop{position:fixed;inset:0;z-index:1100;background:#00000070;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px);animation:strct-drawer-fade .16s ease}.strct-drawer__backdrop--bare{background:transparent;-webkit-backdrop-filter:none;backdrop-filter:none}.strct-drawer{position:fixed;z-index:1101;display:flex;flex-direction:column;background:var(--bg-1);box-shadow:var(--shh)}.strct-drawer--start,.strct-drawer--end{top:0;bottom:0;border-radius:0}.strct-drawer--start{inset-inline-start:0;border-inline-end:1px solid var(--b2);animation:strct-drawer-in-start .18s ease}.strct-drawer--end{inset-inline-end:0;border-inline-start:1px solid var(--b2);animation:strct-drawer-in-end .18s ease}[dir=rtl] .strct-drawer--start{animation-name:strct-drawer-in-end}[dir=rtl] .strct-drawer--end{animation-name:strct-drawer-in-start}.strct-drawer--top,.strct-drawer--bottom{left:0;right:0}.strct-drawer--top{top:0;border-bottom:1px solid var(--b2);animation:strct-drawer-in-top .18s ease}.strct-drawer--bottom{bottom:0;border-top:1px solid var(--b2);animation:strct-drawer-in-bottom .18s ease}.strct-drawer--start.strct-drawer--sm,.strct-drawer--end.strct-drawer--sm{width:300px}.strct-drawer--start.strct-drawer--md,.strct-drawer--end.strct-drawer--md{width:420px}.strct-drawer--start.strct-drawer--lg,.strct-drawer--end.strct-drawer--lg{width:600px}.strct-drawer--top.strct-drawer--sm,.strct-drawer--bottom.strct-drawer--sm{height:220px}.strct-drawer--top.strct-drawer--md,.strct-drawer--bottom.strct-drawer--md{height:340px}.strct-drawer--top.strct-drawer--lg,.strct-drawer--bottom.strct-drawer--lg{height:480px}.strct-drawer{max-width:100vw;max-height:100vh}.strct-drawer__head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 18px;border-bottom:1px solid var(--b1);flex-shrink:0}.strct-drawer__title{font-size:15px;font-weight:600;color:var(--t1)}.strct-drawer__close{display:inline-flex;padding:4px;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-drawer__close:hover{color:var(--t1);background:var(--bg-3)}.strct-drawer__body{flex:1;min-height:0;overflow-y:auto;padding:16px 18px;font-size:13px;color:var(--t1)}.strct-drawer__foot{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:12px 18px;border-top:1px solid var(--b1);flex-shrink:0}@keyframes strct-drawer-fade{0%{opacity:0}}@keyframes strct-drawer-in-start{0%{transform:translate(-100%)}}@keyframes strct-drawer-in-end{0%{transform:translate(100%)}}@keyframes strct-drawer-in-top{0%{transform:translateY(-100%)}}@keyframes strct-drawer-in-bottom{0%{transform:translateY(100%)}}@media(prefers-reduced-motion:reduce){.strct-drawer__backdrop,.strct-drawer{animation:none}}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "size", "strokeWidth", "badge", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
3210
3210
  }
3211
3211
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctDrawer, decorators: [{
3212
3212
  type: Component,
@@ -3246,7 +3246,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
3246
3246
  }
3247
3247
  </aside>
3248
3248
  }
3249
- `, host: { class: 'strct-drawer-host' }, styles: [".strct-drawer__backdrop{position:fixed;inset:0;z-index:1100;background:#00000070;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px);animation:strct-drawer-fade .16s ease}.strct-drawer__backdrop--bare{background:transparent;-webkit-backdrop-filter:none;backdrop-filter:none}.strct-drawer{position:fixed;z-index:1101;display:flex;flex-direction:column;background:var(--bg-1);box-shadow:var(--shh)}.strct-drawer--start,.strct-drawer--end{top:0;bottom:0;border-radius:0}.strct-drawer--start{left:0;border-inline-end:1px solid var(--b2);animation:strct-drawer-in-start .18s ease}.strct-drawer--end{right:0;border-inline-start:1px solid var(--b2);animation:strct-drawer-in-end .18s ease}.strct-drawer--top,.strct-drawer--bottom{left:0;right:0}.strct-drawer--top{top:0;border-bottom:1px solid var(--b2);animation:strct-drawer-in-top .18s ease}.strct-drawer--bottom{bottom:0;border-top:1px solid var(--b2);animation:strct-drawer-in-bottom .18s ease}.strct-drawer--start.strct-drawer--sm,.strct-drawer--end.strct-drawer--sm{width:300px}.strct-drawer--start.strct-drawer--md,.strct-drawer--end.strct-drawer--md{width:420px}.strct-drawer--start.strct-drawer--lg,.strct-drawer--end.strct-drawer--lg{width:600px}.strct-drawer--top.strct-drawer--sm,.strct-drawer--bottom.strct-drawer--sm{height:220px}.strct-drawer--top.strct-drawer--md,.strct-drawer--bottom.strct-drawer--md{height:340px}.strct-drawer--top.strct-drawer--lg,.strct-drawer--bottom.strct-drawer--lg{height:480px}.strct-drawer{max-width:100vw;max-height:100vh}.strct-drawer__head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 18px;border-bottom:1px solid var(--b1);flex-shrink:0}.strct-drawer__title{font-size:15px;font-weight:600;color:var(--t1)}.strct-drawer__close{display:inline-flex;padding:4px;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-drawer__close:hover{color:var(--t1);background:var(--bg-3)}.strct-drawer__body{flex:1;min-height:0;overflow-y:auto;padding:16px 18px;font-size:13px;color:var(--t1)}.strct-drawer__foot{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:12px 18px;border-top:1px solid var(--b1);flex-shrink:0}@keyframes strct-drawer-fade{0%{opacity:0}}@keyframes strct-drawer-in-start{0%{transform:translate(-100%)}}@keyframes strct-drawer-in-end{0%{transform:translate(100%)}}@keyframes strct-drawer-in-top{0%{transform:translateY(-100%)}}@keyframes strct-drawer-in-bottom{0%{transform:translateY(100%)}}@media(prefers-reduced-motion:reduce){.strct-drawer__backdrop,.strct-drawer{animation:none}}\n"] }]
3249
+ `, host: { class: 'strct-drawer-host' }, styles: [".strct-drawer__backdrop{position:fixed;inset:0;z-index:1100;background:#00000070;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px);animation:strct-drawer-fade .16s ease}.strct-drawer__backdrop--bare{background:transparent;-webkit-backdrop-filter:none;backdrop-filter:none}.strct-drawer{position:fixed;z-index:1101;display:flex;flex-direction:column;background:var(--bg-1);box-shadow:var(--shh)}.strct-drawer--start,.strct-drawer--end{top:0;bottom:0;border-radius:0}.strct-drawer--start{inset-inline-start:0;border-inline-end:1px solid var(--b2);animation:strct-drawer-in-start .18s ease}.strct-drawer--end{inset-inline-end:0;border-inline-start:1px solid var(--b2);animation:strct-drawer-in-end .18s ease}[dir=rtl] .strct-drawer--start{animation-name:strct-drawer-in-end}[dir=rtl] .strct-drawer--end{animation-name:strct-drawer-in-start}.strct-drawer--top,.strct-drawer--bottom{left:0;right:0}.strct-drawer--top{top:0;border-bottom:1px solid var(--b2);animation:strct-drawer-in-top .18s ease}.strct-drawer--bottom{bottom:0;border-top:1px solid var(--b2);animation:strct-drawer-in-bottom .18s ease}.strct-drawer--start.strct-drawer--sm,.strct-drawer--end.strct-drawer--sm{width:300px}.strct-drawer--start.strct-drawer--md,.strct-drawer--end.strct-drawer--md{width:420px}.strct-drawer--start.strct-drawer--lg,.strct-drawer--end.strct-drawer--lg{width:600px}.strct-drawer--top.strct-drawer--sm,.strct-drawer--bottom.strct-drawer--sm{height:220px}.strct-drawer--top.strct-drawer--md,.strct-drawer--bottom.strct-drawer--md{height:340px}.strct-drawer--top.strct-drawer--lg,.strct-drawer--bottom.strct-drawer--lg{height:480px}.strct-drawer{max-width:100vw;max-height:100vh}.strct-drawer__head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 18px;border-bottom:1px solid var(--b1);flex-shrink:0}.strct-drawer__title{font-size:15px;font-weight:600;color:var(--t1)}.strct-drawer__close{display:inline-flex;padding:4px;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-drawer__close:hover{color:var(--t1);background:var(--bg-3)}.strct-drawer__body{flex:1;min-height:0;overflow-y:auto;padding:16px 18px;font-size:13px;color:var(--t1)}.strct-drawer__foot{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:12px 18px;border-top:1px solid var(--b1);flex-shrink:0}@keyframes strct-drawer-fade{0%{opacity:0}}@keyframes strct-drawer-in-start{0%{transform:translate(-100%)}}@keyframes strct-drawer-in-end{0%{transform:translate(100%)}}@keyframes strct-drawer-in-top{0%{transform:translateY(-100%)}}@keyframes strct-drawer-in-bottom{0%{transform:translateY(100%)}}@media(prefers-reduced-motion:reduce){.strct-drawer__backdrop,.strct-drawer{animation:none}}\n"] }]
3250
3250
  }], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], dismissable: [{ type: i0.Input, args: [{ isSignal: true, alias: "dismissable", required: false }] }], footerDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StrctDrawerFooter), { isSignal: true }] }] } });
3251
3251
 
3252
3252
  /**
@@ -4762,7 +4762,7 @@ class StrctToggle {
4762
4762
  <span class="strct-tg__track"><span class="strct-tg__thumb"></span></span>
4763
4763
  <span class="strct-tg__label"><ng-content /></span>
4764
4764
  </label>
4765
- `, isInline: true, styles: [".strct-tg{display:inline-flex;align-items:center;gap:9px;cursor:pointer;font-size:13px;color:var(--t1);-webkit-user-select:none;user-select:none}.strct-tg--disabled{opacity:.5;cursor:not-allowed}.strct-tg__native{position:absolute;opacity:0;width:0;height:0}.strct-tg__track{position:relative;width:34px;height:19px;border-radius:11px;flex-shrink:0;background:var(--bg-3);border:1px solid var(--b3);transition:background .16s ease,border-color .16s ease}.strct-tg__thumb{position:absolute;top:2px;left:2px;width:13px;height:13px;border-radius:50%;background:var(--t2);transition:transform .16s ease,background .16s ease}.strct-tg__native:checked+.strct-tg__track{background:var(--acc);border-color:transparent}.strct-tg__native:checked+.strct-tg__track .strct-tg__thumb{transform:translate(15px);background:var(--inv)}.strct-tg__native:focus-visible+.strct-tg__track{box-shadow:0 0 0 3px var(--acc18)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4765
+ `, isInline: true, styles: [".strct-tg{display:inline-flex;align-items:center;gap:9px;cursor:pointer;font-size:13px;color:var(--t1);-webkit-user-select:none;user-select:none}.strct-tg--disabled{opacity:.5;cursor:not-allowed}.strct-tg__native{position:absolute;opacity:0;width:0;height:0}.strct-tg__track{position:relative;width:34px;height:19px;border-radius:11px;flex-shrink:0;background:var(--bg-3);border:1px solid var(--b3);transition:background .16s ease,border-color .16s ease}.strct-tg__thumb{position:absolute;top:2px;left:2px;width:13px;height:13px;border-radius:50%;background:var(--t2);transition:transform .16s ease,background .16s ease}.strct-tg__native:checked+.strct-tg__track{background:var(--acc);border-color:transparent}.strct-tg__native:checked+.strct-tg__track .strct-tg__thumb{transform:translate(15px);background:var(--inv)}:host-context([dir=\"rtl\"]) .strct-tg__native:checked+.strct-tg__track .strct-tg__thumb{transform:translate(-15px)}.strct-tg__native:focus-visible+.strct-tg__track{box-shadow:0 0 0 3px var(--acc18)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4766
4766
  }
4767
4767
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctToggle, decorators: [{
4768
4768
  type: Component,
@@ -4782,7 +4782,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
4782
4782
  <span class="strct-tg__track"><span class="strct-tg__thumb"></span></span>
4783
4783
  <span class="strct-tg__label"><ng-content /></span>
4784
4784
  </label>
4785
- `, styles: [".strct-tg{display:inline-flex;align-items:center;gap:9px;cursor:pointer;font-size:13px;color:var(--t1);-webkit-user-select:none;user-select:none}.strct-tg--disabled{opacity:.5;cursor:not-allowed}.strct-tg__native{position:absolute;opacity:0;width:0;height:0}.strct-tg__track{position:relative;width:34px;height:19px;border-radius:11px;flex-shrink:0;background:var(--bg-3);border:1px solid var(--b3);transition:background .16s ease,border-color .16s ease}.strct-tg__thumb{position:absolute;top:2px;left:2px;width:13px;height:13px;border-radius:50%;background:var(--t2);transition:transform .16s ease,background .16s ease}.strct-tg__native:checked+.strct-tg__track{background:var(--acc);border-color:transparent}.strct-tg__native:checked+.strct-tg__track .strct-tg__thumb{transform:translate(15px);background:var(--inv)}.strct-tg__native:focus-visible+.strct-tg__track{box-shadow:0 0 0 3px var(--acc18)}\n"] }]
4785
+ `, styles: [".strct-tg{display:inline-flex;align-items:center;gap:9px;cursor:pointer;font-size:13px;color:var(--t1);-webkit-user-select:none;user-select:none}.strct-tg--disabled{opacity:.5;cursor:not-allowed}.strct-tg__native{position:absolute;opacity:0;width:0;height:0}.strct-tg__track{position:relative;width:34px;height:19px;border-radius:11px;flex-shrink:0;background:var(--bg-3);border:1px solid var(--b3);transition:background .16s ease,border-color .16s ease}.strct-tg__thumb{position:absolute;top:2px;left:2px;width:13px;height:13px;border-radius:50%;background:var(--t2);transition:transform .16s ease,background .16s ease}.strct-tg__native:checked+.strct-tg__track{background:var(--acc);border-color:transparent}.strct-tg__native:checked+.strct-tg__track .strct-tg__thumb{transform:translate(15px);background:var(--inv)}:host-context([dir=\"rtl\"]) .strct-tg__native:checked+.strct-tg__track .strct-tg__thumb{transform:translate(-15px)}.strct-tg__native:focus-visible+.strct-tg__track{box-shadow:0 0 0 3px var(--acc18)}\n"] }]
4786
4786
  }], ctorParameters: () => [], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
4787
4787
 
4788
4788
  let groupCounter = 0;
@@ -6413,8 +6413,10 @@ const MONTHS = [
6413
6413
  'December',
6414
6414
  ];
6415
6415
  const DOW = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
6416
+ const DOW_FULL = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
6416
6417
  const pad = (n) => String(n).padStart(2, '0');
6417
6418
  const toIso = (y, m, d) => `${y}-${pad(m + 1)}-${pad(d)}`;
6419
+ let dpUid = 0;
6418
6420
  /**
6419
6421
  * Calendar date picker. Value is an ISO `yyyy-mm-dd` string. CVA-compatible.
6420
6422
  * <strct-datepicker [(ngModel)]="date" />
@@ -6424,6 +6426,8 @@ class StrctDatepicker {
6424
6426
  /** Placeholder text when empty. */
6425
6427
  placeholder = input('Select a date', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
6426
6428
  dow = DOW;
6429
+ dowFull = DOW_FULL;
6430
+ titleId = `strct-dp-title-${++dpUid}`;
6427
6431
  value = signal('', ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
6428
6432
  open = signal(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
6429
6433
  isDisabled = signal(false, ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
@@ -6458,6 +6462,17 @@ class StrctDatepicker {
6458
6462
  };
6459
6463
  });
6460
6464
  }, ...(ngDevMode ? [{ debugName: "cells" }] : /* istanbul ignore next */ []));
6465
+ /** The 42 cells chunked into ARIA grid rows (weeks). */
6466
+ weeks = computed(() => {
6467
+ const all = this.cells();
6468
+ return Array.from({ length: 6 }, (_, w) => all.slice(w * 7, w * 7 + 7));
6469
+ }, ...(ngDevMode ? [{ debugName: "weeks" }] : /* istanbul ignore next */ []));
6470
+ /** Accessible name of one day cell: "Tuesday, March 4, 2026". */
6471
+ cellAria(cell) {
6472
+ const [y, m, d] = cell.iso.split('-').map(Number);
6473
+ const dow = DOW_FULL[new Date(y, m - 1, d).getDay()];
6474
+ return `${dow}, ${MONTHS[m - 1]} ${d}, ${y}`;
6475
+ }
6461
6476
  onChange = () => { };
6462
6477
  onTouched = () => { };
6463
6478
  toggle() {
@@ -6477,10 +6492,26 @@ class StrctDatepicker {
6477
6492
  this.focusedIso.set(iso);
6478
6493
  const [y, m] = iso.split('-').map(Number);
6479
6494
  this.view.set({ y, m: m - 1 });
6480
- this.open.set(false);
6495
+ this.close();
6481
6496
  this.onChange(iso);
6482
6497
  this.onTouched();
6483
6498
  }
6499
+ constructor() {
6500
+ // Roving focus: the keyboard cursor's day cell takes real focus while the
6501
+ // calendar is open (APG date-picker dialog pattern); the input gets it back
6502
+ // on close via close().
6503
+ effect(() => {
6504
+ const open = this.open();
6505
+ const iso = this.focusedIso();
6506
+ untracked(() => {
6507
+ if (!open || !iso)
6508
+ return;
6509
+ setTimeout(() => this.host.nativeElement
6510
+ .querySelector(`.strct-dp__day[data-iso="${iso}"]`)
6511
+ ?.focus());
6512
+ });
6513
+ });
6514
+ }
6484
6515
  onKeydown(event) {
6485
6516
  if (this.isDisabled())
6486
6517
  return;
@@ -6508,13 +6539,24 @@ class StrctDatepicker {
6508
6539
  event.preventDefault();
6509
6540
  this.shiftFocus(7);
6510
6541
  break;
6542
+ case 'Home': {
6543
+ // Start of the focused week (APG grid pattern).
6544
+ event.preventDefault();
6545
+ this.shiftFocus(-this.focusedDow());
6546
+ break;
6547
+ }
6548
+ case 'End': {
6549
+ event.preventDefault();
6550
+ this.shiftFocus(6 - this.focusedDow());
6551
+ break;
6552
+ }
6511
6553
  case 'PageUp':
6512
6554
  event.preventDefault();
6513
- this.shiftFocus(0, -1);
6555
+ this.shiftFocus(0, event.shiftKey ? -12 : -1); // Shift = previous year
6514
6556
  break;
6515
6557
  case 'PageDown':
6516
6558
  event.preventDefault();
6517
- this.shiftFocus(0, 1);
6559
+ this.shiftFocus(0, event.shiftKey ? 12 : 1); // Shift = next year
6518
6560
  break;
6519
6561
  case 'Enter':
6520
6562
  case ' ':
@@ -6524,10 +6566,22 @@ class StrctDatepicker {
6524
6566
  break;
6525
6567
  case 'Escape':
6526
6568
  event.preventDefault();
6527
- this.open.set(false);
6569
+ this.close();
6528
6570
  break;
6529
6571
  }
6530
6572
  }
6573
+ /** Day-of-week (0–6) of the keyboard cursor. */
6574
+ focusedDow() {
6575
+ const [y, m, d] = (this.focusedIso() || this.today).split('-').map(Number);
6576
+ return new Date(y, m - 1, d).getDay();
6577
+ }
6578
+ /** Close the panel and hand focus back to the input. */
6579
+ close() {
6580
+ this.open.set(false);
6581
+ this.host.nativeElement
6582
+ .querySelector('.strct-dp__input')
6583
+ ?.focus();
6584
+ }
6531
6585
  syncFocus() {
6532
6586
  const base = this.value() || this.today;
6533
6587
  this.focusedIso.set(base);
@@ -6598,6 +6652,7 @@ class StrctDatepicker {
6598
6652
  <div
6599
6653
  class="strct-dp__panel"
6600
6654
  role="dialog"
6655
+ [attr.aria-labelledby]="titleId"
6601
6656
  [strctOverlay]="field"
6602
6657
  strctOverlayPlacement="bottom-start"
6603
6658
  >
@@ -6610,7 +6665,7 @@ class StrctDatepicker {
6610
6665
  >
6611
6666
  <strct-icon name="chevronLeft" [size]="14" [strokeWidth]="1.7" />
6612
6667
  </button>
6613
- <span class="strct-dp__title">{{ monthLabel() }}</span>
6668
+ <span class="strct-dp__title" [id]="titleId" aria-live="polite">{{ monthLabel() }}</span>
6614
6669
  <button
6615
6670
  type="button"
6616
6671
  class="strct-dp__nav"
@@ -6620,24 +6675,39 @@ class StrctDatepicker {
6620
6675
  <strct-icon name="chevronRight" [size]="14" [strokeWidth]="1.7" />
6621
6676
  </button>
6622
6677
  </div>
6623
- <div class="strct-dp__dow">
6624
- @for (d of dow; track d) {
6625
- <span>{{ d }}</span>
6626
- }
6627
- </div>
6628
- <div class="strct-dp__grid">
6629
- @for (cell of cells(); track cell.iso) {
6630
- <button
6631
- type="button"
6632
- class="strct-dp__day"
6633
- [class.strct-dp__day--muted]="!cell.inMonth"
6634
- [class.strct-dp__day--today]="cell.iso === today"
6635
- [class.strct-dp__day--focused]="cell.iso === focusedIso()"
6636
- [class.strct-dp__day--selected]="cell.iso === value()"
6637
- (click)="pick(cell.iso)"
6638
- >
6639
- {{ cell.day }}
6640
- </button>
6678
+ <!-- ARIA grid (APG date-picker dialog pattern): focus roves the day
6679
+ cells; the input regains focus on close. -->
6680
+ <div class="strct-dp__gridwrap" role="grid" [attr.aria-labelledby]="titleId">
6681
+ <div class="strct-dp__dow" role="row">
6682
+ @for (d of dow; track d; let i = $index) {
6683
+ <span role="columnheader" [attr.aria-label]="dowFull[i]" [attr.abbr]="dowFull[i]">{{
6684
+ d
6685
+ }}</span>
6686
+ }
6687
+ </div>
6688
+ @for (week of weeks(); track $index) {
6689
+ <div class="strct-dp__grid" role="row">
6690
+ @for (cell of week; track cell.iso) {
6691
+ <button
6692
+ type="button"
6693
+ role="gridcell"
6694
+ class="strct-dp__day"
6695
+ [class.strct-dp__day--muted]="!cell.inMonth"
6696
+ [class.strct-dp__day--today]="cell.iso === today"
6697
+ [class.strct-dp__day--focused]="cell.iso === focusedIso()"
6698
+ [class.strct-dp__day--selected]="cell.iso === value()"
6699
+ [attr.data-iso]="cell.iso"
6700
+ [attr.tabindex]="cell.iso === focusedIso() ? 0 : -1"
6701
+ [attr.aria-selected]="cell.iso === value()"
6702
+ [attr.aria-current]="cell.iso === today ? 'date' : null"
6703
+ [attr.aria-label]="cellAria(cell)"
6704
+ (click)="pick(cell.iso)"
6705
+ (keydown)="onKeydown($event)"
6706
+ >
6707
+ {{ cell.day }}
6708
+ </button>
6709
+ }
6710
+ </div>
6641
6711
  }
6642
6712
  </div>
6643
6713
  </div>
@@ -6675,6 +6745,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
6675
6745
  <div
6676
6746
  class="strct-dp__panel"
6677
6747
  role="dialog"
6748
+ [attr.aria-labelledby]="titleId"
6678
6749
  [strctOverlay]="field"
6679
6750
  strctOverlayPlacement="bottom-start"
6680
6751
  >
@@ -6687,7 +6758,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
6687
6758
  >
6688
6759
  <strct-icon name="chevronLeft" [size]="14" [strokeWidth]="1.7" />
6689
6760
  </button>
6690
- <span class="strct-dp__title">{{ monthLabel() }}</span>
6761
+ <span class="strct-dp__title" [id]="titleId" aria-live="polite">{{ monthLabel() }}</span>
6691
6762
  <button
6692
6763
  type="button"
6693
6764
  class="strct-dp__nav"
@@ -6697,30 +6768,45 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
6697
6768
  <strct-icon name="chevronRight" [size]="14" [strokeWidth]="1.7" />
6698
6769
  </button>
6699
6770
  </div>
6700
- <div class="strct-dp__dow">
6701
- @for (d of dow; track d) {
6702
- <span>{{ d }}</span>
6703
- }
6704
- </div>
6705
- <div class="strct-dp__grid">
6706
- @for (cell of cells(); track cell.iso) {
6707
- <button
6708
- type="button"
6709
- class="strct-dp__day"
6710
- [class.strct-dp__day--muted]="!cell.inMonth"
6711
- [class.strct-dp__day--today]="cell.iso === today"
6712
- [class.strct-dp__day--focused]="cell.iso === focusedIso()"
6713
- [class.strct-dp__day--selected]="cell.iso === value()"
6714
- (click)="pick(cell.iso)"
6715
- >
6716
- {{ cell.day }}
6717
- </button>
6771
+ <!-- ARIA grid (APG date-picker dialog pattern): focus roves the day
6772
+ cells; the input regains focus on close. -->
6773
+ <div class="strct-dp__gridwrap" role="grid" [attr.aria-labelledby]="titleId">
6774
+ <div class="strct-dp__dow" role="row">
6775
+ @for (d of dow; track d; let i = $index) {
6776
+ <span role="columnheader" [attr.aria-label]="dowFull[i]" [attr.abbr]="dowFull[i]">{{
6777
+ d
6778
+ }}</span>
6779
+ }
6780
+ </div>
6781
+ @for (week of weeks(); track $index) {
6782
+ <div class="strct-dp__grid" role="row">
6783
+ @for (cell of week; track cell.iso) {
6784
+ <button
6785
+ type="button"
6786
+ role="gridcell"
6787
+ class="strct-dp__day"
6788
+ [class.strct-dp__day--muted]="!cell.inMonth"
6789
+ [class.strct-dp__day--today]="cell.iso === today"
6790
+ [class.strct-dp__day--focused]="cell.iso === focusedIso()"
6791
+ [class.strct-dp__day--selected]="cell.iso === value()"
6792
+ [attr.data-iso]="cell.iso"
6793
+ [attr.tabindex]="cell.iso === focusedIso() ? 0 : -1"
6794
+ [attr.aria-selected]="cell.iso === value()"
6795
+ [attr.aria-current]="cell.iso === today ? 'date' : null"
6796
+ [attr.aria-label]="cellAria(cell)"
6797
+ (click)="pick(cell.iso)"
6798
+ (keydown)="onKeydown($event)"
6799
+ >
6800
+ {{ cell.day }}
6801
+ </button>
6802
+ }
6803
+ </div>
6718
6804
  }
6719
6805
  </div>
6720
6806
  </div>
6721
6807
  }
6722
6808
  `, host: { class: 'strct-dp' }, styles: [".strct-dp{position:relative;display:inline-block;width:100%;max-width:240px}.strct-dp__field{position:relative}.strct-dp__input{padding-inline-end:36px;cursor:pointer}.strct-dp__icon{position:absolute;right:4px;top:50%;transform:translateY(-50%);display:inline-flex;padding:5px;border:0;border-radius:5px;background:transparent;color:var(--t2);cursor:pointer}.strct-dp__icon:hover{color:var(--acc);background:var(--bg-3)}.strct-dp__panel{position:absolute;top:calc(100% + 5px);left:0;z-index:250;width:250px;padding:10px;background:var(--bg-1);border:1px solid var(--b2);border-radius:9px;box-shadow:var(--shh)}.strct-dp__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}.strct-dp__title{font-size:13px;font-weight:600;color:var(--t1)}.strct-dp__nav{display:inline-flex;padding:5px;border:0;border-radius:5px;background:transparent;color:var(--t2);cursor:pointer}.strct-dp__nav:hover{color:var(--t1);background:var(--bg-3)}.strct-dp__dow{display:grid;grid-template-columns:repeat(7,1fr);margin-bottom:4px}.strct-dp__dow span{text-align:center;font-size:12px;font-weight:600;color:var(--t3);padding:4px 0}.strct-dp__grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}.strct-dp__day{aspect-ratio:1;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:6px;background:transparent;cursor:pointer;font-family:var(--font);font-size:12px;color:var(--t1)}.strct-dp__day:hover{background:var(--bg-3)}.strct-dp__day--muted{color:var(--t3)}.strct-dp__day--today{box-shadow:inset 0 0 0 1px var(--acc30)}.strct-dp__day--focused{box-shadow:inset 0 0 0 2px var(--acc)}.strct-dp__day--selected{background:var(--acc);color:var(--inv)}.strct-dp__day--selected:hover{background:var(--acc)}\n"] }]
6723
- }], propDecorators: { placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], onDocClick: [{
6809
+ }], ctorParameters: () => [], propDecorators: { placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], onDocClick: [{
6724
6810
  type: HostListener,
6725
6811
  args: ['document:click', ['$event']]
6726
6812
  }], onEscape: [{
@@ -7386,6 +7472,10 @@ const DG_LABELS = {
7386
7472
  refresh: 'Refresh data',
7387
7473
  actions: 'Actions',
7388
7474
  };
7475
+ /** Utility-column widths used when sticky columns are active (px). */
7476
+ const UTIL_W = { detail: 36, expand: 36, sel: 40 };
7477
+ /** Fallback width for a sticky column without an explicit px width. */
7478
+ const STICKY_FALLBACK_W = 120;
7389
7479
  /**
7390
7480
  * Marks the expandable-row detail template. The row is the template's implicit
7391
7481
  * context: `<ng-template strctRowDetail let-row> … {{ row['name'] }} … </ng-template>`.
@@ -7472,12 +7562,42 @@ class StrctDatagrid {
7472
7562
  labels = input({}, ...(ngDevMode ? [{ debugName: "labels" }] : /* istanbul ignore next */ []));
7473
7563
  /** Effective labels (defaults + overrides). */
7474
7564
  L = computed(() => ({ ...DG_LABELS, ...this.labels() }), ...(ngDevMode ? [{ debugName: "L" }] : /* istanbul ignore next */ []));
7565
+ /**
7566
+ * Virtual scrolling for large data sets: only the rows inside the viewport
7567
+ * (plus a small overscan) are in the DOM — 20k+ rows stay smooth. The scroll
7568
+ * area gets `viewportHeight` and a sticky header. Assumes uniform
7569
+ * `rowHeight`; combine with `expandable` is unsupported.
7570
+ */
7571
+ virtual = input(false, { ...(ngDevMode ? { debugName: "virtual" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
7572
+ /** Scroll viewport height in px (virtual mode). */
7573
+ viewportHeight = input(360, ...(ngDevMode ? [{ debugName: "viewportHeight" }] : /* istanbul ignore next */ []));
7574
+ /** Uniform row height in px (virtual mode; tune when `compact`). */
7575
+ rowHeight = input(38, ...(ngDevMode ? [{ debugName: "rowHeight" }] : /* istanbul ignore next */ []));
7576
+ /**
7577
+ * Server-side mode: the grid never sorts or slices `rows` itself — it shows
7578
+ * them as given and emits `(lazyLoad)` with `{ page, pageSize, sortKey,
7579
+ * sortDir }` whenever the user pages or sorts (and once on init). Provide
7580
+ * `total` so the pager and count reflect the full server-side set.
7581
+ */
7582
+ lazy = input(false, { ...(ngDevMode ? { debugName: "lazy" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
7583
+ /** Total row count on the server (lazy mode). */
7584
+ total = input(null, ...(ngDevMode ? [{ debugName: "total" }] : /* istanbul ignore next */ []));
7585
+ /**
7586
+ * Persist the user's column widths + hidden columns under this key in
7587
+ * localStorage (`strct-dg:<key>`), restoring them on init. For full control
7588
+ * use the two-way `columnState` instead (both may be combined).
7589
+ */
7590
+ stateKey = input(null, ...(ngDevMode ? [{ debugName: "stateKey" }] : /* istanbul ignore next */ []));
7591
+ /** User column preferences (two-way): widths from resize, hidden from the chooser. */
7592
+ columnState = model(null, ...(ngDevMode ? [{ debugName: "columnState" }] : /* istanbul ignore next */ []));
7475
7593
  /** Emitted when the selection changes. */
7476
7594
  selectionChange = output();
7477
7595
  /** Emitted when the refresh button is clicked. */
7478
7596
  syncChange = output();
7479
7597
  /** Emitted when a row's action-menu item is chosen. */
7480
7598
  rowAction = output();
7599
+ /** Server-side data request (lazy mode): load this page / sort and set `rows`. */
7600
+ lazyLoad = output();
7481
7601
  menu = inject(StrctMenuService);
7482
7602
  detailDef = contentChild(StrctRowDetailDef, ...(ngDevMode ? [{ debugName: "detailDef" }] : /* istanbul ignore next */ []));
7483
7603
  actionBarDef = contentChild(StrctDatagridActionBar, ...(ngDevMode ? [{ debugName: "actionBarDef" }] : /* istanbul ignore next */ []));
@@ -7549,6 +7669,9 @@ class StrctDatagrid {
7549
7669
  return this.columns().filter((c) => !hidden.has(c.key));
7550
7670
  }, ...(ngDevMode ? [{ debugName: "visibleColumns" }] : /* istanbul ignore next */ []));
7551
7671
  sorted = computed(() => {
7672
+ // Server-side mode: rows arrive already ordered / sliced — never touch them.
7673
+ if (this.lazy())
7674
+ return this.rows();
7552
7675
  const { key, dir } = this.sort();
7553
7676
  const data = [...this.rows()];
7554
7677
  if (!key)
@@ -7558,11 +7681,87 @@ class StrctDatagrid {
7558
7681
  }, ...(ngDevMode ? [{ debugName: "sorted" }] : /* istanbul ignore next */ []));
7559
7682
  paged = computed(() => {
7560
7683
  const size = this.pageSize();
7561
- if (size <= 0)
7684
+ if (this.lazy() || size <= 0)
7562
7685
  return this.sorted();
7563
7686
  const start = (this.page() - 1) * size;
7564
7687
  return this.sorted().slice(start, start + size);
7565
7688
  }, ...(ngDevMode ? [{ debugName: "paged" }] : /* istanbul ignore next */ []));
7689
+ /** Full count for the pager / footer (server total in lazy mode). */
7690
+ totalCount = computed(() => this.lazy() ? (this.total() ?? this.rows().length) : this.sorted().length, ...(ngDevMode ? [{ debugName: "totalCount" }] : /* istanbul ignore next */ []));
7691
+ // ── Virtual scrolling ──────────────────────────────────────────
7692
+ scrollTop = signal(0, ...(ngDevMode ? [{ debugName: "scrollTop" }] : /* istanbul ignore next */ []));
7693
+ onScroll(event) {
7694
+ this.scrollTop.set(event.target.scrollTop);
7695
+ }
7696
+ /** Visible index window incl. overscan (virtual mode). */
7697
+ vRange = computed(() => {
7698
+ const rh = Math.max(1, this.rowHeight());
7699
+ const n = this.sorted().length;
7700
+ const start = Math.max(0, Math.floor(this.scrollTop() / rh) - 6);
7701
+ const count = Math.ceil(this.viewportHeight() / rh) + 12;
7702
+ return { start, end: Math.min(n, start + count) };
7703
+ }, ...(ngDevMode ? [{ debugName: "vRange" }] : /* istanbul ignore next */ []));
7704
+ /** The rows actually rendered: the virtual window, or the current page. */
7705
+ renderRows = computed(() => this.virtual() ? this.sorted().slice(this.vRange().start, this.vRange().end) : this.paged(), ...(ngDevMode ? [{ debugName: "renderRows" }] : /* istanbul ignore next */ []));
7706
+ topPad = computed(() => this.virtual() ? this.vRange().start * this.rowHeight() : 0, ...(ngDevMode ? [{ debugName: "topPad" }] : /* istanbul ignore next */ []));
7707
+ bottomPad = computed(() => this.virtual() ? Math.max(0, (this.sorted().length - this.vRange().end) * this.rowHeight()) : 0, ...(ngDevMode ? [{ debugName: "bottomPad" }] : /* istanbul ignore next */ []));
7708
+ // ── Sticky (frozen) columns ────────────────────────────────────
7709
+ stickyActive = computed(() => !this.paneOpen() && this.visibleColumns().some((c) => c.sticky), ...(ngDevMode ? [{ debugName: "stickyActive" }] : /* istanbul ignore next */ []));
7710
+ /** Total width of the frozen utility columns (detail / expand / select). */
7711
+ utilityWidth = computed(() => (this.canDetail() ? UTIL_W.detail : 0) +
7712
+ (this.canExpand() ? UTIL_W.expand : 0) +
7713
+ (this.selectable() ? UTIL_W.sel : 0), ...(ngDevMode ? [{ debugName: "utilityWidth" }] : /* istanbul ignore next */ []));
7714
+ /** Left offset of a frozen utility column, or null when sticky is off. */
7715
+ utilLeft(which) {
7716
+ if (!this.stickyActive())
7717
+ return null;
7718
+ let x = 0;
7719
+ if (which === 'detail')
7720
+ return x;
7721
+ if (this.canDetail())
7722
+ x += UTIL_W.detail;
7723
+ if (which === 'expand')
7724
+ return x;
7725
+ if (this.canExpand())
7726
+ x += UTIL_W.expand;
7727
+ return x;
7728
+ }
7729
+ /** Effective px width of a column (resize override → declared px → fallback). */
7730
+ colPx(col) {
7731
+ const resized = this.columnWidths().get(col.key);
7732
+ if (resized != null)
7733
+ return resized;
7734
+ const m = /^(\d+(?:\.\d+)?)px$/.exec(col.width ?? '');
7735
+ return m ? parseFloat(m[1]) : STICKY_FALLBACK_W;
7736
+ }
7737
+ /** key → left px for sticky data columns. */
7738
+ stickyOffsets = computed(() => {
7739
+ const map = new Map();
7740
+ if (!this.stickyActive())
7741
+ return map;
7742
+ let x = this.utilityWidth();
7743
+ for (const col of this.visibleColumns()) {
7744
+ if (!col.sticky)
7745
+ continue;
7746
+ map.set(col.key, x);
7747
+ x += this.colPx(col);
7748
+ }
7749
+ return map;
7750
+ }, ...(ngDevMode ? [{ debugName: "stickyOffsets" }] : /* istanbul ignore next */ []));
7751
+ stickyLeft(key) {
7752
+ return this.stickyOffsets().get(key) ?? null;
7753
+ }
7754
+ isSticky(col) {
7755
+ return !!col.sticky && this.stickyActive();
7756
+ }
7757
+ /** The last frozen column carries the edge shadow. */
7758
+ lastStickyKey = computed(() => {
7759
+ let last = null;
7760
+ for (const col of this.visibleColumns())
7761
+ if (col.sticky)
7762
+ last = col.key;
7763
+ return this.stickyActive() ? last : null;
7764
+ }, ...(ngDevMode ? [{ debugName: "lastStickyKey" }] : /* istanbul ignore next */ []));
7566
7765
  allPageSelected = computed(() => {
7567
7766
  const rows = this.paged();
7568
7767
  return rows.length > 0 && rows.every((r) => this.selected().has(this.idOf(r)));
@@ -7581,13 +7780,18 @@ class StrctDatagrid {
7581
7780
  cellTemplate(key) {
7582
7781
  return this.cellMap().get(key) ?? null;
7583
7782
  }
7783
+ /** Last emitted lazy request (dedupe key). */
7784
+ lastLazyKey = '';
7785
+ /** Last serialized column state pushed outward (loop guard). */
7786
+ lastStateKey = '';
7584
7787
  constructor() {
7585
- // Keep the page in range when the data set shrinks.
7788
+ // Keep the page in range when the data set shrinks (server total in lazy mode).
7586
7789
  effect(() => {
7587
7790
  const size = this.pageSize();
7588
7791
  if (size <= 0)
7589
7792
  return;
7590
- const pageCount = Math.max(1, Math.ceil(this.sorted().length / size));
7793
+ const count = this.totalCount();
7794
+ const pageCount = Math.max(1, Math.ceil(count / size));
7591
7795
  if (this.page() > pageCount)
7592
7796
  this.page.set(pageCount);
7593
7797
  });
@@ -7599,6 +7803,106 @@ class StrctDatagrid {
7599
7803
  return;
7600
7804
  untracked(() => this.selected.set(new Set(init)));
7601
7805
  });
7806
+ // Server-side mode: announce what to load whenever page / sort / pageSize
7807
+ // change (and once on init, so the consumer fetches the first page).
7808
+ effect(() => {
7809
+ if (!this.lazy())
7810
+ return;
7811
+ const state = {
7812
+ page: this.page(),
7813
+ pageSize: this.pageSize(),
7814
+ sortKey: this.sort().key,
7815
+ sortDir: this.sort().dir,
7816
+ };
7817
+ const key = JSON.stringify(state);
7818
+ untracked(() => {
7819
+ if (key === this.lastLazyKey)
7820
+ return;
7821
+ this.lastLazyKey = key;
7822
+ this.lazyLoad.emit(state);
7823
+ });
7824
+ });
7825
+ // Restore persisted column preferences once, before the first render.
7826
+ const persisted = this.readPersistedState();
7827
+ if (persisted)
7828
+ this.applyColumnState(persisted);
7829
+ // Apply externally-driven columnState.
7830
+ effect(() => {
7831
+ const st = this.columnState();
7832
+ untracked(() => {
7833
+ if (!st || JSON.stringify(st) === this.lastStateKey)
7834
+ return;
7835
+ this.lastStateKey = JSON.stringify(st);
7836
+ this.applyColumnState(st);
7837
+ });
7838
+ });
7839
+ // Push user changes (resize / chooser) outward + persist under stateKey.
7840
+ effect(() => {
7841
+ const widths = Object.fromEntries(this.columnWidths());
7842
+ const hidden = [...this.hiddenColumns()];
7843
+ const st = { widths, hidden };
7844
+ const key = JSON.stringify(st);
7845
+ untracked(() => {
7846
+ if (key === this.lastStateKey)
7847
+ return;
7848
+ this.lastStateKey = key;
7849
+ this.columnState.set(st);
7850
+ const sk = this.stateKey();
7851
+ if (sk && typeof localStorage !== 'undefined') {
7852
+ try {
7853
+ localStorage.setItem(`strct-dg:${sk}`, key);
7854
+ }
7855
+ catch {
7856
+ /* storage full / denied — persistence is best-effort */
7857
+ }
7858
+ }
7859
+ });
7860
+ });
7861
+ }
7862
+ readPersistedState() {
7863
+ const sk = this.stateKey();
7864
+ if (!sk || typeof localStorage === 'undefined')
7865
+ return null;
7866
+ try {
7867
+ const raw = localStorage.getItem(`strct-dg:${sk}`);
7868
+ return raw ? JSON.parse(raw) : null;
7869
+ }
7870
+ catch {
7871
+ return null;
7872
+ }
7873
+ }
7874
+ applyColumnState(st) {
7875
+ this.columnWidths.set(new Map(Object.entries(st.widths ?? {}).map(([k, v]) => [k, Number(v)])));
7876
+ this.hiddenColumns.set(new Set(st.hidden ?? []));
7877
+ }
7878
+ /**
7879
+ * The grid as CSV: header labels + every non-hidden column, all rows in the
7880
+ * current order (client mode: the full sorted set, not just the page).
7881
+ */
7882
+ toCSV() {
7883
+ const hidden = this.hiddenColumns();
7884
+ const cols = this.columns().filter((c) => !hidden.has(c.key));
7885
+ const esc = (v) => {
7886
+ const s = v == null ? '' : String(v);
7887
+ return /[",\n;]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
7888
+ };
7889
+ const data = this.lazy() ? this.rows() : this.sorted();
7890
+ return [
7891
+ cols.map((c) => esc(c.label)).join(','),
7892
+ ...data.map((r) => cols.map((c) => esc(r[c.key])).join(',')),
7893
+ ].join('\n');
7894
+ }
7895
+ /** Download the grid as a CSV file. */
7896
+ downloadCSV(filename = 'datagrid.csv') {
7897
+ if (typeof document === 'undefined')
7898
+ return;
7899
+ const blob = new Blob(['\uFEFF' + this.toCSV()], { type: 'text/csv;charset=utf-8' });
7900
+ const url = URL.createObjectURL(blob);
7901
+ const a = document.createElement('a');
7902
+ a.href = url;
7903
+ a.download = filename;
7904
+ a.click();
7905
+ URL.revokeObjectURL(url);
7602
7906
  }
7603
7907
  colspan() {
7604
7908
  return (this.visibleColumns().length +
@@ -7726,24 +8030,43 @@ class StrctDatagrid {
7726
8030
  return String(a ?? '').localeCompare(String(b ?? ''), undefined, { numeric: true });
7727
8031
  }
7728
8032
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctDatagrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
7729
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: StrctDatagrid, isStandalone: true, selector: "strct-datagrid", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: true, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, expandable: { classPropertyName: "expandable", publicName: "expandable", isSignal: true, isRequired: false, transformFunction: null }, detailPane: { classPropertyName: "detailPane", publicName: "detailPane", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, singleLine: { classPropertyName: "singleLine", publicName: "singleLine", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, resizable: { classPropertyName: "resizable", publicName: "resizable", isSignal: true, isRequired: false, transformFunction: null }, columnChooser: { classPropertyName: "columnChooser", publicName: "columnChooser", isSignal: true, isRequired: false, transformFunction: null }, sync: { classPropertyName: "sync", publicName: "sync", isSignal: true, isRequired: false, transformFunction: null }, footerActionsDisabled: { classPropertyName: "footerActionsDisabled", publicName: "footerActionsDisabled", isSignal: true, isRequired: false, transformFunction: null }, rowId: { classPropertyName: "rowId", publicName: "rowId", isSignal: true, isRequired: false, transformFunction: null }, rowActions: { classPropertyName: "rowActions", publicName: "rowActions", isSignal: true, isRequired: false, transformFunction: null }, initialSelection: { classPropertyName: "initialSelection", publicName: "initialSelection", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange", syncChange: "syncChange", rowAction: "rowAction" }, host: { properties: { "class.strct-dg-host--compact": "compact()", "class.strct-dg-host--singleline": "singleLine()" }, classAttribute: "strct-dg-host" }, queries: [{ propertyName: "detailDef", first: true, predicate: StrctRowDetailDef, descendants: true, isSignal: true }, { propertyName: "actionBarDef", first: true, predicate: StrctDatagridActionBar, descendants: true, isSignal: true }, { propertyName: "cellDefs", predicate: StrctCellDef, isSignal: true }], ngImport: i0, template: `
8033
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: StrctDatagrid, isStandalone: true, selector: "strct-datagrid", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: true, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, expandable: { classPropertyName: "expandable", publicName: "expandable", isSignal: true, isRequired: false, transformFunction: null }, detailPane: { classPropertyName: "detailPane", publicName: "detailPane", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, singleLine: { classPropertyName: "singleLine", publicName: "singleLine", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, resizable: { classPropertyName: "resizable", publicName: "resizable", isSignal: true, isRequired: false, transformFunction: null }, columnChooser: { classPropertyName: "columnChooser", publicName: "columnChooser", isSignal: true, isRequired: false, transformFunction: null }, sync: { classPropertyName: "sync", publicName: "sync", isSignal: true, isRequired: false, transformFunction: null }, footerActionsDisabled: { classPropertyName: "footerActionsDisabled", publicName: "footerActionsDisabled", isSignal: true, isRequired: false, transformFunction: null }, rowId: { classPropertyName: "rowId", publicName: "rowId", isSignal: true, isRequired: false, transformFunction: null }, rowActions: { classPropertyName: "rowActions", publicName: "rowActions", isSignal: true, isRequired: false, transformFunction: null }, initialSelection: { classPropertyName: "initialSelection", publicName: "initialSelection", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null }, virtual: { classPropertyName: "virtual", publicName: "virtual", isSignal: true, isRequired: false, transformFunction: null }, viewportHeight: { classPropertyName: "viewportHeight", publicName: "viewportHeight", isSignal: true, isRequired: false, transformFunction: null }, rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: false, transformFunction: null }, lazy: { classPropertyName: "lazy", publicName: "lazy", isSignal: true, isRequired: false, transformFunction: null }, total: { classPropertyName: "total", publicName: "total", isSignal: true, isRequired: false, transformFunction: null }, stateKey: { classPropertyName: "stateKey", publicName: "stateKey", isSignal: true, isRequired: false, transformFunction: null }, columnState: { classPropertyName: "columnState", publicName: "columnState", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { columnState: "columnStateChange", selectionChange: "selectionChange", syncChange: "syncChange", rowAction: "rowAction", lazyLoad: "lazyLoad" }, host: { properties: { "class.strct-dg-host--compact": "compact()", "class.strct-dg-host--singleline": "singleLine()", "class.strct-dg-host--virtual": "virtual()", "class.strct-dg-host--sticky": "stickyActive()" }, classAttribute: "strct-dg-host" }, queries: [{ propertyName: "detailDef", first: true, predicate: StrctRowDetailDef, descendants: true, isSignal: true }, { propertyName: "actionBarDef", first: true, predicate: StrctDatagridActionBar, descendants: true, isSignal: true }, { propertyName: "cellDefs", predicate: StrctCellDef, isSignal: true }], ngImport: i0, template: `
7730
8034
  @if (actionBarDef()) {
7731
8035
  <div class="strct-dg__toolbar"><ng-content select="[strctDatagridActionBar]" /></div>
7732
8036
  }
7733
8037
 
7734
8038
  <div class="strct-dg__layout" [class.strct-dg__layout--paned]="paneOpen()">
7735
- <div class="strct-dg__scroll" tabindex="0" role="region" [attr.aria-label]="L().rows">
8039
+ <div
8040
+ class="strct-dg__scroll"
8041
+ tabindex="0"
8042
+ role="region"
8043
+ [attr.aria-label]="L().rows"
8044
+ [style.max-height.px]="virtual() ? viewportHeight() : null"
8045
+ (scroll)="virtual() && onScroll($event)"
8046
+ >
7736
8047
  <table class="strct-dg">
7737
8048
  <thead>
7738
8049
  <tr>
7739
8050
  @if (canDetail()) {
7740
- <th class="strct-dg__expandcol"></th>
8051
+ <th
8052
+ class="strct-dg__expandcol"
8053
+ [class.strct-dg__cell--sticky]="stickyActive()"
8054
+ [style.insetInlineStart.px]="utilLeft('detail')"
8055
+ ></th>
7741
8056
  }
7742
8057
  @if (canExpand()) {
7743
- <th class="strct-dg__expandcol"></th>
8058
+ <th
8059
+ class="strct-dg__expandcol"
8060
+ [class.strct-dg__cell--sticky]="stickyActive()"
8061
+ [style.insetInlineStart.px]="utilLeft('expand')"
8062
+ ></th>
7744
8063
  }
7745
8064
  @if (selectable()) {
7746
- <th class="strct-dg__sel">
8065
+ <th
8066
+ class="strct-dg__sel"
8067
+ [class.strct-dg__cell--sticky]="stickyActive()"
8068
+ [style.insetInlineStart.px]="utilLeft('sel')"
8069
+ >
7747
8070
  <strct-checkbox
7748
8071
  [ariaLabel]="L().selectAll"
7749
8072
  [checked]="allPageSelected()"
@@ -7757,6 +8080,9 @@ class StrctDatagrid {
7757
8080
  [style.text-align]="col.align ?? 'start'"
7758
8081
  [style.width]="colWidth(col.key) ?? col.width ?? null"
7759
8082
  [class.strct-dg__th--sortable]="col.sortable"
8083
+ [class.strct-dg__cell--sticky]="isSticky(col)"
8084
+ [class.strct-dg__cell--sticky-last]="col.key === lastStickyKey()"
8085
+ [style.insetInlineStart.px]="stickyLeft(col.key)"
7760
8086
  [attr.tabindex]="col.sortable ? 0 : null"
7761
8087
  [attr.aria-sort]="col.sortable ? ariaSort(col.key) : null"
7762
8088
  (click)="col.sortable && sortBy(col.key)"
@@ -7810,13 +8136,22 @@ class StrctDatagrid {
7810
8136
  </tr>
7811
8137
  }
7812
8138
  } @else {
7813
- @for (row of paged(); track rowKey(row)) {
8139
+ @if (virtual() && topPad() > 0) {
8140
+ <tr class="strct-dg__vspacer" aria-hidden="true">
8141
+ <td [attr.colspan]="colspan()" [style.height.px]="topPad()"></td>
8142
+ </tr>
8143
+ }
8144
+ @for (row of renderRows(); track rowKey(row)) {
7814
8145
  <tr
7815
8146
  [class.strct-dg__row--selected]="isSelected(row)"
7816
8147
  [class.strct-dg__row--active]="paneOpen() && row === activeRow()"
7817
8148
  >
7818
8149
  @if (canDetail()) {
7819
- <td class="strct-dg__expandcell">
8150
+ <td
8151
+ class="strct-dg__expandcell"
8152
+ [class.strct-dg__cell--sticky]="stickyActive()"
8153
+ [style.insetInlineStart.px]="utilLeft('detail')"
8154
+ >
7820
8155
  <button
7821
8156
  type="button"
7822
8157
  class="strct-dg__detailbtn"
@@ -7830,7 +8165,11 @@ class StrctDatagrid {
7830
8165
  </td>
7831
8166
  }
7832
8167
  @if (canExpand()) {
7833
- <td class="strct-dg__expandcell">
8168
+ <td
8169
+ class="strct-dg__expandcell"
8170
+ [class.strct-dg__cell--sticky]="stickyActive()"
8171
+ [style.insetInlineStart.px]="utilLeft('expand')"
8172
+ >
7834
8173
  <button
7835
8174
  type="button"
7836
8175
  class="strct-dg__expandbtn"
@@ -7844,7 +8183,11 @@ class StrctDatagrid {
7844
8183
  </td>
7845
8184
  }
7846
8185
  @if (selectable()) {
7847
- <td class="strct-dg__sel">
8186
+ <td
8187
+ class="strct-dg__sel"
8188
+ [class.strct-dg__cell--sticky]="stickyActive()"
8189
+ [style.insetInlineStart.px]="utilLeft('sel')"
8190
+ >
7848
8191
  <strct-checkbox
7849
8192
  [ariaLabel]="L().selectRow"
7850
8193
  [checked]="isSelected(row)"
@@ -7853,7 +8196,12 @@ class StrctDatagrid {
7853
8196
  </td>
7854
8197
  }
7855
8198
  @for (col of visibleColumns(); track col.key) {
7856
- <td [style.text-align]="col.align ?? 'start'">
8199
+ <td
8200
+ [style.text-align]="col.align ?? 'start'"
8201
+ [class.strct-dg__cell--sticky]="isSticky(col)"
8202
+ [class.strct-dg__cell--sticky-last]="col.key === lastStickyKey()"
8203
+ [style.insetInlineStart.px]="stickyLeft(col.key)"
8204
+ >
7857
8205
  @if (cellTemplate(col.key); as tpl) {
7858
8206
  <ng-container
7859
8207
  [ngTemplateOutlet]="tpl"
@@ -7898,6 +8246,11 @@ class StrctDatagrid {
7898
8246
  <td class="strct-dg__empty" [attr.colspan]="colspan()">{{ emptyText() }}</td>
7899
8247
  </tr>
7900
8248
  }
8249
+ @if (virtual() && bottomPad() > 0) {
8250
+ <tr class="strct-dg__vspacer" aria-hidden="true">
8251
+ <td [attr.colspan]="colspan()" [style.height.px]="bottomPad()"></td>
8252
+ </tr>
8253
+ }
7901
8254
  }
7902
8255
  </tbody>
7903
8256
  </table>
@@ -7926,7 +8279,7 @@ class StrctDatagrid {
7926
8279
  }
7927
8280
  </div>
7928
8281
 
7929
- @if (pageSize() > 0 && !loading()) {
8282
+ @if ((pageSize() > 0 || virtual()) && !loading()) {
7930
8283
  <div class="strct-dg__foot">
7931
8284
  <div class="strct-dg__foot-left">
7932
8285
  @if (columnChooser() || sync()) {
@@ -7972,7 +8325,7 @@ class StrctDatagrid {
7972
8325
  </div>
7973
8326
  }
7974
8327
  <span class="strct-dg__count">
7975
- {{ sorted().length }} {{ sorted().length === 1 ? L().row : L().rows }}
8328
+ {{ totalCount() }} {{ totalCount() === 1 ? L().row : L().rows }}
7976
8329
  @if (selectedCount()) {
7977
8330
  <span class="strct-dg__count-sep">|</span>
7978
8331
  <span class="strct-dg__count-sel">{{ selectedCount() }} {{ L().selected }}</span>
@@ -7980,11 +8333,13 @@ class StrctDatagrid {
7980
8333
  </span>
7981
8334
  </div>
7982
8335
  <div class="strct-dg__foot-right">
7983
- <strct-pagination [total]="sorted().length" [pageSize]="pageSize()" [(page)]="page" />
8336
+ @if (pageSize() > 0) {
8337
+ <strct-pagination [total]="totalCount()" [pageSize]="pageSize()" [(page)]="page" />
8338
+ }
7984
8339
  </div>
7985
8340
  </div>
7986
8341
  }
7987
- `, isInline: true, styles: [".strct-dg-host{display:block;border:1px solid var(--b2);border-radius:10px;background:var(--bg-2);box-shadow:var(--shadow-rest)}.strct-dg__scroll{flex:1 1 auto;min-width:0;overflow-x:auto;-webkit-overflow-scrolling:touch}.strct-dg{width:100%;border-collapse:collapse;font-size:13px;overflow:hidden;background:var(--bg-2)}.strct-dg-host:not(:has(.strct-dg__toolbar)) .strct-dg{border-start-start-radius:9px;border-start-end-radius:9px}.strct-dg-host:not(:has(.strct-dg__foot)) .strct-dg{border-end-start-radius:9px;border-end-end-radius:9px}.strct-dg th,.strct-dg td{padding:9px 13px;text-align:start;border-bottom:1px solid var(--b1)}.strct-dg tbody td{background:var(--bg-1)}[data-theme=dark] .strct-dg tbody td{background:var(--bg-3)}.strct-dg-host--compact .strct-dg th,.strct-dg-host--compact .strct-dg td{padding:5px 11px}.strct-dg-host--singleline .strct-dg tbody tr:not(.strct-dg__detailrow)>td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:360px}.strct-dg th{position:relative;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;color:var(--t2);background:var(--bg-2);white-space:nowrap;-webkit-user-select:none;user-select:none}.strct-dg__th--sortable{cursor:pointer}.strct-dg__th--sortable:hover{color:var(--t1)}.strct-dg__th--sortable:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__hd{display:inline-flex;align-items:center;gap:5px}.strct-dg__sorticon{color:var(--t3)}.strct-dg__th--sortable:hover .strct-dg__sorticon{color:var(--acc)}.strct-dg__resize{position:absolute;right:0;top:0;bottom:0;width:4px;cursor:col-resize;background:transparent;z-index:2}.strct-dg__resize:hover{background:var(--acc)}.strct-dg td{color:var(--t1)}.strct-dg tbody tr:last-child td{border-bottom:0}.strct-dg tbody tr:not(.strct-dg__detailrow):hover td{background:var(--acc-s)}.strct-dg__row--selected td{background:var(--acc-m)}.strct-dg__sel{width:1%;white-space:nowrap}.strct-dg__sel input{accent-color:var(--acc);width:15px;height:15px;cursor:pointer}.strct-dg__expandcol,.strct-dg__expandcell{width:1%;white-space:nowrap}.strct-dg__actioncol,.strct-dg__actioncell{width:1%;white-space:nowrap;text-align:end}.strct-dg__kebab{display:inline-flex;padding:4px;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__kebab:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;transition:transform .15s ease,color .15s ease}.strct-dg__expandbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn--open{transform:rotate(90deg);color:var(--acc)}.strct-dg__detailbtn{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__detailbtn:hover{color:var(--acc);background:var(--bg-3)}.strct-dg__detailbtn--active{color:var(--acc);background:var(--acc-m)}.strct-dg__detailrow td{background:var(--bg-2);padding:0}.strct-dg__detail{padding:14px 16px;font-size:13px;color:var(--t2)}.strct-dg__layout{display:flex;align-items:flex-start;min-width:0}.strct-dg__layout--paned{gap:0}.strct-dg__layout--paned .strct-dg__scroll{flex:0 0 auto;width:260px;min-width:260px;max-width:260px}.strct-dg__layout--paned .strct-dg{width:260px;min-width:260px;max-width:260px;flex-shrink:0;border-top-right-radius:0;border-bottom-right-radius:0}.strct-dg__row--clickable{cursor:pointer}.strct-dg__row--active td{background:var(--acc-m)}.strct-dg__layout--paned .strct-dg__row--active td:last-child{position:relative;padding-inline-end:26px}.strct-dg__layout--paned .strct-dg__row--active td:last-child:after{content:\"\";position:absolute;right:11px;top:50%;width:6px;height:6px;border-top:1.6px solid var(--acc);border-inline-end:1.6px solid var(--acc);transform:translateY(-50%) rotate(45deg)}.strct-dg__pane{flex:1;min-width:0;align-self:stretch;background:var(--bg-1);border:1px solid var(--b2);border-inline-start:2px solid var(--acc);border-radius:0 8px 8px 0;overflow:hidden;animation:strct-dg-pane-in .14s ease}.strct-dg__pane-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 14px;border-bottom:1px solid var(--b1);font-size:13px;font-weight:600;color:var(--t1)}.strct-dg__pane-close{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer}.strct-dg__pane-close:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__pane-body{padding:14px 16px;font-size:13px;color:var(--t2)}@keyframes strct-dg-pane-in{0%{opacity:0;transform:translate(8px)}}@keyframes strct-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}.strct-dg__skeleton-block{height:12px;background:var(--bg-3);border-radius:var(--radius-sm);animation:strct-skeleton-pulse 1.4s ease infinite}.strct-dg__skeleton-row td{border-bottom:1px solid var(--b1)}.strct-dg__empty{text-align:center;color:var(--t3);padding:22px}.strct-dg__toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:9px 14px;border-bottom:1px solid var(--b2)}.strct-dg__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 14px;border-top:1px solid var(--b2);flex-wrap:wrap}.strct-dg__foot-left,.strct-dg__foot-right{display:flex;align-items:center;gap:12px}.strct-dg__actions{position:relative}.strct-dg__chooser-menu{position:absolute;bottom:calc(100% + 6px);left:0;z-index:10;min-width:180px;background:var(--bg-1);border:1px solid var(--b2);border-radius:8px;box-shadow:var(--shadow-pop);padding:6px;display:flex;flex-direction:column;gap:2px}.strct-dg__chooser-menu--right{left:auto;right:0}.strct-dg__chooser-item{display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:6px;cursor:pointer;font-size:12px;color:var(--t1);transition:background .1s ease;-webkit-user-select:none;user-select:none}.strct-dg__chooser-item:hover{background:var(--bg-3)}.strct-dg__count{font-size:12px;color:var(--t2)}.strct-dg__count-sep{margin:0 8px;color:var(--b2)}.strct-dg__count-sel{color:var(--acc)}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "size", "strokeWidth", "badge", "ariaLabel"] }, { kind: "component", type: StrctPagination, selector: "strct-pagination", inputs: ["prevLabel", "nextLabel", "regionLabel", "total", "pageSize", "page"], outputs: ["pageChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: StrctCheckbox, selector: "strct-checkbox", inputs: ["checked", "isDisabled", "disabled", "indeterminate", "ariaLabel"], outputs: ["checkedChange", "isDisabledChange"] }, { kind: "component", type: StrctButton, selector: "button[strct-button], a[strct-button]", inputs: ["variant", "size", "solid", "block", "iconOnly"] }, { kind: "component", type: StrctButtonGroup, selector: "strct-button-group" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
8342
+ `, isInline: true, styles: [".strct-dg-host{display:block;border:1px solid var(--b2);border-radius:10px;background:var(--bg-2);box-shadow:var(--shadow-rest)}.strct-dg__scroll{flex:1 1 auto;min-width:0;overflow-x:auto;-webkit-overflow-scrolling:touch}.strct-dg-host--virtual .strct-dg__scroll{overflow-y:auto}.strct-dg-host--virtual .strct-dg thead th{position:sticky;top:0;z-index:5}.strct-dg__vspacer td{padding:0;border:0;background:transparent}.strct-dg-host--sticky .strct-dg,.strct-dg-host--virtual .strct-dg{border-collapse:separate;border-spacing:0;overflow:visible;border-radius:0}.strct-dg-host--sticky .strct-dg{width:max-content;min-width:100%}.strct-dg .strct-dg__cell--sticky{position:sticky;z-index:3}.strct-dg thead th.strct-dg__cell--sticky{z-index:6}.strct-dg .strct-dg__cell--sticky-last:after{content:\"\";position:absolute;top:0;bottom:0;inset-inline-end:-1px;width:7px;pointer-events:none;background:linear-gradient(to right,rgba(0,0,0,.14),transparent)}[dir=rtl] .strct-dg .strct-dg__cell--sticky-last:after{background:linear-gradient(to left,rgba(0,0,0,.14),transparent)}.strct-dg-host--sticky .strct-dg__expandcol,.strct-dg-host--sticky .strct-dg__expandcell{width:36px;min-width:36px;max-width:36px;box-sizing:border-box}.strct-dg-host--sticky .strct-dg__sel{width:40px;min-width:40px;max-width:40px;box-sizing:border-box}.strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-3)}.strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-3)}.strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg{width:100%;border-collapse:collapse;font-size:13px;overflow:hidden;background:var(--bg-2)}.strct-dg-host:not(:has(.strct-dg__toolbar)) .strct-dg{border-start-start-radius:9px;border-start-end-radius:9px}.strct-dg-host:not(:has(.strct-dg__foot)) .strct-dg{border-end-start-radius:9px;border-end-end-radius:9px}.strct-dg th,.strct-dg td{padding:9px 13px;text-align:start;border-bottom:1px solid var(--b1)}.strct-dg tbody td{background:var(--bg-1)}[data-theme=dark] .strct-dg tbody td{background:var(--bg-3)}.strct-dg-host--compact .strct-dg th,.strct-dg-host--compact .strct-dg td{padding:5px 11px}.strct-dg-host--singleline .strct-dg tbody tr:not(.strct-dg__detailrow)>td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:360px}.strct-dg th{position:relative;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;color:var(--t2);background:var(--bg-2);white-space:nowrap;-webkit-user-select:none;user-select:none}.strct-dg__th--sortable{cursor:pointer}.strct-dg__th--sortable:hover{color:var(--t1)}.strct-dg__th--sortable:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__hd{display:inline-flex;align-items:center;gap:5px}.strct-dg__sorticon{color:var(--t3)}.strct-dg__th--sortable:hover .strct-dg__sorticon{color:var(--acc)}.strct-dg__resize{position:absolute;inset-inline-end:0;top:0;bottom:0;width:4px;cursor:col-resize;background:transparent;z-index:2}.strct-dg__resize:hover{background:var(--acc)}.strct-dg td{color:var(--t1)}.strct-dg tbody tr:last-child td{border-bottom:0}.strct-dg tbody tr:not(.strct-dg__detailrow):hover td{background:var(--acc-s)}.strct-dg__row--selected td{background:var(--acc-m)}.strct-dg__sel{width:1%;white-space:nowrap}.strct-dg__sel input{accent-color:var(--acc);width:15px;height:15px;cursor:pointer}.strct-dg__expandcol,.strct-dg__expandcell{width:1%;white-space:nowrap}.strct-dg__actioncol,.strct-dg__actioncell{width:1%;white-space:nowrap;text-align:end}.strct-dg__kebab{display:inline-flex;padding:4px;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__kebab:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;transition:transform .15s ease,color .15s ease}.strct-dg__expandbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn--open{transform:rotate(90deg);color:var(--acc)}.strct-dg__detailbtn{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__detailbtn:hover{color:var(--acc);background:var(--bg-3)}.strct-dg__detailbtn--active{color:var(--acc);background:var(--acc-m)}.strct-dg__detailrow td{background:var(--bg-2);padding:0}.strct-dg__detail{padding:14px 16px;font-size:13px;color:var(--t2)}.strct-dg__layout{display:flex;align-items:flex-start;min-width:0}.strct-dg__layout--paned{gap:0}.strct-dg__layout--paned .strct-dg__scroll{flex:0 0 auto;width:260px;min-width:260px;max-width:260px}.strct-dg__layout--paned .strct-dg{width:260px;min-width:260px;max-width:260px;flex-shrink:0;border-top-right-radius:0;border-bottom-right-radius:0}.strct-dg__row--clickable{cursor:pointer}.strct-dg__row--active td{background:var(--acc-m)}.strct-dg__layout--paned .strct-dg__row--active td:last-child{position:relative;padding-inline-end:26px}.strct-dg__layout--paned .strct-dg__row--active td:last-child:after{content:\"\";position:absolute;right:11px;top:50%;width:6px;height:6px;border-top:1.6px solid var(--acc);border-inline-end:1.6px solid var(--acc);transform:translateY(-50%) rotate(45deg)}.strct-dg__pane{flex:1;min-width:0;align-self:stretch;background:var(--bg-1);border:1px solid var(--b2);border-inline-start:2px solid var(--acc);border-radius:0 8px 8px 0;overflow:hidden;animation:strct-dg-pane-in .14s ease}.strct-dg__pane-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 14px;border-bottom:1px solid var(--b1);font-size:13px;font-weight:600;color:var(--t1)}.strct-dg__pane-close{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer}.strct-dg__pane-close:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__pane-body{padding:14px 16px;font-size:13px;color:var(--t2)}@keyframes strct-dg-pane-in{0%{opacity:0;transform:translate(8px)}}@keyframes strct-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}.strct-dg__skeleton-block{height:12px;background:var(--bg-3);border-radius:var(--radius-sm);animation:strct-skeleton-pulse 1.4s ease infinite}.strct-dg__skeleton-row td{border-bottom:1px solid var(--b1)}.strct-dg__empty{text-align:center;color:var(--t3);padding:22px}.strct-dg__toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:9px 14px;border-bottom:1px solid var(--b2)}.strct-dg__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 14px;border-top:1px solid var(--b2);flex-wrap:wrap}.strct-dg__foot-left,.strct-dg__foot-right{display:flex;align-items:center;gap:12px}.strct-dg__actions{position:relative}.strct-dg__chooser-menu{position:absolute;bottom:calc(100% + 6px);left:0;z-index:10;min-width:180px;background:var(--bg-1);border:1px solid var(--b2);border-radius:8px;box-shadow:var(--shadow-pop);padding:6px;display:flex;flex-direction:column;gap:2px}.strct-dg__chooser-menu--right{inset-inline-start:auto;inset-inline-end:0}.strct-dg__chooser-item{display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:6px;cursor:pointer;font-size:12px;color:var(--t1);transition:background .1s ease;-webkit-user-select:none;user-select:none}.strct-dg__chooser-item:hover{background:var(--bg-3)}.strct-dg__count{font-size:12px;color:var(--t2)}.strct-dg__count-sep{margin:0 8px;color:var(--b2)}.strct-dg__count-sel{color:var(--acc)}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "size", "strokeWidth", "badge", "ariaLabel"] }, { kind: "component", type: StrctPagination, selector: "strct-pagination", inputs: ["prevLabel", "nextLabel", "regionLabel", "total", "pageSize", "page"], outputs: ["pageChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: StrctCheckbox, selector: "strct-checkbox", inputs: ["checked", "isDisabled", "disabled", "indeterminate", "ariaLabel"], outputs: ["checkedChange", "isDisabledChange"] }, { kind: "component", type: StrctButton, selector: "button[strct-button], a[strct-button]", inputs: ["variant", "size", "solid", "block", "iconOnly"] }, { kind: "component", type: StrctButtonGroup, selector: "strct-button-group" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
7988
8343
  }
7989
8344
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctDatagrid, decorators: [{
7990
8345
  type: Component,
@@ -8001,18 +8356,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
8001
8356
  }
8002
8357
 
8003
8358
  <div class="strct-dg__layout" [class.strct-dg__layout--paned]="paneOpen()">
8004
- <div class="strct-dg__scroll" tabindex="0" role="region" [attr.aria-label]="L().rows">
8359
+ <div
8360
+ class="strct-dg__scroll"
8361
+ tabindex="0"
8362
+ role="region"
8363
+ [attr.aria-label]="L().rows"
8364
+ [style.max-height.px]="virtual() ? viewportHeight() : null"
8365
+ (scroll)="virtual() && onScroll($event)"
8366
+ >
8005
8367
  <table class="strct-dg">
8006
8368
  <thead>
8007
8369
  <tr>
8008
8370
  @if (canDetail()) {
8009
- <th class="strct-dg__expandcol"></th>
8371
+ <th
8372
+ class="strct-dg__expandcol"
8373
+ [class.strct-dg__cell--sticky]="stickyActive()"
8374
+ [style.insetInlineStart.px]="utilLeft('detail')"
8375
+ ></th>
8010
8376
  }
8011
8377
  @if (canExpand()) {
8012
- <th class="strct-dg__expandcol"></th>
8378
+ <th
8379
+ class="strct-dg__expandcol"
8380
+ [class.strct-dg__cell--sticky]="stickyActive()"
8381
+ [style.insetInlineStart.px]="utilLeft('expand')"
8382
+ ></th>
8013
8383
  }
8014
8384
  @if (selectable()) {
8015
- <th class="strct-dg__sel">
8385
+ <th
8386
+ class="strct-dg__sel"
8387
+ [class.strct-dg__cell--sticky]="stickyActive()"
8388
+ [style.insetInlineStart.px]="utilLeft('sel')"
8389
+ >
8016
8390
  <strct-checkbox
8017
8391
  [ariaLabel]="L().selectAll"
8018
8392
  [checked]="allPageSelected()"
@@ -8026,6 +8400,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
8026
8400
  [style.text-align]="col.align ?? 'start'"
8027
8401
  [style.width]="colWidth(col.key) ?? col.width ?? null"
8028
8402
  [class.strct-dg__th--sortable]="col.sortable"
8403
+ [class.strct-dg__cell--sticky]="isSticky(col)"
8404
+ [class.strct-dg__cell--sticky-last]="col.key === lastStickyKey()"
8405
+ [style.insetInlineStart.px]="stickyLeft(col.key)"
8029
8406
  [attr.tabindex]="col.sortable ? 0 : null"
8030
8407
  [attr.aria-sort]="col.sortable ? ariaSort(col.key) : null"
8031
8408
  (click)="col.sortable && sortBy(col.key)"
@@ -8079,13 +8456,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
8079
8456
  </tr>
8080
8457
  }
8081
8458
  } @else {
8082
- @for (row of paged(); track rowKey(row)) {
8459
+ @if (virtual() && topPad() > 0) {
8460
+ <tr class="strct-dg__vspacer" aria-hidden="true">
8461
+ <td [attr.colspan]="colspan()" [style.height.px]="topPad()"></td>
8462
+ </tr>
8463
+ }
8464
+ @for (row of renderRows(); track rowKey(row)) {
8083
8465
  <tr
8084
8466
  [class.strct-dg__row--selected]="isSelected(row)"
8085
8467
  [class.strct-dg__row--active]="paneOpen() && row === activeRow()"
8086
8468
  >
8087
8469
  @if (canDetail()) {
8088
- <td class="strct-dg__expandcell">
8470
+ <td
8471
+ class="strct-dg__expandcell"
8472
+ [class.strct-dg__cell--sticky]="stickyActive()"
8473
+ [style.insetInlineStart.px]="utilLeft('detail')"
8474
+ >
8089
8475
  <button
8090
8476
  type="button"
8091
8477
  class="strct-dg__detailbtn"
@@ -8099,7 +8485,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
8099
8485
  </td>
8100
8486
  }
8101
8487
  @if (canExpand()) {
8102
- <td class="strct-dg__expandcell">
8488
+ <td
8489
+ class="strct-dg__expandcell"
8490
+ [class.strct-dg__cell--sticky]="stickyActive()"
8491
+ [style.insetInlineStart.px]="utilLeft('expand')"
8492
+ >
8103
8493
  <button
8104
8494
  type="button"
8105
8495
  class="strct-dg__expandbtn"
@@ -8113,7 +8503,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
8113
8503
  </td>
8114
8504
  }
8115
8505
  @if (selectable()) {
8116
- <td class="strct-dg__sel">
8506
+ <td
8507
+ class="strct-dg__sel"
8508
+ [class.strct-dg__cell--sticky]="stickyActive()"
8509
+ [style.insetInlineStart.px]="utilLeft('sel')"
8510
+ >
8117
8511
  <strct-checkbox
8118
8512
  [ariaLabel]="L().selectRow"
8119
8513
  [checked]="isSelected(row)"
@@ -8122,7 +8516,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
8122
8516
  </td>
8123
8517
  }
8124
8518
  @for (col of visibleColumns(); track col.key) {
8125
- <td [style.text-align]="col.align ?? 'start'">
8519
+ <td
8520
+ [style.text-align]="col.align ?? 'start'"
8521
+ [class.strct-dg__cell--sticky]="isSticky(col)"
8522
+ [class.strct-dg__cell--sticky-last]="col.key === lastStickyKey()"
8523
+ [style.insetInlineStart.px]="stickyLeft(col.key)"
8524
+ >
8126
8525
  @if (cellTemplate(col.key); as tpl) {
8127
8526
  <ng-container
8128
8527
  [ngTemplateOutlet]="tpl"
@@ -8167,6 +8566,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
8167
8566
  <td class="strct-dg__empty" [attr.colspan]="colspan()">{{ emptyText() }}</td>
8168
8567
  </tr>
8169
8568
  }
8569
+ @if (virtual() && bottomPad() > 0) {
8570
+ <tr class="strct-dg__vspacer" aria-hidden="true">
8571
+ <td [attr.colspan]="colspan()" [style.height.px]="bottomPad()"></td>
8572
+ </tr>
8573
+ }
8170
8574
  }
8171
8575
  </tbody>
8172
8576
  </table>
@@ -8195,7 +8599,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
8195
8599
  }
8196
8600
  </div>
8197
8601
 
8198
- @if (pageSize() > 0 && !loading()) {
8602
+ @if ((pageSize() > 0 || virtual()) && !loading()) {
8199
8603
  <div class="strct-dg__foot">
8200
8604
  <div class="strct-dg__foot-left">
8201
8605
  @if (columnChooser() || sync()) {
@@ -8241,7 +8645,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
8241
8645
  </div>
8242
8646
  }
8243
8647
  <span class="strct-dg__count">
8244
- {{ sorted().length }} {{ sorted().length === 1 ? L().row : L().rows }}
8648
+ {{ totalCount() }} {{ totalCount() === 1 ? L().row : L().rows }}
8245
8649
  @if (selectedCount()) {
8246
8650
  <span class="strct-dg__count-sep">|</span>
8247
8651
  <span class="strct-dg__count-sel">{{ selectedCount() }} {{ L().selected }}</span>
@@ -8249,7 +8653,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
8249
8653
  </span>
8250
8654
  </div>
8251
8655
  <div class="strct-dg__foot-right">
8252
- <strct-pagination [total]="sorted().length" [pageSize]="pageSize()" [(page)]="page" />
8656
+ @if (pageSize() > 0) {
8657
+ <strct-pagination [total]="totalCount()" [pageSize]="pageSize()" [(page)]="page" />
8658
+ }
8253
8659
  </div>
8254
8660
  </div>
8255
8661
  }
@@ -8257,8 +8663,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
8257
8663
  class: 'strct-dg-host',
8258
8664
  '[class.strct-dg-host--compact]': 'compact()',
8259
8665
  '[class.strct-dg-host--singleline]': 'singleLine()',
8260
- }, styles: [".strct-dg-host{display:block;border:1px solid var(--b2);border-radius:10px;background:var(--bg-2);box-shadow:var(--shadow-rest)}.strct-dg__scroll{flex:1 1 auto;min-width:0;overflow-x:auto;-webkit-overflow-scrolling:touch}.strct-dg{width:100%;border-collapse:collapse;font-size:13px;overflow:hidden;background:var(--bg-2)}.strct-dg-host:not(:has(.strct-dg__toolbar)) .strct-dg{border-start-start-radius:9px;border-start-end-radius:9px}.strct-dg-host:not(:has(.strct-dg__foot)) .strct-dg{border-end-start-radius:9px;border-end-end-radius:9px}.strct-dg th,.strct-dg td{padding:9px 13px;text-align:start;border-bottom:1px solid var(--b1)}.strct-dg tbody td{background:var(--bg-1)}[data-theme=dark] .strct-dg tbody td{background:var(--bg-3)}.strct-dg-host--compact .strct-dg th,.strct-dg-host--compact .strct-dg td{padding:5px 11px}.strct-dg-host--singleline .strct-dg tbody tr:not(.strct-dg__detailrow)>td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:360px}.strct-dg th{position:relative;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;color:var(--t2);background:var(--bg-2);white-space:nowrap;-webkit-user-select:none;user-select:none}.strct-dg__th--sortable{cursor:pointer}.strct-dg__th--sortable:hover{color:var(--t1)}.strct-dg__th--sortable:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__hd{display:inline-flex;align-items:center;gap:5px}.strct-dg__sorticon{color:var(--t3)}.strct-dg__th--sortable:hover .strct-dg__sorticon{color:var(--acc)}.strct-dg__resize{position:absolute;right:0;top:0;bottom:0;width:4px;cursor:col-resize;background:transparent;z-index:2}.strct-dg__resize:hover{background:var(--acc)}.strct-dg td{color:var(--t1)}.strct-dg tbody tr:last-child td{border-bottom:0}.strct-dg tbody tr:not(.strct-dg__detailrow):hover td{background:var(--acc-s)}.strct-dg__row--selected td{background:var(--acc-m)}.strct-dg__sel{width:1%;white-space:nowrap}.strct-dg__sel input{accent-color:var(--acc);width:15px;height:15px;cursor:pointer}.strct-dg__expandcol,.strct-dg__expandcell{width:1%;white-space:nowrap}.strct-dg__actioncol,.strct-dg__actioncell{width:1%;white-space:nowrap;text-align:end}.strct-dg__kebab{display:inline-flex;padding:4px;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__kebab:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;transition:transform .15s ease,color .15s ease}.strct-dg__expandbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn--open{transform:rotate(90deg);color:var(--acc)}.strct-dg__detailbtn{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__detailbtn:hover{color:var(--acc);background:var(--bg-3)}.strct-dg__detailbtn--active{color:var(--acc);background:var(--acc-m)}.strct-dg__detailrow td{background:var(--bg-2);padding:0}.strct-dg__detail{padding:14px 16px;font-size:13px;color:var(--t2)}.strct-dg__layout{display:flex;align-items:flex-start;min-width:0}.strct-dg__layout--paned{gap:0}.strct-dg__layout--paned .strct-dg__scroll{flex:0 0 auto;width:260px;min-width:260px;max-width:260px}.strct-dg__layout--paned .strct-dg{width:260px;min-width:260px;max-width:260px;flex-shrink:0;border-top-right-radius:0;border-bottom-right-radius:0}.strct-dg__row--clickable{cursor:pointer}.strct-dg__row--active td{background:var(--acc-m)}.strct-dg__layout--paned .strct-dg__row--active td:last-child{position:relative;padding-inline-end:26px}.strct-dg__layout--paned .strct-dg__row--active td:last-child:after{content:\"\";position:absolute;right:11px;top:50%;width:6px;height:6px;border-top:1.6px solid var(--acc);border-inline-end:1.6px solid var(--acc);transform:translateY(-50%) rotate(45deg)}.strct-dg__pane{flex:1;min-width:0;align-self:stretch;background:var(--bg-1);border:1px solid var(--b2);border-inline-start:2px solid var(--acc);border-radius:0 8px 8px 0;overflow:hidden;animation:strct-dg-pane-in .14s ease}.strct-dg__pane-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 14px;border-bottom:1px solid var(--b1);font-size:13px;font-weight:600;color:var(--t1)}.strct-dg__pane-close{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer}.strct-dg__pane-close:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__pane-body{padding:14px 16px;font-size:13px;color:var(--t2)}@keyframes strct-dg-pane-in{0%{opacity:0;transform:translate(8px)}}@keyframes strct-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}.strct-dg__skeleton-block{height:12px;background:var(--bg-3);border-radius:var(--radius-sm);animation:strct-skeleton-pulse 1.4s ease infinite}.strct-dg__skeleton-row td{border-bottom:1px solid var(--b1)}.strct-dg__empty{text-align:center;color:var(--t3);padding:22px}.strct-dg__toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:9px 14px;border-bottom:1px solid var(--b2)}.strct-dg__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 14px;border-top:1px solid var(--b2);flex-wrap:wrap}.strct-dg__foot-left,.strct-dg__foot-right{display:flex;align-items:center;gap:12px}.strct-dg__actions{position:relative}.strct-dg__chooser-menu{position:absolute;bottom:calc(100% + 6px);left:0;z-index:10;min-width:180px;background:var(--bg-1);border:1px solid var(--b2);border-radius:8px;box-shadow:var(--shadow-pop);padding:6px;display:flex;flex-direction:column;gap:2px}.strct-dg__chooser-menu--right{left:auto;right:0}.strct-dg__chooser-item{display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:6px;cursor:pointer;font-size:12px;color:var(--t1);transition:background .1s ease;-webkit-user-select:none;user-select:none}.strct-dg__chooser-item:hover{background:var(--bg-3)}.strct-dg__count{font-size:12px;color:var(--t2)}.strct-dg__count-sep{margin:0 8px;color:var(--b2)}.strct-dg__count-sel{color:var(--acc)}\n"] }]
8261
- }], ctorParameters: () => [], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: true }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], expandable: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandable", required: false }] }], detailPane: [{ type: i0.Input, args: [{ isSignal: true, alias: "detailPane", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], singleLine: [{ type: i0.Input, args: [{ isSignal: true, alias: "singleLine", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], resizable: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizable", required: false }] }], columnChooser: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnChooser", required: false }] }], sync: [{ type: i0.Input, args: [{ isSignal: true, alias: "sync", required: false }] }], footerActionsDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerActionsDisabled", required: false }] }], rowId: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowId", required: false }] }], rowActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowActions", required: false }] }], initialSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialSelection", required: false }] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], syncChange: [{ type: i0.Output, args: ["syncChange"] }], rowAction: [{ type: i0.Output, args: ["rowAction"] }], detailDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StrctRowDetailDef), { isSignal: true }] }], actionBarDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StrctDatagridActionBar), { isSignal: true }] }], cellDefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => StrctCellDef), { isSignal: true }] }] } });
8666
+ '[class.strct-dg-host--virtual]': 'virtual()',
8667
+ '[class.strct-dg-host--sticky]': 'stickyActive()',
8668
+ }, styles: [".strct-dg-host{display:block;border:1px solid var(--b2);border-radius:10px;background:var(--bg-2);box-shadow:var(--shadow-rest)}.strct-dg__scroll{flex:1 1 auto;min-width:0;overflow-x:auto;-webkit-overflow-scrolling:touch}.strct-dg-host--virtual .strct-dg__scroll{overflow-y:auto}.strct-dg-host--virtual .strct-dg thead th{position:sticky;top:0;z-index:5}.strct-dg__vspacer td{padding:0;border:0;background:transparent}.strct-dg-host--sticky .strct-dg,.strct-dg-host--virtual .strct-dg{border-collapse:separate;border-spacing:0;overflow:visible;border-radius:0}.strct-dg-host--sticky .strct-dg{width:max-content;min-width:100%}.strct-dg .strct-dg__cell--sticky{position:sticky;z-index:3}.strct-dg thead th.strct-dg__cell--sticky{z-index:6}.strct-dg .strct-dg__cell--sticky-last:after{content:\"\";position:absolute;top:0;bottom:0;inset-inline-end:-1px;width:7px;pointer-events:none;background:linear-gradient(to right,rgba(0,0,0,.14),transparent)}[dir=rtl] .strct-dg .strct-dg__cell--sticky-last:after{background:linear-gradient(to left,rgba(0,0,0,.14),transparent)}.strct-dg-host--sticky .strct-dg__expandcol,.strct-dg-host--sticky .strct-dg__expandcell{width:36px;min-width:36px;max-width:36px;box-sizing:border-box}.strct-dg-host--sticky .strct-dg__sel{width:40px;min-width:40px;max-width:40px;box-sizing:border-box}.strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__cell--sticky{background:var(--bg-3)}.strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody tr:hover .strct-dg__cell--sticky{background:linear-gradient(var(--acc-s),var(--acc-s)) var(--bg-3)}.strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-1)}[data-theme=dark] .strct-dg-host--sticky tbody .strct-dg__row--selected .strct-dg__cell--sticky{background:linear-gradient(var(--acc-m),var(--acc-m)) var(--bg-3)}.strct-dg{width:100%;border-collapse:collapse;font-size:13px;overflow:hidden;background:var(--bg-2)}.strct-dg-host:not(:has(.strct-dg__toolbar)) .strct-dg{border-start-start-radius:9px;border-start-end-radius:9px}.strct-dg-host:not(:has(.strct-dg__foot)) .strct-dg{border-end-start-radius:9px;border-end-end-radius:9px}.strct-dg th,.strct-dg td{padding:9px 13px;text-align:start;border-bottom:1px solid var(--b1)}.strct-dg tbody td{background:var(--bg-1)}[data-theme=dark] .strct-dg tbody td{background:var(--bg-3)}.strct-dg-host--compact .strct-dg th,.strct-dg-host--compact .strct-dg td{padding:5px 11px}.strct-dg-host--singleline .strct-dg tbody tr:not(.strct-dg__detailrow)>td{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:360px}.strct-dg th{position:relative;font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;color:var(--t2);background:var(--bg-2);white-space:nowrap;-webkit-user-select:none;user-select:none}.strct-dg__th--sortable{cursor:pointer}.strct-dg__th--sortable:hover{color:var(--t1)}.strct-dg__th--sortable:focus-visible{outline:2px solid var(--acc50);outline-offset:-2px}.strct-dg__hd{display:inline-flex;align-items:center;gap:5px}.strct-dg__sorticon{color:var(--t3)}.strct-dg__th--sortable:hover .strct-dg__sorticon{color:var(--acc)}.strct-dg__resize{position:absolute;inset-inline-end:0;top:0;bottom:0;width:4px;cursor:col-resize;background:transparent;z-index:2}.strct-dg__resize:hover{background:var(--acc)}.strct-dg td{color:var(--t1)}.strct-dg tbody tr:last-child td{border-bottom:0}.strct-dg tbody tr:not(.strct-dg__detailrow):hover td{background:var(--acc-s)}.strct-dg__row--selected td{background:var(--acc-m)}.strct-dg__sel{width:1%;white-space:nowrap}.strct-dg__sel input{accent-color:var(--acc);width:15px;height:15px;cursor:pointer}.strct-dg__expandcol,.strct-dg__expandcell{width:1%;white-space:nowrap}.strct-dg__actioncol,.strct-dg__actioncell{width:1%;white-space:nowrap;text-align:end}.strct-dg__kebab{display:inline-flex;padding:4px;border:0;border-radius:5px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__kebab:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;transition:transform .15s ease,color .15s ease}.strct-dg__expandbtn:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__expandbtn--open{transform:rotate(90deg);color:var(--acc)}.strct-dg__detailbtn{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer;transition:color .14s ease,background .14s ease}.strct-dg__detailbtn:hover{color:var(--acc);background:var(--bg-3)}.strct-dg__detailbtn--active{color:var(--acc);background:var(--acc-m)}.strct-dg__detailrow td{background:var(--bg-2);padding:0}.strct-dg__detail{padding:14px 16px;font-size:13px;color:var(--t2)}.strct-dg__layout{display:flex;align-items:flex-start;min-width:0}.strct-dg__layout--paned{gap:0}.strct-dg__layout--paned .strct-dg__scroll{flex:0 0 auto;width:260px;min-width:260px;max-width:260px}.strct-dg__layout--paned .strct-dg{width:260px;min-width:260px;max-width:260px;flex-shrink:0;border-top-right-radius:0;border-bottom-right-radius:0}.strct-dg__row--clickable{cursor:pointer}.strct-dg__row--active td{background:var(--acc-m)}.strct-dg__layout--paned .strct-dg__row--active td:last-child{position:relative;padding-inline-end:26px}.strct-dg__layout--paned .strct-dg__row--active td:last-child:after{content:\"\";position:absolute;right:11px;top:50%;width:6px;height:6px;border-top:1.6px solid var(--acc);border-inline-end:1.6px solid var(--acc);transform:translateY(-50%) rotate(45deg)}.strct-dg__pane{flex:1;min-width:0;align-self:stretch;background:var(--bg-1);border:1px solid var(--b2);border-inline-start:2px solid var(--acc);border-radius:0 8px 8px 0;overflow:hidden;animation:strct-dg-pane-in .14s ease}.strct-dg__pane-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 14px;border-bottom:1px solid var(--b1);font-size:13px;font-weight:600;color:var(--t1)}.strct-dg__pane-close{display:inline-flex;padding:3px;border:0;border-radius:4px;background:transparent;color:var(--t3);cursor:pointer}.strct-dg__pane-close:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__pane-body{padding:14px 16px;font-size:13px;color:var(--t2)}@keyframes strct-dg-pane-in{0%{opacity:0;transform:translate(8px)}}@keyframes strct-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}.strct-dg__skeleton-block{height:12px;background:var(--bg-3);border-radius:var(--radius-sm);animation:strct-skeleton-pulse 1.4s ease infinite}.strct-dg__skeleton-row td{border-bottom:1px solid var(--b1)}.strct-dg__empty{text-align:center;color:var(--t3);padding:22px}.strct-dg__toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:9px 14px;border-bottom:1px solid var(--b2)}.strct-dg__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 14px;border-top:1px solid var(--b2);flex-wrap:wrap}.strct-dg__foot-left,.strct-dg__foot-right{display:flex;align-items:center;gap:12px}.strct-dg__actions{position:relative}.strct-dg__chooser-menu{position:absolute;bottom:calc(100% + 6px);left:0;z-index:10;min-width:180px;background:var(--bg-1);border:1px solid var(--b2);border-radius:8px;box-shadow:var(--shadow-pop);padding:6px;display:flex;flex-direction:column;gap:2px}.strct-dg__chooser-menu--right{inset-inline-start:auto;inset-inline-end:0}.strct-dg__chooser-item{display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:6px;cursor:pointer;font-size:12px;color:var(--t1);transition:background .1s ease;-webkit-user-select:none;user-select:none}.strct-dg__chooser-item:hover{background:var(--bg-3)}.strct-dg__count{font-size:12px;color:var(--t2)}.strct-dg__count-sep{margin:0 8px;color:var(--b2)}.strct-dg__count-sel{color:var(--acc)}\n"] }]
8669
+ }], ctorParameters: () => [], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: true }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], expandable: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandable", required: false }] }], detailPane: [{ type: i0.Input, args: [{ isSignal: true, alias: "detailPane", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], singleLine: [{ type: i0.Input, args: [{ isSignal: true, alias: "singleLine", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], resizable: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizable", required: false }] }], columnChooser: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnChooser", required: false }] }], sync: [{ type: i0.Input, args: [{ isSignal: true, alias: "sync", required: false }] }], footerActionsDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "footerActionsDisabled", required: false }] }], rowId: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowId", required: false }] }], rowActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowActions", required: false }] }], initialSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialSelection", required: false }] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], virtual: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtual", required: false }] }], viewportHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewportHeight", required: false }] }], rowHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowHeight", required: false }] }], lazy: [{ type: i0.Input, args: [{ isSignal: true, alias: "lazy", required: false }] }], total: [{ type: i0.Input, args: [{ isSignal: true, alias: "total", required: false }] }], stateKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "stateKey", required: false }] }], columnState: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnState", required: false }] }, { type: i0.Output, args: ["columnStateChange"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], syncChange: [{ type: i0.Output, args: ["syncChange"] }], rowAction: [{ type: i0.Output, args: ["rowAction"] }], lazyLoad: [{ type: i0.Output, args: ["lazyLoad"] }], detailDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StrctRowDetailDef), { isSignal: true }] }], actionBarDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => StrctDatagridActionBar), { isSignal: true }] }], cellDefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => StrctCellDef), { isSignal: true }] }] } });
8262
8670
 
8263
8671
  /** Vertical timeline container. Wraps `<strct-timeline-item>` children. */
8264
8672
  class StrctTimeline {