@esfaenza/es-table 20.3.17 → 20.3.19

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.
@@ -6214,10 +6214,14 @@ class EsTable2PagerComponent {
6214
6214
  </label>
6215
6215
 
6216
6216
  <div class="est2-pager__nav" *ngIf="showButtons() && pages() > 1">
6217
- <button type="button" class="est2-pager__btn"
6217
+ <button type="button" class="est2-pager__btn est2-pager__btn--nav"
6218
6218
  [disabled]="page()! <= 1"
6219
6219
  (click)="goto(page()! - 1)"
6220
- aria-label="Pagina precedente">‹</button>
6220
+ aria-label="Pagina precedente">
6221
+ <svg class="est2-pager__chev" viewBox="0 0 24 24" aria-hidden="true">
6222
+ <path d="M15 5l-7 7 7 7" />
6223
+ </svg>
6224
+ </button>
6221
6225
 
6222
6226
  @for (p of visiblePages(); track p.key) {
6223
6227
  @if (p.page === -1) {
@@ -6230,13 +6234,17 @@ class EsTable2PagerComponent {
6230
6234
  }
6231
6235
  }
6232
6236
 
6233
- <button type="button" class="est2-pager__btn"
6237
+ <button type="button" class="est2-pager__btn est2-pager__btn--nav"
6234
6238
  [disabled]="page()! >= pages()"
6235
6239
  (click)="goto(page()! + 1)"
6236
- aria-label="Pagina successiva">›</button>
6240
+ aria-label="Pagina successiva">
6241
+ <svg class="est2-pager__chev" viewBox="0 0 24 24" aria-hidden="true">
6242
+ <path d="M9 5l7 7-7 7" />
6243
+ </svg>
6244
+ </button>
6237
6245
  </div>
6238
6246
  </div>
6239
- `, isInline: true, styles: [".est2-pager{--est-ctrl-h: 30px;display:flex;align-items:center;gap:12px;padding:10px 4px 2px;font-size:var(--est-fs-sm);color:var(--est-fg-muted);flex-wrap:wrap;line-height:1}.est2-pager__spacer{flex:1 1 auto}.est2-pager__count{display:inline-flex;align-items:center;height:var(--est-ctrl-h)}.est2-pager__count strong{color:var(--est-fg);font-weight:600}.est2-pager__ipp{display:inline-flex;align-items:center;height:var(--est-ctrl-h);margin:0;gap:6px}.est2-pager__select{font:inherit;height:var(--est-ctrl-h);color:var(--est-fg);background:var(--est-bg);border:1px solid var(--est-border);border-radius:var(--est-radius-sm);padding:0 8px;cursor:pointer;transition:border-color var(--est-transition)}.est2-pager__select:hover{border-color:var(--est-border-strong)}.est2-pager__select:focus-visible{outline:none;box-shadow:var(--est-ring);border-color:var(--est-accent)}.est2-pager__nav{display:inline-flex;align-items:center;gap:4px}.est2-pager__btn{display:inline-flex;align-items:center;justify-content:center;min-width:var(--est-ctrl-h);height:var(--est-ctrl-h);padding:0 8px;border:1px solid var(--est-border);border-radius:var(--est-radius-sm);background:var(--est-bg);color:var(--est-fg);font:inherit;cursor:pointer;transition:background var(--est-transition),border-color var(--est-transition),color var(--est-transition)}.est2-pager__btn:hover:not(:disabled){background:var(--est-bg-hover);border-color:var(--est-border-strong)}.est2-pager__btn:disabled{opacity:.4;cursor:default}.est2-pager__btn:focus-visible{outline:none;box-shadow:var(--est-ring)}.est2-pager__btn--active{background:var(--est-accent);border-color:var(--est-accent);color:var(--est-accent-fg);font-weight:600}.est2-pager__btn--active:hover:not(:disabled){background:var(--est-accent)}.est2-pager__ellipsis{color:var(--est-fg-faint);padding:0 2px}\n"], dependencies: [{ kind: "directive", type: i8.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
6247
+ `, isInline: true, styles: [".est2-pager{--est-ctrl-h: 30px;display:flex;align-items:center;gap:12px;padding:10px 4px 2px;font-size:var(--est-fs);color:var(--est-fg-muted);flex-wrap:wrap;line-height:1}.est2-pager__spacer{flex:1 1 auto}.est2-pager__count{display:inline-flex;align-items:center;height:var(--est-ctrl-h)}.est2-pager__count strong{color:var(--est-fg);font-weight:600;margin-left:6px}.est2-pager__ipp{display:inline-flex;align-items:center;height:var(--est-ctrl-h);margin:0;gap:6px}.est2-pager__select{font:inherit;height:var(--est-ctrl-h);color:var(--est-fg);background:var(--est-bg);border:1px solid var(--est-border);border-radius:var(--est-radius-sm);padding:0 8px;cursor:pointer;transition:border-color var(--est-transition)}.est2-pager__select:hover{border-color:var(--est-border-strong)}.est2-pager__select:focus-visible{outline:none;box-shadow:var(--est-ring);border-color:var(--est-accent)}.est2-pager__nav{display:inline-flex;align-items:center;gap:4px}.est2-pager__btn{display:inline-flex;align-items:center;justify-content:center;min-width:var(--est-ctrl-h);height:var(--est-ctrl-h);padding:0 8px;border:1px solid var(--est-border);border-radius:var(--est-radius-sm);background:var(--est-bg);color:var(--est-fg);font:inherit;cursor:pointer;transition:background var(--est-transition),border-color var(--est-transition),color var(--est-transition)}.est2-pager__btn:hover:not(:disabled){background:var(--est-bg-hover);border-color:var(--est-border-strong)}.est2-pager__btn:disabled{opacity:.4;cursor:default}.est2-pager__btn:focus-visible{outline:none;box-shadow:var(--est-ring)}.est2-pager__btn--active{background:var(--est-accent);border-color:var(--est-accent);color:var(--est-accent-fg);font-weight:600}.est2-pager__btn--active:hover:not(:disabled){background:var(--est-accent)}.est2-pager__btn--nav{padding:0}.est2-pager__chev{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2.25;stroke-linecap:round;stroke-linejoin:round;display:block}.est2-pager__ellipsis{color:var(--est-fg-faint);padding:0 2px}\n"], dependencies: [{ kind: "directive", type: i8.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
6240
6248
  }
6241
6249
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: EsTable2PagerComponent, decorators: [{
6242
6250
  type: Component,
@@ -6260,10 +6268,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
6260
6268
  </label>
6261
6269
 
6262
6270
  <div class="est2-pager__nav" *ngIf="showButtons() && pages() > 1">
6263
- <button type="button" class="est2-pager__btn"
6271
+ <button type="button" class="est2-pager__btn est2-pager__btn--nav"
6264
6272
  [disabled]="page()! <= 1"
6265
6273
  (click)="goto(page()! - 1)"
6266
- aria-label="Pagina precedente">‹</button>
6274
+ aria-label="Pagina precedente">
6275
+ <svg class="est2-pager__chev" viewBox="0 0 24 24" aria-hidden="true">
6276
+ <path d="M15 5l-7 7 7 7" />
6277
+ </svg>
6278
+ </button>
6267
6279
 
6268
6280
  @for (p of visiblePages(); track p.key) {
6269
6281
  @if (p.page === -1) {
@@ -6276,13 +6288,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
6276
6288
  }
6277
6289
  }
6278
6290
 
6279
- <button type="button" class="est2-pager__btn"
6291
+ <button type="button" class="est2-pager__btn est2-pager__btn--nav"
6280
6292
  [disabled]="page()! >= pages()"
6281
6293
  (click)="goto(page()! + 1)"
6282
- aria-label="Pagina successiva">›</button>
6294
+ aria-label="Pagina successiva">
6295
+ <svg class="est2-pager__chev" viewBox="0 0 24 24" aria-hidden="true">
6296
+ <path d="M9 5l7 7-7 7" />
6297
+ </svg>
6298
+ </button>
6283
6299
  </div>
6284
6300
  </div>
6285
- `, styles: [".est2-pager{--est-ctrl-h: 30px;display:flex;align-items:center;gap:12px;padding:10px 4px 2px;font-size:var(--est-fs-sm);color:var(--est-fg-muted);flex-wrap:wrap;line-height:1}.est2-pager__spacer{flex:1 1 auto}.est2-pager__count{display:inline-flex;align-items:center;height:var(--est-ctrl-h)}.est2-pager__count strong{color:var(--est-fg);font-weight:600}.est2-pager__ipp{display:inline-flex;align-items:center;height:var(--est-ctrl-h);margin:0;gap:6px}.est2-pager__select{font:inherit;height:var(--est-ctrl-h);color:var(--est-fg);background:var(--est-bg);border:1px solid var(--est-border);border-radius:var(--est-radius-sm);padding:0 8px;cursor:pointer;transition:border-color var(--est-transition)}.est2-pager__select:hover{border-color:var(--est-border-strong)}.est2-pager__select:focus-visible{outline:none;box-shadow:var(--est-ring);border-color:var(--est-accent)}.est2-pager__nav{display:inline-flex;align-items:center;gap:4px}.est2-pager__btn{display:inline-flex;align-items:center;justify-content:center;min-width:var(--est-ctrl-h);height:var(--est-ctrl-h);padding:0 8px;border:1px solid var(--est-border);border-radius:var(--est-radius-sm);background:var(--est-bg);color:var(--est-fg);font:inherit;cursor:pointer;transition:background var(--est-transition),border-color var(--est-transition),color var(--est-transition)}.est2-pager__btn:hover:not(:disabled){background:var(--est-bg-hover);border-color:var(--est-border-strong)}.est2-pager__btn:disabled{opacity:.4;cursor:default}.est2-pager__btn:focus-visible{outline:none;box-shadow:var(--est-ring)}.est2-pager__btn--active{background:var(--est-accent);border-color:var(--est-accent);color:var(--est-accent-fg);font-weight:600}.est2-pager__btn--active:hover:not(:disabled){background:var(--est-accent)}.est2-pager__ellipsis{color:var(--est-fg-faint);padding:0 2px}\n"] }]
6301
+ `, styles: [".est2-pager{--est-ctrl-h: 30px;display:flex;align-items:center;gap:12px;padding:10px 4px 2px;font-size:var(--est-fs);color:var(--est-fg-muted);flex-wrap:wrap;line-height:1}.est2-pager__spacer{flex:1 1 auto}.est2-pager__count{display:inline-flex;align-items:center;height:var(--est-ctrl-h)}.est2-pager__count strong{color:var(--est-fg);font-weight:600;margin-left:6px}.est2-pager__ipp{display:inline-flex;align-items:center;height:var(--est-ctrl-h);margin:0;gap:6px}.est2-pager__select{font:inherit;height:var(--est-ctrl-h);color:var(--est-fg);background:var(--est-bg);border:1px solid var(--est-border);border-radius:var(--est-radius-sm);padding:0 8px;cursor:pointer;transition:border-color var(--est-transition)}.est2-pager__select:hover{border-color:var(--est-border-strong)}.est2-pager__select:focus-visible{outline:none;box-shadow:var(--est-ring);border-color:var(--est-accent)}.est2-pager__nav{display:inline-flex;align-items:center;gap:4px}.est2-pager__btn{display:inline-flex;align-items:center;justify-content:center;min-width:var(--est-ctrl-h);height:var(--est-ctrl-h);padding:0 8px;border:1px solid var(--est-border);border-radius:var(--est-radius-sm);background:var(--est-bg);color:var(--est-fg);font:inherit;cursor:pointer;transition:background var(--est-transition),border-color var(--est-transition),color var(--est-transition)}.est2-pager__btn:hover:not(:disabled){background:var(--est-bg-hover);border-color:var(--est-border-strong)}.est2-pager__btn:disabled{opacity:.4;cursor:default}.est2-pager__btn:focus-visible{outline:none;box-shadow:var(--est-ring)}.est2-pager__btn--active{background:var(--est-accent);border-color:var(--est-accent);color:var(--est-accent-fg);font-weight:600}.est2-pager__btn--active:hover:not(:disabled){background:var(--est-accent)}.est2-pager__btn--nav{padding:0}.est2-pager__chev{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2.25;stroke-linecap:round;stroke-linejoin:round;display:block}.est2-pager__ellipsis{color:var(--est-fg-faint);padding:0 2px}\n"] }]
6286
6302
  }], propDecorators: { page: [{ type: i0.Input, args: [{ isSignal: true, alias: "page", required: false }] }], pages: [{ type: i0.Input, args: [{ isSignal: true, alias: "pages", required: false }] }], total: [{ type: i0.Input, args: [{ isSignal: true, alias: "total", required: false }] }], itemsPerPage: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemsPerPage", required: false }] }], countLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "countLabel", required: false }] }], showCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCount", required: false }] }], showButtons: [{ type: i0.Input, args: [{ isSignal: true, alias: "showButtons", required: false }] }], showPagingOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPagingOptions", required: false }] }], allowAll: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowAll", required: false }] }], pageChange: [{ type: i0.Output, args: ["pageChange"] }], itemsPerPageChange: [{ type: i0.Output, args: ["itemsPerPageChange"] }] } });
6287
6303
 
6288
6304
  // Angular
