@akcelik/strct 0.5.1 → 0.5.3

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.
@@ -624,6 +624,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
624
624
  args: [{ selector: '[strctOverlay]' }]
625
625
  }], ctorParameters: () => [], propDecorators: { anchor: [{ type: i0.Input, args: [{ isSignal: true, alias: "strctOverlay", required: true }] }], placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "strctOverlayPlacement", required: false }] }], matchWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "strctOverlayMatchWidth", required: false }] }], gap: [{ type: i0.Input, args: [{ isSignal: true, alias: "strctOverlayGap", required: false }] }] } });
626
626
 
627
+ /** Shared layout state between shell parts. */
628
+ class StrctShellService {
629
+ mobileNavOpen = signal(false, ...(ngDevMode ? [{ debugName: "mobileNavOpen" }] : /* istanbul ignore next */ []));
630
+ }
627
631
  /**
628
632
  * Application frame: a full-viewport grid of header / body / footer rows.
629
633
  * <strct-shell>
@@ -634,7 +638,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
634
638
  */
635
639
  class StrctShell {
636
640
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctShell, deps: [], target: i0.ɵɵFactoryTarget.Component });
637
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.16", type: StrctShell, isStandalone: true, selector: "strct-shell", host: { classAttribute: "strct-shell" }, ngImport: i0, template: `
641
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.16", type: StrctShell, isStandalone: true, selector: "strct-shell", host: { classAttribute: "strct-shell" }, providers: [StrctShellService], ngImport: i0, template: `
638
642
  <ng-content select="strct-header" />
639
643
  <div class="strct-shell__main"><ng-content /></div>
640
644
  <ng-content select="strct-footer" />
@@ -642,16 +646,12 @@ class StrctShell {
642
646
  }
643
647
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctShell, decorators: [{
644
648
  type: Component,
645
- args: [{ selector: 'strct-shell', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: `
649
+ args: [{ selector: 'strct-shell', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [StrctShellService], template: `
646
650
  <ng-content select="strct-header" />
647
651
  <div class="strct-shell__main"><ng-content /></div>
648
652
  <ng-content select="strct-footer" />
649
653
  `, host: { class: 'strct-shell' }, styles: [".strct-shell{display:grid;grid-template-rows:auto 1fr auto;height:100vh;overflow:hidden;background:var(--bg-2)}.strct-shell__main{display:flex;min-height:0;overflow:hidden}\n"] }]
650
654
  }] });
651
- /** Shared layout state between shell parts. */
652
- class StrctShellService {
653
- mobileNavOpen = signal(false, ...(ngDevMode ? [{ debugName: "mobileNavOpen" }] : /* istanbul ignore next */ []));
654
- }
655
655
  /** Top application bar. Holds brand on the left and actions on the right. */
656
656
  class StrctHeader {
657
657
  shell = inject(StrctShellService);
@@ -5467,6 +5467,8 @@ class StrctDatagrid {
5467
5467
  emptyText = input('No data', ...(ngDevMode ? [{ debugName: "emptyText" }] : /* istanbul ignore next */ []));
5468
5468
  /** Show skeleton rows while data is loading. */
5469
5469
  loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
5470
+ /** Enable column resizing by dragging column headers. */
5471
+ resizable = input(false, { ...(ngDevMode ? { debugName: "resizable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
5470
5472
  /**
5471
5473
  * Stable row identity (property key or function). Set this for live-refreshing
5472
5474
  * data so selection, expansion and the active detail row survive re-fetches
@@ -5488,7 +5490,41 @@ class StrctDatagrid {
5488
5490
  sort = signal({ key: null, dir: 'asc' }, ...(ngDevMode ? [{ debugName: "sort" }] : /* istanbul ignore next */ []));
5489
5491
  /** Selection / expansion are tracked by row id (see {@link rowId}). */
5490
5492
  selected = signal(new Set(), ...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
5493
+ selectedCount = computed(() => this.selected().size, ...(ngDevMode ? [{ debugName: "selectedCount" }] : /* istanbul ignore next */ []));
5491
5494
  expandedRows = signal(new Set(), ...(ngDevMode ? [{ debugName: "expandedRows" }] : /* istanbul ignore next */ []));
5495
+ columnWidths = signal(new Map(), ...(ngDevMode ? [{ debugName: "columnWidths" }] : /* istanbul ignore next */ []));
5496
+ resizeState = null;
5497
+ onMove = (e) => this.onResizeMove(e);
5498
+ onUp = () => this.onResizeEnd();
5499
+ colWidth(key) {
5500
+ const px = this.columnWidths().get(key);
5501
+ return px != null ? `${px}px` : null;
5502
+ }
5503
+ onResizeStart(e, key) {
5504
+ e.preventDefault();
5505
+ const th = e.target.closest('th');
5506
+ if (!th)
5507
+ return;
5508
+ this.resizeState = { key, startX: e.clientX, startWidth: th.offsetWidth };
5509
+ document.addEventListener('mousemove', this.onMove);
5510
+ document.addEventListener('mouseup', this.onUp);
5511
+ }
5512
+ onResizeMove(e) {
5513
+ if (!this.resizeState)
5514
+ return;
5515
+ const diff = e.clientX - this.resizeState.startX;
5516
+ const newWidth = Math.max(40, this.resizeState.startWidth + diff);
5517
+ this.columnWidths.update((m) => {
5518
+ const next = new Map(m);
5519
+ next.set(this.resizeState.key, newWidth);
5520
+ return next;
5521
+ });
5522
+ }
5523
+ onResizeEnd() {
5524
+ this.resizeState = null;
5525
+ document.removeEventListener('mousemove', this.onMove);
5526
+ document.removeEventListener('mouseup', this.onUp);
5527
+ }
5492
5528
  activeId = signal(null, ...(ngDevMode ? [{ debugName: "activeId" }] : /* istanbul ignore next */ []));
5493
5529
  activeRow = computed(() => {
5494
5530
  const id = this.activeId();
@@ -5516,7 +5552,6 @@ class StrctDatagrid {
5516
5552
  const start = (this.page() - 1) * size;
5517
5553
  return this.sorted().slice(start, start + size);
5518
5554
  }, ...(ngDevMode ? [{ debugName: "paged" }] : /* istanbul ignore next */ []));
5519
- selectedCount = computed(() => this.selected().size, ...(ngDevMode ? [{ debugName: "selectedCount" }] : /* istanbul ignore next */ []));
5520
5555
  allPageSelected = computed(() => {
5521
5556
  const rows = this.paged();
5522
5557
  return rows.length > 0 && rows.every((r) => this.selected().has(this.idOf(r)));
@@ -5643,7 +5678,7 @@ class StrctDatagrid {
5643
5678
  return String(a ?? '').localeCompare(String(b ?? ''), undefined, { numeric: true });
5644
5679
  }
5645
5680
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctDatagrid, deps: [], target: i0.ɵɵFactoryTarget.Component });
5646
- 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 }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, rowId: { classPropertyName: "rowId", publicName: "rowId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange" }, host: { properties: { "class.strct-dg-host--compact": "compact()" }, 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: `
5681
+ 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 }, 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 }, rowId: { classPropertyName: "rowId", publicName: "rowId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange" }, host: { properties: { "class.strct-dg-host--compact": "compact()" }, 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: `
5647
5682
  @if (actionBarDef()) {
5648
5683
  <div class="strct-dg__toolbar"><ng-content select="[strctDatagridActionBar]" /></div>
5649
5684
  }
@@ -5652,19 +5687,6 @@ class StrctDatagrid {
5652
5687
  <div class="strct-dg__scroll">
5653
5688
  <table class="strct-dg">
5654
5689
  <thead>
5655
- @if (selectable() && selectedCount() > 0) {
5656
- <tr class="strct-dg__selbar">
5657
- <th [attr.colspan]="colspan()" class="strct-dg__selbar-cell">
5658
- <span class="strct-dg__selbar-count">{{ selectedCount() }} selected</span>
5659
- <button type="button" class="strct-dg__selbar-clear" (click)="clearSelection()">
5660
- Clear
5661
- </button>
5662
- <span class="strct-dg__selbar-actions">
5663
- <ng-content select="[strctDatagridActions]" />
5664
- </span>
5665
- </th>
5666
- </tr>
5667
- }
5668
5690
  <tr>
5669
5691
  @if (canDetail()) {
5670
5692
  <th class="strct-dg__expandcol"></th>
@@ -5686,7 +5708,7 @@ class StrctDatagrid {
5686
5708
  @for (col of visibleColumns(); track col.key) {
5687
5709
  <th
5688
5710
  [style.text-align]="col.align ?? 'start'"
5689
- [style.width]="col.width"
5711
+ [style.width]="colWidth(col.key) ?? col.width ?? null"
5690
5712
  [class.strct-dg__th--sortable]="col.sortable"
5691
5713
  [attr.tabindex]="col.sortable ? 0 : null"
5692
5714
  [attr.aria-sort]="col.sortable ? ariaSort(col.key) : null"
@@ -5704,6 +5726,12 @@ class StrctDatagrid {
5704
5726
  />
5705
5727
  }
5706
5728
  </span>
5729
+ @if (resizable() && col.resizable !== false) {
5730
+ <div
5731
+ class="strct-dg__resize"
5732
+ (mousedown)="onResizeStart($event, col.key)"
5733
+ ></div>
5734
+ }
5707
5735
  </th>
5708
5736
  }
5709
5737
  </tr>
@@ -5839,13 +5867,14 @@ class StrctDatagrid {
5839
5867
  <span class="strct-dg__count">
5840
5868
  {{ sorted().length }} {{ sorted().length === 1 ? 'row' : 'rows' }}
5841
5869
  @if (selectedCount()) {
5842
- · {{ selectedCount() }} selected
5870
+ <span class="strct-dg__count-sep">|</span>
5871
+ <span class="strct-dg__count-sel">{{ selectedCount() }} selected</span>
5843
5872
  }
5844
5873
  </span>
5845
5874
  <strct-pagination [total]="sorted().length" [pageSize]="pageSize()" [(page)]="page" />
5846
5875
  </div>
5847
5876
  }
5848
- `, isInline: true, styles: [".strct-dg-host{display:block}.strct-dg__scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}.strct-dg{width:100%;border-collapse:collapse;font-size:13px;border:1px solid var(--b2);border-radius:8px;overflow:hidden}.strct-dg th,.strct-dg td{padding:9px 13px;text-align:left;border-bottom:1px solid var(--b1)}.strct-dg-host--compact .strct-dg th,.strct-dg-host--compact .strct-dg td{padding:5px 11px}.strct-dg th{font-size:11px;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 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__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;gap:14px;align-items:flex-start}.strct-dg__layout--paned .strct-dg{width:auto;min-width:180px;max-width:260px;flex-shrink: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-right: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-right: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-left:2px solid var(--acc);border-radius:8px;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:8px 0;margin-bottom:8px;border-bottom:1px solid var(--b1)}.strct-dg__selbar{animation:strct-dg-bar-in .12s ease}.strct-dg__selbar-cell{padding:7px 13px;font-size:12px;font-weight:500;color:var(--acc);border-bottom:1px solid var(--b1);background:var(--acc-m);text-align:left}.strct-dg__selbar-count{font-weight:600}.strct-dg__selbar-clear{border:0;background:transparent;color:var(--t2);cursor:pointer;font-size:12px;padding:2px 6px;margin-left:10px;border-radius:var(--radius-sm)}.strct-dg__selbar-clear:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__selbar-actions{display:inline-flex;gap:8px;margin-left:auto}@keyframes strct-dg-bar-in{0%{opacity:0}}.strct-dg__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:12px;flex-wrap:wrap}.strct-dg__count{font-size:12px;color:var(--t2)}\n"], dependencies: [{ kind: "component", type: StrctIcon, selector: "strct-icon", inputs: ["name", "size", "strokeWidth", "badge", "ariaLabel"] }, { kind: "component", type: StrctPagination, selector: "strct-pagination", inputs: ["total", "pageSize", "page"], outputs: ["pageChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
5877
+ `, isInline: true, styles: [".strct-dg-host{display:block}.strct-dg__scroll{flex:1 1 auto;min-width:0;overflow-x:auto;-webkit-overflow-scrolling:touch}.strct-dg{width:100%;table-layout:fixed;border-collapse:collapse;font-size:13px;border:1px solid var(--b2);border-radius:8px;overflow:hidden}.strct-dg th,.strct-dg td{padding:9px 13px;text-align:left;border-bottom:1px solid var(--b1)}.strct-dg-host--compact .strct-dg th,.strct-dg-host--compact .strct-dg td{padding:5px 11px}.strct-dg th{position:relative;font-size:11px;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__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;gap:14px;align-items:flex-start;min-width:0}.strct-dg__layout--paned .strct-dg{width:auto;min-width:180px;max-width:260px;flex-shrink: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-right: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-right: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-left:2px solid var(--acc);border-radius:8px;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:8px 0;margin-bottom:8px;border-bottom:1px solid var(--b1)}.strct-dg__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:12px;flex-wrap:wrap}.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: ["total", "pageSize", "page"], outputs: ["pageChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
5849
5878
  }
5850
5879
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: StrctDatagrid, decorators: [{
5851
5880
  type: Component,
@@ -5858,19 +5887,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
5858
5887
  <div class="strct-dg__scroll">
5859
5888
  <table class="strct-dg">
5860
5889
  <thead>
5861
- @if (selectable() && selectedCount() > 0) {
5862
- <tr class="strct-dg__selbar">
5863
- <th [attr.colspan]="colspan()" class="strct-dg__selbar-cell">
5864
- <span class="strct-dg__selbar-count">{{ selectedCount() }} selected</span>
5865
- <button type="button" class="strct-dg__selbar-clear" (click)="clearSelection()">
5866
- Clear
5867
- </button>
5868
- <span class="strct-dg__selbar-actions">
5869
- <ng-content select="[strctDatagridActions]" />
5870
- </span>
5871
- </th>
5872
- </tr>
5873
- }
5874
5890
  <tr>
5875
5891
  @if (canDetail()) {
5876
5892
  <th class="strct-dg__expandcol"></th>
@@ -5892,7 +5908,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
5892
5908
  @for (col of visibleColumns(); track col.key) {
5893
5909
  <th
5894
5910
  [style.text-align]="col.align ?? 'start'"
5895
- [style.width]="col.width"
5911
+ [style.width]="colWidth(col.key) ?? col.width ?? null"
5896
5912
  [class.strct-dg__th--sortable]="col.sortable"
5897
5913
  [attr.tabindex]="col.sortable ? 0 : null"
5898
5914
  [attr.aria-sort]="col.sortable ? ariaSort(col.key) : null"
@@ -5910,6 +5926,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
5910
5926
  />
5911
5927
  }
5912
5928
  </span>
5929
+ @if (resizable() && col.resizable !== false) {
5930
+ <div
5931
+ class="strct-dg__resize"
5932
+ (mousedown)="onResizeStart($event, col.key)"
5933
+ ></div>
5934
+ }
5913
5935
  </th>
5914
5936
  }
5915
5937
  </tr>
@@ -6045,7 +6067,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
6045
6067
  <span class="strct-dg__count">
6046
6068
  {{ sorted().length }} {{ sorted().length === 1 ? 'row' : 'rows' }}
6047
6069
  @if (selectedCount()) {
6048
- · {{ selectedCount() }} selected
6070
+ <span class="strct-dg__count-sep">|</span>
6071
+ <span class="strct-dg__count-sel">{{ selectedCount() }} selected</span>
6049
6072
  }
6050
6073
  </span>
6051
6074
  <strct-pagination [total]="sorted().length" [pageSize]="pageSize()" [(page)]="page" />
@@ -6054,8 +6077,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImpo
6054
6077
  `, host: {
6055
6078
  class: 'strct-dg-host',
6056
6079
  '[class.strct-dg-host--compact]': 'compact()',
6057
- }, styles: [".strct-dg-host{display:block}.strct-dg__scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}.strct-dg{width:100%;border-collapse:collapse;font-size:13px;border:1px solid var(--b2);border-radius:8px;overflow:hidden}.strct-dg th,.strct-dg td{padding:9px 13px;text-align:left;border-bottom:1px solid var(--b1)}.strct-dg-host--compact .strct-dg th,.strct-dg-host--compact .strct-dg td{padding:5px 11px}.strct-dg th{font-size:11px;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 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__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;gap:14px;align-items:flex-start}.strct-dg__layout--paned .strct-dg{width:auto;min-width:180px;max-width:260px;flex-shrink: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-right: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-right: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-left:2px solid var(--acc);border-radius:8px;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:8px 0;margin-bottom:8px;border-bottom:1px solid var(--b1)}.strct-dg__selbar{animation:strct-dg-bar-in .12s ease}.strct-dg__selbar-cell{padding:7px 13px;font-size:12px;font-weight:500;color:var(--acc);border-bottom:1px solid var(--b1);background:var(--acc-m);text-align:left}.strct-dg__selbar-count{font-weight:600}.strct-dg__selbar-clear{border:0;background:transparent;color:var(--t2);cursor:pointer;font-size:12px;padding:2px 6px;margin-left:10px;border-radius:var(--radius-sm)}.strct-dg__selbar-clear:hover{color:var(--t1);background:var(--bg-3)}.strct-dg__selbar-actions{display:inline-flex;gap:8px;margin-left:auto}@keyframes strct-dg-bar-in{0%{opacity:0}}.strct-dg__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:12px;flex-wrap:wrap}.strct-dg__count{font-size:12px;color:var(--t2)}\n"] }]
6058
- }], 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 }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], rowId: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowId", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], 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 }] }] } });
6080
+ }, styles: [".strct-dg-host{display:block}.strct-dg__scroll{flex:1 1 auto;min-width:0;overflow-x:auto;-webkit-overflow-scrolling:touch}.strct-dg{width:100%;table-layout:fixed;border-collapse:collapse;font-size:13px;border:1px solid var(--b2);border-radius:8px;overflow:hidden}.strct-dg th,.strct-dg td{padding:9px 13px;text-align:left;border-bottom:1px solid var(--b1)}.strct-dg-host--compact .strct-dg th,.strct-dg-host--compact .strct-dg td{padding:5px 11px}.strct-dg th{position:relative;font-size:11px;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__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;gap:14px;align-items:flex-start;min-width:0}.strct-dg__layout--paned .strct-dg{width:auto;min-width:180px;max-width:260px;flex-shrink: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-right: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-right: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-left:2px solid var(--acc);border-radius:8px;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:8px 0;margin-bottom:8px;border-bottom:1px solid var(--b1)}.strct-dg__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:12px;flex-wrap:wrap}.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"] }]
6081
+ }], 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 }] }], 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 }] }], rowId: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowId", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], 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 }] }] } });
6059
6082
 
6060
6083
  /** Vertical timeline container. Wraps `<strct-timeline-item>` children. */
6061
6084
  class StrctTimeline {