@@ -6430,7 +6446,9 @@ class EsTable2Component {
6430
6446
  this.HasHeaderGroup = input(false, ...(ngDevMode ? [{ debugName: "HasHeaderGroup" }] : []));
6431
6447
  this.HasSecondaryHeaderGroup = input(false, ...(ngDevMode ? [{ debugName: "HasSecondaryHeaderGroup" }] : []));
6432
6448
  this.SearchView = input(null, ...(ngDevMode ? [{ debugName: "SearchView" }] : []));
6449
+ /** Abilita il "patacchino" di auto-aggiornamento (toggle + intervallo) in alto a destra */
6433
6450
  this._AutoUpdate = input(null, ...(ngDevMode ? [{ debugName: "_AutoUpdate", alias: 'AutoUpdate' }] : [{ alias: 'AutoUpdate' }]));
6451
+ this.AutoUpdate = linkedSignal(() => this.io(this._AutoUpdate(), this.defaults?.AutoUpdate, false), ...(ngDevMode ? [{ debugName: "AutoUpdate" }] : []));
6434
6452
  // ===========================================================================
6435
6453
  // Superficie pubblica — Output
6436
6454
  // ===========================================================================
@@ -6485,6 +6503,8 @@ class EsTable2Component {
6485
6503
  this.directiveColumns = [];
6486
6504
  /** Definizioni Multi da srotolare sui dati (`*th Multi:true`) */
6487
6505
  this.multiDefs = [];
6506
+ /** true quando le colonne Multi sono state generate almeno una volta (per il gating delle prefs) */
6507
+ this.multiColumnsBuilt = false;
6488
6508
  // ===========================================================================
6489
6509
  // Theme host bindings
6490
6510
  // ===========================================================================
@@ -6566,6 +6586,26 @@ class EsTable2Component {
6566
6586
  }, ...(ngDevMode ? [{ debugName: "headerGroupRows" }] : []));
6567
6587
  /** true se ci sono header-group da renderizzare */
6568
6588
  this.hasHeaderGroups = computed(() => this.headerGroupRows().length > 0, ...(ngDevMode ? [{ debugName: "hasHeaderGroups" }] : []));
6589
+ /**
6590
+ * Indici (in visibleColumns) delle colonne che aprono un nuovo gruppo-colonna,
6591
+ * cioè dove il gruppo padre immediato cambia rispetto alla colonna precedente.
6592
+ * Serve a disegnare i confini dei gruppi anche nel corpo della tabella.
6593
+ */
6594
+ this.columnGroupBoundaries = computed(() => {
6595
+ const set = new Set();
6596
+ if (this.hgParentIds().size === 0)
6597
+ return set;
6598
+ const cols = this.visibleColumns();
6599
+ const thById = this.hgThById();
6600
+ let prev = undefined;
6601
+ for (let i = 0; i < cols.length; i++) {
6602
+ const parent = thById.get(cols[i].id)?.thParent ?? null;
6603
+ if (i > 0 && parent !== prev)
6604
+ set.add(i);
6605
+ prev = parent;
6606
+ }
6607
+ return set;
6608
+ }, ...(ngDevMode ? [{ debugName: "columnGroupBoundaries" }] : []));
6569
6609
  /** Numero di elementi totali (per il pager) */
6570
6610
  this.totalCount = computed(() => {
6571
6611
  const v = this.view();
@@ -6593,11 +6633,15 @@ class EsTable2Component {
6593
6633
  // ===========================================================================
6594
6634
  this.onChange = () => { };
6595
6635
  this.onTouched = () => { };
6636
+ this.providerSubs = [];
6596
6637
  // ===========================================================================
6597
6638
  // ControlValueAccessor
6598
6639
  // ===========================================================================
6599
6640
  /** Timeout di debounce del writeValue in modalità EsTableHandledSearch */
6600
6641
  this.searchCallTimeout = null;
6642
+ // --- Auto-aggiornamento (polling) ------------------------------------------
6643
+ /** Interval attivo quando `autoUpdate` è on (in modalità `[AutoUpdate]`) */
6644
+ this.updateTimer = null;
6601
6645
  /** Ancora per la selezione a range stile Windows (Shift+click) */
6602
6646
  this.selectionAnchor = null;
6603
6647
  // ===========================================================================
@@ -6677,6 +6721,9 @@ class EsTable2Component {
6677
6721
  clearTimeout(this.noticeTimer);
6678
6722
  if (this.searchCallTimeout)
6679
6723
  clearTimeout(this.searchCallTimeout);
6724
+ if (this.updateTimer)
6725
+ clearInterval(this.updateTimer);
6726
+ this.providerSubs.forEach(s => s.unsubscribe());
6680
6727
  }
6681
6728
  /** Risoluzione input: valore esplicito || default di progetto || hard default */
6682
6729
  io(v, d, hard) {
@@ -6686,6 +6733,28 @@ class EsTable2Component {
6686
6733
  this.buildColumns();
6687
6734
  this.thDirectives?.changes.subscribe(() => { this.buildColumns(); this.refresh(); });
6688
6735
  this.tdDirectives?.changes.subscribe(() => { this.buildColumns(); this.refresh(); });
6736
+ this.wireProviders();
6737
+ this.thTdProviders?.changes.subscribe(() => this.wireProviders());
6738
+ }
6739
+ /** Provider `td_th_provider` attivi: quello passato via `[EsThTdProvider]` + quelli annidati */
6740
+ collectProviders() {
6741
+ return [...(this.EsThTdProvider ? [this.EsThTdProvider] : []), ...(this.thTdProviders?.toArray() ?? [])];
6742
+ }
6743
+ /** (Ri)aggancia i provider: ricostruisce colonne quando caricano o cambiano i loro `*th`/`*td` */
6744
+ wireProviders() {
6745
+ this.providerSubs.forEach(s => s.unsubscribe());
6746
+ this.providerSubs = [];
6747
+ for (const p of this.collectProviders()) {
6748
+ const rebuild = () => { this.buildColumns(); this.refresh(); };
6749
+ if (p.LoadedSignal)
6750
+ this.providerSubs.push(p.LoadedSignal.subscribe(rebuild));
6751
+ if (p.EsThsDirective)
6752
+ this.providerSubs.push(p.EsThsDirective.changes.subscribe(rebuild));
6753
+ if (p.EsTdsDirective)
6754
+ this.providerSubs.push(p.EsTdsDirective.changes.subscribe(rebuild));
6755
+ }
6756
+ this.buildColumns();
6757
+ this.refresh();
6689
6758
  }
6690
6759
  writeValue(obj, throttle = true) {
6691
6760
  // Modalità EsTableHandledSearch: il writeValue viene debouncato (come l'originale),
@@ -6745,6 +6814,17 @@ class EsTable2Component {
6745
6814
  this.onSearchRequest.emit(arg);
6746
6815
  }
6747
6816
  }
6817
+ /** (Ri)avvia/ferma il polling in base al toggle `autoUpdate` e a `seconds` */
6818
+ autoUpdateChanged() {
6819
+ if (this.updateTimer) {
6820
+ clearInterval(this.updateTimer);
6821
+ this.updateTimer = null;
6822
+ }
6823
+ if (!/^[1-9]\d*$/.test(this.seconds()))
6824
+ this.seconds.set('10');
6825
+ if (this.autoUpdate())
6826
+ this.updateTimer = setInterval(() => this.emitSearchRequest(false), parseInt(this.seconds(), 10) * 1000);
6827
+ }
6748
6828
  changed(clearItems = false) {
6749
6829
  if (clearItems && this.viewMode()) {
6750
6830
  const isp = this.ItemSourceProperty();
@@ -6768,7 +6848,16 @@ class EsTable2Component {
6768
6848
  this.arrayMode.set(!isSearch && Array.isArray(obj));
6769
6849
  }
6770
6850
  buildColumns() {
6771
- const ths = this.thDirectives?.toArray() ?? [];
6851
+ // th/td diretti (proiettati) + quelli forniti dai provider `td_th_provider`
6852
+ const provs = this.collectProviders();
6853
+ const ths = [
6854
+ ...(this.thDirectives?.toArray() ?? []),
6855
+ ...provs.flatMap(p => p.EsThsDirective?.toArray() ?? [])
6856
+ ];
6857
+ const tds = [
6858
+ ...(this.tdDirectives?.toArray() ?? []),
6859
+ ...provs.flatMap(p => p.EsTdsDirective?.toArray() ?? [])
6860
+ ];
6772
6861
  this.directivesBased.set(ths.length > 0);
6773
6862
  if (ths.length === 0) {
6774
6863
  this.columns.set([]);
@@ -6781,11 +6870,12 @@ class EsTable2Component {
6781
6870
  return;
6782
6871
  }
6783
6872
  const tdByCol = new Map();
6784
- for (const td of this.tdDirectives?.toArray() ?? [])
6873
+ for (const td of tds)
6785
6874
  if (!tdByCol.has(td.td))
6786
6875
  tdByCol.set(td.td, td);
6787
6876
  // Colonne Multi (`*th Multi:true`): srotolate sui dati in resolveColumns()
6788
6877
  this.multiDefs = ths.filter(t => t.thMulti && t.thIf).map(t => ({ prop: t.th, th: t, td: tdByCol.get(t.th) }));
6878
+ this.multiColumnsBuilt = false;
6789
6879
  // Header groups multi-livello: un `*th` è un GRUPPO (non una colonna-dato) se
6790
6880
  // il suo id è referenziato da un altro `*th` come `Parent` (`thParent`).
6791
6881
  const parentIds = new Set();
@@ -6903,6 +6993,7 @@ class EsTable2Component {
6903
6993
  }
6904
6994
  this.hgThById.set(thById);
6905
6995
  this.hgParentIds.set(parentIds);
6996
+ this.multiColumnsBuilt = true;
6906
6997
  return cols;
6907
6998
  }
6908
6999
  /** Costruisce le colonne da una `EsTableColumnsDefinition[]` (modalità dinamica) */
@@ -7383,6 +7474,15 @@ class EsTable2Component {
7383
7474
  const sel = this.currentSelection();
7384
7475
  const shift = !!event?.shiftKey;
7385
7476
  const ctrl = !!(event?.ctrlKey || event?.metaKey);
7477
+ // In modalità "tutto selezionato" (selectEverything → sel.all), un Ctrl+click
7478
+ // NON deve azzerare la selezione: deve solo togliere/rimettere la singola riga
7479
+ // dalle esclusioni, mantenendo sel.all. `toggleRow` gestisce già esattamente
7480
+ // questo caso (come fa la checkbox). Senza questo ramo, il reset di sel.all/
7481
+ // exclusions in coda a questa funzione collasserebbe la selezione a 0.
7482
+ if (sel.all && ctrl && !shift) {
7483
+ this.toggleRow(item);
7484
+ return;
7485
+ }
7386
7486
  if (shift && this.selectionAnchor != null && rows.indexOf(this.selectionAnchor) >= 0) {
7387
7487
  const a = rows.indexOf(this.selectionAnchor);
7388
7488
  const b = rows.indexOf(item);
@@ -8089,6 +8189,10 @@ class EsTable2Component {
8089
8189
  return;
8090
8190
  if (this.columns().length === 0)
8091
8191
  return; // attendo che le colonne esistano
8192
+ // Se ci sono colonne Multi (data-dependent), attendo che siano state generate:
8193
+ // altrimenti il guard di coerenza rifiuterebbe le prefs che le citano.
8194
+ if (this.multiDefs.length > 0 && !this.multiColumnsBuilt)
8195
+ return;
8092
8196
  const key = this.prefsKey();
8093
8197
  if (!key) {
8094
8198
  this.prefsLoaded = true;
@@ -8122,7 +8226,15 @@ class EsTable2Component {
8122
8226
  // `pinned` è un'estensione retro-compatibile: se assente (prefs vecchie/originali)
8123
8227
  // resta il pin di default delle direttive.
8124
8228
  const pinned = Array.isArray(prefs.pinned) ? prefs.pinned.filter(id => currentIds.has(id)) : undefined;
8125
- this.columnPrefs = { order, hidden: [...currentIds].filter(id => !visible.includes(id)), pinned };
8229
+ // Nascondo SOLO le colonne che le preferenze conoscevano davvero (presenti
8230
+ // nell'ordinamento o nell'elenco visibili) ma non marcate come visibili.
8231
+ // Una colonna del tutto assente dalle prefs è NUOVA (aggiunta dopo il
8232
+ // salvataggio): resta visibile — `setColumns` la accoda in fondo. Diversamente
8233
+ // dall'originale (che nascondeva ogni colonna non salvata), così gli utenti non
8234
+ // "perdono" le colonne aggiunte a una tabella con preferenze già memorizzate.
8235
+ const knownToPrefs = new Set([...order, ...visible]);
8236
+ const hidden = [...currentIds].filter(id => knownToPrefs.has(id) && !visible.includes(id));
8237
+ this.columnPrefs = { order, hidden, pinned };
8126
8238
  this.setColumns(this.columns());
8127
8239
  if (prefs.orders?.length) {
8128
8240
  this.orders.set([...prefs.orders]);
@@ -8141,10 +8253,9 @@ class EsTable2Component {
8141
8253
  const key = this.prefsKey();
8142
8254
  if (!key)
8143
8255
  return;
8144
- // Escludo le sotto-colonne Multi: sono auto-generate dai dati, non vanno
8145
- // persistite (altrimenti il guard di coerenza le rifiuterebbe al reload,
8146
- // quando ancora non esistono).
8147
- const cols = this.columns().filter(c => c.multiProp == null);
8256
+ // Includo anche le sotto-colonne Multi (id stabili `prop_index`): il
8257
+ // caricamento è gated finché non esistono, quindi il guard non le rifiuta.
8258
+ const cols = this.columns();
8148
8259
  const payload = {
8149
8260
  columns: cols.filter(c => c.visible).map(c => c.id),
8150
8261
  column_ordering: cols.map(c => c.id),
@@ -8164,12 +8275,12 @@ class EsTable2Component {
8164
8275
  togglePin(col, ev) {
8165
8276
  ev?.stopPropagation();
8166
8277
  col.pinned = !col.pinned;
8167
- // aggiorno le prefs correnti (ordine/visibilità invariati) — escludo le Multi
8168
- const nonMulti = this.columns().filter(c => c.multiProp == null);
8278
+ // aggiorno le prefs correnti (ordine/visibilità invariati)
8279
+ const cols = this.columns();
8169
8280
  this.columnPrefs = {
8170
- order: nonMulti.map(c => c.id),
8171
- hidden: nonMulti.filter(c => !c.visible).map(c => c.id),
8172
- pinned: nonMulti.filter(c => c.pinned).map(c => c.id)
8281
+ order: cols.map(c => c.id),
8282
+ hidden: cols.filter(c => !c.visible).map(c => c.id),
8283
+ pinned: cols.filter(c => c.pinned).map(c => c.id)
8173
8284
  };
8174
8285
  this.columns.set([...this.columns()]); // forza il ricalcolo di visibleColumns/headerGroupRows
8175
8286
  this.saveColumnPrefs();
@@ -8179,11 +8290,45 @@ class EsTable2Component {
8179
8290
  columnLabel(col) {
8180
8291
  return (col.headerText && String(col.headerText).trim()) || col.id;
8181
8292
  }
8293
+ /** true se la colonna appartiene a un gruppo (multi o `Parent`): non è pinnabile */
8294
+ isGrouped(col) {
8295
+ return !!this.hgThById().get(col.id)?.thParent;
8296
+ }
8297
+ /**
8298
+ * Etichetta della dialog: testo header renderizzato (letto dal DOM, così
8299
+ * rispetta casing/contenuto) preceduto dal percorso dei gruppi, es.
8300
+ * `( Energia - Attiva ) Fascia F1`.
8301
+ */
8302
+ dialogLabelFor(col, headerTexts, groupLabels) {
8303
+ const leaf = headerTexts.get(col.id) || this.columnLabel(col);
8304
+ const thById = this.hgThById();
8305
+ const path = [];
8306
+ let p = thById.get(col.id)?.thParent ?? null;
8307
+ let guard = 0;
8308
+ while (p && guard++ < 32) {
8309
+ path.push(groupLabels.get(p) || (thById.get(p)?.thStaticContent?.trim()) || p);
8310
+ p = thById.get(p)?.thParent ?? null;
8311
+ }
8312
+ path.reverse(); // root-first
8313
+ return path.length ? `( ${path.join(' - ')} ) ${leaf}` : leaf;
8314
+ }
8182
8315
  openColumnsDialog() {
8183
- // Le sotto-colonne Multi sono auto-generate: non le espongo nella dialog
8184
- // (riordinarle/pinnarle singolarmente romperebbe il raggruppamento).
8185
- this.dialogCols.set(this.columns().filter(c => c.multiProp == null)
8186
- .map(c => ({ id: c.id, label: this.columnLabel(c), visible: c.visible, pinned: !!c.pinned })));
8316
+ // Leggo dal DOM i testi header renderizzati (leaf + gruppi) per etichette esatte.
8317
+ const headerTexts = new Map();
8318
+ const groupLabels = new Map();
8319
+ const host = this.hostEl?.nativeElement;
8320
+ if (host) {
8321
+ host.querySelectorAll('thead th[data-colid]').forEach((el) => headerTexts.set(el.getAttribute('data-colid'), (el.textContent || '').trim()));
8322
+ host.querySelectorAll('thead th[data-groupid]').forEach((el) => groupLabels.set(el.getAttribute('data-groupid'), (el.textContent || '').trim()));
8323
+ }
8324
+ // TUTTE le colonne (comprese le Multi), con etichetta gruppo-consapevole.
8325
+ this.dialogCols.set(this.columns().map(c => ({
8326
+ id: c.id,
8327
+ label: this.dialogLabelFor(c, headerTexts, groupLabels),
8328
+ visible: c.visible,
8329
+ pinned: !!c.pinned,
8330
+ grouped: this.isGrouped(c)
8331
+ })));
8187
8332
  this.columnsDialogOpen.set(true);
8188
8333
  this.cdr.markForCheck();
8189
8334
  }
@@ -8195,26 +8340,67 @@ class EsTable2Component {
8195
8340
  }
8196
8341
  dialogTogglePin(i) {
8197
8342
  const list = [...this.dialogCols()];
8343
+ if (list[i].grouped)
8344
+ return; // le colonne raggruppate non sono pinnabili
8198
8345
  list[i] = { ...list[i], pinned: !list[i].pinned };
8199
8346
  this.dialogCols.set(list);
8200
8347
  }
8201
8348
  dialogSetAll(visible) {
8202
8349
  this.dialogCols.set(this.dialogCols().map(c => ({ ...c, visible })));
8203
8350
  }
8351
+ /**
8352
+ * Spostamento gruppo-consapevole nella dialog: i gruppi restano SEMPRE contigui
8353
+ * anche durante l'editing (non solo all'Applica). Se la colonna adiacente è nello
8354
+ * stesso gruppo → swap semplice (riordino interno); se è oltre il confine del
8355
+ * gruppo → si sposta l'INTERO blocco del gruppo (al livello di divergenza).
8356
+ */
8204
8357
  dialogMove(i, dir) {
8205
8358
  const list = [...this.dialogCols()];
8206
8359
  const j = i + dir;
8207
8360
  if (j < 0 || j >= list.length)
8208
8361
  return;
8209
- [list[i], list[j]] = [list[j], list[i]];
8210
- this.dialogCols.set(list);
8362
+ // Nessun gruppo: swap semplice
8363
+ if (this.hgParentIds().size === 0) {
8364
+ [list[i], list[j]] = [list[j], list[i]];
8365
+ this.dialogCols.set(list);
8366
+ return;
8367
+ }
8368
+ const chainA = this.columnChain(list[i].id);
8369
+ const chainB = this.columnChain(list[j].id);
8370
+ // livello dove le due catene divergono
8371
+ let d = 0;
8372
+ while (chainA[d] !== undefined && chainB[d] !== undefined && chainA[d] === chainB[d])
8373
+ d++;
8374
+ const ancAt = (id, lvl) => this.columnChain(id)[lvl];
8375
+ const blockAround = (idx) => {
8376
+ const anc = ancAt(list[idx].id, d);
8377
+ if (anc === undefined)
8378
+ return [idx, idx]; // nessun gruppo a questo livello → singola colonna
8379
+ let s = idx, e = idx;
8380
+ while (s - 1 >= 0 && ancAt(list[s - 1].id, d) === anc)
8381
+ s--;
8382
+ while (e + 1 < list.length && ancAt(list[e + 1].id, d) === anc)
8383
+ e++;
8384
+ return [s, e];
8385
+ };
8386
+ const [aStart, aEnd] = blockAround(i);
8387
+ const [bStart, bEnd] = blockAround(j);
8388
+ // i due blocchi sono adiacenti: li scambio conservando tutto il resto
8389
+ const newList = dir === 1
8390
+ ? [...list.slice(0, aStart), ...list.slice(bStart, bEnd + 1), ...list.slice(aStart, aEnd + 1), ...list.slice(bEnd + 1)]
8391
+ : [...list.slice(0, bStart), ...list.slice(aStart, aEnd + 1), ...list.slice(bStart, bEnd + 1), ...list.slice(aEnd + 1)];
8392
+ this.dialogCols.set(newList);
8211
8393
  }
8212
8394
  applyColumnsDialog() {
8213
- const list = this.dialogCols();
8395
+ // Riparo l'ordine mantenendo CONTIGUI i membri di ogni gruppo: spostare una
8396
+ // colonna fuori dal suo gruppo non deve produrre header-group spezzati.
8397
+ const orderIds = this.enforceGroupContiguity(this.dialogCols().map(c => c.id));
8398
+ const hiddenSet = new Set(this.dialogCols().filter(c => !c.visible).map(c => c.id));
8399
+ const pinnedSet = new Set(this.dialogCols().filter(c => c.pinned).map(c => c.id));
8214
8400
  this.columnPrefs = {
8215
- order: list.map(c => c.id),
8216
- hidden: list.filter(c => !c.visible).map(c => c.id),
8217
- pinned: list.filter(c => c.pinned).map(c => c.id)
8401
+ order: orderIds,
8402
+ hidden: [...hiddenSet],
8403
+ pinned: [...pinnedSet]
8218
8404
  };
8219
8405
  // riapplico alla lista corrente conservando gli oggetti-colonna...
8220
8406
  this.setColumns(this.columns());
@@ -8223,6 +8409,50 @@ class EsTable2Component {
8223
8409
  this.columnsDialogOpen.set(false);
8224
8410
  this.cdr.markForCheck();
8225
8411
  }
8412
+ /**
8413
+ * Riordina gli id in modo che i membri di ogni gruppo-colonna restino contigui,
8414
+ * rispettando il più possibile l'ordine scelto dall'utente: ordina per chiave
8415
+ * = [prima-apparizione di ogni antenato (root→foglia), poi indice proprio].
8416
+ * Così due colonne dello stesso gruppo non possono essere interlacciate con
8417
+ * colonne esterne.
8418
+ */
8419
+ /** Catena degli antenati-gruppo (root→padre immediato) di una colonna; `[]` se non raggruppata */
8420
+ columnChain(id) {
8421
+ const thById = this.hgThById();
8422
+ const chain = [];
8423
+ let p = thById.get(id)?.thParent ?? null;
8424
+ let guard = 0;
8425
+ while (p && guard++ < 32) {
8426
+ chain.push(p);
8427
+ p = thById.get(p)?.thParent ?? null;
8428
+ }
8429
+ return chain.reverse(); // root-first
8430
+ }
8431
+ enforceGroupContiguity(orderIds) {
8432
+ if (this.hgParentIds().size === 0)
8433
+ return orderIds;
8434
+ const chainOf = (id) => this.columnChain(id);
8435
+ // prima apparizione di ogni id-gruppo nell'ordine utente
8436
+ const firstIdx = new Map();
8437
+ orderIds.forEach((id, i) => {
8438
+ for (const g of chainOf(id))
8439
+ if (!firstIdx.has(g))
8440
+ firstIdx.set(g, i);
8441
+ });
8442
+ const keyOf = (id, i) => [...chainOf(id).map(g => firstIdx.get(g)), i];
8443
+ return orderIds
8444
+ .map((id, i) => ({ id, key: keyOf(id, i), i }))
8445
+ .sort((a, b) => {
8446
+ const n = Math.max(a.key.length, b.key.length);
8447
+ for (let k = 0; k < n; k++) {
8448
+ const av = a.key[k] ?? -1, bv = b.key[k] ?? -1;
8449
+ if (av !== bv)
8450
+ return av - bv;
8451
+ }
8452
+ return a.i - b.i;
8453
+ })
8454
+ .map(x => x.id);
8455
+ }
8226
8456
  resetColumnsDialog() {
8227
8457
  this.columnPrefs = null;
8228
8458
  this.buildColumns(); // ricostruisce dalle direttive nell'ordine originale
@@ -8366,11 +8596,11 @@ class EsTable2Component {
8366
8596
  return (Array.isArray(arr) ? arr[col.multiIndex] : null) ?? {};
8367
8597
  }
8368
8598
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: EsTable2Component, deps: [{ token: i1.NgControl, optional: true, self: true }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i2$1.PreferencesService, optional: true }, { token: EST2_DEFAULTS, optional: true }, { token: EST2_DEBUG, optional: true }, { token: EST2_EXPORT_GLOBAL_ACL, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
8369
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: EsTable2Component, isStandalone: false, selector: "es-table2", inputs: { ContextMenu: { classPropertyName: "ContextMenu", publicName: "ContextMenu", isSignal: false, isRequired: false, transformFunction: null }, _Selection: { classPropertyName: "_Selection", publicName: "Selection", isSignal: true, isRequired: false, transformFunction: null }, SingleSelection: { classPropertyName: "SingleSelection", publicName: "SingleSelection", isSignal: true, isRequired: false, transformFunction: null }, SelectionDisabled: { classPropertyName: "SelectionDisabled", publicName: "SelectionDisabled", isSignal: true, isRequired: false, transformFunction: null }, _SelectAll: { classPropertyName: "_SelectAll", publicName: "SelectAll", isSignal: true, isRequired: false, transformFunction: null }, _UseSelectionCache: { classPropertyName: "_UseSelectionCache", publicName: "UseSelectionCache", isSignal: true, isRequired: false, transformFunction: null }, _ShiftClick: { classPropertyName: "_ShiftClick", publicName: "ShiftClick", isSignal: true, isRequired: false, transformFunction: null }, _OrderByColumn: { classPropertyName: "_OrderByColumn", publicName: "OrderByColumn", isSignal: true, isRequired: false, transformFunction: null }, MultipleOrderingDirectives: { classPropertyName: "MultipleOrderingDirectives", publicName: "MultipleOrderingDirectives", isSignal: true, isRequired: false, transformFunction: null }, Removal: { classPropertyName: "Removal", publicName: "Removal", isSignal: true, isRequired: false, transformFunction: null }, RemovalCondition: { classPropertyName: "RemovalCondition", publicName: "RemovalCondition", isSignal: true, isRequired: false, transformFunction: null }, RowClassAssigner: { classPropertyName: "RowClassAssigner", publicName: "RowClassAssigner", isSignal: false, isRequired: false, transformFunction: null }, _HidePaging: { classPropertyName: "_HidePaging", publicName: "HidePaging", isSignal: true, isRequired: false, transformFunction: null }, _HidePagingCount: { classPropertyName: "_HidePagingCount", publicName: "HidePagingCount", isSignal: true, isRequired: false, transformFunction: null }, _HidePagingButtons: { classPropertyName: "_HidePagingButtons", publicName: "HidePagingButtons", isSignal: true, isRequired: false, transformFunction: null }, _AllSearch: { classPropertyName: "_AllSearch", publicName: "AllSearch", isSignal: true, isRequired: false, transformFunction: null }, _PagingStyle: { classPropertyName: "_PagingStyle", publicName: "PagingStyle", isSignal: true, isRequired: false, transformFunction: null }, _ArraymodeItemsPerPage: { classPropertyName: "_ArraymodeItemsPerPage", publicName: "ArraymodeItemsPerPage", isSignal: true, isRequired: false, transformFunction: null }, _UseArrayModePaging: { classPropertyName: "_UseArrayModePaging", publicName: "UseArrayModePaging", isSignal: true, isRequired: false, transformFunction: null }, CountLabel: { classPropertyName: "CountLabel", publicName: "CountLabel", isSignal: true, isRequired: false, transformFunction: null }, Height: { classPropertyName: "Height", publicName: "Height", isSignal: true, isRequired: false, transformFunction: null }, MaxHeight: { classPropertyName: "MaxHeight", publicName: "MaxHeight", isSignal: true, isRequired: false, transformFunction: null }, EmptySpaceBackgroundColor: { classPropertyName: "EmptySpaceBackgroundColor", publicName: "EmptySpaceBackgroundColor", isSignal: true, isRequired: false, transformFunction: null }, HighCellDensity: { classPropertyName: "HighCellDensity", publicName: "HighCellDensity", isSignal: true, isRequired: false, transformFunction: null }, HeaderHidden: { classPropertyName: "HeaderHidden", publicName: "HeaderHidden", isSignal: true, isRequired: false, transformFunction: null }, BodyHidden: { classPropertyName: "BodyHidden", publicName: "BodyHidden", isSignal: true, isRequired: false, transformFunction: null }, ShowLoadingOnBootstrap: { classPropertyName: "ShowLoadingOnBootstrap", publicName: "ShowLoadingOnBootstrap", isSignal: true, isRequired: false, transformFunction: null }, _DefaultAlignment: { classPropertyName: "_DefaultAlignment", publicName: "DefaultAlignment", isSignal: true, isRequired: false, transformFunction: null }, _TableClass: { classPropertyName: "_TableClass", publicName: "TableClass", isSignal: true, isRequired: false, transformFunction: null }, _ContainerClass: { classPropertyName: "_ContainerClass", publicName: "ContainerClass", isSignal: true, isRequired: false, transformFunction: null }, EsTableHandledSearch: { classPropertyName: "EsTableHandledSearch", publicName: "EsTableHandledSearch", isSignal: true, isRequired: false, transformFunction: null }, SearchThrottle: { classPropertyName: "SearchThrottle", publicName: "SearchThrottle", isSignal: true, isRequired: false, transformFunction: null }, _ColumnsResizable: { classPropertyName: "_ColumnsResizable", publicName: "ColumnsResizable", isSignal: true, isRequired: false, transformFunction: null }, _ColumnsPinnable: { classPropertyName: "_ColumnsPinnable", publicName: "ColumnsPinnable", isSignal: true, isRequired: false, transformFunction: null }, _HiddenColumns: { classPropertyName: "_HiddenColumns", publicName: "HiddenColumns", isSignal: true, isRequired: false, transformFunction: null }, _ColumnsOrdering: { classPropertyName: "_ColumnsOrdering", publicName: "ColumnsOrdering", isSignal: true, isRequired: false, transformFunction: null }, _Export: { classPropertyName: "_Export", publicName: "Export", isSignal: true, isRequired: false, transformFunction: null }, XLSXExport: { classPropertyName: "XLSXExport", publicName: "XLSXExport", isSignal: true, isRequired: false, transformFunction: null }, CSVExport: { classPropertyName: "CSVExport", publicName: "CSVExport", isSignal: true, isRequired: false, transformFunction: null }, ExportFileName: { classPropertyName: "ExportFileName", publicName: "ExportFileName", isSignal: true, isRequired: false, transformFunction: null }, ExportOnlyVisibleColumns: { classPropertyName: "ExportOnlyVisibleColumns", publicName: "ExportOnlyVisibleColumns", isSignal: true, isRequired: false, transformFunction: null }, ExportFunction: { classPropertyName: "ExportFunction", publicName: "ExportFunction", isSignal: false, isRequired: false, transformFunction: null }, CornerMenuOptions: { classPropertyName: "CornerMenuOptions", publicName: "CornerMenuOptions", isSignal: true, isRequired: false, transformFunction: null }, DynamicOperations: { classPropertyName: "DynamicOperations", publicName: "DynamicOperations", isSignal: true, isRequired: false, transformFunction: null }, _DynamicRowColumnsDefinition: { classPropertyName: "_DynamicRowColumnsDefinition", publicName: "DynamicRowColumnsDefinition", isSignal: true, isRequired: false, transformFunction: null }, Hierarchy: { classPropertyName: "Hierarchy", publicName: "Hierarchy", isSignal: true, isRequired: false, transformFunction: null }, _ParentKey: { classPropertyName: "_ParentKey", publicName: "ParentKey", isSignal: true, isRequired: false, transformFunction: null }, _OwnKey: { classPropertyName: "_OwnKey", publicName: "OwnKey", isSignal: true, isRequired: false, transformFunction: null }, _AutoSortHierarchy: { classPropertyName: "_AutoSortHierarchy", publicName: "AutoSortHierarchy", isSignal: true, isRequired: false, transformFunction: null }, StartsExpanded: { classPropertyName: "StartsExpanded", publicName: "StartsExpanded", isSignal: true, isRequired: false, transformFunction: null }, CascadeSelection: { classPropertyName: "CascadeSelection", publicName: "CascadeSelection", isSignal: true, isRequired: false, transformFunction: null }, _SavePreferences: { classPropertyName: "_SavePreferences", publicName: "SavePreferences", isSignal: true, isRequired: false, transformFunction: null }, Name: { classPropertyName: "Name", publicName: "Name", isSignal: true, isRequired: false, transformFunction: null }, _RowGroupingPagingStyle: { classPropertyName: "_RowGroupingPagingStyle", publicName: "RowGroupingPagingStyle", isSignal: true, isRequired: false, transformFunction: null }, _ShowItemGroupsColumns: { classPropertyName: "_ShowItemGroupsColumns", publicName: "ShowItemGroupsColumns", isSignal: true, isRequired: false, transformFunction: null }, Editable: { classPropertyName: "Editable", publicName: "Editable", isSignal: true, isRequired: false, transformFunction: null }, RangeSelection: { classPropertyName: "RangeSelection", publicName: "RangeSelection", isSignal: true, isRequired: false, transformFunction: null }, ItemSourceProperty: { classPropertyName: "ItemSourceProperty", publicName: "ItemSourceProperty", isSignal: true, isRequired: false, transformFunction: null }, HasHeaderGroup: { classPropertyName: "HasHeaderGroup", publicName: "HasHeaderGroup", isSignal: true, isRequired: false, transformFunction: null }, HasSecondaryHeaderGroup: { classPropertyName: "HasSecondaryHeaderGroup", publicName: "HasSecondaryHeaderGroup", isSignal: true, isRequired: false, transformFunction: null }, SearchView: { classPropertyName: "SearchView", publicName: "SearchView", isSignal: true, isRequired: false, transformFunction: null }, _AutoUpdate: { classPropertyName: "_AutoUpdate", publicName: "AutoUpdate", isSignal: true, isRequired: false, transformFunction: null }, globalCheck: { classPropertyName: "globalCheck", publicName: "globalCheck", isSignal: true, isRequired: false, transformFunction: null }, autoUpdate: { classPropertyName: "autoUpdate", publicName: "autoUpdate", isSignal: true, isRequired: false, transformFunction: null }, seconds: { classPropertyName: "seconds", publicName: "seconds", isSignal: true, isRequired: false, transformFunction: null }, researchInProgress: { classPropertyName: "researchInProgress", publicName: "researchInProgress", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { onOrderChanged: "onOrderChanged", onSearchRequest: "onSearchRequest", onSelectionChanged: "onSelectionChanged", onRemoval: "onRemoval", onAbortRemoval: "onAbortRemoval", onModelChange: "onModelChange", onOpenContextMenu: "onOpenContextMenu", onCornerAction: "onCornerAction", onDynamicOperation: "onDynamicOperation", globalCheck: "globalCheckChange", autoUpdate: "autoUpdateChange", seconds: "secondsChange", researchInProgress: "researchInProgressChange" }, host: { listeners: { "document:mouseup": "onDocMouseUp()", "document:copy": "onDocCopy($event)", "document:paste": "onDocPaste($event)", "document:click": "onDocClick()" }, properties: { "class.est2": "this.hostClass", "class.est2--dense": "this.denseClass" } }, queries: [{ propertyName: "headerRef", first: true, predicate: ["header"], descendants: true }, { propertyName: "bodyRef", first: true, predicate: ["body"], descendants: true }, { propertyName: "thDirectives", predicate: EsThDirective }, { propertyName: "tdDirectives", predicate: EsTdDirective }, { propertyName: "editorDirectives", predicate: EsTdEditorDirective }], viewQueries: [{ propertyName: "tableEmptyMenu", first: true, predicate: ["emptyMenu"], descendants: true, static: true }, { propertyName: "theadRef", first: true, predicate: ["theadRef"], descendants: true }], ngImport: i0, template: "@if (view()) {\n <div class=\"est2-wrap {{ ContainerClass() }}\"\n [style.height]=\"Height()\"\n [style.background-color]=\"EmptySpaceBackgroundColor() || null\">\n\n <!-- Pager superiore -->\n @if (PagingStyle() === 'both' || PagingStyle() === 'top') {\n <ng-container *ngTemplateOutlet=\"pager\"></ng-container>\n }\n\n <!-- Barra \"seleziona tutto\" (visibile solo con selezione multipla attiva e righe presenti) -->\n @if (Selection() && !SingleSelection() && hasSelection) {\n <div class=\"est2-selectbar\" [style.height.px]=\"selbarHeight() ? selbarHeight() + 1 : null\">\n @if (allSelected) {\n <span>Tutti i <strong>{{ selectedCount }}</strong> elementi sono selezionati</span>\n } @else {\n <span><strong>{{ selectedCount }}</strong> {{ selectedCount === 1 ? 'elemento selezionato' : 'elementi selezionati' }}</span>\n @if (canSelectEverything) {\n <span class=\"est2-link\" (click)=\"selectEverything()\">Seleziona tutti i {{ totalCount() }} elementi</span>\n }\n }\n <span class=\"est2-selectbar__spacer\"></span>\n <span class=\"est2-link\" (click)=\"clearSelection()\">Azzera selezione</span>\n </div>\n }\n\n <div class=\"est2-scroll\" [style.max-height.px]=\"MaxHeight()\">\n <table class=\"est2-table {{ TableClass() }}\"\n [class.est2-table--range]=\"rangeActive()\"\n [class.est2-table--dragging]=\"rangeDragging()\"\n (mousedown)=\"onGridMouseDown($event)\"\n (mouseover)=\"onGridMouseOver($event)\">\n\n <!-- ================= HEADER ================= -->\n @if (!HeaderHidden()) {\n <thead #theadRef>\n <!-- Righe di header-group multi-livello (dall'alto verso il basso) -->\n @if (hasHeaderGroups()) {\n @for (grow of headerGroupRows(); track $index) {\n <tr class=\"est2-hgroup-row\">\n @if (Selection()) { <th class=\"est2-col-min\" [class.est2-pinned]=\"hasPinned()\" [style.left.px]=\"hasPinned() ? 0 : null\"></th> }\n @for (op of DynamicOperations(); track op.id) { <th class=\"est2-col-min\"></th> }\n @for (cell of grow; track cell.id; let gi = $index) {\n <th [attr.colspan]=\"cell.span\"\n [class.est2-hgroup]=\"cell.isGroup\"\n [class.est2-pinned]=\"gi < pinnedCount()\"\n [style.left.px]=\"gi < pinnedCount() ? pinnedLeftPx(gi) : null\"\n class=\"est2-hgroup-cell\">\n @if (cell.isGroup) {\n @if (cell.template) {\n <ng-container *ngTemplateOutlet=\"cell.template\"></ng-container>\n } @else {\n {{ cell.label }}\n }\n }\n </th>\n }\n @if (Removal()) { <th class=\"est2-col-min\"></th> }\n @if (hasChrome()) { <th class=\"est2-col-min\"></th> }\n </tr>\n }\n }\n <tr>\n <!-- Colonna di selezione -->\n @if (Selection()) {\n <th class=\"est2-col-min\"\n [class.est2-pinned]=\"hasPinned()\"\n [style.left.px]=\"hasPinned() ? 0 : null\">\n @if (!SingleSelection()) {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"globalCheck()\"\n [indeterminate]=\"selectionIndeterminate\"\n [disabled]=\"SelectionDisabled()\"\n (change)=\"toggleAll()\"\n aria-label=\"Seleziona tutto\" />\n }\n </th>\n }\n\n <!-- Header da colonne (direttive / dinamica / report) -->\n @if (usesColumns()) {\n <!-- intestazioni vuote per le operazioni dinamiche -->\n @for (op of DynamicOperations(); track op.id) {\n <th class=\"est2-col-min\"></th>\n }\n @for (col of visibleColumns(); track trackCol($index, col); let ci = $index) {\n <th [class]=\"col.cssClass\"\n [class.est2-th--orderable]=\"OrderByColumn() && col.orderable\"\n [class.est2-col-min]=\"col.header?.thShrink\"\n [class.est2-pinned]=\"col.pinned\"\n [style.left.px]=\"col.pinned ? pinnedLeftPx(ci) : null\"\n [style.min-width.px]=\"col.pinned && col.pinnedWidth ? col.pinnedWidth : null\"\n [style.max-width.px]=\"col.pinned && col.pinnedWidth ? col.pinnedWidth : null\"\n [style.text-align]=\"col.alignment\"\n [style.background-color]=\"col.headerBg || null\"\n (click)=\"toggleSort(col)\">\n <span class=\"est2-th__inner\">\n @if (col.header?.Template) {\n <ng-container *ngTemplateOutlet=\"col.header!.Template!; context: col.multiProp != null ? { $implicit: col.headerText } : null\"></ng-container>\n } @else {\n {{ col.headerText }}\n }\n @if (OrderByColumn() && col.orderable && orderOf(col.id)) {\n <span class=\"est2-sort est2-sort--active\"\n [class.est2-sort--desc]=\"orderOf(col.id) === 'DESC'\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M6 15l6-6 6 6\"/></svg>\n </span>\n @if (orderIndex(col.id) > 0 && MultipleOrderingDirectives()) {\n <span class=\"est2-sort__badge\">{{ orderIndex(col.id) }}</span>\n }\n }\n <!-- Indicatore/toggle di pin (visibile se pinnata o all'hover) -->\n @if (ColumnsPinnable() && col.multiProp == null) {\n <button type=\"button\" class=\"est2-pinbtn\"\n [class.est2-pinbtn--on]=\"col.pinned\"\n [title]=\"col.pinned ? 'Sblocca colonna' : 'Blocca colonna a sinistra'\"\n (click)=\"togglePin(col, $event)\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 17v5\"/><path d=\"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z\"/></svg>\n </button>\n }\n </span>\n </th>\n }\n }\n <!-- Header da template semplice -->\n @else if (headerRef) {\n <ng-container *ngTemplateOutlet=\"headerRef\"></ng-container>\n }\n\n <!-- Colonna rimozione -->\n @if (Removal()) { <th class=\"est2-col-min\"></th> }\n <!-- Colonna chrome (export / gestione colonne / menu) -->\n @if (hasChrome()) {\n <th class=\"est2-col-min est2-chrome-th\">\n <div class=\"est2-chrome\">\n @if (Export()) {\n <div class=\"est2-chrome-wrap\">\n <button type=\"button\" class=\"est2-chrome-btn\" title=\"Esporta\" (click)=\"$event.stopPropagation(); toggleExportMenu()\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"/><path d=\"M7 10l5 5 5-5\"/><path d=\"M12 15V3\"/></svg>\n </button>\n @if (exportMenuOpen()) {\n <div class=\"est2-menu\" (click)=\"$event.stopPropagation()\">\n @if (CSVExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('CSV')\">Esporta CSV</button> }\n @if (XLSXExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('XLSX')\">Esporta Excel (XLSX)</button> }\n @if (!CSVExport() && !XLSXExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('CSV')\">Esporta CSV</button> }\n </div>\n }\n </div>\n }\n @if (HiddenColumns() || ColumnsOrdering()) {\n <button type=\"button\" class=\"est2-chrome-btn\" title=\"Colonne\" (click)=\"$event.stopPropagation(); openColumnsDialog()\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"1\"/><path d=\"M9 3v18\"/><path d=\"M15 3v18\"/></svg>\n </button>\n }\n @if (CornerMenuOptions().length > 0) {\n <div class=\"est2-chrome-wrap\">\n <button type=\"button\" class=\"est2-chrome-btn\" title=\"Opzioni\" (click)=\"$event.stopPropagation(); toggleCornerMenu()\">\u22EE</button>\n @if (cornerMenuOpen()) {\n <div class=\"est2-menu\" (click)=\"$event.stopPropagation()\">\n @for (opt of CornerMenuOptions(); track opt.id) {\n <button type=\"button\" class=\"est2-menu-item\" (click)=\"cornerAction(opt.id); cornerMenuOpen.set(false)\">{{ opt.description }}</button>\n }\n </div>\n }\n </div>\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n }\n\n <!-- ================= BODY ================= -->\n @if (!BodyHidden()) {\n <tbody>\n @for (item of boundSource(); track trackRow($index, item); let ri = $index) {\n @if ((!grouped() && !Hierarchy()) || item._visible) {\n <tr [class]=\"rowClass(item)\"\n [class.est2-row--selected]=\"item._selected\"\n [class.est2-row--removed]=\"item.removed || item.deleted\"\n [class.est2-row--group]=\"item._group\"\n [class.est2-row--clickable]=\"Selection() || item._group\"\n [contextMenu]=\"ContextMenu || emptyMenu\"\n [contextMenuSubject]=\"item\"\n (click)=\"handleRowClick(item, $event)\">\n\n <!-- Cella di selezione -->\n @if (Selection()) {\n <td class=\"est2-col-min\"\n [class.est2-pinned]=\"hasPinned()\"\n [style.left.px]=\"hasPinned() ? 0 : null\">\n @if (item._group) {\n @if (!SingleSelection()) {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"groupSelectionState(item) === 'all'\"\n [indeterminate]=\"groupSelectionState(item) === 'some'\"\n [disabled]=\"SelectionDisabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleGroupSelection(item)\"\n aria-label=\"Seleziona gruppo\" />\n }\n } @else {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"item._selected\"\n [indeterminate]=\"hierarchyIndeterminate(item)\"\n [disabled]=\"SelectionDisabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(item)\"\n aria-label=\"Seleziona riga\" />\n }\n </td>\n }\n\n <!-- Celle da colonne (direttive / dinamica / report) -->\n @if (usesColumns()) {\n <!-- Operazioni dinamiche (icone a sinistra) -->\n @for (op of DynamicOperations(); track op.id) {\n <td class=\"est2-col-min est2-op-cell\">\n @if (!item._group && operationVisible(op, item)) {\n <span class=\"est2-op\" [class]=\"op.iconClass || ''\" [title]=\"op.title\"\n (click)=\"$event.stopPropagation(); dynamicOperation(item, op.id)\">{{ op.text }}</span>\n }\n </td>\n }\n @for (col of visibleColumns(); track trackCol($index, col); let first = $first, ci = $index) {\n <td [class]=\"col.cssClass\"\n [style.text-align]=\"col.alignment\"\n [style.color]=\"cellColor(item, col, 'fore')\"\n [style.background-color]=\"cellColor(item, col, 'back')\"\n [class.est2-nowrap]=\"!col.wrap\"\n [class.est2-pinned]=\"col.pinned\"\n [style.left.px]=\"col.pinned ? pinnedLeftPx(ci) : null\"\n [style.min-width.px]=\"col.pinned && col.pinnedWidth ? col.pinnedWidth : null\"\n [style.max-width.px]=\"col.pinned && col.pinnedWidth ? col.pinnedWidth : null\"\n [class.est2-td--group-key]=\"item._group && item.column === col.id\"\n [attr.data-r]=\"rangeActive() && !item._group ? ri : null\"\n [attr.data-c]=\"rangeActive() && !item._group ? ci : null\"\n [class.est2-cell-sel]=\"rangeActive() && inRange(ri, ci)\"\n [class.est2-cell-sel-t]=\"rangeActive() && inRange(ri, ci) && ri === rangeRect()!.top\"\n [class.est2-cell-sel-b]=\"rangeActive() && inRange(ri, ci) && ri === rangeRect()!.bottom\"\n [class.est2-cell-sel-l]=\"rangeActive() && inRange(ri, ci) && ci === rangeRect()!.left\"\n [class.est2-cell-sel-r]=\"rangeActive() && inRange(ri, ci) && ci === rangeRect()!.right\"\n [class.est2-cell-editing]=\"isEditing(ri, ci)\"\n (dblclick)=\"onCellDblClick(item, col, ri, ci)\">\n @if (isEditing(ri, ci)) {\n @if (editorFor(col); as edTpl) {\n <ng-container *ngTemplateOutlet=\"edTpl; context: editorContext(item, col)\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"defaultEditor; context: { $implicit: item, col: col }\"></ng-container>\n }\n } @else if (item._group) {\n @if (item.column === col.id) {\n <span class=\"est2-group-key\" [style.padding-left.px]=\"groupIndent(item)\">\n <span class=\"est2-group-chevron\" [class.est2-group-chevron--open]=\"item._expanded\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 6l6 6-6 6\"/></svg>\n </span>\n {{ groupCellDisplay(item, col) }}\n </span>\n } @else {\n {{ groupCellDisplay(item, col) }}\n }\n } @else {\n <!-- Navigatore albero nella prima colonna -->\n @if (Hierarchy() && first) {\n <span class=\"est2-hier-lead\" [style.padding-left.px]=\"hierarchyIndent(item)\">\n @if (item.parent) {\n <span class=\"est2-group-chevron est2-hier-toggle\" [class.est2-group-chevron--open]=\"item._expanded\"\n (click)=\"$event.stopPropagation(); toggleHierarchyNode(item)\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 6l6 6-6 6\"/></svg>\n </span>\n } @else {\n <span class=\"est2-hier-toggle\"></span>\n }\n </span>\n }\n @if (itemCellHidden(col)) {\n <!-- colonna di gruppo nascosta sulla riga-oggetto -->\n } @else if (col.multiProp != null) {\n @if (col.cell?.Template) {\n <ng-container *ngTemplateOutlet=\"col.cell!.Template; context: { $implicit: multiCell(item, col) }\"></ng-container>\n } @else {\n {{ multiCell(item, col)?.value }}\n }\n } @else if (col.cell?.Template) {\n <ng-container *ngTemplateOutlet=\"col.cell!.Template; context: { $implicit: item }\"></ng-container>\n } @else if (col.routePath) {\n <a class=\"est2-link\" [routerLink]=\"routerLinkFor(item, col)\">{{ cellValue(item, col) }}</a>\n } @else if (col.propAccessor != null) {\n {{ reportCellDisplay(item, col) }}\n } @else if (col.type === 'enum') {\n {{ (cellValue(item, col) | est2_lookup : col.source).description }}\n } @else {\n {{ cellValue(item, col) | est2_format : col.type : col.format : locale }}\n }\n }\n </td>\n }\n }\n <!-- Celle da template semplice -->\n @else if (bodyRef) {\n <ng-container *ngTemplateOutlet=\"bodyRef; context: { $implicit: item }\"></ng-container>\n }\n\n <!-- Rimozione (non sulle righe-gruppo) -->\n @if (Removal()) {\n <td class=\"est2-col-min\">\n @if (!item._group && canRemove(item)) {\n @if (item.removed || item.deleted) {\n <button type=\"button\" class=\"est2-rowaction\" title=\"Ripristina\" (click)=\"abortRemoval(item)\">\u21BA</button>\n } @else {\n <button type=\"button\" class=\"est2-rowaction est2-rowaction--danger\" title=\"Rimuovi\" (click)=\"removeItem(item)\">\u2715</button>\n }\n }\n </td>\n }\n <!-- Chrome -->\n @if (hasChrome()) { <td class=\"est2-col-min\"></td> }\n </tr>\n }\n } @empty {\n <tr>\n <td class=\"est2-empty\" [attr.colspan]=\"totalColspan()\">Nessun elemento da visualizzare</td>\n </tr>\n }\n </tbody>\n }\n </table>\n\n <!-- Overlay di caricamento -->\n @if (researchInProgress() || (firstBind() && ShowLoadingOnBootstrap())) {\n <div class=\"est2-loading\">\n <span class=\"est2-spinner\"></span>\n <span>Caricamento\u2026</span>\n </div>\n }\n </div>\n\n <!-- Pager inferiore -->\n @if (PagingStyle() === 'both' || PagingStyle() === 'bottom') {\n <ng-container *ngTemplateOutlet=\"pager\"></ng-container>\n }\n\n <!-- Avviso transitorio (es. incolla con dimensioni incompatibili) -->\n @if (notice()) {\n <div class=\"est2-toast\" role=\"alert\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/><path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/></svg>\n <span>{{ notice() }}</span>\n </div>\n }\n\n <!-- Dialog visibilit\u00E0 / ordine colonne -->\n @if (columnsDialogOpen()) {\n <div class=\"est2-dialog-backdrop\" (click)=\"closeColumnsDialog()\">\n <div class=\"est2-dialog\" (click)=\"$event.stopPropagation()\" role=\"dialog\" aria-modal=\"true\">\n <div class=\"est2-dialog__head\">\n <span>\n @if (HiddenColumns() && ColumnsOrdering()) { Visibilit\u00E0 e ordine colonne }\n @else if (HiddenColumns()) { Visibilit\u00E0 colonne }\n @else { Ordine colonne }\n </span>\n <button type=\"button\" class=\"est2-dialog__close\" (click)=\"closeColumnsDialog()\" aria-label=\"Chiudi\">\u2715</button>\n </div>\n\n @if (HiddenColumns()) {\n <div class=\"est2-dialog__tools\">\n <button type=\"button\" class=\"est2-link\" (click)=\"dialogSetAll(true)\">Mostra tutte</button>\n <span class=\"est2-dialog__sep\">\u00B7</span>\n <button type=\"button\" class=\"est2-link\" (click)=\"dialogSetAll(false)\">Nascondi tutte</button>\n </div>\n }\n\n <ul class=\"est2-collist\">\n @for (c of dialogCols(); track c.id; let i = $index) {\n <li class=\"est2-collist__row\">\n @if (HiddenColumns()) {\n <label class=\"est2-collist__vis\">\n <input type=\"checkbox\" class=\"est2-check\" [checked]=\"c.visible\" (change)=\"dialogToggle(i)\" />\n </label>\n }\n <span class=\"est2-collist__label\">{{ c.label }}</span>\n @if (ColumnsPinnable()) {\n <button type=\"button\" class=\"est2-iconbtn est2-collist__pin\" [class.est2-collist__pin--on]=\"c.pinned\"\n [title]=\"c.pinned ? 'Sblocca' : 'Blocca a sinistra'\" (click)=\"dialogTogglePin(i)\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 17v5\"/><path d=\"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z\"/></svg>\n </button>\n }\n @if (ColumnsOrdering()) {\n <span class=\"est2-collist__ord\">\n <button type=\"button\" class=\"est2-iconbtn\" [disabled]=\"i === 0\" title=\"Su\" (click)=\"dialogMove(i, -1)\">\u2191</button>\n <button type=\"button\" class=\"est2-iconbtn\" [disabled]=\"i === dialogCols().length - 1\" title=\"Gi\u00F9\" (click)=\"dialogMove(i, 1)\">\u2193</button>\n </span>\n }\n </li>\n }\n </ul>\n\n <div class=\"est2-dialog__foot\">\n <button type=\"button\" class=\"est2-btn est2-btn--ghost\" (click)=\"resetColumnsDialog()\">Ripristina</button>\n <span class=\"est2-dialog__spacer\"></span>\n <button type=\"button\" class=\"est2-btn est2-btn--ghost\" (click)=\"closeColumnsDialog()\">Annulla</button>\n <button type=\"button\" class=\"est2-btn est2-btn--primary\" (click)=\"applyColumnsDialog()\">Applica</button>\n </div>\n </div>\n </div>\n }\n </div>\n}\n\n<!-- Template pager riutilizzabile sopra/sotto -->\n<ng-template #pager>\n @if (!HidePaging() && !grouped()) {\n <es-table2-pager\n [page]=\"currentPage()\"\n [pages]=\"totalPages()\"\n [total]=\"totalCount()\"\n [itemsPerPage]=\"viewMode() ? (view()?.itemsperpageoverride ?? 15) : ArraymodeItemsPerPage()\"\n [countLabel]=\"CountLabel()\"\n [showCount]=\"!HidePagingCount()\"\n [showButtons]=\"!HidePagingButtons()\"\n [showPagingOptions]=\"!HidePagingButtons()\"\n [allowAll]=\"AllSearch()\"\n (pageChange)=\"goToPage($event)\"\n (itemsPerPageChange)=\"changeItemsPerPage($event)\">\n </es-table2-pager>\n }\n</ng-template>\n\n<!-- Editor di cella di default (usato quando il consumer non fornisce un `*editor`) -->\n<ng-template #defaultEditor let-item let-col=\"col\">\n @switch (col.type) {\n @case ('enum') {\n <select class=\"est2-editor-input\"\n [value]=\"editDraft\"\n (change)=\"editDraft = $any($event.target).value\"\n (keydown.enter)=\"commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\"\n (blur)=\"commitEdit(item, col)\">\n @for (o of col.source || []; track o.id) {\n <option [value]=\"o.id\" [selected]=\"o.id == editDraft\">{{ o.description }}</option>\n }\n </select>\n }\n @case ('boolean') {\n <input type=\"checkbox\" class=\"est2-editor-input est2-check\"\n [checked]=\"editDraft === true || editDraft === 'true'\"\n (change)=\"editDraft = $any($event.target).checked; commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\" />\n }\n @default {\n <input class=\"est2-editor-input\"\n [type]=\"editorInputType(col.type)\"\n [value]=\"editDraft\"\n (input)=\"editDraft = $any($event.target).value\"\n (keydown.enter)=\"commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\"\n (blur)=\"commitEdit(item, col)\" />\n }\n }\n</ng-template>\n\n<!-- Menu di default (nessuna operazione) usato quando il consumer non passa [ContextMenu] -->\n<context-menu #emptyMenu>\n <ng-template contextMenuItem [passive]=\"true\"><em>Nessuna operazione disponibile\u2026</em></ng-template>\n</context-menu>\n", styles: [".est2{--est-bg: #ffffff;--est-bg-subtle: #f7f8fa;--est-bg-raised: #ffffff;--est-bg-hover: #f2f4f7;--est-bg-selected: color-mix(in srgb, var(--est-accent) 12%, transparent);--est-fg: #1a1d24;--est-fg-muted: #626b7a;--est-fg-faint: #9aa3b2;--est-border: #e6e9ef;--est-border-strong: #d3d8e0;--est-accent: #4f46e5;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 14%, transparent);--est-danger: #dc2626;--est-warning: #d97706;--est-success: #059669;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 4px 12px -8px rgba(16, 24, 40, .24);--est-shadow-pop: 0 8px 24px -6px rgba(16, 24, 40, .18), 0 2px 6px -2px rgba(16, 24, 40, .12);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 40%, transparent);--est-radius: 10px;--est-radius-sm: 6px;--est-radius-pill: 999px;--est-gap: 8px;--est-cell-py: 10px;--est-cell-px: 14px;--est-row-h: 44px;--est-font: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;--est-fs: 13.5px;--est-fs-sm: 12px;--est-fw-head: 600;--est-transition: .14s cubic-bezier(.4, 0, .2, 1);font-family:var(--est-font);font-size:var(--est-fs);color:var(--est-fg);position:relative;display:block}@media(prefers-color-scheme:dark){.est2{--est-bg: #14161c;--est-bg-subtle: #1a1d25;--est-bg-raised: #1e222b;--est-bg-hover: #232733;--est-bg-selected: color-mix(in srgb, var(--est-accent) 26%, transparent);--est-fg: #e7eaf0;--est-fg-muted: #9aa3b2;--est-fg-faint: #6b7484;--est-border: #2a2f3a;--est-border-strong: #39404d;--est-accent: #7c74ff;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 22%, transparent);--est-danger: #f87171;--est-warning: #fbbf24;--est-success: #34d399;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 6px 16px -10px rgba(0, 0, 0, .7);--est-shadow-pop: 0 10px 28px -8px rgba(0, 0, 0, .6), 0 2px 6px -2px rgba(0, 0, 0, .5);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 55%, transparent)}}.est2.est2--dark{--est-bg: #14161c;--est-bg-subtle: #1a1d25;--est-bg-raised: #1e222b;--est-bg-hover: #232733;--est-bg-selected: color-mix(in srgb, var(--est-accent) 26%, transparent);--est-fg: #e7eaf0;--est-fg-muted: #9aa3b2;--est-fg-faint: #6b7484;--est-border: #2a2f3a;--est-border-strong: #39404d;--est-accent: #7c74ff;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 22%, transparent);--est-danger: #f87171;--est-warning: #fbbf24;--est-success: #34d399;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 6px 16px -10px rgba(0, 0, 0, .7);--est-shadow-pop: 0 10px 28px -8px rgba(0, 0, 0, .6), 0 2px 6px -2px rgba(0, 0, 0, .5);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 55%, transparent)}.est2.est2--light{--est-bg: #ffffff;--est-bg-subtle: #f7f8fa;--est-bg-raised: #ffffff;--est-bg-hover: #f2f4f7;--est-bg-selected: color-mix(in srgb, var(--est-accent) 12%, transparent);--est-fg: #1a1d24;--est-fg-muted: #626b7a;--est-fg-faint: #9aa3b2;--est-border: #e6e9ef;--est-border-strong: #d3d8e0;--est-accent: #4f46e5;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 14%, transparent);--est-danger: #dc2626;--est-warning: #d97706;--est-success: #059669;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 4px 12px -8px rgba(16, 24, 40, .24);--est-shadow-pop: 0 8px 24px -6px rgba(16, 24, 40, .18), 0 2px 6px -2px rgba(16, 24, 40, .12);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 40%, transparent)}.est2.est2--dense{--est-cell-py: 5px;--est-cell-px: 10px;--est-row-h: 32px;--est-fs: 12.5px}.est2 *,.est2 *:before,.est2 *:after{box-sizing:border-box}.est2 .est2-scroll{position:relative;width:100%;overflow:auto;border:1px solid var(--est-border);border-radius:var(--est-radius);background:var(--est-bg);-webkit-overflow-scrolling:touch}.est2 table.est2-table{width:100%;border-collapse:separate;border-spacing:0;background:var(--est-bg)}.est2 thead th{position:sticky;top:0;z-index:3;background:var(--est-bg-subtle);color:var(--est-fg-muted);font-weight:var(--est-fw-head);font-size:var(--est-fs-sm);letter-spacing:.02em;text-transform:uppercase;text-align:left;white-space:nowrap;padding:var(--est-cell-py) var(--est-cell-px);border-bottom:1px solid var(--est-border);box-shadow:var(--est-shadow-sticky);-webkit-user-select:none;user-select:none}.est2 thead tr.est2-hgroup-row th{font-size:var(--est-fs-sm);font-weight:600;letter-spacing:.02em;text-transform:uppercase;color:var(--est-fg-muted);text-align:center;white-space:nowrap;padding:var(--est-cell-py) var(--est-cell-px);background:var(--est-bg-subtle);border-bottom:1px solid var(--est-border)}.est2 thead tr.est2-hgroup-row th.est2-hgroup{color:var(--est-fg);border-left:1px solid var(--est-border);border-right:1px solid var(--est-border)}.est2 thead tr.est2-hgroup-row th:not(.est2-hgroup){background:var(--est-bg);border-bottom-color:transparent}.est2 tbody td{padding:var(--est-cell-py) var(--est-cell-px);border-bottom:1px solid var(--est-border);color:var(--est-fg);vertical-align:middle;background:transparent}.est2 th.est2-pinned,.est2 td.est2-pinned{position:sticky;background:var(--est-bg);box-shadow:1px 0 0 var(--est-border)}.est2 td.est2-pinned{z-index:3}.est2 thead th.est2-pinned{z-index:6;background:var(--est-bg-subtle)}.est2 thead tr.est2-hgroup-row th.est2-pinned{z-index:6;background:var(--est-bg)}.est2 tbody tr:hover td.est2-pinned{background:color-mix(in srgb,var(--est-fg) 5%,var(--est-bg))}.est2 tbody tr.est2-row--selected td.est2-pinned{background:color-mix(in srgb,var(--est-accent) 12%,var(--est-bg))}.est2 tbody tr.est2-row--group td.est2-pinned{background:var(--est-bg-subtle)}.est2 .est2-pinbtn{display:inline-flex;align-items:center;justify-content:center;margin-left:4px;padding:2px;border:none;background:transparent;color:var(--est-fg-faint);border-radius:var(--est-radius-sm);cursor:pointer;opacity:0;transition:opacity var(--est-transition),color var(--est-transition),background var(--est-transition)}.est2 thead th:hover .est2-pinbtn{opacity:.7}.est2 .est2-pinbtn:hover{background:var(--est-bg-hover);color:var(--est-fg);opacity:1}.est2 .est2-pinbtn--on{opacity:1;color:var(--est-accent);transform:rotate(0)}.est2 thead th:hover .est2-pinbtn--on{opacity:1}.est2 .est2-collist__pin.est2-collist__pin--on{color:var(--est-accent);border-color:var(--est-accent)}.est2 tbody tr{height:var(--est-row-h);transition:background var(--est-transition)}.est2 tbody tr:last-child td{border-bottom:none}.est2 tbody tr:hover td{background:var(--est-bg-hover)}.est2 tbody tr.est2-row--selected td{background:var(--est-bg-selected)}.est2 tbody tr.est2-row--clickable{cursor:pointer;-webkit-user-select:none;user-select:none}.est2 tbody tr.est2-row--removed td{text-decoration:line-through;color:var(--est-fg-faint)}.est2 .est2-table--range tbody td[data-r]{cursor:cell}.est2 .est2-table--dragging,.est2 .est2-table--dragging tbody td{-webkit-user-select:none;user-select:none}.est2 tbody td.est2-cell-sel{background:color-mix(in srgb,var(--est-accent) 14%,transparent)}.est2 tbody td.est2-cell-sel-t{box-shadow:inset 0 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b{box-shadow:inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-l{box-shadow:inset 2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-r{box-shadow:inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-l{box-shadow:inset 2px 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-r{box-shadow:inset -2px 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-l{box-shadow:inset 2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-r{box-shadow:inset -2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b{box-shadow:inset 0 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 0 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-l{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-r{box-shadow:inset -2px 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px -2px 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset -2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-editing{padding:2px 6px}.est2 .est2-editor-input{width:100%;box-sizing:border-box;height:calc(var(--est-row-h) - 8px);padding:2px 6px;font:inherit;color:var(--est-fg);background:var(--est-bg);border:1.5px solid var(--est-accent);border-radius:var(--est-radius-sm);outline:none}.est2 .est2-editor-input:focus-visible{box-shadow:var(--est-ring)}.est2 input.est2-editor-input[type=checkbox]{width:16px;height:16px}.est2 .est2-toast{position:absolute;left:50%;bottom:14px;transform:translate(-50%);z-index:20;display:inline-flex;align-items:center;gap:8px;max-width:calc(100% - 24px);padding:8px 14px;font-size:13px;font-weight:500;color:#fff;background:#b91c1c;border-radius:var(--est-radius);box-shadow:0 6px 20px #00000040;animation:est2-toast-in .16s ease-out}.est2 .est2-toast svg{flex:0 0 auto}@keyframes est2-toast-in{0%{opacity:0;transform:translate(-50%,8px)}to{opacity:1;transform:translate(-50%)}}@media(prefers-reduced-motion:reduce){.est2 .est2-toast{animation:none}}.est2 tbody tr.est2-row--group{cursor:pointer;-webkit-user-select:none;user-select:none}.est2 tbody tr.est2-row--group td{background:var(--est-bg-subtle);font-weight:600;color:var(--est-fg);border-bottom:1px solid var(--est-border)}.est2 tbody tr.est2-row--group:hover td{background:var(--est-bg-hover)}.est2 .est2-td--group-key{color:var(--est-fg)}.est2 .est2-group-key{display:inline-flex;align-items:center;gap:6px}.est2 .est2-group-chevron{display:inline-flex;color:var(--est-fg-muted);transition:transform var(--est-transition)}.est2 .est2-group-chevron--open{transform:rotate(90deg)}.est2 .est2-hier-lead{display:inline-flex;align-items:center;vertical-align:middle;margin-right:4px}.est2 .est2-hier-toggle{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;flex:none}.est2 .est2-group-chevron.est2-hier-toggle{cursor:pointer;border-radius:var(--est-radius-sm);transition:transform var(--est-transition),background var(--est-transition),color var(--est-transition)}.est2 .est2-group-chevron.est2-hier-toggle:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 th.est2-th--orderable{cursor:pointer;transition:color var(--est-transition)}.est2 th.est2-th--orderable:hover{color:var(--est-fg)}.est2 .est2-th__inner{display:inline-flex;align-items:center;gap:6px}.est2 .est2-sort{display:inline-flex;width:14px;height:14px;opacity:.35;transition:opacity var(--est-transition),transform var(--est-transition)}.est2 .est2-sort--active{opacity:1;color:var(--est-accent)}.est2 .est2-sort--desc{transform:rotate(180deg)}.est2 .est2-sort__badge{font-size:9px;font-weight:700;color:var(--est-accent);margin-left:2px}.est2 .est2-check{appearance:none;width:16px;height:16px;border:1.5px solid var(--est-border-strong);border-radius:var(--est-radius-sm);background:var(--est-bg);cursor:pointer;position:relative;transition:border-color var(--est-transition),background var(--est-transition);vertical-align:middle;flex:none}.est2 .est2-check:hover{border-color:var(--est-accent)}.est2 .est2-check:checked{background:var(--est-accent);border-color:var(--est-accent)}.est2 .est2-check:checked:after{content:\"\";position:absolute;left:4.5px;top:1.5px;width:4px;height:8px;border:solid var(--est-accent-fg);border-width:0 2px 2px 0;transform:rotate(45deg)}.est2 .est2-check:focus-visible{outline:none;box-shadow:var(--est-ring)}.est2 .est2-check:indeterminate{background:var(--est-accent);border-color:var(--est-accent)}.est2 .est2-check:indeterminate:after{content:\"\";position:absolute;left:3px;top:6px;width:8px;height:2px;background:var(--est-accent-fg);transform:none;border:none}.est2 th.est2-col-min,.est2 td.est2-col-min{width:1%;white-space:nowrap}.est2 .est2-wrap{position:relative}.est2 .est2-selectbar{position:absolute;top:0;left:0;right:0;z-index:15;display:flex;align-items:center;gap:12px;padding:9px 14px;font-size:var(--est-fs-sm);color:var(--est-fg);background:var(--est-bg-subtle);border:none;border-radius:var(--est-radius) var(--est-radius) 0 0;box-shadow:inset 3px 0 0 var(--est-accent)}.est2 .est2-selectbar strong{color:var(--est-fg);font-weight:700}.est2 .est2-selectbar__spacer{flex:1 1 auto}.est2 .est2-link{color:var(--est-accent);cursor:pointer;font-weight:600}.est2 .est2-link:hover{text-decoration:underline}.est2 .est2-rowaction{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--est-radius-sm);border:none;background:transparent;color:var(--est-fg-faint);cursor:pointer;transition:background var(--est-transition),color var(--est-transition)}.est2 .est2-rowaction:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-rowaction--danger:hover{color:var(--est-danger)}.est2 .est2-op-cell{text-align:center}.est2 .est2-op{display:inline-flex;align-items:center;justify-content:center;min-width:26px;height:26px;padding:0 6px;border-radius:var(--est-radius-sm);color:var(--est-accent);cursor:pointer;font-size:var(--est-fs-sm);transition:background var(--est-transition)}.est2 .est2-op:hover{background:var(--est-accent-weak)}.est2 .est2-loading{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;gap:10px;background:color-mix(in srgb,var(--est-bg) 70%,transparent);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:5;color:var(--est-fg-muted);font-size:var(--est-fs-sm)}.est2 .est2-spinner{width:16px;height:16px;border:2px solid var(--est-border-strong);border-top-color:var(--est-accent);border-radius:50%;animation:est2-spin .7s linear infinite}@keyframes est2-spin{to{transform:rotate(360deg)}}.est2 .est2-nowrap{white-space:nowrap}.est2 .est2-cornermenu{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--est-radius-sm);cursor:pointer;color:var(--est-fg-muted);transition:background var(--est-transition)}.est2 .est2-cornermenu:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-chrome-th{position:relative}.est2 .est2-chrome{display:inline-flex;align-items:center;gap:2px}.est2 .est2-chrome-wrap{position:relative;display:inline-flex}.est2 .est2-chrome-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;background:transparent;border-radius:var(--est-radius-sm);color:var(--est-fg-muted);cursor:pointer;font-size:16px;line-height:1;transition:background var(--est-transition),color var(--est-transition)}.est2 .est2-chrome-btn:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-menu{position:absolute;top:calc(100% + 4px);right:0;z-index:30;min-width:180px;padding:4px;background:var(--est-bg);border:1px solid var(--est-border);border-radius:var(--est-radius);box-shadow:0 8px 24px #0000002e;display:flex;flex-direction:column}.est2 .est2-menu-item{display:block;width:100%;padding:8px 10px;border:none;background:transparent;text-align:left;font:inherit;color:var(--est-fg);border-radius:var(--est-radius-sm);cursor:pointer}.est2 .est2-menu-item:hover{background:var(--est-bg-hover)}.est2 .est2-dialog-backdrop{position:absolute;inset:0;z-index:40;display:flex;align-items:center;justify-content:center;padding:16px;background:color-mix(in srgb,#000 32%,transparent)}.est2 .est2-dialog{width:380px;max-width:100%;max-height:100%;display:flex;flex-direction:column;background:var(--est-bg);color:var(--est-fg);border:1px solid var(--est-border);border-radius:var(--est-radius);box-shadow:0 16px 48px #0000004d;overflow:hidden}.est2 .est2-dialog__head{display:flex;align-items:center;justify-content:space-between;padding:12px 14px;font-weight:700;border-bottom:1px solid var(--est-border)}.est2 .est2-dialog__close{border:none;background:transparent;cursor:pointer;color:var(--est-fg-muted);font-size:15px;line-height:1;padding:4px;border-radius:var(--est-radius-sm)}.est2 .est2-dialog__close:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-dialog__tools{padding:8px 14px;font-size:var(--est-fs-sm);border-bottom:1px solid var(--est-border)}.est2 .est2-dialog__tools .est2-link{border:none;background:none;padding:0;font:inherit;font-weight:600}.est2 .est2-dialog__sep{margin:0 6px;color:var(--est-fg-faint)}.est2 .est2-collist{list-style:none;margin:0;padding:6px;overflow-y:auto}.est2 .est2-collist__row{display:flex;align-items:center;gap:10px;padding:6px 8px;border-radius:var(--est-radius-sm)}.est2 .est2-collist__row:hover{background:var(--est-bg-hover)}.est2 .est2-collist__vis{display:inline-flex}.est2 .est2-collist__label{flex:1 1 auto}.est2 .est2-collist__ord{display:inline-flex;gap:4px}.est2 .est2-iconbtn{width:26px;height:26px;border:1px solid var(--est-border);background:var(--est-bg);border-radius:var(--est-radius-sm);color:var(--est-fg-muted);cursor:pointer}.est2 .est2-iconbtn:hover:not(:disabled){background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-iconbtn:disabled{opacity:.4;cursor:default}.est2 .est2-dialog__foot{display:flex;align-items:center;gap:8px;padding:12px 14px;border-top:1px solid var(--est-border)}.est2 .est2-dialog__spacer{flex:1 1 auto}.est2 .est2-btn{padding:7px 14px;border-radius:var(--est-radius-sm);font:inherit;font-weight:600;cursor:pointer;border:1px solid transparent}.est2 .est2-btn--ghost{background:transparent;color:var(--est-fg);border-color:var(--est-border)}.est2 .est2-btn--ghost:hover{background:var(--est-bg-hover)}.est2 .est2-btn--primary{background:var(--est-accent);color:var(--est-accent-fg)}.est2 .est2-btn--primary:hover{filter:brightness(1.05)}.est2 .est2-empty{padding:48px 16px;text-align:center;color:var(--est-fg-faint);font-size:var(--est-fs-sm)}.ngx-contextmenu{--ctx-bg: #ffffff;--ctx-fg: #1a1d24;--ctx-muted: #626b7a;--ctx-border: #e6e9ef;--ctx-hover: #f2f4f7;--ctx-accent: #4f46e5;--ctx-shadow: 0 10px 28px -8px rgba(16, 24, 40, .22), 0 2px 8px -3px rgba(16, 24, 40, .14);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.ngx-contextmenu .dropdown-menu{display:block;min-width:200px;margin:0;padding:6px;list-style:none;background:var(--ctx-bg);border:1px solid var(--ctx-border);border-radius:12px;box-shadow:var(--ctx-shadow);animation:est2-ctx-in .12s cubic-bezier(.16,1,.3,1)}.ngx-contextmenu li{list-style:none;margin:0}.ngx-contextmenu li>a{display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:7px;color:var(--ctx-fg);font-size:13.5px;line-height:1.2;text-decoration:none;cursor:pointer;white-space:nowrap;transition:background .12s ease,color .12s ease}.ngx-contextmenu li>a:hover,.ngx-contextmenu li>a:focus{background:var(--ctx-hover);color:var(--ctx-fg);text-decoration:none;outline:none}.ngx-contextmenu li.divider,.ngx-contextmenu li[role=separator]{height:1px;margin:6px 8px;padding:0;background:var(--ctx-border)}.ngx-contextmenu li.disabled>a,.ngx-contextmenu li[aria-disabled=true]>a{color:var(--ctx-muted);opacity:.55;pointer-events:none}@media(prefers-color-scheme:dark){.ngx-contextmenu{--ctx-bg: #1e222b;--ctx-fg: #e7eaf0;--ctx-muted: #9aa3b2;--ctx-border: #2a2f3a;--ctx-hover: #232733;--ctx-accent: #7c74ff;--ctx-shadow: 0 12px 30px -8px rgba(0, 0, 0, .6), 0 2px 8px -3px rgba(0, 0, 0, .5)}}@keyframes est2-ctx-in{0%{opacity:0;transform:translateY(-4px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@media(prefers-reduced-motion:reduce){.ngx-contextmenu .dropdown-menu{animation:none}}\n"], dependencies: [{ kind: "directive", type: i8.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i9.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i12.ContextMenuAttachDirective, selector: "[contextMenu]", inputs: ["contextMenuSubject", "contextMenu"] }, { kind: "component", type: i12.ContextMenuComponent, selector: "context-menu", inputs: ["menuClass", "autoFocus", "useBootstrap4", "disabled"], outputs: ["close", "open"] }, { kind: "directive", type: i12.ContextMenuItemDirective, selector: "[contextMenuItem]", inputs: ["subMenu", "divider", "enabled", "passive", "visible"], outputs: ["execute"] }, { kind: "component", type: EsTable2PagerComponent, selector: "es-table2-pager", inputs: ["page", "pages", "total", "itemsPerPage", "countLabel", "showCount", "showButtons", "showPagingOptions", "allowAll"], outputs: ["pageChange", "itemsPerPageChange"] }, { kind: "pipe", type: Est2FormatPipe, name: "est2_format" }, { kind: "pipe", type: Est2LookupPipe, name: "est2_lookup" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
8599
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: EsTable2Component, isStandalone: false, selector: "es-table2", inputs: { ContextMenu: { classPropertyName: "ContextMenu", publicName: "ContextMenu", isSignal: false, isRequired: false, transformFunction: null }, _Selection: { classPropertyName: "_Selection", publicName: "Selection", isSignal: true, isRequired: false, transformFunction: null }, SingleSelection: { classPropertyName: "SingleSelection", publicName: "SingleSelection", isSignal: true, isRequired: false, transformFunction: null }, SelectionDisabled: { classPropertyName: "SelectionDisabled", publicName: "SelectionDisabled", isSignal: true, isRequired: false, transformFunction: null }, _SelectAll: { classPropertyName: "_SelectAll", publicName: "SelectAll", isSignal: true, isRequired: false, transformFunction: null }, _UseSelectionCache: { classPropertyName: "_UseSelectionCache", publicName: "UseSelectionCache", isSignal: true, isRequired: false, transformFunction: null }, _ShiftClick: { classPropertyName: "_ShiftClick", publicName: "ShiftClick", isSignal: true, isRequired: false, transformFunction: null }, _OrderByColumn: { classPropertyName: "_OrderByColumn", publicName: "OrderByColumn", isSignal: true, isRequired: false, transformFunction: null }, MultipleOrderingDirectives: { classPropertyName: "MultipleOrderingDirectives", publicName: "MultipleOrderingDirectives", isSignal: true, isRequired: false, transformFunction: null }, Removal: { classPropertyName: "Removal", publicName: "Removal", isSignal: true, isRequired: false, transformFunction: null }, RemovalCondition: { classPropertyName: "RemovalCondition", publicName: "RemovalCondition", isSignal: true, isRequired: false, transformFunction: null }, RowClassAssigner: { classPropertyName: "RowClassAssigner", publicName: "RowClassAssigner", isSignal: false, isRequired: false, transformFunction: null }, _HidePaging: { classPropertyName: "_HidePaging", publicName: "HidePaging", isSignal: true, isRequired: false, transformFunction: null }, _HidePagingCount: { classPropertyName: "_HidePagingCount", publicName: "HidePagingCount", isSignal: true, isRequired: false, transformFunction: null }, _HidePagingButtons: { classPropertyName: "_HidePagingButtons", publicName: "HidePagingButtons", isSignal: true, isRequired: false, transformFunction: null }, _AllSearch: { classPropertyName: "_AllSearch", publicName: "AllSearch", isSignal: true, isRequired: false, transformFunction: null }, _PagingStyle: { classPropertyName: "_PagingStyle", publicName: "PagingStyle", isSignal: true, isRequired: false, transformFunction: null }, _ArraymodeItemsPerPage: { classPropertyName: "_ArraymodeItemsPerPage", publicName: "ArraymodeItemsPerPage", isSignal: true, isRequired: false, transformFunction: null }, _UseArrayModePaging: { classPropertyName: "_UseArrayModePaging", publicName: "UseArrayModePaging", isSignal: true, isRequired: false, transformFunction: null }, CountLabel: { classPropertyName: "CountLabel", publicName: "CountLabel", isSignal: true, isRequired: false, transformFunction: null }, Height: { classPropertyName: "Height", publicName: "Height", isSignal: true, isRequired: false, transformFunction: null }, MaxHeight: { classPropertyName: "MaxHeight", publicName: "MaxHeight", isSignal: true, isRequired: false, transformFunction: null }, EmptySpaceBackgroundColor: { classPropertyName: "EmptySpaceBackgroundColor", publicName: "EmptySpaceBackgroundColor", isSignal: true, isRequired: false, transformFunction: null }, HighCellDensity: { classPropertyName: "HighCellDensity", publicName: "HighCellDensity", isSignal: true, isRequired: false, transformFunction: null }, HeaderHidden: { classPropertyName: "HeaderHidden", publicName: "HeaderHidden", isSignal: true, isRequired: false, transformFunction: null }, BodyHidden: { classPropertyName: "BodyHidden", publicName: "BodyHidden", isSignal: true, isRequired: false, transformFunction: null }, ShowLoadingOnBootstrap: { classPropertyName: "ShowLoadingOnBootstrap", publicName: "ShowLoadingOnBootstrap", isSignal: true, isRequired: false, transformFunction: null }, _DefaultAlignment: { classPropertyName: "_DefaultAlignment", publicName: "DefaultAlignment", isSignal: true, isRequired: false, transformFunction: null }, _TableClass: { classPropertyName: "_TableClass", publicName: "TableClass", isSignal: true, isRequired: false, transformFunction: null }, _ContainerClass: { classPropertyName: "_ContainerClass", publicName: "ContainerClass", isSignal: true, isRequired: false, transformFunction: null }, EsTableHandledSearch: { classPropertyName: "EsTableHandledSearch", publicName: "EsTableHandledSearch", isSignal: true, isRequired: false, transformFunction: null }, SearchThrottle: { classPropertyName: "SearchThrottle", publicName: "SearchThrottle", isSignal: true, isRequired: false, transformFunction: null }, _ColumnsResizable: { classPropertyName: "_ColumnsResizable", publicName: "ColumnsResizable", isSignal: true, isRequired: false, transformFunction: null }, _ColumnsPinnable: { classPropertyName: "_ColumnsPinnable", publicName: "ColumnsPinnable", isSignal: true, isRequired: false, transformFunction: null }, _HiddenColumns: { classPropertyName: "_HiddenColumns", publicName: "HiddenColumns", isSignal: true, isRequired: false, transformFunction: null }, _ColumnsOrdering: { classPropertyName: "_ColumnsOrdering", publicName: "ColumnsOrdering", isSignal: true, isRequired: false, transformFunction: null }, _Export: { classPropertyName: "_Export", publicName: "Export", isSignal: true, isRequired: false, transformFunction: null }, XLSXExport: { classPropertyName: "XLSXExport", publicName: "XLSXExport", isSignal: true, isRequired: false, transformFunction: null }, CSVExport: { classPropertyName: "CSVExport", publicName: "CSVExport", isSignal: true, isRequired: false, transformFunction: null }, ExportFileName: { classPropertyName: "ExportFileName", publicName: "ExportFileName", isSignal: true, isRequired: false, transformFunction: null }, ExportOnlyVisibleColumns: { classPropertyName: "ExportOnlyVisibleColumns", publicName: "ExportOnlyVisibleColumns", isSignal: true, isRequired: false, transformFunction: null }, ExportFunction: { classPropertyName: "ExportFunction", publicName: "ExportFunction", isSignal: false, isRequired: false, transformFunction: null }, CornerMenuOptions: { classPropertyName: "CornerMenuOptions", publicName: "CornerMenuOptions", isSignal: true, isRequired: false, transformFunction: null }, DynamicOperations: { classPropertyName: "DynamicOperations", publicName: "DynamicOperations", isSignal: true, isRequired: false, transformFunction: null }, _DynamicRowColumnsDefinition: { classPropertyName: "_DynamicRowColumnsDefinition", publicName: "DynamicRowColumnsDefinition", isSignal: true, isRequired: false, transformFunction: null }, Hierarchy: { classPropertyName: "Hierarchy", publicName: "Hierarchy", isSignal: true, isRequired: false, transformFunction: null }, _ParentKey: { classPropertyName: "_ParentKey", publicName: "ParentKey", isSignal: true, isRequired: false, transformFunction: null }, _OwnKey: { classPropertyName: "_OwnKey", publicName: "OwnKey", isSignal: true, isRequired: false, transformFunction: null }, _AutoSortHierarchy: { classPropertyName: "_AutoSortHierarchy", publicName: "AutoSortHierarchy", isSignal: true, isRequired: false, transformFunction: null }, StartsExpanded: { classPropertyName: "StartsExpanded", publicName: "StartsExpanded", isSignal: true, isRequired: false, transformFunction: null }, CascadeSelection: { classPropertyName: "CascadeSelection", publicName: "CascadeSelection", isSignal: true, isRequired: false, transformFunction: null }, _SavePreferences: { classPropertyName: "_SavePreferences", publicName: "SavePreferences", isSignal: true, isRequired: false, transformFunction: null }, Name: { classPropertyName: "Name", publicName: "Name", isSignal: true, isRequired: false, transformFunction: null }, _RowGroupingPagingStyle: { classPropertyName: "_RowGroupingPagingStyle", publicName: "RowGroupingPagingStyle", isSignal: true, isRequired: false, transformFunction: null }, _ShowItemGroupsColumns: { classPropertyName: "_ShowItemGroupsColumns", publicName: "ShowItemGroupsColumns", isSignal: true, isRequired: false, transformFunction: null }, Editable: { classPropertyName: "Editable", publicName: "Editable", isSignal: true, isRequired: false, transformFunction: null }, RangeSelection: { classPropertyName: "RangeSelection", publicName: "RangeSelection", isSignal: true, isRequired: false, transformFunction: null }, ItemSourceProperty: { classPropertyName: "ItemSourceProperty", publicName: "ItemSourceProperty", isSignal: true, isRequired: false, transformFunction: null }, HasHeaderGroup: { classPropertyName: "HasHeaderGroup", publicName: "HasHeaderGroup", isSignal: true, isRequired: false, transformFunction: null }, HasSecondaryHeaderGroup: { classPropertyName: "HasSecondaryHeaderGroup", publicName: "HasSecondaryHeaderGroup", isSignal: true, isRequired: false, transformFunction: null }, SearchView: { classPropertyName: "SearchView", publicName: "SearchView", isSignal: true, isRequired: false, transformFunction: null }, _AutoUpdate: { classPropertyName: "_AutoUpdate", publicName: "AutoUpdate", isSignal: true, isRequired: false, transformFunction: null }, EsThTdProvider: { classPropertyName: "EsThTdProvider", publicName: "EsThTdProvider", isSignal: false, isRequired: false, transformFunction: null }, globalCheck: { classPropertyName: "globalCheck", publicName: "globalCheck", isSignal: true, isRequired: false, transformFunction: null }, autoUpdate: { classPropertyName: "autoUpdate", publicName: "autoUpdate", isSignal: true, isRequired: false, transformFunction: null }, seconds: { classPropertyName: "seconds", publicName: "seconds", isSignal: true, isRequired: false, transformFunction: null }, researchInProgress: { classPropertyName: "researchInProgress", publicName: "researchInProgress", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { onOrderChanged: "onOrderChanged", onSearchRequest: "onSearchRequest", onSelectionChanged: "onSelectionChanged", onRemoval: "onRemoval", onAbortRemoval: "onAbortRemoval", onModelChange: "onModelChange", onOpenContextMenu: "onOpenContextMenu", onCornerAction: "onCornerAction", onDynamicOperation: "onDynamicOperation", globalCheck: "globalCheckChange", autoUpdate: "autoUpdateChange", seconds: "secondsChange", researchInProgress: "researchInProgressChange" }, host: { listeners: { "document:mouseup": "onDocMouseUp()", "document:copy": "onDocCopy($event)", "document:paste": "onDocPaste($event)", "document:click": "onDocClick()" }, properties: { "class.est2": "this.hostClass", "class.est2--dense": "this.denseClass" } }, queries: [{ propertyName: "headerRef", first: true, predicate: ["header"], descendants: true }, { propertyName: "bodyRef", first: true, predicate: ["body"], descendants: true }, { propertyName: "thDirectives", predicate: EsThDirective }, { propertyName: "tdDirectives", predicate: EsTdDirective }, { propertyName: "editorDirectives", predicate: EsTdEditorDirective }, { propertyName: "thTdProviders", predicate: ThTdProvider }], viewQueries: [{ propertyName: "tableEmptyMenu", first: true, predicate: ["emptyMenu"], descendants: true, static: true }, { propertyName: "theadRef", first: true, predicate: ["theadRef"], descendants: true }], ngImport: i0, template: "@if (view()) {\n <div class=\"est2-wrap {{ ContainerClass() }}\"\n [style.height]=\"Height()\"\n [style.background-color]=\"EmptySpaceBackgroundColor() || null\">\n\n <!-- Auto-aggiornamento: toggle + intervallo (in alto a destra) -->\n @if (AutoUpdate()) {\n <div class=\"est2-autoupdate\">\n <label class=\"est2-autoupdate__label\">\n Aggiorna ogni\n <input type=\"text\" maxlength=\"3\" class=\"est2-autoupdate__secs\"\n [ngModel]=\"seconds()\" (ngModelChange)=\"seconds.set($event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n (change)=\"autoUpdateChanged()\" />\n secondi\n </label>\n <label class=\"est2-switch\" title=\"Attiva/disattiva auto-aggiornamento\">\n <input type=\"checkbox\" [ngModel]=\"autoUpdate()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"autoUpdate.set($event); autoUpdateChanged()\" />\n <span class=\"est2-switch__slider\"></span>\n </label>\n </div>\n }\n\n <!-- Pager superiore -->\n @if (PagingStyle() === 'both' || PagingStyle() === 'top') {\n <ng-container *ngTemplateOutlet=\"pager\"></ng-container>\n }\n\n <!-- Barra \"seleziona tutto\" (visibile solo con selezione multipla attiva e righe presenti) -->\n @if (Selection() && !SingleSelection() && hasSelection) {\n <div class=\"est2-selectbar\" [style.height.px]=\"selbarHeight() ? selbarHeight() + 1 : null\">\n @if (allSelected) {\n <span>Tutti i <strong>{{ selectedCount }}</strong> elementi sono selezionati</span>\n } @else {\n <span><strong>{{ selectedCount }}</strong> {{ selectedCount === 1 ? 'elemento selezionato' : 'elementi selezionati' }}</span>\n @if (canSelectEverything) {\n <span class=\"est2-link\" (click)=\"selectEverything()\">Seleziona tutti i {{ totalCount() }} elementi</span>\n }\n }\n <span class=\"est2-selectbar__spacer\"></span>\n <span class=\"est2-link\" (click)=\"clearSelection()\">Azzera selezione</span>\n </div>\n }\n\n <div class=\"est2-scroll\" [style.max-height.px]=\"MaxHeight()\">\n <table class=\"est2-table {{ TableClass() }}\"\n [class.est2-table--range]=\"rangeActive()\"\n [class.est2-table--dragging]=\"rangeDragging()\"\n (mousedown)=\"onGridMouseDown($event)\"\n (mouseover)=\"onGridMouseOver($event)\">\n\n <!-- ================= HEADER ================= -->\n @if (!HeaderHidden()) {\n <thead #theadRef>\n <!-- Righe di header-group multi-livello (dall'alto verso il basso) -->\n @if (hasHeaderGroups()) {\n @for (grow of headerGroupRows(); track $index) {\n <tr class=\"est2-hgroup-row\">\n @if (Selection()) { <th class=\"est2-col-min est2-selcol\" [class.est2-pinned]=\"hasPinned()\" [style.left.px]=\"hasPinned() ? 0 : null\"></th> }\n @for (op of DynamicOperations(); track op.id) { <th class=\"est2-col-min\"></th> }\n @for (cell of grow; track cell.id; let gi = $index) {\n <th [attr.colspan]=\"cell.span\"\n [attr.data-groupid]=\"cell.isGroup ? cell.id : null\"\n [class.est2-hgroup]=\"cell.isGroup\"\n [class.est2-pinned]=\"gi < pinnedCount()\"\n [style.left.px]=\"gi < pinnedCount() ? pinnedLeftPx(gi) : null\"\n class=\"est2-hgroup-cell\">\n @if (cell.isGroup) {\n @if (cell.template) {\n <ng-container *ngTemplateOutlet=\"cell.template\"></ng-container>\n } @else {\n {{ cell.label }}\n }\n }\n </th>\n }\n @if (Removal()) { <th class=\"est2-col-min\"></th> }\n @if (hasChrome()) { <th class=\"est2-col-min\"></th> }\n </tr>\n }\n }\n <tr>\n <!-- Colonna di selezione -->\n @if (Selection()) {\n <th class=\"est2-col-min est2-selcol\"\n [class.est2-pinned]=\"hasPinned()\"\n [style.left.px]=\"hasPinned() ? 0 : null\">\n @if (!SingleSelection()) {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"globalCheck()\"\n [indeterminate]=\"selectionIndeterminate\"\n [disabled]=\"SelectionDisabled()\"\n (change)=\"toggleAll()\"\n aria-label=\"Seleziona tutto\" />\n }\n </th>\n }\n\n <!-- Header da colonne (direttive / dinamica / report) -->\n @if (usesColumns()) {\n <!-- intestazioni vuote per le operazioni dinamiche -->\n @for (op of DynamicOperations(); track op.id) {\n <th class=\"est2-col-min\"></th>\n }\n @for (col of visibleColumns(); track trackCol($index, col); let ci = $index) {\n <th [attr.data-colid]=\"col.id\"\n [class]=\"col.cssClass\"\n [class.est2-th--orderable]=\"OrderByColumn() && col.orderable\"\n [class.est2-col-min]=\"col.header?.thShrink\"\n [class.est2-col-groupstart]=\"columnGroupBoundaries().has(ci)\"\n [class.est2-pinned]=\"col.pinned\"\n [style.left.px]=\"col.pinned ? pinnedLeftPx(ci) : null\"\n [style.min-width.px]=\"col.pinned && col.pinnedWidth ? col.pinnedWidth : null\"\n [style.max-width.px]=\"col.pinned && col.pinnedWidth ? col.pinnedWidth : null\"\n [style.text-align]=\"col.alignment\"\n [style.background-color]=\"col.headerBg || null\"\n (click)=\"toggleSort(col)\">\n <span class=\"est2-th__inner\">\n @if (col.header?.Template) {\n <ng-container *ngTemplateOutlet=\"col.header!.Template!; context: col.multiProp != null ? { $implicit: col.headerText } : null\"></ng-container>\n } @else {\n {{ col.headerText }}\n }\n @if (OrderByColumn() && col.orderable && orderOf(col.id)) {\n <span class=\"est2-sort est2-sort--active\"\n [class.est2-sort--desc]=\"orderOf(col.id) === 'DESC'\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M6 15l6-6 6 6\"/></svg>\n </span>\n @if (orderIndex(col.id) > 0 && MultipleOrderingDirectives()) {\n <span class=\"est2-sort__badge\">{{ orderIndex(col.id) }}</span>\n }\n }\n <!-- Indicatore/toggle di pin (visibile se pinnata o all'hover) -->\n @if (ColumnsPinnable() && col.multiProp == null) {\n <button type=\"button\" class=\"est2-pinbtn\"\n [class.est2-pinbtn--on]=\"col.pinned\"\n [title]=\"col.pinned ? 'Sblocca colonna' : 'Blocca colonna a sinistra'\"\n (click)=\"togglePin(col, $event)\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 17v5\"/><path d=\"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z\"/></svg>\n </button>\n }\n </span>\n </th>\n }\n }\n <!-- Header da template semplice -->\n @else if (headerRef) {\n <ng-container *ngTemplateOutlet=\"headerRef\"></ng-container>\n }\n\n <!-- Colonna rimozione -->\n @if (Removal()) { <th class=\"est2-col-min\"></th> }\n <!-- Colonna chrome (export / gestione colonne / menu) -->\n @if (hasChrome()) {\n <th class=\"est2-col-min est2-chrome-th\">\n <div class=\"est2-chrome\">\n @if (Export()) {\n <div class=\"est2-chrome-wrap\">\n <button type=\"button\" class=\"est2-chrome-btn\" title=\"Esporta\" (click)=\"$event.stopPropagation(); toggleExportMenu()\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"/><path d=\"M7 10l5 5 5-5\"/><path d=\"M12 15V3\"/></svg>\n </button>\n @if (exportMenuOpen()) {\n <div class=\"est2-menu\" (click)=\"$event.stopPropagation()\">\n @if (CSVExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('CSV')\">Esporta CSV</button> }\n @if (XLSXExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('XLSX')\">Esporta Excel (XLSX)</button> }\n @if (!CSVExport() && !XLSXExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('CSV')\">Esporta CSV</button> }\n </div>\n }\n </div>\n }\n @if (HiddenColumns() || ColumnsOrdering()) {\n <button type=\"button\" class=\"est2-chrome-btn\" title=\"Colonne\" (click)=\"$event.stopPropagation(); openColumnsDialog()\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"1\"/><path d=\"M9 3v18\"/><path d=\"M15 3v18\"/></svg>\n </button>\n }\n @if (CornerMenuOptions().length > 0) {\n <div class=\"est2-chrome-wrap\">\n <button type=\"button\" class=\"est2-chrome-btn\" title=\"Opzioni\" (click)=\"$event.stopPropagation(); toggleCornerMenu()\">\u22EE</button>\n @if (cornerMenuOpen()) {\n <div class=\"est2-menu\" (click)=\"$event.stopPropagation()\">\n @for (opt of CornerMenuOptions(); track opt.id) {\n <button type=\"button\" class=\"est2-menu-item\" (click)=\"cornerAction(opt.id); cornerMenuOpen.set(false)\">{{ opt.description }}</button>\n }\n </div>\n }\n </div>\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n }\n\n <!-- ================= BODY ================= -->\n @if (!BodyHidden()) {\n <tbody>\n @for (item of boundSource(); track trackRow($index, item); let ri = $index) {\n @if ((!grouped() && !Hierarchy()) || item._visible) {\n <tr [class]=\"rowClass(item)\"\n [class.est2-row--selected]=\"item._selected\"\n [class.est2-row--removed]=\"item.removed || item.deleted\"\n [class.est2-row--group]=\"item._group\"\n [class.est2-row--clickable]=\"Selection() || item._group\"\n [contextMenu]=\"ContextMenu || emptyMenu\"\n [contextMenuSubject]=\"item\"\n (click)=\"handleRowClick(item, $event)\">\n\n <!-- Cella di selezione -->\n @if (Selection()) {\n <td class=\"est2-col-min est2-selcol\"\n [class.est2-pinned]=\"hasPinned()\"\n [style.left.px]=\"hasPinned() ? 0 : null\">\n @if (item._group) {\n @if (!SingleSelection()) {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"groupSelectionState(item) === 'all'\"\n [indeterminate]=\"groupSelectionState(item) === 'some'\"\n [disabled]=\"SelectionDisabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleGroupSelection(item)\"\n aria-label=\"Seleziona gruppo\" />\n }\n } @else {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"item._selected\"\n [indeterminate]=\"hierarchyIndeterminate(item)\"\n [disabled]=\"SelectionDisabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(item)\"\n aria-label=\"Seleziona riga\" />\n }\n </td>\n }\n\n <!-- Celle da colonne (direttive / dinamica / report) -->\n @if (usesColumns()) {\n <!-- Operazioni dinamiche (icone a sinistra) -->\n @for (op of DynamicOperations(); track op.id) {\n <td class=\"est2-col-min est2-op-cell\">\n @if (!item._group && operationVisible(op, item)) {\n <span class=\"est2-op\" [class]=\"op.iconClass || ''\" [title]=\"op.title\"\n (click)=\"$event.stopPropagation(); dynamicOperation(item, op.id)\">{{ op.text }}</span>\n }\n </td>\n }\n @for (col of visibleColumns(); track trackCol($index, col); let first = $first, ci = $index) {\n <td [class]=\"col.cssClass\"\n [style.text-align]=\"col.alignment\"\n [style.color]=\"cellColor(item, col, 'fore')\"\n [style.background-color]=\"cellColor(item, col, 'back')\"\n [class.est2-nowrap]=\"!col.wrap\"\n [class.est2-col-groupstart]=\"columnGroupBoundaries().has(ci)\"\n [class.est2-pinned]=\"col.pinned\"\n [style.left.px]=\"col.pinned ? pinnedLeftPx(ci) : null\"\n [style.min-width.px]=\"col.pinned && col.pinnedWidth ? col.pinnedWidth : null\"\n [style.max-width.px]=\"col.pinned && col.pinnedWidth ? col.pinnedWidth : null\"\n [class.est2-td--group-key]=\"item._group && item.column === col.id\"\n [attr.data-r]=\"rangeActive() && !item._group ? ri : null\"\n [attr.data-c]=\"rangeActive() && !item._group ? ci : null\"\n [class.est2-cell-sel]=\"rangeActive() && inRange(ri, ci)\"\n [class.est2-cell-sel-t]=\"rangeActive() && inRange(ri, ci) && ri === rangeRect()!.top\"\n [class.est2-cell-sel-b]=\"rangeActive() && inRange(ri, ci) && ri === rangeRect()!.bottom\"\n [class.est2-cell-sel-l]=\"rangeActive() && inRange(ri, ci) && ci === rangeRect()!.left\"\n [class.est2-cell-sel-r]=\"rangeActive() && inRange(ri, ci) && ci === rangeRect()!.right\"\n [class.est2-cell-editing]=\"isEditing(ri, ci)\"\n (dblclick)=\"onCellDblClick(item, col, ri, ci)\">\n @if (isEditing(ri, ci)) {\n @if (editorFor(col); as edTpl) {\n <ng-container *ngTemplateOutlet=\"edTpl; context: editorContext(item, col)\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"defaultEditor; context: { $implicit: item, col: col }\"></ng-container>\n }\n } @else if (item._group) {\n @if (item.column === col.id) {\n <span class=\"est2-group-key\" [style.padding-left.px]=\"groupIndent(item)\">\n <span class=\"est2-group-chevron\" [class.est2-group-chevron--open]=\"item._expanded\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 6l6 6-6 6\"/></svg>\n </span>\n {{ groupCellDisplay(item, col) }}\n </span>\n } @else {\n {{ groupCellDisplay(item, col) }}\n }\n } @else {\n <!-- Navigatore albero nella prima colonna -->\n @if (Hierarchy() && first) {\n <span class=\"est2-hier-lead\" [style.padding-left.px]=\"hierarchyIndent(item)\">\n @if (item.parent) {\n <span class=\"est2-group-chevron est2-hier-toggle\" [class.est2-group-chevron--open]=\"item._expanded\"\n (click)=\"$event.stopPropagation(); toggleHierarchyNode(item)\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 6l6 6-6 6\"/></svg>\n </span>\n } @else {\n <span class=\"est2-hier-toggle\"></span>\n }\n </span>\n }\n @if (itemCellHidden(col)) {\n <!-- colonna di gruppo nascosta sulla riga-oggetto -->\n } @else if (col.multiProp != null) {\n @if (col.cell?.Template) {\n <ng-container *ngTemplateOutlet=\"col.cell!.Template; context: { $implicit: multiCell(item, col) }\"></ng-container>\n } @else {\n {{ multiCell(item, col)?.value }}\n }\n } @else if (col.cell?.Template) {\n <ng-container *ngTemplateOutlet=\"col.cell!.Template; context: { $implicit: item }\"></ng-container>\n } @else if (col.routePath) {\n <a class=\"est2-link\" [routerLink]=\"routerLinkFor(item, col)\">{{ cellValue(item, col) }}</a>\n } @else if (col.propAccessor != null) {\n {{ reportCellDisplay(item, col) }}\n } @else if (col.type === 'enum') {\n {{ (cellValue(item, col) | est2_lookup : col.source).description }}\n } @else {\n {{ cellValue(item, col) | est2_format : col.type : col.format : locale }}\n }\n }\n </td>\n }\n }\n <!-- Celle da template semplice -->\n @else if (bodyRef) {\n <ng-container *ngTemplateOutlet=\"bodyRef; context: { $implicit: item }\"></ng-container>\n }\n\n <!-- Rimozione (non sulle righe-gruppo) -->\n @if (Removal()) {\n <td class=\"est2-col-min\">\n @if (!item._group && canRemove(item)) {\n @if (item.removed || item.deleted) {\n <button type=\"button\" class=\"est2-rowaction\" title=\"Ripristina\" (click)=\"abortRemoval(item)\">\u21BA</button>\n } @else {\n <button type=\"button\" class=\"est2-rowaction est2-rowaction--danger\" title=\"Rimuovi\" (click)=\"removeItem(item)\">\u2715</button>\n }\n }\n </td>\n }\n <!-- Chrome -->\n @if (hasChrome()) { <td class=\"est2-col-min\"></td> }\n </tr>\n }\n } @empty {\n <tr>\n <td class=\"est2-empty\" [attr.colspan]=\"totalColspan()\">Nessun elemento da visualizzare</td>\n </tr>\n }\n </tbody>\n }\n </table>\n\n <!-- Overlay di caricamento -->\n @if (researchInProgress() || (firstBind() && ShowLoadingOnBootstrap())) {\n <div class=\"est2-loading\">\n <span class=\"est2-spinner\"></span>\n <span>Caricamento\u2026</span>\n </div>\n }\n </div>\n\n <!-- Pager inferiore -->\n @if (PagingStyle() === 'both' || PagingStyle() === 'bottom') {\n <ng-container *ngTemplateOutlet=\"pager\"></ng-container>\n }\n\n <!-- Avviso transitorio (es. incolla con dimensioni incompatibili) -->\n @if (notice()) {\n <div class=\"est2-toast\" role=\"alert\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/><path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/></svg>\n <span>{{ notice() }}</span>\n </div>\n }\n\n <!-- Dialog visibilit\u00E0 / ordine colonne -->\n @if (columnsDialogOpen()) {\n <div class=\"est2-dialog-backdrop\" (click)=\"closeColumnsDialog()\">\n <div class=\"est2-dialog\" (click)=\"$event.stopPropagation()\" role=\"dialog\" aria-modal=\"true\">\n <div class=\"est2-dialog__head\">\n <span>\n @if (HiddenColumns() && ColumnsOrdering()) { Visibilit\u00E0 e ordine colonne }\n @else if (HiddenColumns()) { Visibilit\u00E0 colonne }\n @else { Ordine colonne }\n </span>\n <button type=\"button\" class=\"est2-dialog__close\" (click)=\"closeColumnsDialog()\" aria-label=\"Chiudi\">\u2715</button>\n </div>\n\n @if (HiddenColumns()) {\n <div class=\"est2-dialog__tools\">\n <button type=\"button\" class=\"est2-link\" (click)=\"dialogSetAll(true)\">Mostra tutte</button>\n <span class=\"est2-dialog__sep\">\u00B7</span>\n <button type=\"button\" class=\"est2-link\" (click)=\"dialogSetAll(false)\">Nascondi tutte</button>\n </div>\n }\n\n <ul class=\"est2-collist\">\n @for (c of dialogCols(); track c.id; let i = $index) {\n <li class=\"est2-collist__row\">\n @if (HiddenColumns()) {\n <label class=\"est2-collist__vis\">\n <input type=\"checkbox\" class=\"est2-check\" [checked]=\"c.visible\" (change)=\"dialogToggle(i)\" />\n </label>\n }\n <span class=\"est2-collist__label\">{{ c.label }}</span>\n @if (ColumnsPinnable()) {\n <button type=\"button\" class=\"est2-iconbtn est2-collist__pin\" [class.est2-collist__pin--on]=\"c.pinned\"\n [disabled]=\"c.grouped\"\n [title]=\"c.grouped ? 'Le colonne di un gruppo non sono bloccabili' : (c.pinned ? 'Sblocca' : 'Blocca a sinistra')\"\n (click)=\"dialogTogglePin(i)\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 17v5\"/><path d=\"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z\"/></svg>\n </button>\n }\n @if (ColumnsOrdering()) {\n <span class=\"est2-collist__ord\">\n <button type=\"button\" class=\"est2-iconbtn\" [disabled]=\"i === 0\" title=\"Su\" (click)=\"dialogMove(i, -1)\">\u2191</button>\n <button type=\"button\" class=\"est2-iconbtn\" [disabled]=\"i === dialogCols().length - 1\" title=\"Gi\u00F9\" (click)=\"dialogMove(i, 1)\">\u2193</button>\n </span>\n }\n </li>\n }\n </ul>\n\n <div class=\"est2-dialog__foot\">\n <button type=\"button\" class=\"est2-btn est2-btn--ghost\" (click)=\"resetColumnsDialog()\">Ripristina</button>\n <span class=\"est2-dialog__spacer\"></span>\n <button type=\"button\" class=\"est2-btn est2-btn--ghost\" (click)=\"closeColumnsDialog()\">Annulla</button>\n <button type=\"button\" class=\"est2-btn est2-btn--primary\" (click)=\"applyColumnsDialog()\">Applica</button>\n </div>\n </div>\n </div>\n }\n </div>\n}\n\n<!-- Template pager riutilizzabile sopra/sotto -->\n<ng-template #pager>\n @if (!HidePaging() && !grouped()) {\n <es-table2-pager\n [page]=\"currentPage()\"\n [pages]=\"totalPages()\"\n [total]=\"totalCount()\"\n [itemsPerPage]=\"viewMode() ? (view()?.itemsperpageoverride ?? 15) : ArraymodeItemsPerPage()\"\n [countLabel]=\"CountLabel()\"\n [showCount]=\"!HidePagingCount()\"\n [showButtons]=\"!HidePagingButtons()\"\n [showPagingOptions]=\"!HidePagingButtons()\"\n [allowAll]=\"AllSearch()\"\n (pageChange)=\"goToPage($event)\"\n (itemsPerPageChange)=\"changeItemsPerPage($event)\">\n </es-table2-pager>\n }\n</ng-template>\n\n<!-- Editor di cella di default (usato quando il consumer non fornisce un `*editor`) -->\n<ng-template #defaultEditor let-item let-col=\"col\">\n @switch (col.type) {\n @case ('enum') {\n <select class=\"est2-editor-input\"\n [value]=\"editDraft\"\n (change)=\"editDraft = $any($event.target).value\"\n (keydown.enter)=\"commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\"\n (blur)=\"commitEdit(item, col)\">\n @for (o of col.source || []; track o.id) {\n <option [value]=\"o.id\" [selected]=\"o.id == editDraft\">{{ o.description }}</option>\n }\n </select>\n }\n @case ('boolean') {\n <input type=\"checkbox\" class=\"est2-editor-input est2-check\"\n [checked]=\"editDraft === true || editDraft === 'true'\"\n (change)=\"editDraft = $any($event.target).checked; commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\" />\n }\n @default {\n <input class=\"est2-editor-input\"\n [type]=\"editorInputType(col.type)\"\n [value]=\"editDraft\"\n (input)=\"editDraft = $any($event.target).value\"\n (keydown.enter)=\"commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\"\n (blur)=\"commitEdit(item, col)\" />\n }\n }\n</ng-template>\n\n<!-- Menu di default (nessuna operazione) usato quando il consumer non passa [ContextMenu] -->\n<context-menu #emptyMenu>\n <ng-template contextMenuItem [passive]=\"true\"><em>Nessuna operazione disponibile\u2026</em></ng-template>\n</context-menu>\n", styles: [".est2{--est-bg: #ffffff;--est-bg-subtle: #f7f8fa;--est-bg-raised: #ffffff;--est-bg-hover: #f2f4f7;--est-bg-selected: color-mix(in srgb, var(--est-accent) 12%, transparent);--est-fg: #1a1d24;--est-fg-muted: #626b7a;--est-fg-faint: #9aa3b2;--est-border: #e6e9ef;--est-border-strong: #d3d8e0;--est-accent: #4f46e5;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 14%, transparent);--est-danger: #dc2626;--est-warning: #d97706;--est-success: #059669;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 4px 12px -8px rgba(16, 24, 40, .24);--est-shadow-pop: 0 8px 24px -6px rgba(16, 24, 40, .18), 0 2px 6px -2px rgba(16, 24, 40, .12);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 40%, transparent);--est-radius: 10px;--est-radius-sm: 6px;--est-radius-pill: 999px;--est-gap: 8px;--est-cell-py: 6px;--est-cell-px: 12px;--est-row-h: 33px;--est-font: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;--est-fs: 13px;--est-fs-sm: 12px;--est-fw-head: 700;--est-transition: .14s cubic-bezier(.4, 0, .2, 1);--est-bg-zebra: color-mix(in srgb, var(--est-fg) 3.5%, var(--est-bg));font-family:var(--est-font);font-size:var(--est-fs);color:var(--est-fg);position:relative;display:block}@media(prefers-color-scheme:dark){.est2{--est-bg: #14161c;--est-bg-subtle: #1a1d25;--est-bg-raised: #1e222b;--est-bg-hover: #232733;--est-bg-selected: color-mix(in srgb, var(--est-accent) 26%, transparent);--est-fg: #e7eaf0;--est-fg-muted: #9aa3b2;--est-fg-faint: #6b7484;--est-border: #2a2f3a;--est-border-strong: #39404d;--est-accent: #7c74ff;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 22%, transparent);--est-danger: #f87171;--est-warning: #fbbf24;--est-success: #34d399;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 6px 16px -10px rgba(0, 0, 0, .7);--est-shadow-pop: 0 10px 28px -8px rgba(0, 0, 0, .6), 0 2px 6px -2px rgba(0, 0, 0, .5);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 55%, transparent)}}.est2.est2--dark{--est-bg: #14161c;--est-bg-subtle: #1a1d25;--est-bg-raised: #1e222b;--est-bg-hover: #232733;--est-bg-selected: color-mix(in srgb, var(--est-accent) 26%, transparent);--est-fg: #e7eaf0;--est-fg-muted: #9aa3b2;--est-fg-faint: #6b7484;--est-border: #2a2f3a;--est-border-strong: #39404d;--est-accent: #7c74ff;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 22%, transparent);--est-danger: #f87171;--est-warning: #fbbf24;--est-success: #34d399;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 6px 16px -10px rgba(0, 0, 0, .7);--est-shadow-pop: 0 10px 28px -8px rgba(0, 0, 0, .6), 0 2px 6px -2px rgba(0, 0, 0, .5);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 55%, transparent)}.est2.est2--light{--est-bg: #ffffff;--est-bg-subtle: #f7f8fa;--est-bg-raised: #ffffff;--est-bg-hover: #f2f4f7;--est-bg-selected: color-mix(in srgb, var(--est-accent) 12%, transparent);--est-fg: #1a1d24;--est-fg-muted: #626b7a;--est-fg-faint: #9aa3b2;--est-border: #e6e9ef;--est-border-strong: #d3d8e0;--est-accent: #4f46e5;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 14%, transparent);--est-danger: #dc2626;--est-warning: #d97706;--est-success: #059669;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 4px 12px -8px rgba(16, 24, 40, .24);--est-shadow-pop: 0 8px 24px -6px rgba(16, 24, 40, .18), 0 2px 6px -2px rgba(16, 24, 40, .12);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 40%, transparent)}.est2.est2--dense{--est-cell-py: 3px;--est-cell-px: 9px;--est-row-h: 27px;--est-fs: 12.5px}.est2 *,.est2 *:before,.est2 *:after{box-sizing:border-box}.est2 .est2-scroll{position:relative;width:100%;overflow:auto;border:1px solid var(--est-border);border-radius:var(--est-radius);background:var(--est-bg);-webkit-overflow-scrolling:touch}.est2 table.est2-table{width:100%;border-collapse:separate;border-spacing:0;background:var(--est-bg)}.est2 thead th{position:sticky;top:0;z-index:3;background:var(--est-bg-subtle);color:var(--est-fg);font-weight:var(--est-fw-head);font-size:var(--est-fs);text-align:left;white-space:nowrap;padding:var(--est-cell-py) var(--est-cell-px);border-bottom:1px solid var(--est-border);box-shadow:var(--est-shadow-sticky);-webkit-user-select:none;user-select:none}.est2 thead tr.est2-hgroup-row th{font-size:var(--est-fs-sm);font-weight:700;color:var(--est-fg-muted);text-align:center;white-space:nowrap;padding:var(--est-cell-py) var(--est-cell-px);background:var(--est-bg-subtle);border-bottom:1px solid var(--est-border)}.est2 thead tr.est2-hgroup-row th.est2-hgroup{color:var(--est-fg);border-left:1px solid var(--est-border);border-right:1px solid var(--est-border)}.est2 thead tr.est2-hgroup-row th:not(.est2-hgroup){background:var(--est-bg-subtle);border-bottom-color:transparent}.est2 thead tr:last-child th.est2-col-groupstart,.est2 tbody td.est2-col-groupstart{border-left:1px solid var(--est-border)}.est2 tbody td{padding:var(--est-cell-py) var(--est-cell-px);border-bottom:1px solid var(--est-border);color:var(--est-fg);vertical-align:middle;background:transparent}.est2 tbody tr:nth-child(2n) td{background:var(--est-bg-zebra)}.est2 tbody tr:nth-child(2n) td.est2-pinned{background:var(--est-bg-zebra)}.est2 th.est2-pinned,.est2 td.est2-pinned{position:sticky;background:var(--est-bg);box-shadow:1px 0 0 var(--est-border)}.est2 .est2-selcol{width:44px;min-width:44px;max-width:44px}.est2 td.est2-pinned{z-index:3}.est2 thead th.est2-pinned,.est2 thead tr.est2-hgroup-row th.est2-pinned{z-index:6;background:var(--est-bg-subtle)}.est2 tbody tr:hover td.est2-pinned{background:color-mix(in srgb,var(--est-fg) 5%,var(--est-bg))}.est2 tbody tr.est2-row--selected td.est2-pinned{background:color-mix(in srgb,var(--est-accent) 12%,var(--est-bg))}.est2 tbody tr.est2-row--group td.est2-pinned{background:var(--est-bg-subtle)}.est2 .est2-pinbtn{display:inline-flex;align-items:center;justify-content:center;margin-left:4px;padding:2px;border:none;background:transparent;color:var(--est-fg-faint);border-radius:var(--est-radius-sm);cursor:pointer;opacity:0;transition:opacity var(--est-transition),color var(--est-transition),background var(--est-transition)}.est2 thead th:hover .est2-pinbtn{opacity:.7}.est2 .est2-pinbtn:hover{background:var(--est-bg-hover);color:var(--est-fg);opacity:1}.est2 .est2-pinbtn--on{opacity:1;color:var(--est-accent);transform:rotate(0)}.est2 thead th:hover .est2-pinbtn--on{opacity:1}.est2 .est2-collist__pin.est2-collist__pin--on{color:var(--est-accent);border-color:var(--est-accent)}.est2 tbody tr{height:var(--est-row-h);transition:background var(--est-transition)}.est2 tbody tr:last-child td{border-bottom:none}.est2 tbody tr:hover td{background:var(--est-bg-hover)}.est2 tbody tr.est2-row--selected td{background:var(--est-bg-selected)}.est2 tbody tr.est2-row--clickable{cursor:pointer;-webkit-user-select:none;user-select:none}.est2 tbody tr.est2-row--removed td{text-decoration:line-through;color:var(--est-fg-faint)}.est2 .est2-table--range tbody td[data-r]{cursor:cell}.est2 .est2-table--dragging,.est2 .est2-table--dragging tbody td{-webkit-user-select:none;user-select:none}.est2 tbody td.est2-cell-sel{background:color-mix(in srgb,var(--est-accent) 14%,transparent)}.est2 tbody td.est2-cell-sel-t{box-shadow:inset 0 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b{box-shadow:inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-l{box-shadow:inset 2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-r{box-shadow:inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-l{box-shadow:inset 2px 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-r{box-shadow:inset -2px 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-l{box-shadow:inset 2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-r{box-shadow:inset -2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b{box-shadow:inset 0 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 0 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-l{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-r{box-shadow:inset -2px 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px -2px 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset -2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-editing{padding:2px 6px}.est2 .est2-editor-input{width:100%;box-sizing:border-box;height:calc(var(--est-row-h) - 8px);padding:2px 6px;font:inherit;color:var(--est-fg);background:var(--est-bg);border:1.5px solid var(--est-accent);border-radius:var(--est-radius-sm);outline:none}.est2 .est2-editor-input:focus-visible{box-shadow:var(--est-ring)}.est2 input.est2-editor-input[type=checkbox]{width:16px;height:16px}.est2 .est2-autoupdate{display:flex;align-items:center;justify-content:flex-end;gap:12px;padding:4px 2px 8px;font-size:var(--est-fs-sm);color:var(--est-fg-muted)}.est2 .est2-autoupdate__label{display:inline-flex;align-items:center;gap:6px}.est2 .est2-autoupdate__secs{width:44px;text-align:center;padding:3px 4px;font:inherit;color:var(--est-fg);background:var(--est-bg);border:1px solid var(--est-border);border-radius:var(--est-radius-sm);outline:none}.est2 .est2-autoupdate__secs:focus-visible{box-shadow:var(--est-ring);border-color:var(--est-accent)}.est2 .est2-switch{position:relative;display:inline-flex;width:38px;height:20px;cursor:pointer}.est2 .est2-switch input{position:absolute;opacity:0;width:0;height:0}.est2 .est2-switch__slider{flex:1;border-radius:var(--est-radius-pill);background:var(--est-border-strong);transition:background var(--est-transition)}.est2 .est2-switch__slider:before{content:\"\";position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:#fff;box-shadow:0 1px 2px #00000040;transition:transform var(--est-transition)}.est2 .est2-switch input:checked+.est2-switch__slider{background:var(--est-accent)}.est2 .est2-switch input:checked+.est2-switch__slider:before{transform:translate(18px)}.est2 .est2-switch input:focus-visible+.est2-switch__slider{box-shadow:var(--est-ring)}.est2 .est2-toast{position:absolute;left:50%;bottom:14px;transform:translate(-50%);z-index:20;display:inline-flex;align-items:center;gap:8px;max-width:calc(100% - 24px);padding:8px 14px;font-size:13px;font-weight:500;color:#fff;background:#b91c1c;border-radius:var(--est-radius);box-shadow:0 6px 20px #00000040;animation:est2-toast-in .16s ease-out}.est2 .est2-toast svg{flex:0 0 auto}@keyframes est2-toast-in{0%{opacity:0;transform:translate(-50%,8px)}to{opacity:1;transform:translate(-50%)}}@media(prefers-reduced-motion:reduce){.est2 .est2-toast{animation:none}}.est2 tbody tr.est2-row--group{cursor:pointer;-webkit-user-select:none;user-select:none}.est2 tbody tr.est2-row--group td{background:var(--est-bg-subtle);font-weight:600;color:var(--est-fg);border-bottom:1px solid var(--est-border)}.est2 tbody tr.est2-row--group:hover td{background:var(--est-bg-hover)}.est2 .est2-td--group-key{color:var(--est-fg)}.est2 .est2-group-key{display:inline-flex;align-items:center;gap:6px}.est2 .est2-group-chevron{display:inline-flex;color:var(--est-fg-muted);transition:transform var(--est-transition)}.est2 .est2-group-chevron--open{transform:rotate(90deg)}.est2 .est2-hier-lead{display:inline-flex;align-items:center;vertical-align:middle;margin-right:4px}.est2 .est2-hier-toggle{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;flex:none}.est2 .est2-group-chevron.est2-hier-toggle{cursor:pointer;border-radius:var(--est-radius-sm);transition:transform var(--est-transition),background var(--est-transition),color var(--est-transition)}.est2 .est2-group-chevron.est2-hier-toggle:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 th.est2-th--orderable{cursor:pointer;transition:color var(--est-transition)}.est2 th.est2-th--orderable:hover{color:var(--est-fg)}.est2 .est2-th__inner{display:inline-flex;align-items:center;gap:6px}.est2 .est2-sort{display:inline-flex;width:14px;height:14px;opacity:.35;transition:opacity var(--est-transition),transform var(--est-transition)}.est2 .est2-sort--active{opacity:1;color:var(--est-accent)}.est2 .est2-sort--desc{transform:rotate(180deg)}.est2 .est2-sort__badge{font-size:9px;font-weight:700;color:var(--est-accent);margin-left:2px}.est2 .est2-check{appearance:none;width:16px;height:16px;border:1.5px solid var(--est-border-strong);border-radius:var(--est-radius-sm);background:var(--est-bg);cursor:pointer;position:relative;transition:border-color var(--est-transition),background var(--est-transition);vertical-align:middle;flex:none}.est2 .est2-check:hover{border-color:var(--est-accent)}.est2 .est2-check:checked{background:var(--est-accent);border-color:var(--est-accent)}.est2 .est2-check:checked:after{content:\"\";position:absolute;left:4.5px;top:1.5px;width:4px;height:8px;border:solid var(--est-accent-fg);border-width:0 2px 2px 0;transform:rotate(45deg)}.est2 .est2-check:focus-visible{outline:none;box-shadow:var(--est-ring)}.est2 .est2-check:indeterminate{background:var(--est-accent);border-color:var(--est-accent)}.est2 .est2-check:indeterminate:after{content:\"\";position:absolute;left:3px;top:6px;width:8px;height:2px;background:var(--est-accent-fg);transform:none;border:none}.est2 th.est2-col-min,.est2 td.est2-col-min{width:1%;white-space:nowrap}.est2 .est2-wrap{position:relative}.est2 .est2-selectbar{position:absolute;top:0;left:0;right:0;z-index:15;display:flex;align-items:center;gap:12px;padding:9px 14px;font-size:var(--est-fs-sm);color:var(--est-fg);background:var(--est-bg-subtle);border:none;border-radius:var(--est-radius) var(--est-radius) 0 0;box-shadow:inset 3px 0 0 var(--est-accent)}.est2 .est2-selectbar strong{color:var(--est-fg);font-weight:700}.est2 .est2-selectbar__spacer{flex:1 1 auto}.est2 .est2-link{color:var(--est-accent);cursor:pointer;font-weight:600}.est2 .est2-link:hover{text-decoration:underline}.est2 .est2-rowaction{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--est-radius-sm);border:none;background:transparent;color:var(--est-fg-faint);cursor:pointer;transition:background var(--est-transition),color var(--est-transition)}.est2 .est2-rowaction:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-rowaction--danger:hover{color:var(--est-danger)}.est2 .est2-op-cell{text-align:center}.est2 .est2-op{display:inline-flex;align-items:center;justify-content:center;min-width:26px;height:26px;padding:0 6px;border-radius:var(--est-radius-sm);color:var(--est-accent);cursor:pointer;font-size:var(--est-fs-sm);transition:background var(--est-transition)}.est2 .est2-op:hover{background:var(--est-accent-weak)}.est2 .est2-loading{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;gap:10px;background:color-mix(in srgb,var(--est-bg) 70%,transparent);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:5;color:var(--est-fg-muted);font-size:var(--est-fs-sm)}.est2 .est2-spinner{width:16px;height:16px;border:2px solid var(--est-border-strong);border-top-color:var(--est-accent);border-radius:50%;animation:est2-spin .7s linear infinite}@keyframes est2-spin{to{transform:rotate(360deg)}}.est2 .est2-nowrap{white-space:nowrap}.est2 .est2-cornermenu{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--est-radius-sm);cursor:pointer;color:var(--est-fg-muted);transition:background var(--est-transition)}.est2 .est2-cornermenu:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-chrome-th{position:relative}.est2 .est2-chrome{display:inline-flex;align-items:center;gap:2px}.est2 .est2-chrome-wrap{position:relative;display:inline-flex}.est2 .est2-chrome-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;background:transparent;border-radius:var(--est-radius-sm);color:var(--est-fg-muted);cursor:pointer;font-size:16px;line-height:1;transition:background var(--est-transition),color var(--est-transition)}.est2 .est2-chrome-btn:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-menu{position:absolute;top:calc(100% + 4px);right:0;z-index:30;min-width:180px;padding:4px;background:var(--est-bg);border:1px solid var(--est-border);border-radius:var(--est-radius);box-shadow:0 8px 24px #0000002e;display:flex;flex-direction:column}.est2 .est2-menu-item{display:block;width:100%;padding:8px 10px;border:none;background:transparent;text-align:left;font:inherit;color:var(--est-fg);border-radius:var(--est-radius-sm);cursor:pointer}.est2 .est2-menu-item:hover{background:var(--est-bg-hover)}.est2 .est2-dialog-backdrop{position:absolute;inset:0;z-index:40;display:flex;align-items:center;justify-content:center;padding:16px;background:color-mix(in srgb,#000 32%,transparent)}.est2 .est2-dialog{width:380px;max-width:100%;max-height:100%;display:flex;flex-direction:column;background:var(--est-bg);color:var(--est-fg);border:1px solid var(--est-border);border-radius:var(--est-radius);box-shadow:0 16px 48px #0000004d;overflow:hidden}.est2 .est2-dialog__head{display:flex;align-items:center;justify-content:space-between;padding:12px 14px;font-weight:700;border-bottom:1px solid var(--est-border)}.est2 .est2-dialog__close{border:none;background:transparent;cursor:pointer;color:var(--est-fg-muted);font-size:15px;line-height:1;padding:4px;border-radius:var(--est-radius-sm)}.est2 .est2-dialog__close:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-dialog__tools{padding:8px 14px;font-size:var(--est-fs-sm);border-bottom:1px solid var(--est-border)}.est2 .est2-dialog__tools .est2-link{border:none;background:none;padding:0;font:inherit;font-weight:600}.est2 .est2-dialog__sep{margin:0 6px;color:var(--est-fg-faint)}.est2 .est2-collist{list-style:none;margin:0;padding:6px;overflow-y:auto}.est2 .est2-collist__row{display:flex;align-items:center;gap:10px;padding:6px 8px;border-radius:var(--est-radius-sm)}.est2 .est2-collist__row:hover{background:var(--est-bg-hover)}.est2 .est2-collist__vis{display:inline-flex}.est2 .est2-collist__label{flex:1 1 auto}.est2 .est2-collist__ord{display:inline-flex;gap:4px}.est2 .est2-iconbtn{width:26px;height:26px;border:1px solid var(--est-border);background:var(--est-bg);border-radius:var(--est-radius-sm);color:var(--est-fg-muted);cursor:pointer}.est2 .est2-iconbtn:hover:not(:disabled){background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-iconbtn:disabled{opacity:.4;cursor:default}.est2 .est2-dialog__foot{display:flex;align-items:center;gap:8px;padding:12px 14px;border-top:1px solid var(--est-border)}.est2 .est2-dialog__spacer{flex:1 1 auto}.est2 .est2-btn{padding:7px 14px;border-radius:var(--est-radius-sm);font:inherit;font-weight:600;cursor:pointer;border:1px solid transparent}.est2 .est2-btn--ghost{background:transparent;color:var(--est-fg);border-color:var(--est-border)}.est2 .est2-btn--ghost:hover{background:var(--est-bg-hover)}.est2 .est2-btn--primary{background:var(--est-accent);color:var(--est-accent-fg)}.est2 .est2-btn--primary:hover{filter:brightness(1.05)}.est2 .est2-empty{padding:48px 16px;text-align:center;color:var(--est-fg-faint);font-size:var(--est-fs-sm)}.ngx-contextmenu{--ctx-bg: #ffffff;--ctx-fg: #1a1d24;--ctx-muted: #626b7a;--ctx-border: #e6e9ef;--ctx-hover: #f2f4f7;--ctx-accent: #4f46e5;--ctx-shadow: 0 10px 28px -8px rgba(16, 24, 40, .22), 0 2px 8px -3px rgba(16, 24, 40, .14);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.ngx-contextmenu .dropdown-menu{display:block;min-width:200px;margin:0;padding:6px;list-style:none;background:var(--ctx-bg);border:1px solid var(--ctx-border);border-radius:12px;box-shadow:var(--ctx-shadow);animation:est2-ctx-in .12s cubic-bezier(.16,1,.3,1)}.ngx-contextmenu li{list-style:none;margin:0}.ngx-contextmenu li>a{display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:7px;color:var(--ctx-fg);font-size:13.5px;line-height:1.2;text-decoration:none;cursor:pointer;white-space:nowrap;transition:background .12s ease,color .12s ease}.ngx-contextmenu li>a:hover,.ngx-contextmenu li>a:focus{background:var(--ctx-hover);color:var(--ctx-fg);text-decoration:none;outline:none}.ngx-contextmenu li.divider,.ngx-contextmenu li[role=separator]{height:1px;margin:6px 8px;padding:0;background:var(--ctx-border)}.ngx-contextmenu li.disabled>a,.ngx-contextmenu li[aria-disabled=true]>a{color:var(--ctx-muted);opacity:.55;pointer-events:none}@media(prefers-color-scheme:dark){.ngx-contextmenu{--ctx-bg: #1e222b;--ctx-fg: #e7eaf0;--ctx-muted: #9aa3b2;--ctx-border: #2a2f3a;--ctx-hover: #232733;--ctx-accent: #7c74ff;--ctx-shadow: 0 12px 30px -8px rgba(0, 0, 0, .6), 0 2px 8px -3px rgba(0, 0, 0, .5)}}@keyframes est2-ctx-in{0%{opacity:0;transform:translateY(-4px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@media(prefers-reduced-motion:reduce){.ngx-contextmenu .dropdown-menu{animation:none}}\n"], dependencies: [{ kind: "directive", type: i8.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i9.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i12.ContextMenuAttachDirective, selector: "[contextMenu]", inputs: ["contextMenuSubject", "contextMenu"] }, { kind: "component", type: i12.ContextMenuComponent, selector: "context-menu", inputs: ["menuClass", "autoFocus", "useBootstrap4", "disabled"], outputs: ["close", "open"] }, { kind: "directive", type: i12.ContextMenuItemDirective, selector: "[contextMenuItem]", inputs: ["subMenu", "divider", "enabled", "passive", "visible"], outputs: ["execute"] }, { kind: "component", type: EsTable2PagerComponent, selector: "es-table2-pager", inputs: ["page", "pages", "total", "itemsPerPage", "countLabel", "showCount", "showButtons", "showPagingOptions", "allowAll"], outputs: ["pageChange", "itemsPerPageChange"] }, { kind: "pipe", type: Est2FormatPipe, name: "est2_format" }, { kind: "pipe", type: Est2LookupPipe, name: "est2_lookup" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
8370
8600
  }
8371
8601
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: EsTable2Component, decorators: [{
8372
8602
  type: Component,
8373
- args: [{ selector: 'es-table2', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "@if (view()) {\n <div class=\"est2-wrap {{ ContainerClass() }}\"\n [style.height]=\"Height()\"\n [style.background-color]=\"EmptySpaceBackgroundColor() || null\">\n\n <!-- Pager superiore -->\n @if (PagingStyle() === 'both' || PagingStyle() === 'top') {\n <ng-container *ngTemplateOutlet=\"pager\"></ng-container>\n }\n\n <!-- Barra \"seleziona tutto\" (visibile solo con selezione multipla attiva e righe presenti) -->\n @if (Selection() && !SingleSelection() && hasSelection) {\n <div class=\"est2-selectbar\" [style.height.px]=\"selbarHeight() ? selbarHeight() + 1 : null\">\n @if (allSelected) {\n <span>Tutti i <strong>{{ selectedCount }}</strong> elementi sono selezionati</span>\n } @else {\n <span><strong>{{ selectedCount }}</strong> {{ selectedCount === 1 ? 'elemento selezionato' : 'elementi selezionati' }}</span>\n @if (canSelectEverything) {\n <span class=\"est2-link\" (click)=\"selectEverything()\">Seleziona tutti i {{ totalCount() }} elementi</span>\n }\n }\n <span class=\"est2-selectbar__spacer\"></span>\n <span class=\"est2-link\" (click)=\"clearSelection()\">Azzera selezione</span>\n </div>\n }\n\n <div class=\"est2-scroll\" [style.max-height.px]=\"MaxHeight()\">\n <table class=\"est2-table {{ TableClass() }}\"\n [class.est2-table--range]=\"rangeActive()\"\n [class.est2-table--dragging]=\"rangeDragging()\"\n (mousedown)=\"onGridMouseDown($event)\"\n (mouseover)=\"onGridMouseOver($event)\">\n\n <!-- ================= HEADER ================= -->\n @if (!HeaderHidden()) {\n <thead #theadRef>\n <!-- Righe di header-group multi-livello (dall'alto verso il basso) -->\n @if (hasHeaderGroups()) {\n @for (grow of headerGroupRows(); track $index) {\n <tr class=\"est2-hgroup-row\">\n @if (Selection()) { <th class=\"est2-col-min\" [class.est2-pinned]=\"hasPinned()\" [style.left.px]=\"hasPinned() ? 0 : null\"></th> }\n @for (op of DynamicOperations(); track op.id) { <th class=\"est2-col-min\"></th> }\n @for (cell of grow; track cell.id; let gi = $index) {\n <th [attr.colspan]=\"cell.span\"\n [class.est2-hgroup]=\"cell.isGroup\"\n [class.est2-pinned]=\"gi < pinnedCount()\"\n [style.left.px]=\"gi < pinnedCount() ? pinnedLeftPx(gi) : null\"\n class=\"est2-hgroup-cell\">\n @if (cell.isGroup) {\n @if (cell.template) {\n <ng-container *ngTemplateOutlet=\"cell.template\"></ng-container>\n } @else {\n {{ cell.label }}\n }\n }\n </th>\n }\n @if (Removal()) { <th class=\"est2-col-min\"></th> }\n @if (hasChrome()) { <th class=\"est2-col-min\"></th> }\n </tr>\n }\n }\n <tr>\n <!-- Colonna di selezione -->\n @if (Selection()) {\n <th class=\"est2-col-min\"\n [class.est2-pinned]=\"hasPinned()\"\n [style.left.px]=\"hasPinned() ? 0 : null\">\n @if (!SingleSelection()) {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"globalCheck()\"\n [indeterminate]=\"selectionIndeterminate\"\n [disabled]=\"SelectionDisabled()\"\n (change)=\"toggleAll()\"\n aria-label=\"Seleziona tutto\" />\n }\n </th>\n }\n\n <!-- Header da colonne (direttive / dinamica / report) -->\n @if (usesColumns()) {\n <!-- intestazioni vuote per le operazioni dinamiche -->\n @for (op of DynamicOperations(); track op.id) {\n <th class=\"est2-col-min\"></th>\n }\n @for (col of visibleColumns(); track trackCol($index, col); let ci = $index) {\n <th [class]=\"col.cssClass\"\n [class.est2-th--orderable]=\"OrderByColumn() && col.orderable\"\n [class.est2-col-min]=\"col.header?.thShrink\"\n [class.est2-pinned]=\"col.pinned\"\n [style.left.px]=\"col.pinned ? pinnedLeftPx(ci) : null\"\n [style.min-width.px]=\"col.pinned && col.pinnedWidth ? col.pinnedWidth : null\"\n [style.max-width.px]=\"col.pinned && col.pinnedWidth ? col.pinnedWidth : null\"\n [style.text-align]=\"col.alignment\"\n [style.background-color]=\"col.headerBg || null\"\n (click)=\"toggleSort(col)\">\n <span class=\"est2-th__inner\">\n @if (col.header?.Template) {\n <ng-container *ngTemplateOutlet=\"col.header!.Template!; context: col.multiProp != null ? { $implicit: col.headerText } : null\"></ng-container>\n } @else {\n {{ col.headerText }}\n }\n @if (OrderByColumn() && col.orderable && orderOf(col.id)) {\n <span class=\"est2-sort est2-sort--active\"\n [class.est2-sort--desc]=\"orderOf(col.id) === 'DESC'\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M6 15l6-6 6 6\"/></svg>\n </span>\n @if (orderIndex(col.id) > 0 && MultipleOrderingDirectives()) {\n <span class=\"est2-sort__badge\">{{ orderIndex(col.id) }}</span>\n }\n }\n <!-- Indicatore/toggle di pin (visibile se pinnata o all'hover) -->\n @if (ColumnsPinnable() && col.multiProp == null) {\n <button type=\"button\" class=\"est2-pinbtn\"\n [class.est2-pinbtn--on]=\"col.pinned\"\n [title]=\"col.pinned ? 'Sblocca colonna' : 'Blocca colonna a sinistra'\"\n (click)=\"togglePin(col, $event)\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 17v5\"/><path d=\"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z\"/></svg>\n </button>\n }\n </span>\n </th>\n }\n }\n <!-- Header da template semplice -->\n @else if (headerRef) {\n <ng-container *ngTemplateOutlet=\"headerRef\"></ng-container>\n }\n\n <!-- Colonna rimozione -->\n @if (Removal()) { <th class=\"est2-col-min\"></th> }\n <!-- Colonna chrome (export / gestione colonne / menu) -->\n @if (hasChrome()) {\n <th class=\"est2-col-min est2-chrome-th\">\n <div class=\"est2-chrome\">\n @if (Export()) {\n <div class=\"est2-chrome-wrap\">\n <button type=\"button\" class=\"est2-chrome-btn\" title=\"Esporta\" (click)=\"$event.stopPropagation(); toggleExportMenu()\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"/><path d=\"M7 10l5 5 5-5\"/><path d=\"M12 15V3\"/></svg>\n </button>\n @if (exportMenuOpen()) {\n <div class=\"est2-menu\" (click)=\"$event.stopPropagation()\">\n @if (CSVExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('CSV')\">Esporta CSV</button> }\n @if (XLSXExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('XLSX')\">Esporta Excel (XLSX)</button> }\n @if (!CSVExport() && !XLSXExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('CSV')\">Esporta CSV</button> }\n </div>\n }\n </div>\n }\n @if (HiddenColumns() || ColumnsOrdering()) {\n <button type=\"button\" class=\"est2-chrome-btn\" title=\"Colonne\" (click)=\"$event.stopPropagation(); openColumnsDialog()\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"1\"/><path d=\"M9 3v18\"/><path d=\"M15 3v18\"/></svg>\n </button>\n }\n @if (CornerMenuOptions().length > 0) {\n <div class=\"est2-chrome-wrap\">\n <button type=\"button\" class=\"est2-chrome-btn\" title=\"Opzioni\" (click)=\"$event.stopPropagation(); toggleCornerMenu()\">\u22EE</button>\n @if (cornerMenuOpen()) {\n <div class=\"est2-menu\" (click)=\"$event.stopPropagation()\">\n @for (opt of CornerMenuOptions(); track opt.id) {\n <button type=\"button\" class=\"est2-menu-item\" (click)=\"cornerAction(opt.id); cornerMenuOpen.set(false)\">{{ opt.description }}</button>\n }\n </div>\n }\n </div>\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n }\n\n <!-- ================= BODY ================= -->\n @if (!BodyHidden()) {\n <tbody>\n @for (item of boundSource(); track trackRow($index, item); let ri = $index) {\n @if ((!grouped() && !Hierarchy()) || item._visible) {\n <tr [class]=\"rowClass(item)\"\n [class.est2-row--selected]=\"item._selected\"\n [class.est2-row--removed]=\"item.removed || item.deleted\"\n [class.est2-row--group]=\"item._group\"\n [class.est2-row--clickable]=\"Selection() || item._group\"\n [contextMenu]=\"ContextMenu || emptyMenu\"\n [contextMenuSubject]=\"item\"\n (click)=\"handleRowClick(item, $event)\">\n\n <!-- Cella di selezione -->\n @if (Selection()) {\n <td class=\"est2-col-min\"\n [class.est2-pinned]=\"hasPinned()\"\n [style.left.px]=\"hasPinned() ? 0 : null\">\n @if (item._group) {\n @if (!SingleSelection()) {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"groupSelectionState(item) === 'all'\"\n [indeterminate]=\"groupSelectionState(item) === 'some'\"\n [disabled]=\"SelectionDisabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleGroupSelection(item)\"\n aria-label=\"Seleziona gruppo\" />\n }\n } @else {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"item._selected\"\n [indeterminate]=\"hierarchyIndeterminate(item)\"\n [disabled]=\"SelectionDisabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(item)\"\n aria-label=\"Seleziona riga\" />\n }\n </td>\n }\n\n <!-- Celle da colonne (direttive / dinamica / report) -->\n @if (usesColumns()) {\n <!-- Operazioni dinamiche (icone a sinistra) -->\n @for (op of DynamicOperations(); track op.id) {\n <td class=\"est2-col-min est2-op-cell\">\n @if (!item._group && operationVisible(op, item)) {\n <span class=\"est2-op\" [class]=\"op.iconClass || ''\" [title]=\"op.title\"\n (click)=\"$event.stopPropagation(); dynamicOperation(item, op.id)\">{{ op.text }}</span>\n }\n </td>\n }\n @for (col of visibleColumns(); track trackCol($index, col); let first = $first, ci = $index) {\n <td [class]=\"col.cssClass\"\n [style.text-align]=\"col.alignment\"\n [style.color]=\"cellColor(item, col, 'fore')\"\n [style.background-color]=\"cellColor(item, col, 'back')\"\n [class.est2-nowrap]=\"!col.wrap\"\n [class.est2-pinned]=\"col.pinned\"\n [style.left.px]=\"col.pinned ? pinnedLeftPx(ci) : null\"\n [style.min-width.px]=\"col.pinned && col.pinnedWidth ? col.pinnedWidth : null\"\n [style.max-width.px]=\"col.pinned && col.pinnedWidth ? col.pinnedWidth : null\"\n [class.est2-td--group-key]=\"item._group && item.column === col.id\"\n [attr.data-r]=\"rangeActive() && !item._group ? ri : null\"\n [attr.data-c]=\"rangeActive() && !item._group ? ci : null\"\n [class.est2-cell-sel]=\"rangeActive() && inRange(ri, ci)\"\n [class.est2-cell-sel-t]=\"rangeActive() && inRange(ri, ci) && ri === rangeRect()!.top\"\n [class.est2-cell-sel-b]=\"rangeActive() && inRange(ri, ci) && ri === rangeRect()!.bottom\"\n [class.est2-cell-sel-l]=\"rangeActive() && inRange(ri, ci) && ci === rangeRect()!.left\"\n [class.est2-cell-sel-r]=\"rangeActive() && inRange(ri, ci) && ci === rangeRect()!.right\"\n [class.est2-cell-editing]=\"isEditing(ri, ci)\"\n (dblclick)=\"onCellDblClick(item, col, ri, ci)\">\n @if (isEditing(ri, ci)) {\n @if (editorFor(col); as edTpl) {\n <ng-container *ngTemplateOutlet=\"edTpl; context: editorContext(item, col)\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"defaultEditor; context: { $implicit: item, col: col }\"></ng-container>\n }\n } @else if (item._group) {\n @if (item.column === col.id) {\n <span class=\"est2-group-key\" [style.padding-left.px]=\"groupIndent(item)\">\n <span class=\"est2-group-chevron\" [class.est2-group-chevron--open]=\"item._expanded\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 6l6 6-6 6\"/></svg>\n </span>\n {{ groupCellDisplay(item, col) }}\n </span>\n } @else {\n {{ groupCellDisplay(item, col) }}\n }\n } @else {\n <!-- Navigatore albero nella prima colonna -->\n @if (Hierarchy() && first) {\n <span class=\"est2-hier-lead\" [style.padding-left.px]=\"hierarchyIndent(item)\">\n @if (item.parent) {\n <span class=\"est2-group-chevron est2-hier-toggle\" [class.est2-group-chevron--open]=\"item._expanded\"\n (click)=\"$event.stopPropagation(); toggleHierarchyNode(item)\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 6l6 6-6 6\"/></svg>\n </span>\n } @else {\n <span class=\"est2-hier-toggle\"></span>\n }\n </span>\n }\n @if (itemCellHidden(col)) {\n <!-- colonna di gruppo nascosta sulla riga-oggetto -->\n } @else if (col.multiProp != null) {\n @if (col.cell?.Template) {\n <ng-container *ngTemplateOutlet=\"col.cell!.Template; context: { $implicit: multiCell(item, col) }\"></ng-container>\n } @else {\n {{ multiCell(item, col)?.value }}\n }\n } @else if (col.cell?.Template) {\n <ng-container *ngTemplateOutlet=\"col.cell!.Template; context: { $implicit: item }\"></ng-container>\n } @else if (col.routePath) {\n <a class=\"est2-link\" [routerLink]=\"routerLinkFor(item, col)\">{{ cellValue(item, col) }}</a>\n } @else if (col.propAccessor != null) {\n {{ reportCellDisplay(item, col) }}\n } @else if (col.type === 'enum') {\n {{ (cellValue(item, col) | est2_lookup : col.source).description }}\n } @else {\n {{ cellValue(item, col) | est2_format : col.type : col.format : locale }}\n }\n }\n </td>\n }\n }\n <!-- Celle da template semplice -->\n @else if (bodyRef) {\n <ng-container *ngTemplateOutlet=\"bodyRef; context: { $implicit: item }\"></ng-container>\n }\n\n <!-- Rimozione (non sulle righe-gruppo) -->\n @if (Removal()) {\n <td class=\"est2-col-min\">\n @if (!item._group && canRemove(item)) {\n @if (item.removed || item.deleted) {\n <button type=\"button\" class=\"est2-rowaction\" title=\"Ripristina\" (click)=\"abortRemoval(item)\">\u21BA</button>\n } @else {\n <button type=\"button\" class=\"est2-rowaction est2-rowaction--danger\" title=\"Rimuovi\" (click)=\"removeItem(item)\">\u2715</button>\n }\n }\n </td>\n }\n <!-- Chrome -->\n @if (hasChrome()) { <td class=\"est2-col-min\"></td> }\n </tr>\n }\n } @empty {\n <tr>\n <td class=\"est2-empty\" [attr.colspan]=\"totalColspan()\">Nessun elemento da visualizzare</td>\n </tr>\n }\n </tbody>\n }\n </table>\n\n <!-- Overlay di caricamento -->\n @if (researchInProgress() || (firstBind() && ShowLoadingOnBootstrap())) {\n <div class=\"est2-loading\">\n <span class=\"est2-spinner\"></span>\n <span>Caricamento\u2026</span>\n </div>\n }\n </div>\n\n <!-- Pager inferiore -->\n @if (PagingStyle() === 'both' || PagingStyle() === 'bottom') {\n <ng-container *ngTemplateOutlet=\"pager\"></ng-container>\n }\n\n <!-- Avviso transitorio (es. incolla con dimensioni incompatibili) -->\n @if (notice()) {\n <div class=\"est2-toast\" role=\"alert\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/><path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/></svg>\n <span>{{ notice() }}</span>\n </div>\n }\n\n <!-- Dialog visibilit\u00E0 / ordine colonne -->\n @if (columnsDialogOpen()) {\n <div class=\"est2-dialog-backdrop\" (click)=\"closeColumnsDialog()\">\n <div class=\"est2-dialog\" (click)=\"$event.stopPropagation()\" role=\"dialog\" aria-modal=\"true\">\n <div class=\"est2-dialog__head\">\n <span>\n @if (HiddenColumns() && ColumnsOrdering()) { Visibilit\u00E0 e ordine colonne }\n @else if (HiddenColumns()) { Visibilit\u00E0 colonne }\n @else { Ordine colonne }\n </span>\n <button type=\"button\" class=\"est2-dialog__close\" (click)=\"closeColumnsDialog()\" aria-label=\"Chiudi\">\u2715</button>\n </div>\n\n @if (HiddenColumns()) {\n <div class=\"est2-dialog__tools\">\n <button type=\"button\" class=\"est2-link\" (click)=\"dialogSetAll(true)\">Mostra tutte</button>\n <span class=\"est2-dialog__sep\">\u00B7</span>\n <button type=\"button\" class=\"est2-link\" (click)=\"dialogSetAll(false)\">Nascondi tutte</button>\n </div>\n }\n\n <ul class=\"est2-collist\">\n @for (c of dialogCols(); track c.id; let i = $index) {\n <li class=\"est2-collist__row\">\n @if (HiddenColumns()) {\n <label class=\"est2-collist__vis\">\n <input type=\"checkbox\" class=\"est2-check\" [checked]=\"c.visible\" (change)=\"dialogToggle(i)\" />\n </label>\n }\n <span class=\"est2-collist__label\">{{ c.label }}</span>\n @if (ColumnsPinnable()) {\n <button type=\"button\" class=\"est2-iconbtn est2-collist__pin\" [class.est2-collist__pin--on]=\"c.pinned\"\n [title]=\"c.pinned ? 'Sblocca' : 'Blocca a sinistra'\" (click)=\"dialogTogglePin(i)\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 17v5\"/><path d=\"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z\"/></svg>\n </button>\n }\n @if (ColumnsOrdering()) {\n <span class=\"est2-collist__ord\">\n <button type=\"button\" class=\"est2-iconbtn\" [disabled]=\"i === 0\" title=\"Su\" (click)=\"dialogMove(i, -1)\">\u2191</button>\n <button type=\"button\" class=\"est2-iconbtn\" [disabled]=\"i === dialogCols().length - 1\" title=\"Gi\u00F9\" (click)=\"dialogMove(i, 1)\">\u2193</button>\n </span>\n }\n </li>\n }\n </ul>\n\n <div class=\"est2-dialog__foot\">\n <button type=\"button\" class=\"est2-btn est2-btn--ghost\" (click)=\"resetColumnsDialog()\">Ripristina</button>\n <span class=\"est2-dialog__spacer\"></span>\n <button type=\"button\" class=\"est2-btn est2-btn--ghost\" (click)=\"closeColumnsDialog()\">Annulla</button>\n <button type=\"button\" class=\"est2-btn est2-btn--primary\" (click)=\"applyColumnsDialog()\">Applica</button>\n </div>\n </div>\n </div>\n }\n </div>\n}\n\n<!-- Template pager riutilizzabile sopra/sotto -->\n<ng-template #pager>\n @if (!HidePaging() && !grouped()) {\n <es-table2-pager\n [page]=\"currentPage()\"\n [pages]=\"totalPages()\"\n [total]=\"totalCount()\"\n [itemsPerPage]=\"viewMode() ? (view()?.itemsperpageoverride ?? 15) : ArraymodeItemsPerPage()\"\n [countLabel]=\"CountLabel()\"\n [showCount]=\"!HidePagingCount()\"\n [showButtons]=\"!HidePagingButtons()\"\n [showPagingOptions]=\"!HidePagingButtons()\"\n [allowAll]=\"AllSearch()\"\n (pageChange)=\"goToPage($event)\"\n (itemsPerPageChange)=\"changeItemsPerPage($event)\">\n </es-table2-pager>\n }\n</ng-template>\n\n<!-- Editor di cella di default (usato quando il consumer non fornisce un `*editor`) -->\n<ng-template #defaultEditor let-item let-col=\"col\">\n @switch (col.type) {\n @case ('enum') {\n <select class=\"est2-editor-input\"\n [value]=\"editDraft\"\n (change)=\"editDraft = $any($event.target).value\"\n (keydown.enter)=\"commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\"\n (blur)=\"commitEdit(item, col)\">\n @for (o of col.source || []; track o.id) {\n <option [value]=\"o.id\" [selected]=\"o.id == editDraft\">{{ o.description }}</option>\n }\n </select>\n }\n @case ('boolean') {\n <input type=\"checkbox\" class=\"est2-editor-input est2-check\"\n [checked]=\"editDraft === true || editDraft === 'true'\"\n (change)=\"editDraft = $any($event.target).checked; commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\" />\n }\n @default {\n <input class=\"est2-editor-input\"\n [type]=\"editorInputType(col.type)\"\n [value]=\"editDraft\"\n (input)=\"editDraft = $any($event.target).value\"\n (keydown.enter)=\"commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\"\n (blur)=\"commitEdit(item, col)\" />\n }\n }\n</ng-template>\n\n<!-- Menu di default (nessuna operazione) usato quando il consumer non passa [ContextMenu] -->\n<context-menu #emptyMenu>\n <ng-template contextMenuItem [passive]=\"true\"><em>Nessuna operazione disponibile\u2026</em></ng-template>\n</context-menu>\n", styles: [".est2{--est-bg: #ffffff;--est-bg-subtle: #f7f8fa;--est-bg-raised: #ffffff;--est-bg-hover: #f2f4f7;--est-bg-selected: color-mix(in srgb, var(--est-accent) 12%, transparent);--est-fg: #1a1d24;--est-fg-muted: #626b7a;--est-fg-faint: #9aa3b2;--est-border: #e6e9ef;--est-border-strong: #d3d8e0;--est-accent: #4f46e5;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 14%, transparent);--est-danger: #dc2626;--est-warning: #d97706;--est-success: #059669;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 4px 12px -8px rgba(16, 24, 40, .24);--est-shadow-pop: 0 8px 24px -6px rgba(16, 24, 40, .18), 0 2px 6px -2px rgba(16, 24, 40, .12);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 40%, transparent);--est-radius: 10px;--est-radius-sm: 6px;--est-radius-pill: 999px;--est-gap: 8px;--est-cell-py: 10px;--est-cell-px: 14px;--est-row-h: 44px;--est-font: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;--est-fs: 13.5px;--est-fs-sm: 12px;--est-fw-head: 600;--est-transition: .14s cubic-bezier(.4, 0, .2, 1);font-family:var(--est-font);font-size:var(--est-fs);color:var(--est-fg);position:relative;display:block}@media(prefers-color-scheme:dark){.est2{--est-bg: #14161c;--est-bg-subtle: #1a1d25;--est-bg-raised: #1e222b;--est-bg-hover: #232733;--est-bg-selected: color-mix(in srgb, var(--est-accent) 26%, transparent);--est-fg: #e7eaf0;--est-fg-muted: #9aa3b2;--est-fg-faint: #6b7484;--est-border: #2a2f3a;--est-border-strong: #39404d;--est-accent: #7c74ff;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 22%, transparent);--est-danger: #f87171;--est-warning: #fbbf24;--est-success: #34d399;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 6px 16px -10px rgba(0, 0, 0, .7);--est-shadow-pop: 0 10px 28px -8px rgba(0, 0, 0, .6), 0 2px 6px -2px rgba(0, 0, 0, .5);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 55%, transparent)}}.est2.est2--dark{--est-bg: #14161c;--est-bg-subtle: #1a1d25;--est-bg-raised: #1e222b;--est-bg-hover: #232733;--est-bg-selected: color-mix(in srgb, var(--est-accent) 26%, transparent);--est-fg: #e7eaf0;--est-fg-muted: #9aa3b2;--est-fg-faint: #6b7484;--est-border: #2a2f3a;--est-border-strong: #39404d;--est-accent: #7c74ff;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 22%, transparent);--est-danger: #f87171;--est-warning: #fbbf24;--est-success: #34d399;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 6px 16px -10px rgba(0, 0, 0, .7);--est-shadow-pop: 0 10px 28px -8px rgba(0, 0, 0, .6), 0 2px 6px -2px rgba(0, 0, 0, .5);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 55%, transparent)}.est2.est2--light{--est-bg: #ffffff;--est-bg-subtle: #f7f8fa;--est-bg-raised: #ffffff;--est-bg-hover: #f2f4f7;--est-bg-selected: color-mix(in srgb, var(--est-accent) 12%, transparent);--est-fg: #1a1d24;--est-fg-muted: #626b7a;--est-fg-faint: #9aa3b2;--est-border: #e6e9ef;--est-border-strong: #d3d8e0;--est-accent: #4f46e5;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 14%, transparent);--est-danger: #dc2626;--est-warning: #d97706;--est-success: #059669;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 4px 12px -8px rgba(16, 24, 40, .24);--est-shadow-pop: 0 8px 24px -6px rgba(16, 24, 40, .18), 0 2px 6px -2px rgba(16, 24, 40, .12);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 40%, transparent)}.est2.est2--dense{--est-cell-py: 5px;--est-cell-px: 10px;--est-row-h: 32px;--est-fs: 12.5px}.est2 *,.est2 *:before,.est2 *:after{box-sizing:border-box}.est2 .est2-scroll{position:relative;width:100%;overflow:auto;border:1px solid var(--est-border);border-radius:var(--est-radius);background:var(--est-bg);-webkit-overflow-scrolling:touch}.est2 table.est2-table{width:100%;border-collapse:separate;border-spacing:0;background:var(--est-bg)}.est2 thead th{position:sticky;top:0;z-index:3;background:var(--est-bg-subtle);color:var(--est-fg-muted);font-weight:var(--est-fw-head);font-size:var(--est-fs-sm);letter-spacing:.02em;text-transform:uppercase;text-align:left;white-space:nowrap;padding:var(--est-cell-py) var(--est-cell-px);border-bottom:1px solid var(--est-border);box-shadow:var(--est-shadow-sticky);-webkit-user-select:none;user-select:none}.est2 thead tr.est2-hgroup-row th{font-size:var(--est-fs-sm);font-weight:600;letter-spacing:.02em;text-transform:uppercase;color:var(--est-fg-muted);text-align:center;white-space:nowrap;padding:var(--est-cell-py) var(--est-cell-px);background:var(--est-bg-subtle);border-bottom:1px solid var(--est-border)}.est2 thead tr.est2-hgroup-row th.est2-hgroup{color:var(--est-fg);border-left:1px solid var(--est-border);border-right:1px solid var(--est-border)}.est2 thead tr.est2-hgroup-row th:not(.est2-hgroup){background:var(--est-bg);border-bottom-color:transparent}.est2 tbody td{padding:var(--est-cell-py) var(--est-cell-px);border-bottom:1px solid var(--est-border);color:var(--est-fg);vertical-align:middle;background:transparent}.est2 th.est2-pinned,.est2 td.est2-pinned{position:sticky;background:var(--est-bg);box-shadow:1px 0 0 var(--est-border)}.est2 td.est2-pinned{z-index:3}.est2 thead th.est2-pinned{z-index:6;background:var(--est-bg-subtle)}.est2 thead tr.est2-hgroup-row th.est2-pinned{z-index:6;background:var(--est-bg)}.est2 tbody tr:hover td.est2-pinned{background:color-mix(in srgb,var(--est-fg) 5%,var(--est-bg))}.est2 tbody tr.est2-row--selected td.est2-pinned{background:color-mix(in srgb,var(--est-accent) 12%,var(--est-bg))}.est2 tbody tr.est2-row--group td.est2-pinned{background:var(--est-bg-subtle)}.est2 .est2-pinbtn{display:inline-flex;align-items:center;justify-content:center;margin-left:4px;padding:2px;border:none;background:transparent;color:var(--est-fg-faint);border-radius:var(--est-radius-sm);cursor:pointer;opacity:0;transition:opacity var(--est-transition),color var(--est-transition),background var(--est-transition)}.est2 thead th:hover .est2-pinbtn{opacity:.7}.est2 .est2-pinbtn:hover{background:var(--est-bg-hover);color:var(--est-fg);opacity:1}.est2 .est2-pinbtn--on{opacity:1;color:var(--est-accent);transform:rotate(0)}.est2 thead th:hover .est2-pinbtn--on{opacity:1}.est2 .est2-collist__pin.est2-collist__pin--on{color:var(--est-accent);border-color:var(--est-accent)}.est2 tbody tr{height:var(--est-row-h);transition:background var(--est-transition)}.est2 tbody tr:last-child td{border-bottom:none}.est2 tbody tr:hover td{background:var(--est-bg-hover)}.est2 tbody tr.est2-row--selected td{background:var(--est-bg-selected)}.est2 tbody tr.est2-row--clickable{cursor:pointer;-webkit-user-select:none;user-select:none}.est2 tbody tr.est2-row--removed td{text-decoration:line-through;color:var(--est-fg-faint)}.est2 .est2-table--range tbody td[data-r]{cursor:cell}.est2 .est2-table--dragging,.est2 .est2-table--dragging tbody td{-webkit-user-select:none;user-select:none}.est2 tbody td.est2-cell-sel{background:color-mix(in srgb,var(--est-accent) 14%,transparent)}.est2 tbody td.est2-cell-sel-t{box-shadow:inset 0 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b{box-shadow:inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-l{box-shadow:inset 2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-r{box-shadow:inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-l{box-shadow:inset 2px 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-r{box-shadow:inset -2px 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-l{box-shadow:inset 2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-r{box-shadow:inset -2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b{box-shadow:inset 0 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 0 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-l{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-r{box-shadow:inset -2px 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px -2px 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset -2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-editing{padding:2px 6px}.est2 .est2-editor-input{width:100%;box-sizing:border-box;height:calc(var(--est-row-h) - 8px);padding:2px 6px;font:inherit;color:var(--est-fg);background:var(--est-bg);border:1.5px solid var(--est-accent);border-radius:var(--est-radius-sm);outline:none}.est2 .est2-editor-input:focus-visible{box-shadow:var(--est-ring)}.est2 input.est2-editor-input[type=checkbox]{width:16px;height:16px}.est2 .est2-toast{position:absolute;left:50%;bottom:14px;transform:translate(-50%);z-index:20;display:inline-flex;align-items:center;gap:8px;max-width:calc(100% - 24px);padding:8px 14px;font-size:13px;font-weight:500;color:#fff;background:#b91c1c;border-radius:var(--est-radius);box-shadow:0 6px 20px #00000040;animation:est2-toast-in .16s ease-out}.est2 .est2-toast svg{flex:0 0 auto}@keyframes est2-toast-in{0%{opacity:0;transform:translate(-50%,8px)}to{opacity:1;transform:translate(-50%)}}@media(prefers-reduced-motion:reduce){.est2 .est2-toast{animation:none}}.est2 tbody tr.est2-row--group{cursor:pointer;-webkit-user-select:none;user-select:none}.est2 tbody tr.est2-row--group td{background:var(--est-bg-subtle);font-weight:600;color:var(--est-fg);border-bottom:1px solid var(--est-border)}.est2 tbody tr.est2-row--group:hover td{background:var(--est-bg-hover)}.est2 .est2-td--group-key{color:var(--est-fg)}.est2 .est2-group-key{display:inline-flex;align-items:center;gap:6px}.est2 .est2-group-chevron{display:inline-flex;color:var(--est-fg-muted);transition:transform var(--est-transition)}.est2 .est2-group-chevron--open{transform:rotate(90deg)}.est2 .est2-hier-lead{display:inline-flex;align-items:center;vertical-align:middle;margin-right:4px}.est2 .est2-hier-toggle{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;flex:none}.est2 .est2-group-chevron.est2-hier-toggle{cursor:pointer;border-radius:var(--est-radius-sm);transition:transform var(--est-transition),background var(--est-transition),color var(--est-transition)}.est2 .est2-group-chevron.est2-hier-toggle:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 th.est2-th--orderable{cursor:pointer;transition:color var(--est-transition)}.est2 th.est2-th--orderable:hover{color:var(--est-fg)}.est2 .est2-th__inner{display:inline-flex;align-items:center;gap:6px}.est2 .est2-sort{display:inline-flex;width:14px;height:14px;opacity:.35;transition:opacity var(--est-transition),transform var(--est-transition)}.est2 .est2-sort--active{opacity:1;color:var(--est-accent)}.est2 .est2-sort--desc{transform:rotate(180deg)}.est2 .est2-sort__badge{font-size:9px;font-weight:700;color:var(--est-accent);margin-left:2px}.est2 .est2-check{appearance:none;width:16px;height:16px;border:1.5px solid var(--est-border-strong);border-radius:var(--est-radius-sm);background:var(--est-bg);cursor:pointer;position:relative;transition:border-color var(--est-transition),background var(--est-transition);vertical-align:middle;flex:none}.est2 .est2-check:hover{border-color:var(--est-accent)}.est2 .est2-check:checked{background:var(--est-accent);border-color:var(--est-accent)}.est2 .est2-check:checked:after{content:\"\";position:absolute;left:4.5px;top:1.5px;width:4px;height:8px;border:solid var(--est-accent-fg);border-width:0 2px 2px 0;transform:rotate(45deg)}.est2 .est2-check:focus-visible{outline:none;box-shadow:var(--est-ring)}.est2 .est2-check:indeterminate{background:var(--est-accent);border-color:var(--est-accent)}.est2 .est2-check:indeterminate:after{content:\"\";position:absolute;left:3px;top:6px;width:8px;height:2px;background:var(--est-accent-fg);transform:none;border:none}.est2 th.est2-col-min,.est2 td.est2-col-min{width:1%;white-space:nowrap}.est2 .est2-wrap{position:relative}.est2 .est2-selectbar{position:absolute;top:0;left:0;right:0;z-index:15;display:flex;align-items:center;gap:12px;padding:9px 14px;font-size:var(--est-fs-sm);color:var(--est-fg);background:var(--est-bg-subtle);border:none;border-radius:var(--est-radius) var(--est-radius) 0 0;box-shadow:inset 3px 0 0 var(--est-accent)}.est2 .est2-selectbar strong{color:var(--est-fg);font-weight:700}.est2 .est2-selectbar__spacer{flex:1 1 auto}.est2 .est2-link{color:var(--est-accent);cursor:pointer;font-weight:600}.est2 .est2-link:hover{text-decoration:underline}.est2 .est2-rowaction{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--est-radius-sm);border:none;background:transparent;color:var(--est-fg-faint);cursor:pointer;transition:background var(--est-transition),color var(--est-transition)}.est2 .est2-rowaction:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-rowaction--danger:hover{color:var(--est-danger)}.est2 .est2-op-cell{text-align:center}.est2 .est2-op{display:inline-flex;align-items:center;justify-content:center;min-width:26px;height:26px;padding:0 6px;border-radius:var(--est-radius-sm);color:var(--est-accent);cursor:pointer;font-size:var(--est-fs-sm);transition:background var(--est-transition)}.est2 .est2-op:hover{background:var(--est-accent-weak)}.est2 .est2-loading{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;gap:10px;background:color-mix(in srgb,var(--est-bg) 70%,transparent);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:5;color:var(--est-fg-muted);font-size:var(--est-fs-sm)}.est2 .est2-spinner{width:16px;height:16px;border:2px solid var(--est-border-strong);border-top-color:var(--est-accent);border-radius:50%;animation:est2-spin .7s linear infinite}@keyframes est2-spin{to{transform:rotate(360deg)}}.est2 .est2-nowrap{white-space:nowrap}.est2 .est2-cornermenu{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--est-radius-sm);cursor:pointer;color:var(--est-fg-muted);transition:background var(--est-transition)}.est2 .est2-cornermenu:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-chrome-th{position:relative}.est2 .est2-chrome{display:inline-flex;align-items:center;gap:2px}.est2 .est2-chrome-wrap{position:relative;display:inline-flex}.est2 .est2-chrome-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;background:transparent;border-radius:var(--est-radius-sm);color:var(--est-fg-muted);cursor:pointer;font-size:16px;line-height:1;transition:background var(--est-transition),color var(--est-transition)}.est2 .est2-chrome-btn:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-menu{position:absolute;top:calc(100% + 4px);right:0;z-index:30;min-width:180px;padding:4px;background:var(--est-bg);border:1px solid var(--est-border);border-radius:var(--est-radius);box-shadow:0 8px 24px #0000002e;display:flex;flex-direction:column}.est2 .est2-menu-item{display:block;width:100%;padding:8px 10px;border:none;background:transparent;text-align:left;font:inherit;color:var(--est-fg);border-radius:var(--est-radius-sm);cursor:pointer}.est2 .est2-menu-item:hover{background:var(--est-bg-hover)}.est2 .est2-dialog-backdrop{position:absolute;inset:0;z-index:40;display:flex;align-items:center;justify-content:center;padding:16px;background:color-mix(in srgb,#000 32%,transparent)}.est2 .est2-dialog{width:380px;max-width:100%;max-height:100%;display:flex;flex-direction:column;background:var(--est-bg);color:var(--est-fg);border:1px solid var(--est-border);border-radius:var(--est-radius);box-shadow:0 16px 48px #0000004d;overflow:hidden}.est2 .est2-dialog__head{display:flex;align-items:center;justify-content:space-between;padding:12px 14px;font-weight:700;border-bottom:1px solid var(--est-border)}.est2 .est2-dialog__close{border:none;background:transparent;cursor:pointer;color:var(--est-fg-muted);font-size:15px;line-height:1;padding:4px;border-radius:var(--est-radius-sm)}.est2 .est2-dialog__close:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-dialog__tools{padding:8px 14px;font-size:var(--est-fs-sm);border-bottom:1px solid var(--est-border)}.est2 .est2-dialog__tools .est2-link{border:none;background:none;padding:0;font:inherit;font-weight:600}.est2 .est2-dialog__sep{margin:0 6px;color:var(--est-fg-faint)}.est2 .est2-collist{list-style:none;margin:0;padding:6px;overflow-y:auto}.est2 .est2-collist__row{display:flex;align-items:center;gap:10px;padding:6px 8px;border-radius:var(--est-radius-sm)}.est2 .est2-collist__row:hover{background:var(--est-bg-hover)}.est2 .est2-collist__vis{display:inline-flex}.est2 .est2-collist__label{flex:1 1 auto}.est2 .est2-collist__ord{display:inline-flex;gap:4px}.est2 .est2-iconbtn{width:26px;height:26px;border:1px solid var(--est-border);background:var(--est-bg);border-radius:var(--est-radius-sm);color:var(--est-fg-muted);cursor:pointer}.est2 .est2-iconbtn:hover:not(:disabled){background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-iconbtn:disabled{opacity:.4;cursor:default}.est2 .est2-dialog__foot{display:flex;align-items:center;gap:8px;padding:12px 14px;border-top:1px solid var(--est-border)}.est2 .est2-dialog__spacer{flex:1 1 auto}.est2 .est2-btn{padding:7px 14px;border-radius:var(--est-radius-sm);font:inherit;font-weight:600;cursor:pointer;border:1px solid transparent}.est2 .est2-btn--ghost{background:transparent;color:var(--est-fg);border-color:var(--est-border)}.est2 .est2-btn--ghost:hover{background:var(--est-bg-hover)}.est2 .est2-btn--primary{background:var(--est-accent);color:var(--est-accent-fg)}.est2 .est2-btn--primary:hover{filter:brightness(1.05)}.est2 .est2-empty{padding:48px 16px;text-align:center;color:var(--est-fg-faint);font-size:var(--est-fs-sm)}.ngx-contextmenu{--ctx-bg: #ffffff;--ctx-fg: #1a1d24;--ctx-muted: #626b7a;--ctx-border: #e6e9ef;--ctx-hover: #f2f4f7;--ctx-accent: #4f46e5;--ctx-shadow: 0 10px 28px -8px rgba(16, 24, 40, .22), 0 2px 8px -3px rgba(16, 24, 40, .14);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.ngx-contextmenu .dropdown-menu{display:block;min-width:200px;margin:0;padding:6px;list-style:none;background:var(--ctx-bg);border:1px solid var(--ctx-border);border-radius:12px;box-shadow:var(--ctx-shadow);animation:est2-ctx-in .12s cubic-bezier(.16,1,.3,1)}.ngx-contextmenu li{list-style:none;margin:0}.ngx-contextmenu li>a{display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:7px;color:var(--ctx-fg);font-size:13.5px;line-height:1.2;text-decoration:none;cursor:pointer;white-space:nowrap;transition:background .12s ease,color .12s ease}.ngx-contextmenu li>a:hover,.ngx-contextmenu li>a:focus{background:var(--ctx-hover);color:var(--ctx-fg);text-decoration:none;outline:none}.ngx-contextmenu li.divider,.ngx-contextmenu li[role=separator]{height:1px;margin:6px 8px;padding:0;background:var(--ctx-border)}.ngx-contextmenu li.disabled>a,.ngx-contextmenu li[aria-disabled=true]>a{color:var(--ctx-muted);opacity:.55;pointer-events:none}@media(prefers-color-scheme:dark){.ngx-contextmenu{--ctx-bg: #1e222b;--ctx-fg: #e7eaf0;--ctx-muted: #9aa3b2;--ctx-border: #2a2f3a;--ctx-hover: #232733;--ctx-accent: #7c74ff;--ctx-shadow: 0 12px 30px -8px rgba(0, 0, 0, .6), 0 2px 8px -3px rgba(0, 0, 0, .5)}}@keyframes est2-ctx-in{0%{opacity:0;transform:translateY(-4px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@media(prefers-reduced-motion:reduce){.ngx-contextmenu .dropdown-menu{animation:none}}\n"] }]
8603
+ args: [{ selector: 'es-table2', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "@if (view()) {\n <div class=\"est2-wrap {{ ContainerClass() }}\"\n [style.height]=\"Height()\"\n [style.background-color]=\"EmptySpaceBackgroundColor() || null\">\n\n <!-- Auto-aggiornamento: toggle + intervallo (in alto a destra) -->\n @if (AutoUpdate()) {\n <div class=\"est2-autoupdate\">\n <label class=\"est2-autoupdate__label\">\n Aggiorna ogni\n <input type=\"text\" maxlength=\"3\" class=\"est2-autoupdate__secs\"\n [ngModel]=\"seconds()\" (ngModelChange)=\"seconds.set($event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n (change)=\"autoUpdateChanged()\" />\n secondi\n </label>\n <label class=\"est2-switch\" title=\"Attiva/disattiva auto-aggiornamento\">\n <input type=\"checkbox\" [ngModel]=\"autoUpdate()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"autoUpdate.set($event); autoUpdateChanged()\" />\n <span class=\"est2-switch__slider\"></span>\n </label>\n </div>\n }\n\n <!-- Pager superiore -->\n @if (PagingStyle() === 'both' || PagingStyle() === 'top') {\n <ng-container *ngTemplateOutlet=\"pager\"></ng-container>\n }\n\n <!-- Barra \"seleziona tutto\" (visibile solo con selezione multipla attiva e righe presenti) -->\n @if (Selection() && !SingleSelection() && hasSelection) {\n <div class=\"est2-selectbar\" [style.height.px]=\"selbarHeight() ? selbarHeight() + 1 : null\">\n @if (allSelected) {\n <span>Tutti i <strong>{{ selectedCount }}</strong> elementi sono selezionati</span>\n } @else {\n <span><strong>{{ selectedCount }}</strong> {{ selectedCount === 1 ? 'elemento selezionato' : 'elementi selezionati' }}</span>\n @if (canSelectEverything) {\n <span class=\"est2-link\" (click)=\"selectEverything()\">Seleziona tutti i {{ totalCount() }} elementi</span>\n }\n }\n <span class=\"est2-selectbar__spacer\"></span>\n <span class=\"est2-link\" (click)=\"clearSelection()\">Azzera selezione</span>\n </div>\n }\n\n <div class=\"est2-scroll\" [style.max-height.px]=\"MaxHeight()\">\n <table class=\"est2-table {{ TableClass() }}\"\n [class.est2-table--range]=\"rangeActive()\"\n [class.est2-table--dragging]=\"rangeDragging()\"\n (mousedown)=\"onGridMouseDown($event)\"\n (mouseover)=\"onGridMouseOver($event)\">\n\n <!-- ================= HEADER ================= -->\n @if (!HeaderHidden()) {\n <thead #theadRef>\n <!-- Righe di header-group multi-livello (dall'alto verso il basso) -->\n @if (hasHeaderGroups()) {\n @for (grow of headerGroupRows(); track $index) {\n <tr class=\"est2-hgroup-row\">\n @if (Selection()) { <th class=\"est2-col-min est2-selcol\" [class.est2-pinned]=\"hasPinned()\" [style.left.px]=\"hasPinned() ? 0 : null\"></th> }\n @for (op of DynamicOperations(); track op.id) { <th class=\"est2-col-min\"></th> }\n @for (cell of grow; track cell.id; let gi = $index) {\n <th [attr.colspan]=\"cell.span\"\n [attr.data-groupid]=\"cell.isGroup ? cell.id : null\"\n [class.est2-hgroup]=\"cell.isGroup\"\n [class.est2-pinned]=\"gi < pinnedCount()\"\n [style.left.px]=\"gi < pinnedCount() ? pinnedLeftPx(gi) : null\"\n class=\"est2-hgroup-cell\">\n @if (cell.isGroup) {\n @if (cell.template) {\n <ng-container *ngTemplateOutlet=\"cell.template\"></ng-container>\n } @else {\n {{ cell.label }}\n }\n }\n </th>\n }\n @if (Removal()) { <th class=\"est2-col-min\"></th> }\n @if (hasChrome()) { <th class=\"est2-col-min\"></th> }\n </tr>\n }\n }\n <tr>\n <!-- Colonna di selezione -->\n @if (Selection()) {\n <th class=\"est2-col-min est2-selcol\"\n [class.est2-pinned]=\"hasPinned()\"\n [style.left.px]=\"hasPinned() ? 0 : null\">\n @if (!SingleSelection()) {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"globalCheck()\"\n [indeterminate]=\"selectionIndeterminate\"\n [disabled]=\"SelectionDisabled()\"\n (change)=\"toggleAll()\"\n aria-label=\"Seleziona tutto\" />\n }\n </th>\n }\n\n <!-- Header da colonne (direttive / dinamica / report) -->\n @if (usesColumns()) {\n <!-- intestazioni vuote per le operazioni dinamiche -->\n @for (op of DynamicOperations(); track op.id) {\n <th class=\"est2-col-min\"></th>\n }\n @for (col of visibleColumns(); track trackCol($index, col); let ci = $index) {\n <th [attr.data-colid]=\"col.id\"\n [class]=\"col.cssClass\"\n [class.est2-th--orderable]=\"OrderByColumn() && col.orderable\"\n [class.est2-col-min]=\"col.header?.thShrink\"\n [class.est2-col-groupstart]=\"columnGroupBoundaries().has(ci)\"\n [class.est2-pinned]=\"col.pinned\"\n [style.left.px]=\"col.pinned ? pinnedLeftPx(ci) : null\"\n [style.min-width.px]=\"col.pinned && col.pinnedWidth ? col.pinnedWidth : null\"\n [style.max-width.px]=\"col.pinned && col.pinnedWidth ? col.pinnedWidth : null\"\n [style.text-align]=\"col.alignment\"\n [style.background-color]=\"col.headerBg || null\"\n (click)=\"toggleSort(col)\">\n <span class=\"est2-th__inner\">\n @if (col.header?.Template) {\n <ng-container *ngTemplateOutlet=\"col.header!.Template!; context: col.multiProp != null ? { $implicit: col.headerText } : null\"></ng-container>\n } @else {\n {{ col.headerText }}\n }\n @if (OrderByColumn() && col.orderable && orderOf(col.id)) {\n <span class=\"est2-sort est2-sort--active\"\n [class.est2-sort--desc]=\"orderOf(col.id) === 'DESC'\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M6 15l6-6 6 6\"/></svg>\n </span>\n @if (orderIndex(col.id) > 0 && MultipleOrderingDirectives()) {\n <span class=\"est2-sort__badge\">{{ orderIndex(col.id) }}</span>\n }\n }\n <!-- Indicatore/toggle di pin (visibile se pinnata o all'hover) -->\n @if (ColumnsPinnable() && col.multiProp == null) {\n <button type=\"button\" class=\"est2-pinbtn\"\n [class.est2-pinbtn--on]=\"col.pinned\"\n [title]=\"col.pinned ? 'Sblocca colonna' : 'Blocca colonna a sinistra'\"\n (click)=\"togglePin(col, $event)\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 17v5\"/><path d=\"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z\"/></svg>\n </button>\n }\n </span>\n </th>\n }\n }\n <!-- Header da template semplice -->\n @else if (headerRef) {\n <ng-container *ngTemplateOutlet=\"headerRef\"></ng-container>\n }\n\n <!-- Colonna rimozione -->\n @if (Removal()) { <th class=\"est2-col-min\"></th> }\n <!-- Colonna chrome (export / gestione colonne / menu) -->\n @if (hasChrome()) {\n <th class=\"est2-col-min est2-chrome-th\">\n <div class=\"est2-chrome\">\n @if (Export()) {\n <div class=\"est2-chrome-wrap\">\n <button type=\"button\" class=\"est2-chrome-btn\" title=\"Esporta\" (click)=\"$event.stopPropagation(); toggleExportMenu()\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"/><path d=\"M7 10l5 5 5-5\"/><path d=\"M12 15V3\"/></svg>\n </button>\n @if (exportMenuOpen()) {\n <div class=\"est2-menu\" (click)=\"$event.stopPropagation()\">\n @if (CSVExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('CSV')\">Esporta CSV</button> }\n @if (XLSXExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('XLSX')\">Esporta Excel (XLSX)</button> }\n @if (!CSVExport() && !XLSXExport()) { <button type=\"button\" class=\"est2-menu-item\" (click)=\"export('CSV')\">Esporta CSV</button> }\n </div>\n }\n </div>\n }\n @if (HiddenColumns() || ColumnsOrdering()) {\n <button type=\"button\" class=\"est2-chrome-btn\" title=\"Colonne\" (click)=\"$event.stopPropagation(); openColumnsDialog()\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"1\"/><path d=\"M9 3v18\"/><path d=\"M15 3v18\"/></svg>\n </button>\n }\n @if (CornerMenuOptions().length > 0) {\n <div class=\"est2-chrome-wrap\">\n <button type=\"button\" class=\"est2-chrome-btn\" title=\"Opzioni\" (click)=\"$event.stopPropagation(); toggleCornerMenu()\">\u22EE</button>\n @if (cornerMenuOpen()) {\n <div class=\"est2-menu\" (click)=\"$event.stopPropagation()\">\n @for (opt of CornerMenuOptions(); track opt.id) {\n <button type=\"button\" class=\"est2-menu-item\" (click)=\"cornerAction(opt.id); cornerMenuOpen.set(false)\">{{ opt.description }}</button>\n }\n </div>\n }\n </div>\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n }\n\n <!-- ================= BODY ================= -->\n @if (!BodyHidden()) {\n <tbody>\n @for (item of boundSource(); track trackRow($index, item); let ri = $index) {\n @if ((!grouped() && !Hierarchy()) || item._visible) {\n <tr [class]=\"rowClass(item)\"\n [class.est2-row--selected]=\"item._selected\"\n [class.est2-row--removed]=\"item.removed || item.deleted\"\n [class.est2-row--group]=\"item._group\"\n [class.est2-row--clickable]=\"Selection() || item._group\"\n [contextMenu]=\"ContextMenu || emptyMenu\"\n [contextMenuSubject]=\"item\"\n (click)=\"handleRowClick(item, $event)\">\n\n <!-- Cella di selezione -->\n @if (Selection()) {\n <td class=\"est2-col-min est2-selcol\"\n [class.est2-pinned]=\"hasPinned()\"\n [style.left.px]=\"hasPinned() ? 0 : null\">\n @if (item._group) {\n @if (!SingleSelection()) {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"groupSelectionState(item) === 'all'\"\n [indeterminate]=\"groupSelectionState(item) === 'some'\"\n [disabled]=\"SelectionDisabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleGroupSelection(item)\"\n aria-label=\"Seleziona gruppo\" />\n }\n } @else {\n <input type=\"checkbox\" class=\"est2-check\"\n [checked]=\"item._selected\"\n [indeterminate]=\"hierarchyIndeterminate(item)\"\n [disabled]=\"SelectionDisabled()\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(item)\"\n aria-label=\"Seleziona riga\" />\n }\n </td>\n }\n\n <!-- Celle da colonne (direttive / dinamica / report) -->\n @if (usesColumns()) {\n <!-- Operazioni dinamiche (icone a sinistra) -->\n @for (op of DynamicOperations(); track op.id) {\n <td class=\"est2-col-min est2-op-cell\">\n @if (!item._group && operationVisible(op, item)) {\n <span class=\"est2-op\" [class]=\"op.iconClass || ''\" [title]=\"op.title\"\n (click)=\"$event.stopPropagation(); dynamicOperation(item, op.id)\">{{ op.text }}</span>\n }\n </td>\n }\n @for (col of visibleColumns(); track trackCol($index, col); let first = $first, ci = $index) {\n <td [class]=\"col.cssClass\"\n [style.text-align]=\"col.alignment\"\n [style.color]=\"cellColor(item, col, 'fore')\"\n [style.background-color]=\"cellColor(item, col, 'back')\"\n [class.est2-nowrap]=\"!col.wrap\"\n [class.est2-col-groupstart]=\"columnGroupBoundaries().has(ci)\"\n [class.est2-pinned]=\"col.pinned\"\n [style.left.px]=\"col.pinned ? pinnedLeftPx(ci) : null\"\n [style.min-width.px]=\"col.pinned && col.pinnedWidth ? col.pinnedWidth : null\"\n [style.max-width.px]=\"col.pinned && col.pinnedWidth ? col.pinnedWidth : null\"\n [class.est2-td--group-key]=\"item._group && item.column === col.id\"\n [attr.data-r]=\"rangeActive() && !item._group ? ri : null\"\n [attr.data-c]=\"rangeActive() && !item._group ? ci : null\"\n [class.est2-cell-sel]=\"rangeActive() && inRange(ri, ci)\"\n [class.est2-cell-sel-t]=\"rangeActive() && inRange(ri, ci) && ri === rangeRect()!.top\"\n [class.est2-cell-sel-b]=\"rangeActive() && inRange(ri, ci) && ri === rangeRect()!.bottom\"\n [class.est2-cell-sel-l]=\"rangeActive() && inRange(ri, ci) && ci === rangeRect()!.left\"\n [class.est2-cell-sel-r]=\"rangeActive() && inRange(ri, ci) && ci === rangeRect()!.right\"\n [class.est2-cell-editing]=\"isEditing(ri, ci)\"\n (dblclick)=\"onCellDblClick(item, col, ri, ci)\">\n @if (isEditing(ri, ci)) {\n @if (editorFor(col); as edTpl) {\n <ng-container *ngTemplateOutlet=\"edTpl; context: editorContext(item, col)\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"defaultEditor; context: { $implicit: item, col: col }\"></ng-container>\n }\n } @else if (item._group) {\n @if (item.column === col.id) {\n <span class=\"est2-group-key\" [style.padding-left.px]=\"groupIndent(item)\">\n <span class=\"est2-group-chevron\" [class.est2-group-chevron--open]=\"item._expanded\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 6l6 6-6 6\"/></svg>\n </span>\n {{ groupCellDisplay(item, col) }}\n </span>\n } @else {\n {{ groupCellDisplay(item, col) }}\n }\n } @else {\n <!-- Navigatore albero nella prima colonna -->\n @if (Hierarchy() && first) {\n <span class=\"est2-hier-lead\" [style.padding-left.px]=\"hierarchyIndent(item)\">\n @if (item.parent) {\n <span class=\"est2-group-chevron est2-hier-toggle\" [class.est2-group-chevron--open]=\"item._expanded\"\n (click)=\"$event.stopPropagation(); toggleHierarchyNode(item)\">\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 6l6 6-6 6\"/></svg>\n </span>\n } @else {\n <span class=\"est2-hier-toggle\"></span>\n }\n </span>\n }\n @if (itemCellHidden(col)) {\n <!-- colonna di gruppo nascosta sulla riga-oggetto -->\n } @else if (col.multiProp != null) {\n @if (col.cell?.Template) {\n <ng-container *ngTemplateOutlet=\"col.cell!.Template; context: { $implicit: multiCell(item, col) }\"></ng-container>\n } @else {\n {{ multiCell(item, col)?.value }}\n }\n } @else if (col.cell?.Template) {\n <ng-container *ngTemplateOutlet=\"col.cell!.Template; context: { $implicit: item }\"></ng-container>\n } @else if (col.routePath) {\n <a class=\"est2-link\" [routerLink]=\"routerLinkFor(item, col)\">{{ cellValue(item, col) }}</a>\n } @else if (col.propAccessor != null) {\n {{ reportCellDisplay(item, col) }}\n } @else if (col.type === 'enum') {\n {{ (cellValue(item, col) | est2_lookup : col.source).description }}\n } @else {\n {{ cellValue(item, col) | est2_format : col.type : col.format : locale }}\n }\n }\n </td>\n }\n }\n <!-- Celle da template semplice -->\n @else if (bodyRef) {\n <ng-container *ngTemplateOutlet=\"bodyRef; context: { $implicit: item }\"></ng-container>\n }\n\n <!-- Rimozione (non sulle righe-gruppo) -->\n @if (Removal()) {\n <td class=\"est2-col-min\">\n @if (!item._group && canRemove(item)) {\n @if (item.removed || item.deleted) {\n <button type=\"button\" class=\"est2-rowaction\" title=\"Ripristina\" (click)=\"abortRemoval(item)\">\u21BA</button>\n } @else {\n <button type=\"button\" class=\"est2-rowaction est2-rowaction--danger\" title=\"Rimuovi\" (click)=\"removeItem(item)\">\u2715</button>\n }\n }\n </td>\n }\n <!-- Chrome -->\n @if (hasChrome()) { <td class=\"est2-col-min\"></td> }\n </tr>\n }\n } @empty {\n <tr>\n <td class=\"est2-empty\" [attr.colspan]=\"totalColspan()\">Nessun elemento da visualizzare</td>\n </tr>\n }\n </tbody>\n }\n </table>\n\n <!-- Overlay di caricamento -->\n @if (researchInProgress() || (firstBind() && ShowLoadingOnBootstrap())) {\n <div class=\"est2-loading\">\n <span class=\"est2-spinner\"></span>\n <span>Caricamento\u2026</span>\n </div>\n }\n </div>\n\n <!-- Pager inferiore -->\n @if (PagingStyle() === 'both' || PagingStyle() === 'bottom') {\n <ng-container *ngTemplateOutlet=\"pager\"></ng-container>\n }\n\n <!-- Avviso transitorio (es. incolla con dimensioni incompatibili) -->\n @if (notice()) {\n <div class=\"est2-toast\" role=\"alert\">\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/><path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/></svg>\n <span>{{ notice() }}</span>\n </div>\n }\n\n <!-- Dialog visibilit\u00E0 / ordine colonne -->\n @if (columnsDialogOpen()) {\n <div class=\"est2-dialog-backdrop\" (click)=\"closeColumnsDialog()\">\n <div class=\"est2-dialog\" (click)=\"$event.stopPropagation()\" role=\"dialog\" aria-modal=\"true\">\n <div class=\"est2-dialog__head\">\n <span>\n @if (HiddenColumns() && ColumnsOrdering()) { Visibilit\u00E0 e ordine colonne }\n @else if (HiddenColumns()) { Visibilit\u00E0 colonne }\n @else { Ordine colonne }\n </span>\n <button type=\"button\" class=\"est2-dialog__close\" (click)=\"closeColumnsDialog()\" aria-label=\"Chiudi\">\u2715</button>\n </div>\n\n @if (HiddenColumns()) {\n <div class=\"est2-dialog__tools\">\n <button type=\"button\" class=\"est2-link\" (click)=\"dialogSetAll(true)\">Mostra tutte</button>\n <span class=\"est2-dialog__sep\">\u00B7</span>\n <button type=\"button\" class=\"est2-link\" (click)=\"dialogSetAll(false)\">Nascondi tutte</button>\n </div>\n }\n\n <ul class=\"est2-collist\">\n @for (c of dialogCols(); track c.id; let i = $index) {\n <li class=\"est2-collist__row\">\n @if (HiddenColumns()) {\n <label class=\"est2-collist__vis\">\n <input type=\"checkbox\" class=\"est2-check\" [checked]=\"c.visible\" (change)=\"dialogToggle(i)\" />\n </label>\n }\n <span class=\"est2-collist__label\">{{ c.label }}</span>\n @if (ColumnsPinnable()) {\n <button type=\"button\" class=\"est2-iconbtn est2-collist__pin\" [class.est2-collist__pin--on]=\"c.pinned\"\n [disabled]=\"c.grouped\"\n [title]=\"c.grouped ? 'Le colonne di un gruppo non sono bloccabili' : (c.pinned ? 'Sblocca' : 'Blocca a sinistra')\"\n (click)=\"dialogTogglePin(i)\">\n <svg viewBox=\"0 0 24 24\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 17v5\"/><path d=\"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z\"/></svg>\n </button>\n }\n @if (ColumnsOrdering()) {\n <span class=\"est2-collist__ord\">\n <button type=\"button\" class=\"est2-iconbtn\" [disabled]=\"i === 0\" title=\"Su\" (click)=\"dialogMove(i, -1)\">\u2191</button>\n <button type=\"button\" class=\"est2-iconbtn\" [disabled]=\"i === dialogCols().length - 1\" title=\"Gi\u00F9\" (click)=\"dialogMove(i, 1)\">\u2193</button>\n </span>\n }\n </li>\n }\n </ul>\n\n <div class=\"est2-dialog__foot\">\n <button type=\"button\" class=\"est2-btn est2-btn--ghost\" (click)=\"resetColumnsDialog()\">Ripristina</button>\n <span class=\"est2-dialog__spacer\"></span>\n <button type=\"button\" class=\"est2-btn est2-btn--ghost\" (click)=\"closeColumnsDialog()\">Annulla</button>\n <button type=\"button\" class=\"est2-btn est2-btn--primary\" (click)=\"applyColumnsDialog()\">Applica</button>\n </div>\n </div>\n </div>\n }\n </div>\n}\n\n<!-- Template pager riutilizzabile sopra/sotto -->\n<ng-template #pager>\n @if (!HidePaging() && !grouped()) {\n <es-table2-pager\n [page]=\"currentPage()\"\n [pages]=\"totalPages()\"\n [total]=\"totalCount()\"\n [itemsPerPage]=\"viewMode() ? (view()?.itemsperpageoverride ?? 15) : ArraymodeItemsPerPage()\"\n [countLabel]=\"CountLabel()\"\n [showCount]=\"!HidePagingCount()\"\n [showButtons]=\"!HidePagingButtons()\"\n [showPagingOptions]=\"!HidePagingButtons()\"\n [allowAll]=\"AllSearch()\"\n (pageChange)=\"goToPage($event)\"\n (itemsPerPageChange)=\"changeItemsPerPage($event)\">\n </es-table2-pager>\n }\n</ng-template>\n\n<!-- Editor di cella di default (usato quando il consumer non fornisce un `*editor`) -->\n<ng-template #defaultEditor let-item let-col=\"col\">\n @switch (col.type) {\n @case ('enum') {\n <select class=\"est2-editor-input\"\n [value]=\"editDraft\"\n (change)=\"editDraft = $any($event.target).value\"\n (keydown.enter)=\"commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\"\n (blur)=\"commitEdit(item, col)\">\n @for (o of col.source || []; track o.id) {\n <option [value]=\"o.id\" [selected]=\"o.id == editDraft\">{{ o.description }}</option>\n }\n </select>\n }\n @case ('boolean') {\n <input type=\"checkbox\" class=\"est2-editor-input est2-check\"\n [checked]=\"editDraft === true || editDraft === 'true'\"\n (change)=\"editDraft = $any($event.target).checked; commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\" />\n }\n @default {\n <input class=\"est2-editor-input\"\n [type]=\"editorInputType(col.type)\"\n [value]=\"editDraft\"\n (input)=\"editDraft = $any($event.target).value\"\n (keydown.enter)=\"commitEdit(item, col)\"\n (keydown.escape)=\"cancelEdit()\"\n (blur)=\"commitEdit(item, col)\" />\n }\n }\n</ng-template>\n\n<!-- Menu di default (nessuna operazione) usato quando il consumer non passa [ContextMenu] -->\n<context-menu #emptyMenu>\n <ng-template contextMenuItem [passive]=\"true\"><em>Nessuna operazione disponibile\u2026</em></ng-template>\n</context-menu>\n", styles: [".est2{--est-bg: #ffffff;--est-bg-subtle: #f7f8fa;--est-bg-raised: #ffffff;--est-bg-hover: #f2f4f7;--est-bg-selected: color-mix(in srgb, var(--est-accent) 12%, transparent);--est-fg: #1a1d24;--est-fg-muted: #626b7a;--est-fg-faint: #9aa3b2;--est-border: #e6e9ef;--est-border-strong: #d3d8e0;--est-accent: #4f46e5;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 14%, transparent);--est-danger: #dc2626;--est-warning: #d97706;--est-success: #059669;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 4px 12px -8px rgba(16, 24, 40, .24);--est-shadow-pop: 0 8px 24px -6px rgba(16, 24, 40, .18), 0 2px 6px -2px rgba(16, 24, 40, .12);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 40%, transparent);--est-radius: 10px;--est-radius-sm: 6px;--est-radius-pill: 999px;--est-gap: 8px;--est-cell-py: 6px;--est-cell-px: 12px;--est-row-h: 33px;--est-font: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;--est-fs: 13px;--est-fs-sm: 12px;--est-fw-head: 700;--est-transition: .14s cubic-bezier(.4, 0, .2, 1);--est-bg-zebra: color-mix(in srgb, var(--est-fg) 3.5%, var(--est-bg));font-family:var(--est-font);font-size:var(--est-fs);color:var(--est-fg);position:relative;display:block}@media(prefers-color-scheme:dark){.est2{--est-bg: #14161c;--est-bg-subtle: #1a1d25;--est-bg-raised: #1e222b;--est-bg-hover: #232733;--est-bg-selected: color-mix(in srgb, var(--est-accent) 26%, transparent);--est-fg: #e7eaf0;--est-fg-muted: #9aa3b2;--est-fg-faint: #6b7484;--est-border: #2a2f3a;--est-border-strong: #39404d;--est-accent: #7c74ff;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 22%, transparent);--est-danger: #f87171;--est-warning: #fbbf24;--est-success: #34d399;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 6px 16px -10px rgba(0, 0, 0, .7);--est-shadow-pop: 0 10px 28px -8px rgba(0, 0, 0, .6), 0 2px 6px -2px rgba(0, 0, 0, .5);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 55%, transparent)}}.est2.est2--dark{--est-bg: #14161c;--est-bg-subtle: #1a1d25;--est-bg-raised: #1e222b;--est-bg-hover: #232733;--est-bg-selected: color-mix(in srgb, var(--est-accent) 26%, transparent);--est-fg: #e7eaf0;--est-fg-muted: #9aa3b2;--est-fg-faint: #6b7484;--est-border: #2a2f3a;--est-border-strong: #39404d;--est-accent: #7c74ff;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 22%, transparent);--est-danger: #f87171;--est-warning: #fbbf24;--est-success: #34d399;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 6px 16px -10px rgba(0, 0, 0, .7);--est-shadow-pop: 0 10px 28px -8px rgba(0, 0, 0, .6), 0 2px 6px -2px rgba(0, 0, 0, .5);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 55%, transparent)}.est2.est2--light{--est-bg: #ffffff;--est-bg-subtle: #f7f8fa;--est-bg-raised: #ffffff;--est-bg-hover: #f2f4f7;--est-bg-selected: color-mix(in srgb, var(--est-accent) 12%, transparent);--est-fg: #1a1d24;--est-fg-muted: #626b7a;--est-fg-faint: #9aa3b2;--est-border: #e6e9ef;--est-border-strong: #d3d8e0;--est-accent: #4f46e5;--est-accent-fg: #ffffff;--est-accent-weak: color-mix(in srgb, var(--est-accent) 14%, transparent);--est-danger: #dc2626;--est-warning: #d97706;--est-success: #059669;--est-shadow-sticky: 0 1px 0 var(--est-border), 0 4px 12px -8px rgba(16, 24, 40, .24);--est-shadow-pop: 0 8px 24px -6px rgba(16, 24, 40, .18), 0 2px 6px -2px rgba(16, 24, 40, .12);--est-ring: 0 0 0 3px color-mix(in srgb, var(--est-accent) 40%, transparent)}.est2.est2--dense{--est-cell-py: 3px;--est-cell-px: 9px;--est-row-h: 27px;--est-fs: 12.5px}.est2 *,.est2 *:before,.est2 *:after{box-sizing:border-box}.est2 .est2-scroll{position:relative;width:100%;overflow:auto;border:1px solid var(--est-border);border-radius:var(--est-radius);background:var(--est-bg);-webkit-overflow-scrolling:touch}.est2 table.est2-table{width:100%;border-collapse:separate;border-spacing:0;background:var(--est-bg)}.est2 thead th{position:sticky;top:0;z-index:3;background:var(--est-bg-subtle);color:var(--est-fg);font-weight:var(--est-fw-head);font-size:var(--est-fs);text-align:left;white-space:nowrap;padding:var(--est-cell-py) var(--est-cell-px);border-bottom:1px solid var(--est-border);box-shadow:var(--est-shadow-sticky);-webkit-user-select:none;user-select:none}.est2 thead tr.est2-hgroup-row th{font-size:var(--est-fs-sm);font-weight:700;color:var(--est-fg-muted);text-align:center;white-space:nowrap;padding:var(--est-cell-py) var(--est-cell-px);background:var(--est-bg-subtle);border-bottom:1px solid var(--est-border)}.est2 thead tr.est2-hgroup-row th.est2-hgroup{color:var(--est-fg);border-left:1px solid var(--est-border);border-right:1px solid var(--est-border)}.est2 thead tr.est2-hgroup-row th:not(.est2-hgroup){background:var(--est-bg-subtle);border-bottom-color:transparent}.est2 thead tr:last-child th.est2-col-groupstart,.est2 tbody td.est2-col-groupstart{border-left:1px solid var(--est-border)}.est2 tbody td{padding:var(--est-cell-py) var(--est-cell-px);border-bottom:1px solid var(--est-border);color:var(--est-fg);vertical-align:middle;background:transparent}.est2 tbody tr:nth-child(2n) td{background:var(--est-bg-zebra)}.est2 tbody tr:nth-child(2n) td.est2-pinned{background:var(--est-bg-zebra)}.est2 th.est2-pinned,.est2 td.est2-pinned{position:sticky;background:var(--est-bg);box-shadow:1px 0 0 var(--est-border)}.est2 .est2-selcol{width:44px;min-width:44px;max-width:44px}.est2 td.est2-pinned{z-index:3}.est2 thead th.est2-pinned,.est2 thead tr.est2-hgroup-row th.est2-pinned{z-index:6;background:var(--est-bg-subtle)}.est2 tbody tr:hover td.est2-pinned{background:color-mix(in srgb,var(--est-fg) 5%,var(--est-bg))}.est2 tbody tr.est2-row--selected td.est2-pinned{background:color-mix(in srgb,var(--est-accent) 12%,var(--est-bg))}.est2 tbody tr.est2-row--group td.est2-pinned{background:var(--est-bg-subtle)}.est2 .est2-pinbtn{display:inline-flex;align-items:center;justify-content:center;margin-left:4px;padding:2px;border:none;background:transparent;color:var(--est-fg-faint);border-radius:var(--est-radius-sm);cursor:pointer;opacity:0;transition:opacity var(--est-transition),color var(--est-transition),background var(--est-transition)}.est2 thead th:hover .est2-pinbtn{opacity:.7}.est2 .est2-pinbtn:hover{background:var(--est-bg-hover);color:var(--est-fg);opacity:1}.est2 .est2-pinbtn--on{opacity:1;color:var(--est-accent);transform:rotate(0)}.est2 thead th:hover .est2-pinbtn--on{opacity:1}.est2 .est2-collist__pin.est2-collist__pin--on{color:var(--est-accent);border-color:var(--est-accent)}.est2 tbody tr{height:var(--est-row-h);transition:background var(--est-transition)}.est2 tbody tr:last-child td{border-bottom:none}.est2 tbody tr:hover td{background:var(--est-bg-hover)}.est2 tbody tr.est2-row--selected td{background:var(--est-bg-selected)}.est2 tbody tr.est2-row--clickable{cursor:pointer;-webkit-user-select:none;user-select:none}.est2 tbody tr.est2-row--removed td{text-decoration:line-through;color:var(--est-fg-faint)}.est2 .est2-table--range tbody td[data-r]{cursor:cell}.est2 .est2-table--dragging,.est2 .est2-table--dragging tbody td{-webkit-user-select:none;user-select:none}.est2 tbody td.est2-cell-sel{background:color-mix(in srgb,var(--est-accent) 14%,transparent)}.est2 tbody td.est2-cell-sel-t{box-shadow:inset 0 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b{box-shadow:inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-l{box-shadow:inset 2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-r{box-shadow:inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-l{box-shadow:inset 2px 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-r{box-shadow:inset -2px 2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-l{box-shadow:inset 2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-r{box-shadow:inset -2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b{box-shadow:inset 0 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 0 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-l{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-r{box-shadow:inset -2px 2px 0 0 var(--est-accent),inset 0 -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-b.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px -2px 0 0 var(--est-accent),inset -2px 0 0 0 var(--est-accent)}.est2 tbody td.est2-cell-sel-t.est2-cell-sel-b.est2-cell-sel-l.est2-cell-sel-r{box-shadow:inset 2px 2px 0 0 var(--est-accent),inset -2px -2px 0 0 var(--est-accent)}.est2 tbody td.est2-cell-editing{padding:2px 6px}.est2 .est2-editor-input{width:100%;box-sizing:border-box;height:calc(var(--est-row-h) - 8px);padding:2px 6px;font:inherit;color:var(--est-fg);background:var(--est-bg);border:1.5px solid var(--est-accent);border-radius:var(--est-radius-sm);outline:none}.est2 .est2-editor-input:focus-visible{box-shadow:var(--est-ring)}.est2 input.est2-editor-input[type=checkbox]{width:16px;height:16px}.est2 .est2-autoupdate{display:flex;align-items:center;justify-content:flex-end;gap:12px;padding:4px 2px 8px;font-size:var(--est-fs-sm);color:var(--est-fg-muted)}.est2 .est2-autoupdate__label{display:inline-flex;align-items:center;gap:6px}.est2 .est2-autoupdate__secs{width:44px;text-align:center;padding:3px 4px;font:inherit;color:var(--est-fg);background:var(--est-bg);border:1px solid var(--est-border);border-radius:var(--est-radius-sm);outline:none}.est2 .est2-autoupdate__secs:focus-visible{box-shadow:var(--est-ring);border-color:var(--est-accent)}.est2 .est2-switch{position:relative;display:inline-flex;width:38px;height:20px;cursor:pointer}.est2 .est2-switch input{position:absolute;opacity:0;width:0;height:0}.est2 .est2-switch__slider{flex:1;border-radius:var(--est-radius-pill);background:var(--est-border-strong);transition:background var(--est-transition)}.est2 .est2-switch__slider:before{content:\"\";position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:#fff;box-shadow:0 1px 2px #00000040;transition:transform var(--est-transition)}.est2 .est2-switch input:checked+.est2-switch__slider{background:var(--est-accent)}.est2 .est2-switch input:checked+.est2-switch__slider:before{transform:translate(18px)}.est2 .est2-switch input:focus-visible+.est2-switch__slider{box-shadow:var(--est-ring)}.est2 .est2-toast{position:absolute;left:50%;bottom:14px;transform:translate(-50%);z-index:20;display:inline-flex;align-items:center;gap:8px;max-width:calc(100% - 24px);padding:8px 14px;font-size:13px;font-weight:500;color:#fff;background:#b91c1c;border-radius:var(--est-radius);box-shadow:0 6px 20px #00000040;animation:est2-toast-in .16s ease-out}.est2 .est2-toast svg{flex:0 0 auto}@keyframes est2-toast-in{0%{opacity:0;transform:translate(-50%,8px)}to{opacity:1;transform:translate(-50%)}}@media(prefers-reduced-motion:reduce){.est2 .est2-toast{animation:none}}.est2 tbody tr.est2-row--group{cursor:pointer;-webkit-user-select:none;user-select:none}.est2 tbody tr.est2-row--group td{background:var(--est-bg-subtle);font-weight:600;color:var(--est-fg);border-bottom:1px solid var(--est-border)}.est2 tbody tr.est2-row--group:hover td{background:var(--est-bg-hover)}.est2 .est2-td--group-key{color:var(--est-fg)}.est2 .est2-group-key{display:inline-flex;align-items:center;gap:6px}.est2 .est2-group-chevron{display:inline-flex;color:var(--est-fg-muted);transition:transform var(--est-transition)}.est2 .est2-group-chevron--open{transform:rotate(90deg)}.est2 .est2-hier-lead{display:inline-flex;align-items:center;vertical-align:middle;margin-right:4px}.est2 .est2-hier-toggle{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;flex:none}.est2 .est2-group-chevron.est2-hier-toggle{cursor:pointer;border-radius:var(--est-radius-sm);transition:transform var(--est-transition),background var(--est-transition),color var(--est-transition)}.est2 .est2-group-chevron.est2-hier-toggle:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 th.est2-th--orderable{cursor:pointer;transition:color var(--est-transition)}.est2 th.est2-th--orderable:hover{color:var(--est-fg)}.est2 .est2-th__inner{display:inline-flex;align-items:center;gap:6px}.est2 .est2-sort{display:inline-flex;width:14px;height:14px;opacity:.35;transition:opacity var(--est-transition),transform var(--est-transition)}.est2 .est2-sort--active{opacity:1;color:var(--est-accent)}.est2 .est2-sort--desc{transform:rotate(180deg)}.est2 .est2-sort__badge{font-size:9px;font-weight:700;color:var(--est-accent);margin-left:2px}.est2 .est2-check{appearance:none;width:16px;height:16px;border:1.5px solid var(--est-border-strong);border-radius:var(--est-radius-sm);background:var(--est-bg);cursor:pointer;position:relative;transition:border-color var(--est-transition),background var(--est-transition);vertical-align:middle;flex:none}.est2 .est2-check:hover{border-color:var(--est-accent)}.est2 .est2-check:checked{background:var(--est-accent);border-color:var(--est-accent)}.est2 .est2-check:checked:after{content:\"\";position:absolute;left:4.5px;top:1.5px;width:4px;height:8px;border:solid var(--est-accent-fg);border-width:0 2px 2px 0;transform:rotate(45deg)}.est2 .est2-check:focus-visible{outline:none;box-shadow:var(--est-ring)}.est2 .est2-check:indeterminate{background:var(--est-accent);border-color:var(--est-accent)}.est2 .est2-check:indeterminate:after{content:\"\";position:absolute;left:3px;top:6px;width:8px;height:2px;background:var(--est-accent-fg);transform:none;border:none}.est2 th.est2-col-min,.est2 td.est2-col-min{width:1%;white-space:nowrap}.est2 .est2-wrap{position:relative}.est2 .est2-selectbar{position:absolute;top:0;left:0;right:0;z-index:15;display:flex;align-items:center;gap:12px;padding:9px 14px;font-size:var(--est-fs-sm);color:var(--est-fg);background:var(--est-bg-subtle);border:none;border-radius:var(--est-radius) var(--est-radius) 0 0;box-shadow:inset 3px 0 0 var(--est-accent)}.est2 .est2-selectbar strong{color:var(--est-fg);font-weight:700}.est2 .est2-selectbar__spacer{flex:1 1 auto}.est2 .est2-link{color:var(--est-accent);cursor:pointer;font-weight:600}.est2 .est2-link:hover{text-decoration:underline}.est2 .est2-rowaction{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--est-radius-sm);border:none;background:transparent;color:var(--est-fg-faint);cursor:pointer;transition:background var(--est-transition),color var(--est-transition)}.est2 .est2-rowaction:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-rowaction--danger:hover{color:var(--est-danger)}.est2 .est2-op-cell{text-align:center}.est2 .est2-op{display:inline-flex;align-items:center;justify-content:center;min-width:26px;height:26px;padding:0 6px;border-radius:var(--est-radius-sm);color:var(--est-accent);cursor:pointer;font-size:var(--est-fs-sm);transition:background var(--est-transition)}.est2 .est2-op:hover{background:var(--est-accent-weak)}.est2 .est2-loading{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;gap:10px;background:color-mix(in srgb,var(--est-bg) 70%,transparent);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:5;color:var(--est-fg-muted);font-size:var(--est-fs-sm)}.est2 .est2-spinner{width:16px;height:16px;border:2px solid var(--est-border-strong);border-top-color:var(--est-accent);border-radius:50%;animation:est2-spin .7s linear infinite}@keyframes est2-spin{to{transform:rotate(360deg)}}.est2 .est2-nowrap{white-space:nowrap}.est2 .est2-cornermenu{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--est-radius-sm);cursor:pointer;color:var(--est-fg-muted);transition:background var(--est-transition)}.est2 .est2-cornermenu:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-chrome-th{position:relative}.est2 .est2-chrome{display:inline-flex;align-items:center;gap:2px}.est2 .est2-chrome-wrap{position:relative;display:inline-flex}.est2 .est2-chrome-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:none;background:transparent;border-radius:var(--est-radius-sm);color:var(--est-fg-muted);cursor:pointer;font-size:16px;line-height:1;transition:background var(--est-transition),color var(--est-transition)}.est2 .est2-chrome-btn:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-menu{position:absolute;top:calc(100% + 4px);right:0;z-index:30;min-width:180px;padding:4px;background:var(--est-bg);border:1px solid var(--est-border);border-radius:var(--est-radius);box-shadow:0 8px 24px #0000002e;display:flex;flex-direction:column}.est2 .est2-menu-item{display:block;width:100%;padding:8px 10px;border:none;background:transparent;text-align:left;font:inherit;color:var(--est-fg);border-radius:var(--est-radius-sm);cursor:pointer}.est2 .est2-menu-item:hover{background:var(--est-bg-hover)}.est2 .est2-dialog-backdrop{position:absolute;inset:0;z-index:40;display:flex;align-items:center;justify-content:center;padding:16px;background:color-mix(in srgb,#000 32%,transparent)}.est2 .est2-dialog{width:380px;max-width:100%;max-height:100%;display:flex;flex-direction:column;background:var(--est-bg);color:var(--est-fg);border:1px solid var(--est-border);border-radius:var(--est-radius);box-shadow:0 16px 48px #0000004d;overflow:hidden}.est2 .est2-dialog__head{display:flex;align-items:center;justify-content:space-between;padding:12px 14px;font-weight:700;border-bottom:1px solid var(--est-border)}.est2 .est2-dialog__close{border:none;background:transparent;cursor:pointer;color:var(--est-fg-muted);font-size:15px;line-height:1;padding:4px;border-radius:var(--est-radius-sm)}.est2 .est2-dialog__close:hover{background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-dialog__tools{padding:8px 14px;font-size:var(--est-fs-sm);border-bottom:1px solid var(--est-border)}.est2 .est2-dialog__tools .est2-link{border:none;background:none;padding:0;font:inherit;font-weight:600}.est2 .est2-dialog__sep{margin:0 6px;color:var(--est-fg-faint)}.est2 .est2-collist{list-style:none;margin:0;padding:6px;overflow-y:auto}.est2 .est2-collist__row{display:flex;align-items:center;gap:10px;padding:6px 8px;border-radius:var(--est-radius-sm)}.est2 .est2-collist__row:hover{background:var(--est-bg-hover)}.est2 .est2-collist__vis{display:inline-flex}.est2 .est2-collist__label{flex:1 1 auto}.est2 .est2-collist__ord{display:inline-flex;gap:4px}.est2 .est2-iconbtn{width:26px;height:26px;border:1px solid var(--est-border);background:var(--est-bg);border-radius:var(--est-radius-sm);color:var(--est-fg-muted);cursor:pointer}.est2 .est2-iconbtn:hover:not(:disabled){background:var(--est-bg-hover);color:var(--est-fg)}.est2 .est2-iconbtn:disabled{opacity:.4;cursor:default}.est2 .est2-dialog__foot{display:flex;align-items:center;gap:8px;padding:12px 14px;border-top:1px solid var(--est-border)}.est2 .est2-dialog__spacer{flex:1 1 auto}.est2 .est2-btn{padding:7px 14px;border-radius:var(--est-radius-sm);font:inherit;font-weight:600;cursor:pointer;border:1px solid transparent}.est2 .est2-btn--ghost{background:transparent;color:var(--est-fg);border-color:var(--est-border)}.est2 .est2-btn--ghost:hover{background:var(--est-bg-hover)}.est2 .est2-btn--primary{background:var(--est-accent);color:var(--est-accent-fg)}.est2 .est2-btn--primary:hover{filter:brightness(1.05)}.est2 .est2-empty{padding:48px 16px;text-align:center;color:var(--est-fg-faint);font-size:var(--est-fs-sm)}.ngx-contextmenu{--ctx-bg: #ffffff;--ctx-fg: #1a1d24;--ctx-muted: #626b7a;--ctx-border: #e6e9ef;--ctx-hover: #f2f4f7;--ctx-accent: #4f46e5;--ctx-shadow: 0 10px 28px -8px rgba(16, 24, 40, .22), 0 2px 8px -3px rgba(16, 24, 40, .14);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.ngx-contextmenu .dropdown-menu{display:block;min-width:200px;margin:0;padding:6px;list-style:none;background:var(--ctx-bg);border:1px solid var(--ctx-border);border-radius:12px;box-shadow:var(--ctx-shadow);animation:est2-ctx-in .12s cubic-bezier(.16,1,.3,1)}.ngx-contextmenu li{list-style:none;margin:0}.ngx-contextmenu li>a{display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:7px;color:var(--ctx-fg);font-size:13.5px;line-height:1.2;text-decoration:none;cursor:pointer;white-space:nowrap;transition:background .12s ease,color .12s ease}.ngx-contextmenu li>a:hover,.ngx-contextmenu li>a:focus{background:var(--ctx-hover);color:var(--ctx-fg);text-decoration:none;outline:none}.ngx-contextmenu li.divider,.ngx-contextmenu li[role=separator]{height:1px;margin:6px 8px;padding:0;background:var(--ctx-border)}.ngx-contextmenu li.disabled>a,.ngx-contextmenu li[aria-disabled=true]>a{color:var(--ctx-muted);opacity:.55;pointer-events:none}@media(prefers-color-scheme:dark){.ngx-contextmenu{--ctx-bg: #1e222b;--ctx-fg: #e7eaf0;--ctx-muted: #9aa3b2;--ctx-border: #2a2f3a;--ctx-hover: #232733;--ctx-accent: #7c74ff;--ctx-shadow: 0 12px 30px -8px rgba(0, 0, 0, .6), 0 2px 8px -3px rgba(0, 0, 0, .5)}}@keyframes est2-ctx-in{0%{opacity:0;transform:translateY(-4px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@media(prefers-reduced-motion:reduce){.ngx-contextmenu .dropdown-menu{animation:none}}\n"] }]
8374
8604
  }], ctorParameters: () => [{ type: i1.NgControl, decorators: [{
8375
8605
  type: Self
8376
8606
  }, {
@@ -8407,6 +8637,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
8407
8637
  }], editorDirectives: [{
8408
8638
  type: ContentChildren,
8409
8639
  args: [EsTdEditorDirective]
8640
+ }], thTdProviders: [{
8641
+ type: ContentChildren,
8642
+ args: [ThTdProvider]
8410
8643
  }], ContextMenu: [{
8411
8644
  type: Input
8412
8645
  }], tableEmptyMenu: [{
@@ -8419,7 +8652,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
8419
8652
  type: Input
8420
8653
  }], _HidePaging: [{ type: i0.Input, args: [{ isSignal: true, alias: "HidePaging", required: false }] }], _HidePagingCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "HidePagingCount", required: false }] }], _HidePagingButtons: [{ type: i0.Input, args: [{ isSignal: true, alias: "HidePagingButtons", required: false }] }], _AllSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "AllSearch", required: false }] }], _PagingStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "PagingStyle", required: false }] }], _ArraymodeItemsPerPage: [{ type: i0.Input, args: [{ isSignal: true, alias: "ArraymodeItemsPerPage", required: false }] }], _UseArrayModePaging: [{ type: i0.Input, args: [{ isSignal: true, alias: "UseArrayModePaging", required: false }] }], CountLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "CountLabel", required: false }] }], Height: [{ type: i0.Input, args: [{ isSignal: true, alias: "Height", required: false }] }], MaxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "MaxHeight", required: false }] }], EmptySpaceBackgroundColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "EmptySpaceBackgroundColor", required: false }] }], HighCellDensity: [{ type: i0.Input, args: [{ isSignal: true, alias: "HighCellDensity", required: false }] }], HeaderHidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "HeaderHidden", required: false }] }], BodyHidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "BodyHidden", required: false }] }], ShowLoadingOnBootstrap: [{ type: i0.Input, args: [{ isSignal: true, alias: "ShowLoadingOnBootstrap", required: false }] }], _DefaultAlignment: [{ type: i0.Input, args: [{ isSignal: true, alias: "DefaultAlignment", required: false }] }], _TableClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "TableClass", required: false }] }], _ContainerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "ContainerClass", required: false }] }], EsTableHandledSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "EsTableHandledSearch", required: false }] }], SearchThrottle: [{ type: i0.Input, args: [{ isSignal: true, alias: "SearchThrottle", required: false }] }], _ColumnsResizable: [{ type: i0.Input, args: [{ isSignal: true, alias: "ColumnsResizable", required: false }] }], _ColumnsPinnable: [{ type: i0.Input, args: [{ isSignal: true, alias: "ColumnsPinnable", required: false }] }], _HiddenColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "HiddenColumns", required: false }] }], _ColumnsOrdering: [{ type: i0.Input, args: [{ isSignal: true, alias: "ColumnsOrdering", required: false }] }], _Export: [{ type: i0.Input, args: [{ isSignal: true, alias: "Export", required: false }] }], XLSXExport: [{ type: i0.Input, args: [{ isSignal: true, alias: "XLSXExport", required: false }] }], CSVExport: [{ type: i0.Input, args: [{ isSignal: true, alias: "CSVExport", required: false }] }], ExportFileName: [{ type: i0.Input, args: [{ isSignal: true, alias: "ExportFileName", required: false }] }], ExportOnlyVisibleColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "ExportOnlyVisibleColumns", required: false }] }], ExportFunction: [{
8421
8654
  type: Input
8422
- }], CornerMenuOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "CornerMenuOptions", required: false }] }], DynamicOperations: [{ type: i0.Input, args: [{ isSignal: true, alias: "DynamicOperations", required: false }] }], _DynamicRowColumnsDefinition: [{ type: i0.Input, args: [{ isSignal: true, alias: "DynamicRowColumnsDefinition", required: false }] }], Hierarchy: [{ type: i0.Input, args: [{ isSignal: true, alias: "Hierarchy", required: false }] }], _ParentKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "ParentKey", required: false }] }], _OwnKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "OwnKey", required: false }] }], _AutoSortHierarchy: [{ type: i0.Input, args: [{ isSignal: true, alias: "AutoSortHierarchy", required: false }] }], StartsExpanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "StartsExpanded", required: false }] }], CascadeSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "CascadeSelection", required: false }] }], _SavePreferences: [{ type: i0.Input, args: [{ isSignal: true, alias: "SavePreferences", required: false }] }], Name: [{ type: i0.Input, args: [{ isSignal: true, alias: "Name", required: false }] }], _RowGroupingPagingStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "RowGroupingPagingStyle", required: false }] }], _ShowItemGroupsColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "ShowItemGroupsColumns", required: false }] }], Editable: [{ type: i0.Input, args: [{ isSignal: true, alias: "Editable", required: false }] }], RangeSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "RangeSelection", required: false }] }], ItemSourceProperty: [{ type: i0.Input, args: [{ isSignal: true, alias: "ItemSourceProperty", required: false }] }], HasHeaderGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "HasHeaderGroup", required: false }] }], HasSecondaryHeaderGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "HasSecondaryHeaderGroup", required: false }] }], SearchView: [{ type: i0.Input, args: [{ isSignal: true, alias: "SearchView", required: false }] }], _AutoUpdate: [{ type: i0.Input, args: [{ isSignal: true, alias: "AutoUpdate", required: false }] }], onOrderChanged: [{
8655
+ }], CornerMenuOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "CornerMenuOptions", required: false }] }], DynamicOperations: [{ type: i0.Input, args: [{ isSignal: true, alias: "DynamicOperations", required: false }] }], _DynamicRowColumnsDefinition: [{ type: i0.Input, args: [{ isSignal: true, alias: "DynamicRowColumnsDefinition", required: false }] }], Hierarchy: [{ type: i0.Input, args: [{ isSignal: true, alias: "Hierarchy", required: false }] }], _ParentKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "ParentKey", required: false }] }], _OwnKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "OwnKey", required: false }] }], _AutoSortHierarchy: [{ type: i0.Input, args: [{ isSignal: true, alias: "AutoSortHierarchy", required: false }] }], StartsExpanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "StartsExpanded", required: false }] }], CascadeSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "CascadeSelection", required: false }] }], _SavePreferences: [{ type: i0.Input, args: [{ isSignal: true, alias: "SavePreferences", required: false }] }], Name: [{ type: i0.Input, args: [{ isSignal: true, alias: "Name", required: false }] }], _RowGroupingPagingStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "RowGroupingPagingStyle", required: false }] }], _ShowItemGroupsColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "ShowItemGroupsColumns", required: false }] }], Editable: [{ type: i0.Input, args: [{ isSignal: true, alias: "Editable", required: false }] }], RangeSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "RangeSelection", required: false }] }], ItemSourceProperty: [{ type: i0.Input, args: [{ isSignal: true, alias: "ItemSourceProperty", required: false }] }], HasHeaderGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "HasHeaderGroup", required: false }] }], HasSecondaryHeaderGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "HasSecondaryHeaderGroup", required: false }] }], SearchView: [{ type: i0.Input, args: [{ isSignal: true, alias: "SearchView", required: false }] }], _AutoUpdate: [{ type: i0.Input, args: [{ isSignal: true, alias: "AutoUpdate", required: false }] }], EsThTdProvider: [{
8656
+ type: Input
8657
+ }], onOrderChanged: [{
8423
8658
  type: Output
8424
8659
  }], onSearchRequest: [{
8425
8660
  type: Output